xref: /illumos-gate/usr/src/lib/libnwam/common/libnwam_loc.c (revision 6b1abd46bd2c746d42947df930a0a3a632f81256)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <assert.h>
28 #include <ctype.h>
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <unistd.h>
36 #include <libscf.h>
37 
38 #include "libnwam_impl.h"
39 #include <libnwam_priv.h>
40 #include <libnwam.h>
41 
42 /*
43  * Functions to support creating, modifying, destroying, querying the
44  * state of and changing the state of location objects. Locations
45  * represent the configuration to be applied once basic network configuration
46  * has been established - name services, IPsec config, etc, and can be enabled
47  * either manually or conditionally for a combination of the set of
48  * available conditions (an IP address is present, an ENM is active etc).
49  */
50 
51 #define	NSSWITCH_PREFIX		"/etc/nsswitch."
52 
53 typedef nwam_error_t (*nwam_loc_prop_validate_func_t)(nwam_value_t);
54 
55 static nwam_error_t valid_loc_activation_mode(nwam_value_t);
56 static nwam_error_t valid_loc_condition(nwam_value_t);
57 static nwam_error_t valid_nameservices(nwam_value_t);
58 static nwam_error_t valid_configsrc(nwam_value_t);
59 
60 struct nwam_prop_table_entry loc_prop_table_entries[] = {
61 	{NWAM_LOC_PROP_ACTIVATION_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1,
62 	    valid_loc_activation_mode,
63 	    "specifies the location activation mode - valid values are:\n"
64 	    "\'manual\', \'conditional-any\' and \'conditional-all\'",
65 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
66 	{NWAM_LOC_PROP_CONDITIONS, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
67 	    NWAM_MAX_NUM_VALUES, valid_loc_condition,
68 	    "specifies the activation condition. Conditions are of the form:\n"
69 	    "ncp|ncu|enm name is|is-not active\n"
70 	    "ip-address is|is-not|is-in-range|is-not-in-range| 1.2.3.4[/24]\n"
71 	    "advertised-domain is|is-not|contains|does-not-contain string\n"
72 	    "system-domain is|is-not|contains|does-not-contain string\n"
73 	    "essid is|is-not|contains|does-not-contain string\n"
74 	    "bssid is|is-not string",
75 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
76 	{NWAM_LOC_PROP_ENABLED, NWAM_VALUE_TYPE_BOOLEAN, B_TRUE, 1, 1,
77 	    nwam_valid_boolean,
78 	    "specifies if location is to be enabled",
79 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
80 	{NWAM_LOC_PROP_NAMESERVICES, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1,
81 	    NWAM_MAX_NUM_VALUES, valid_nameservices,
82 	    "specifies name service(s) to be used - valid values are:\n"
83 	    "\'files\', \'dns\', \'nis\', and \'ldap\'",
84 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
85 	{NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE, NWAM_VALUE_TYPE_STRING,
86 	    B_FALSE, 0, 1, nwam_valid_file,
87 	    "specifies path to configuration file for name services switch "
88 	    "for this location - see nsswitch.conf(4)",
89 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
90 	{NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, NWAM_VALUE_TYPE_UINT64,
91 	    B_FALSE, 0, NWAM_MAX_NUM_VALUES, valid_configsrc,
92 	    "specifies sources of DNS configuration parameters - valid values "
93 	    "are:\n\'dhcp\', or \'manual\'",
94 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
95 	{NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN, NWAM_VALUE_TYPE_STRING, B_FALSE,
96 	    0, 1, nwam_valid_domain,
97 	    "specifies DNS domain name to be set for this location",
98 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
99 	{NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS, NWAM_VALUE_TYPE_STRING, B_FALSE,
100 	    0, NWAM_MAX_NUM_VALUES, nwam_valid_host_any,
101 	    "specifies DNS server host address(es)",
102 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
103 	{NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH, NWAM_VALUE_TYPE_STRING, B_FALSE,
104 	    0, NWAM_MAX_NUM_VALUES, nwam_valid_domain,
105 	    "specifies DNS search list for host name lookup",
106 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
107 	{NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC, NWAM_VALUE_TYPE_UINT64,
108 	    B_FALSE, 0, NWAM_MAX_NUM_VALUES, valid_configsrc,
109 	    "specifies sources of NIS configuration parameters - valid values "
110 	    "are:\n\'dhcp\', or \'manual\'",
111 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
112 	{NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS, NWAM_VALUE_TYPE_STRING, B_FALSE,
113 	    0, NWAM_MAX_NUM_VALUES, nwam_valid_host_any,
114 	    "specifies NIS server host address(es)",
115 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
116 	{NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, NWAM_VALUE_TYPE_UINT64,
117 	    B_FALSE, 0, NWAM_MAX_NUM_VALUES, valid_configsrc,
118 	    "specifies sources of NIS configuration parameters - currently, "
119 	    "the only valid value is \'manual\'",
120 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
121 	{NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS, NWAM_VALUE_TYPE_STRING,
122 	    B_FALSE, 0, NWAM_MAX_NUM_VALUES, nwam_valid_host_or_domain,
123 	    "specifies LDAP server host address(es)",
124 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
125 	{NWAM_LOC_PROP_DEFAULT_DOMAIN, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 1,
126 	    nwam_valid_domain,
127 	    "specifies the domainname(1M) to be set for this location",
128 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
129 	{NWAM_LOC_PROP_NFSV4_DOMAIN, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 1,
130 	    nwam_valid_domain,
131 	    "specifies an NFSv4 domain for this location",
132 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
133 	{NWAM_LOC_PROP_IPFILTER_CONFIG_FILE, NWAM_VALUE_TYPE_STRING, B_FALSE,
134 	    0, 1, nwam_valid_file,
135 	    "specifies an absolute path to an ipf.conf(4) file for this "
136 	    "location",
137 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
138 	{NWAM_LOC_PROP_IPFILTER_V6_CONFIG_FILE, NWAM_VALUE_TYPE_STRING,
139 	    B_FALSE, 0, 1, nwam_valid_file,
140 	    "specifies an absolute path to an ipf6.conf file for this "
141 	    "location",
142 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
143 	{NWAM_LOC_PROP_IPNAT_CONFIG_FILE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
144 	    1, nwam_valid_file,
145 	    "specifies an absolute path to an ipnat.conf(4) file for this "
146 	    "location",
147 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
148 	{NWAM_LOC_PROP_IPPOOL_CONFIG_FILE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
149 	    1, nwam_valid_file,
150 	    "specifies an absolute path to an ippool.conf(4) file for this "
151 	    "location",
152 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
153 	{NWAM_LOC_PROP_IKE_CONFIG_FILE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 1,
154 	    nwam_valid_file,
155 	    "specifies an absolute path to an ike config file "
156 	    "(see ike.config(4))",
157 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
158 	{NWAM_LOC_PROP_IPSECPOLICY_CONFIG_FILE, NWAM_VALUE_TYPE_STRING,
159 	    B_FALSE, 0, 1, nwam_valid_file,
160 	    "specifies an absolute path to an IPsec policy configuration file "
161 	    "(see ipsecconf(1M)",
162 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
163 };
164 
165 #define	NWAM_NUM_LOC_PROPS	(sizeof (loc_prop_table_entries) / \
166 				sizeof (*loc_prop_table_entries))
167 
168 struct nwam_prop_table loc_prop_table =
169 	{ NWAM_NUM_LOC_PROPS, loc_prop_table_entries };
170 
171 static uint64_t
172 nwam_loc_activation_to_flag(nwam_activation_mode_t activation)
173 {
174 	switch (activation) {
175 	case NWAM_ACTIVATION_MODE_MANUAL:
176 		return (NWAM_FLAG_ACTIVATION_MODE_MANUAL);
177 	case NWAM_ACTIVATION_MODE_SYSTEM:
178 		return (NWAM_FLAG_ACTIVATION_MODE_SYSTEM);
179 	case NWAM_ACTIVATION_MODE_CONDITIONAL_ANY:
180 		return (NWAM_FLAG_ACTIVATION_MODE_CONDITIONAL_ANY);
181 	case NWAM_ACTIVATION_MODE_CONDITIONAL_ALL:
182 		return (NWAM_FLAG_ACTIVATION_MODE_CONDITIONAL_ALL);
183 	default:
184 		return (0);
185 	}
186 }
187 
188 nwam_error_t
189 nwam_loc_read(const char *name, uint64_t flags, nwam_loc_handle_t *lochp)
190 {
191 	return (nwam_read(NWAM_OBJECT_TYPE_LOC, NWAM_LOC_CONF_FILE, name,
192 	    flags, lochp));
193 }
194 
195 nwam_error_t
196 nwam_loc_create(const char *name, nwam_loc_handle_t *lochp)
197 {
198 	nwam_error_t err;
199 	nwam_value_t val = NULL;
200 	char *nsswitch = NULL;
201 
202 	assert(lochp != NULL && name != NULL);
203 
204 	if ((err = nwam_create(NWAM_OBJECT_TYPE_LOC, NWAM_LOC_CONF_FILE, name,
205 	    lochp)) != NWAM_SUCCESS)
206 		return (err);
207 
208 	/* Create new object list for loc */
209 	if ((err = nwam_alloc_object_list(&((*lochp)->nwh_data)))
210 	    != NWAM_SUCCESS)
211 		goto finish;
212 
213 	/* NWAM_LOC_PROP_ACTIVATION_MODE is mandatory */
214 	if ((err = nwam_value_create_uint64(NWAM_ACTIVATION_MODE_MANUAL, &val))
215 	    != NWAM_SUCCESS) {
216 		goto finish;
217 	}
218 	if ((err = nwam_set_prop_value((*lochp)->nwh_data,
219 	    NWAM_LOC_PROP_ACTIVATION_MODE, val)) != NWAM_SUCCESS) {
220 		goto finish;
221 	}
222 	nwam_value_free(val);
223 	val = NULL;
224 
225 	/*
226 	 * NWAM_LOC_PROP_ENABLED defaults to false.
227 	 */
228 	if ((err = nwam_value_create_boolean(B_FALSE, &val)) != NWAM_SUCCESS)
229 		goto finish;
230 	if ((err = nwam_set_prop_value((*lochp)->nwh_data,
231 	    NWAM_LOC_PROP_ENABLED, val)) != NWAM_SUCCESS)
232 		goto finish;
233 	nwam_value_free(val);
234 	val = NULL;
235 
236 	/*
237 	 * Initialize name service properties: use DNS, configured
238 	 * via DHCP, with default nsswitch (/etc/nsswitch.dns).
239 	 */
240 	if ((err = nwam_value_create_uint64(NWAM_NAMESERVICES_DNS, &val)) !=
241 	    NWAM_SUCCESS)
242 		goto finish;
243 	if ((err = nwam_set_prop_value((*lochp)->nwh_data,
244 	    NWAM_LOC_PROP_NAMESERVICES, val)) != NWAM_SUCCESS)
245 		goto finish;
246 	nwam_value_free(val);
247 	val = NULL;
248 
249 	if ((err = nwam_value_create_uint64(NWAM_CONFIGSRC_DHCP, &val)) !=
250 	    NWAM_SUCCESS)
251 		goto finish;
252 	if ((err = nwam_set_prop_value((*lochp)->nwh_data,
253 	    NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, val)) != NWAM_SUCCESS)
254 		goto finish;
255 	nwam_value_free(val);
256 	val = NULL;
257 
258 	/* concatenate these two strings */
259 	nsswitch = strdup(NSSWITCH_PREFIX NWAM_NAMESERVICES_DNS_STRING);
260 	if (nsswitch == NULL) {
261 		err = NWAM_NO_MEMORY;
262 		goto finish;
263 	}
264 	if ((err = nwam_value_create_string(nsswitch, &val)) != NWAM_SUCCESS)
265 		goto finish;
266 	err = nwam_set_prop_value((*lochp)->nwh_data,
267 	    NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE, val);
268 
269 finish:
270 	if (nsswitch != NULL)
271 		free(nsswitch);
272 	if (val != NULL)
273 		nwam_value_free(val);
274 	if (err != NWAM_SUCCESS) {
275 		nwam_loc_free(*lochp);
276 		*lochp = NULL;
277 	}
278 	return (err);
279 }
280 
281 nwam_error_t
282 nwam_loc_get_name(nwam_loc_handle_t loch, char **namep)
283 {
284 	return (nwam_get_name(loch, namep));
285 }
286 
287 nwam_error_t
288 nwam_loc_set_name(nwam_loc_handle_t loch, const char *name)
289 {
290 	return (nwam_set_name(loch, name));
291 }
292 
293 boolean_t
294 nwam_loc_can_set_name(nwam_loc_handle_t loch)
295 {
296 	return (!loch->nwh_committed);
297 }
298 
299 /* ARGSUSED2 */
300 static int
301 loc_selectcb(struct nwam_handle *hp, uint64_t flags, void *data)
302 {
303 	nwam_loc_handle_t loch = hp;
304 	char *locname;
305 	uint64_t activation, actflag, walkfilter;
306 	nwam_value_t activationval;
307 
308 	/* Skip the Legacy location in all cases */
309 	if (nwam_loc_get_name(loch, &locname) != NWAM_SUCCESS)
310 		return (NWAM_INVALID_ARG);
311 	if (strcmp(locname, NWAM_LOC_NAME_LEGACY) == 0) {
312 		free(locname);
313 		return (NWAM_INVALID_ARG);
314 	}
315 	free(locname);
316 
317 	/*
318 	 * Get a bitmapped flag value corresponding to this loc's
319 	 * activation.
320 	 */
321 	if (nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_ACTIVATION_MODE,
322 	    &activationval) != NWAM_SUCCESS) {
323 		return (NWAM_INVALID_ARG);
324 	}
325 	if (nwam_value_get_uint64(activationval, &activation) != NWAM_SUCCESS) {
326 		nwam_value_free(activationval);
327 		return (NWAM_INVALID_ARG);
328 	}
329 
330 	actflag = nwam_loc_activation_to_flag(activation);
331 	nwam_value_free(activationval);
332 	if ((walkfilter = (flags & NWAM_WALK_FILTER_MASK)) == 0)
333 		walkfilter = NWAM_FLAG_ACTIVATION_MODE_ALL;
334 	if (actflag & walkfilter)
335 		return (NWAM_SUCCESS);
336 	return (NWAM_INVALID_ARG);
337 }
338 
339 nwam_error_t
340 nwam_walk_locs(int(*cb)(nwam_loc_handle_t, void *), void *data, uint64_t flags,
341     int *retp)
342 {
343 	nwam_error_t err = nwam_valid_flags(flags,
344 	    NWAM_FLAG_ACTIVATION_MODE_ALL | NWAM_FLAG_BLOCKING);
345 
346 	if (err != NWAM_SUCCESS)
347 		return (err);
348 
349 	return (nwam_walk(NWAM_OBJECT_TYPE_LOC, NWAM_LOC_CONF_FILE,
350 	    cb, data, flags, retp, loc_selectcb));
351 }
352 
353 void
354 nwam_loc_free(nwam_loc_handle_t loch)
355 {
356 	nwam_free(loch);
357 }
358 
359 nwam_error_t
360 nwam_loc_delete_prop(nwam_loc_handle_t loch, const char *propname)
361 {
362 	nwam_error_t err;
363 	boolean_t ro;
364 	void *olddata;
365 
366 	assert(loch != NULL && propname != NULL);
367 
368 	if ((err = nwam_loc_prop_read_only(propname, &ro)) != NWAM_SUCCESS)
369 		return (err);
370 	if (ro)
371 		return (NWAM_ENTITY_READ_ONLY);
372 
373 	/*
374 	 * Duplicate data, remove property and validate. If validation
375 	 * fails, revert to data duplicated prior to remove.
376 	 */
377 	if ((err = nwam_dup_object_list(loch->nwh_data, &olddata))
378 	    != NWAM_SUCCESS)
379 		return (err);
380 	if ((err = nwam_delete_prop(loch->nwh_data, propname))
381 	    != NWAM_SUCCESS) {
382 		nwam_free_object_list(loch->nwh_data);
383 		loch->nwh_data = olddata;
384 		return (err);
385 	}
386 	if ((err = nwam_loc_validate(loch, NULL)) != NWAM_SUCCESS) {
387 		nwam_free_object_list(loch->nwh_data);
388 		loch->nwh_data = olddata;
389 		return (err);
390 	}
391 	nwam_free_object_list(olddata);
392 
393 	return (NWAM_SUCCESS);
394 }
395 
396 nwam_error_t
397 nwam_loc_set_prop_value(nwam_loc_handle_t loch, const char *propname,
398     nwam_value_t value)
399 {
400 	nwam_error_t err;
401 	boolean_t ro;
402 
403 	assert(loch != NULL && propname != NULL && value  != NULL);
404 
405 	if ((err = nwam_loc_validate_prop(loch, propname, value))
406 	    != NWAM_SUCCESS ||
407 	    (err = nwam_loc_prop_read_only(propname, &ro)) != NWAM_SUCCESS)
408 		return (err);
409 	if (ro)
410 		return (NWAM_ENTITY_READ_ONLY);
411 
412 	return (nwam_set_prop_value(loch->nwh_data, propname, value));
413 }
414 
415 nwam_error_t
416 nwam_loc_get_prop_value(nwam_loc_handle_t loch, const char *propname,
417     nwam_value_t *valuep)
418 {
419 	return (nwam_get_prop_value(loch->nwh_data, propname, valuep));
420 }
421 
422 nwam_error_t
423 nwam_loc_walk_props(nwam_loc_handle_t loch,
424     int (*cb)(const char *, nwam_value_t, void *),
425     void *data, uint64_t flags, int *retp)
426 {
427 	return (nwam_walk_props(loch, cb, data, flags, retp));
428 }
429 
430 nwam_error_t
431 nwam_loc_commit(nwam_loc_handle_t loch, uint64_t flags)
432 {
433 	nwam_error_t err;
434 
435 	assert(loch != NULL && loch->nwh_data != NULL);
436 
437 	if ((err = nwam_loc_validate(loch, NULL)) != NWAM_SUCCESS)
438 		return (err);
439 
440 	return (nwam_commit(NWAM_LOC_CONF_FILE, loch, flags));
441 }
442 
443 nwam_error_t
444 nwam_loc_destroy(nwam_loc_handle_t loch, uint64_t flags)
445 {
446 	nwam_error_t err;
447 	nwam_value_t actval;
448 	uint64_t activation;
449 
450 	/*
451 	 * Automatic and NoNet are not destroyable and Legacy is
452 	 * destroyable by netadm only.  These have system activation-mode.
453 	 */
454 	if ((err = nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_ACTIVATION_MODE,
455 	    &actval)) != NWAM_SUCCESS)
456 		return (err);
457 	err = nwam_value_get_uint64(actval, &activation);
458 	nwam_value_free(actval);
459 	if (err != NWAM_SUCCESS)
460 		return (err);
461 
462 	if (activation == NWAM_ACTIVATION_MODE_SYSTEM) {
463 		if (strcmp(loch->nwh_name, NWAM_LOC_NAME_LEGACY) == 0) {
464 			if (!nwam_uid_is_netadm())
465 				return (NWAM_ENTITY_NOT_DESTROYABLE);
466 		} else {
467 			return (NWAM_ENTITY_NOT_DESTROYABLE);
468 		}
469 	}
470 
471 	return (nwam_destroy(NWAM_LOC_CONF_FILE, loch, flags));
472 }
473 
474 nwam_error_t
475 nwam_loc_get_prop_description(const char *propname, const char **descriptionp)
476 {
477 	return (nwam_get_prop_description(loc_prop_table, propname,
478 	    descriptionp));
479 }
480 
481 nwam_error_t
482 nwam_loc_prop_read_only(const char *propname, boolean_t *readp)
483 {
484 	return (nwam_prop_read_only(loc_prop_table, propname, readp));
485 }
486 
487 static nwam_error_t
488 valid_loc_activation_mode(nwam_value_t value)
489 {
490 	uint64_t activation_mode;
491 
492 	if (nwam_value_get_uint64(value, &activation_mode) != NWAM_SUCCESS)
493 		return (NWAM_ENTITY_INVALID_VALUE);
494 
495 	switch (activation_mode) {
496 	case NWAM_ACTIVATION_MODE_MANUAL:
497 	case NWAM_ACTIVATION_MODE_SYSTEM:
498 	case NWAM_ACTIVATION_MODE_CONDITIONAL_ANY:
499 	case NWAM_ACTIVATION_MODE_CONDITIONAL_ALL:
500 		return (NWAM_SUCCESS);
501 	}
502 	return (NWAM_ENTITY_INVALID_VALUE);
503 }
504 
505 /*
506  * Identical to nwam_valid_condition(), except locations cannot specify other
507  * location's activation as a condition, e.g. loc2 cannot specify
508  * "loc1 is active" since only one location is active at a time, and
509  * as a consequence the condition is unsatisfiable.
510  */
511 nwam_error_t
512 valid_loc_condition(nwam_value_t value)
513 {
514 	char **conditions;
515 	uint_t i, numvalues;
516 	nwam_condition_object_type_t object_type;
517 	nwam_condition_t condition;
518 
519 	if (nwam_value_get_string_array(value, &conditions, &numvalues)
520 	    != NWAM_SUCCESS)
521 		return (NWAM_ENTITY_INVALID_VALUE);
522 
523 	for (i = 0; i < numvalues; i++) {
524 		char *object_name = NULL;
525 
526 		if (nwam_condition_string_to_condition(conditions[i],
527 		    &object_type, &condition, &object_name) != NWAM_SUCCESS)
528 			return (NWAM_ENTITY_INVALID_VALUE);
529 		if (object_type == NWAM_CONDITION_OBJECT_TYPE_LOC &&
530 		    condition == NWAM_CONDITION_IS) {
531 			free(object_name);
532 			return (NWAM_ENTITY_INVALID_VALUE);
533 		}
534 		if (object_name != NULL)
535 			free(object_name);
536 	}
537 	return (NWAM_SUCCESS);
538 }
539 
540 static nwam_error_t
541 valid_nameservices(nwam_value_t value)
542 {
543 	uint64_t *nameservices;
544 	uint_t i, numvalues;
545 
546 	if (nwam_value_get_uint64_array(value, &nameservices, &numvalues)
547 	    != NWAM_SUCCESS)
548 		return (NWAM_ENTITY_INVALID_VALUE);
549 
550 	for (i = 0; i < numvalues; i++) {
551 		if (nameservices[i] > NWAM_NAMESERVICES_LDAP)
552 			return (NWAM_ENTITY_INVALID_VALUE);
553 	}
554 	return (NWAM_SUCCESS);
555 }
556 
557 static nwam_error_t
558 valid_configsrc(nwam_value_t value)
559 {
560 	uint64_t *configsrcs;
561 	uint_t i, numvalues;
562 
563 	if (nwam_value_get_uint64_array(value, &configsrcs, &numvalues)
564 	    != NWAM_SUCCESS)
565 		return (NWAM_ENTITY_INVALID_VALUE);
566 
567 	for (i = 0; i < numvalues; i++) {
568 		if (configsrcs[i] > NWAM_CONFIGSRC_DHCP)
569 			return (NWAM_ENTITY_INVALID_VALUE);
570 	}
571 	return (NWAM_SUCCESS);
572 }
573 
574 /*
575  * Validates that the activation-mode is system for Automatic and NoNet
576  * locations, and not system for all other locations.
577  */
578 static nwam_error_t
579 nwam_loc_validate_activation_mode(nwam_loc_handle_t loch, nwam_value_t actval)
580 {
581 	nwam_error_t err;
582 	uint64_t activation;
583 
584 	if ((err = nwam_value_get_uint64(actval, &activation)) != NWAM_SUCCESS)
585 		return (err);
586 
587 	if (NWAM_LOC_NAME_PRE_DEFINED(loch->nwh_name)) {
588 		if (activation != NWAM_ACTIVATION_MODE_SYSTEM)
589 			return (NWAM_ENTITY_INVALID_VALUE);
590 	} else {
591 		if (activation == NWAM_ACTIVATION_MODE_SYSTEM)
592 			return (NWAM_ENTITY_INVALID_VALUE);
593 	}
594 	return (NWAM_SUCCESS);
595 }
596 
597 /*
598  * Helper function to validate one nameservice, used by
599  * nwam_loc_validate_all_nameservices().
600  *
601  * requiredprop denotes the property that is mandatory when the
602  * configsrcprop is manual.  errpropp is used to return the invalid
603  * property.
604  */
605 static nwam_error_t
606 nwam_loc_validate_one_nameservice(nwam_loc_handle_t loch,
607     const char *configsrcprop, const char *requiredprop, const char **errpropp)
608 {
609 	nwam_value_t configsrcval, requiredval;
610 	uint64_t *configsrcs;
611 	uint_t i, numvalues;
612 
613 	if (nwam_loc_get_prop_value(loch, configsrcprop, &configsrcval)
614 	    != NWAM_SUCCESS) {
615 		if (errpropp != NULL)
616 			*errpropp = configsrcprop;
617 		return (NWAM_ENTITY_MISSING_MEMBER);
618 	}
619 
620 	if (nwam_value_get_uint64_array(configsrcval, &configsrcs, &numvalues)
621 	    != NWAM_SUCCESS) {
622 		if (errpropp != NULL)
623 			*errpropp = configsrcprop;
624 		nwam_value_free(configsrcval);
625 		return (NWAM_ENTITY_NO_VALUE);
626 	}
627 
628 	/* If -configsrc is manual, requiredprop is required */
629 	for (i = 0; i < numvalues; i++) {
630 		if (configsrcs[i] == NWAM_CONFIGSRC_MANUAL) {
631 			if (nwam_loc_get_prop_value(loch, requiredprop,
632 			    &requiredval) != NWAM_SUCCESS) {
633 				if (errpropp != NULL)
634 					*errpropp = requiredprop;
635 				return (NWAM_ENTITY_MISSING_MEMBER);
636 			}
637 			nwam_value_free(requiredval);
638 		}
639 	}
640 	nwam_value_free(configsrcval);
641 
642 	return (NWAM_SUCCESS);
643 }
644 
645 /*
646  * Helper function to validate LDAP nameservice, used by
647  * nwam_loc_validate_all_nameservices().  Separated because LDAP must be
648  * configured manually only and both default-domain and -servers are required.
649  */
650 static nwam_error_t
651 nwam_loc_validate_ldap_nameservice(nwam_loc_handle_t loch,
652     const char **errpropp)
653 {
654 	nwam_value_t val;
655 	uint64_t *configsrcs;
656 	uint_t i, numvalues;
657 
658 	if (nwam_loc_get_prop_value(loch,
659 	    NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, &val) != NWAM_SUCCESS) {
660 		if (errpropp != NULL)
661 			*errpropp = NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC;
662 		return (NWAM_ENTITY_MISSING_MEMBER);
663 	}
664 	/* -configsrc is defined as an array */
665 	if (nwam_value_get_uint64_array(val, &configsrcs, &numvalues)
666 	    != NWAM_SUCCESS) {
667 		if (errpropp != NULL)
668 			*errpropp = NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC;
669 		nwam_value_free(val);
670 		return (NWAM_ENTITY_NO_VALUE);
671 	}
672 
673 	/* -configsrc must be manual */
674 	for (i = 0; i < numvalues; i++) {
675 		if (configsrcs[i] != NWAM_CONFIGSRC_MANUAL) {
676 			if (errpropp != NULL)
677 				*errpropp =
678 				    NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC;
679 			nwam_value_free(val);
680 			return (NWAM_ENTITY_INVALID_VALUE);
681 		}
682 	}
683 	nwam_value_free(val);
684 
685 	/* both default-domain and -servers are required */
686 	if (nwam_loc_get_prop_value(loch,
687 	    NWAM_LOC_PROP_DEFAULT_DOMAIN, &val) != NWAM_SUCCESS) {
688 		if (errpropp != NULL)
689 			*errpropp = NWAM_LOC_PROP_DEFAULT_DOMAIN;
690 		return (NWAM_ENTITY_MISSING_MEMBER);
691 	}
692 	nwam_value_free(val);
693 
694 	if (nwam_loc_get_prop_value(loch,
695 	    NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS, &val) != NWAM_SUCCESS) {
696 		if (errpropp != NULL)
697 			*errpropp = NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS;
698 		return (NWAM_ENTITY_MISSING_MEMBER);
699 	}
700 	nwam_value_free(val);
701 
702 	return (NWAM_SUCCESS);
703 }
704 
705 /*
706  * Validates the different nameservices properties.
707  *
708  * If "nameservices" property has more than one nameservice to configure,
709  * "nameservices-config-file" must be specified.  If only one nameservice
710  * is configured and "nameservices-config-file" is missing, set the
711  * property with the appropriately suffixed nsswitch file.
712  *
713  * For any nameservice being configured, the respective -configsrc property
714  * must be specified.  For DNS, -servers is required if -configsrc is
715  * manual.  For NIS and LDAP, default-domain is required if -configsrc is
716  * manual.  For LDAP, -configsrc must be manual and -servers is required.
717  */
718 static nwam_error_t
719 nwam_loc_validate_all_nameservices(nwam_loc_handle_t loch,
720     nwam_value_t nameservicesval, const char **errpropp)
721 {
722 	nwam_error_t err;
723 	nwam_value_t val;
724 	uint64_t *nameservices;
725 	uint_t i, numvalues;
726 
727 	if ((err = nwam_value_get_uint64_array(nameservicesval, &nameservices,
728 	    &numvalues)) != NWAM_SUCCESS)
729 		return (err);
730 
731 	/*
732 	 * nameservices-config-file is required if nameservices has more
733 	 * than one value.
734 	 */
735 	if (numvalues > 1) {
736 		if (nwam_loc_get_prop_value(loch,
737 		    NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE, &val)
738 		    != NWAM_SUCCESS) {
739 			if (errpropp != NULL)
740 				*errpropp =
741 				    NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE;
742 			return (NWAM_ENTITY_MISSING_MEMBER);
743 		}
744 		nwam_value_free(val);
745 	} else if (numvalues == 1) {
746 		/*
747 		 * If only one nameservice is being configured and
748 		 * nameservices-config-file doesn't exist, create it to
749 		 * point to the respective nsswitch file.
750 		 */
751 		err = nwam_loc_get_prop_value(loch,
752 		    NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE, &val);
753 		if (err == NWAM_INVALID_ARG || err == NWAM_ENTITY_NOT_FOUND) {
754 			char *nsswitch;
755 			const char *nsswitch_suffix;
756 
757 			/* get the single nameservice being configured */
758 			if ((err = nwam_uint64_get_value_string(
759 			    NWAM_LOC_PROP_NAMESERVICES, nameservices[0],
760 			    &nsswitch_suffix)) != NWAM_SUCCESS)
761 				goto config_file_fail;
762 			if ((nsswitch = malloc(MAXPATHLEN)) == NULL) {
763 				err = NWAM_NO_MEMORY;
764 				goto config_file_fail;
765 			}
766 
767 			/* create appropriately suffixed nsswitch name */
768 			(void) snprintf(nsswitch, MAXPATHLEN, "%s%s",
769 			    NSSWITCH_PREFIX, nsswitch_suffix);
770 			if ((err = nwam_value_create_string(nsswitch, &val))
771 			    != NWAM_SUCCESS) {
772 				free(nsswitch);
773 				goto config_file_fail;
774 			}
775 
776 			err = nwam_set_prop_value(loch->nwh_data,
777 			    NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE, val);
778 			free(nsswitch);
779 			nwam_value_free(val);
780 			if (err != NWAM_SUCCESS) {
781 				nwam_value_free(val);
782 				goto config_file_fail;
783 			}
784 		} else if (err != NWAM_SUCCESS) {
785 			goto config_file_fail;
786 		} else {
787 			nwam_value_free(val);
788 		}
789 	}
790 
791 	/*
792 	 * validate the -configsrc property and the required default-domain
793 	 * and/or -servers property for each nameservice being configured.
794 	 */
795 	for (i = 0; i < numvalues; i++) {
796 		switch (nameservices[i]) {
797 		case NWAM_NAMESERVICES_DNS:
798 			if ((err = nwam_loc_validate_one_nameservice(loch,
799 			    NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
800 			    NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS, errpropp))
801 			    != NWAM_SUCCESS)
802 				return (err);
803 			break;
804 		case NWAM_NAMESERVICES_NIS:
805 			if ((err = nwam_loc_validate_one_nameservice(loch,
806 			    NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC,
807 			    NWAM_LOC_PROP_DEFAULT_DOMAIN, errpropp))
808 			    != NWAM_SUCCESS)
809 				return (err);
810 			break;
811 		case NWAM_NAMESERVICES_LDAP:
812 			if ((err = nwam_loc_validate_ldap_nameservice(loch,
813 			    errpropp)) != NWAM_SUCCESS)
814 				return (err);
815 			break;
816 		case NWAM_NAMESERVICES_FILES:
817 			break;
818 		default:
819 			return (NWAM_ENTITY_INVALID_VALUE);
820 		}
821 	}
822 	return (NWAM_SUCCESS);
823 
824 config_file_fail:
825 	if (errpropp != NULL)
826 		*errpropp =  NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE;
827 	return (err);
828 }
829 
830 nwam_error_t
831 nwam_loc_validate(nwam_loc_handle_t loch, const char **errpropp)
832 {
833 	nwam_error_t err;
834 	nwam_value_t activationval, conditionval, nameservicesval;
835 	uint64_t activation;
836 	char **conditions, *name;
837 	uint_t i, numvalues;
838 	nwam_condition_object_type_t object_type;
839 	nwam_condition_t condition;
840 
841 	assert(loch != NULL);
842 
843 	/*
844 	 * Make sure loc is internally consistent: if activation type is
845 	 * conditional, the condition string must be specified.
846 	 */
847 	if (nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_ACTIVATION_MODE,
848 	    &activationval) != NWAM_SUCCESS) {
849 		if (errpropp != NULL)
850 			*errpropp = NWAM_LOC_PROP_ACTIVATION_MODE;
851 		return (NWAM_ENTITY_MISSING_MEMBER);
852 	}
853 
854 	if (nwam_value_get_uint64(activationval, &activation)
855 	    != NWAM_SUCCESS) {
856 		if (errpropp != NULL)
857 			*errpropp = NWAM_LOC_PROP_ACTIVATION_MODE;
858 		nwam_value_free(activationval);
859 		return (NWAM_ENTITY_NO_VALUE);
860 	}
861 
862 	/* validate activation against the location first */
863 	if ((err = nwam_loc_validate_activation_mode(loch, activationval))
864 	    != NWAM_SUCCESS) {
865 		if (errpropp != NULL)
866 			*errpropp = NWAM_LOC_PROP_ACTIVATION_MODE;
867 		nwam_value_free(activationval);
868 		return (err);
869 	}
870 	nwam_value_free(activationval);
871 
872 	if (activation == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY ||
873 	    activation == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL) {
874 		if (nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_CONDITIONS,
875 		    &conditionval) != NWAM_SUCCESS) {
876 			if (errpropp != NULL)
877 				*errpropp = NWAM_LOC_PROP_CONDITIONS;
878 			return (NWAM_ENTITY_MISSING_MEMBER);
879 		}
880 		/*
881 		 * Are conditions self-referential? In other words, do any
882 		 * of the activation conditions refer to this location?
883 		 */
884 		if (nwam_value_get_string_array(conditionval, &conditions,
885 		    &numvalues) != NWAM_SUCCESS) {
886 			nwam_value_free(conditionval);
887 			if (errpropp != NULL)
888 				*errpropp = NWAM_LOC_PROP_CONDITIONS;
889 			return (NWAM_ENTITY_INVALID_VALUE);
890 		}
891 		if (nwam_loc_get_name(loch, &name) != NWAM_SUCCESS) {
892 			nwam_value_free(conditionval);
893 			return (NWAM_INVALID_ARG);
894 		}
895 		for (i = 0; i < numvalues; i++) {
896 			char *object_name = NULL;
897 
898 			if (nwam_condition_string_to_condition(conditions[i],
899 			    &object_type, &condition, &object_name)
900 			    != NWAM_SUCCESS) {
901 				if (errpropp != NULL)
902 					*errpropp = NWAM_LOC_PROP_CONDITIONS;
903 				free(name);
904 				nwam_value_free(conditionval);
905 				return (NWAM_ENTITY_INVALID_VALUE);
906 			}
907 			if (object_name != NULL &&
908 			    object_type == NWAM_CONDITION_OBJECT_TYPE_LOC &&
909 			    strcmp(object_name, name) == 0) {
910 				if (errpropp != NULL)
911 					*errpropp = NWAM_LOC_PROP_CONDITIONS;
912 				free(name);
913 				free(object_name);
914 				nwam_value_free(conditionval);
915 				return (NWAM_ENTITY_INVALID_VALUE);
916 			}
917 			free(object_name);
918 		}
919 		free(name);
920 		nwam_value_free(conditionval);
921 	}
922 
923 	/* validate namerservices */
924 	if (nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_NAMESERVICES,
925 	    &nameservicesval) != NWAM_SUCCESS) {
926 		if (errpropp != NULL)
927 			*errpropp = NWAM_LOC_PROP_NAMESERVICES;
928 		return (NWAM_ENTITY_MISSING_MEMBER);
929 	}
930 	err = nwam_loc_validate_all_nameservices(loch, nameservicesval,
931 	    errpropp);
932 	nwam_value_free(nameservicesval);
933 	if (err != NWAM_SUCCESS)
934 		return (err);
935 
936 	return (nwam_validate(loc_prop_table, loch, errpropp));
937 }
938 
939 nwam_error_t
940 nwam_loc_validate_prop(nwam_loc_handle_t loch, const char *propname,
941     nwam_value_t value)
942 {
943 	nwam_error_t err;
944 
945 	assert(loch != NULL);
946 
947 	if (strcmp(propname, NWAM_LOC_PROP_ACTIVATION_MODE) == 0) {
948 		if ((err = nwam_loc_validate_activation_mode(loch, value))
949 		    != NWAM_SUCCESS)
950 			return (err);
951 	}
952 
953 	return (nwam_validate_prop(loc_prop_table, loch, propname, value));
954 }
955 
956 nwam_error_t
957 nwam_loc_copy(nwam_loc_handle_t oldloch, const char *newname,
958     nwam_loc_handle_t *newlochp)
959 {
960 	nwam_error_t err;
961 	nwam_value_t val;
962 
963 	if ((err = nwam_copy(NWAM_LOC_CONF_FILE, oldloch, newname, newlochp))
964 	    != NWAM_SUCCESS)
965 		return (err);
966 
967 	/* If the activation-mode is system, change it to manual */
968 	if ((err = nwam_loc_get_prop_value(*newlochp,
969 	    NWAM_LOC_PROP_ACTIVATION_MODE, &val)) != NWAM_SUCCESS)
970 		goto finish;
971 	err = nwam_loc_validate_activation_mode(*newlochp, val);
972 	nwam_value_free(val);
973 	if (err != NWAM_SUCCESS) {
974 		if ((err = nwam_value_create_uint64(NWAM_ACTIVATION_MODE_MANUAL,
975 		    &val)) != NWAM_SUCCESS)
976 			goto finish;
977 		err = nwam_set_prop_value((*newlochp)->nwh_data,
978 		    NWAM_LOC_PROP_ACTIVATION_MODE, val);
979 		nwam_value_free(val);
980 		if (err != NWAM_SUCCESS)
981 			goto finish;
982 
983 		if ((err = nwam_value_create_boolean(B_FALSE, &val))
984 		    != NWAM_SUCCESS)
985 			goto finish;
986 		err = nwam_set_prop_value((*newlochp)->nwh_data,
987 		    NWAM_LOC_PROP_ENABLED, val);
988 		nwam_value_free(val);
989 		if (err != NWAM_SUCCESS)
990 			goto finish;
991 	}
992 
993 	return (NWAM_SUCCESS);
994 
995 finish:
996 	nwam_loc_free(*newlochp);
997 	*newlochp = NULL;
998 	return (err);
999 }
1000 
1001 /*
1002  * Given a property, return expected property data type
1003  */
1004 nwam_error_t
1005 nwam_loc_get_prop_type(const char *propname, nwam_value_type_t *typep)
1006 {
1007 	return (nwam_get_prop_type(loc_prop_table, propname, typep));
1008 }
1009 
1010 nwam_error_t
1011 nwam_loc_prop_multivalued(const char *propname, boolean_t *multip)
1012 {
1013 	return (nwam_prop_multivalued(loc_prop_table, propname, multip));
1014 }
1015 
1016 /*
1017  * Determine if the location has manual activation-mode or not.
1018  */
1019 nwam_error_t
1020 nwam_loc_is_manual(nwam_loc_handle_t loch, boolean_t *manualp)
1021 {
1022 	nwam_error_t err;
1023 	nwam_value_t actval;
1024 	uint64_t activation;
1025 
1026 	assert(loch != NULL);
1027 
1028 	if ((err = nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_ACTIVATION_MODE,
1029 	    &actval)) != NWAM_SUCCESS)
1030 		return (err);
1031 	err = nwam_value_get_uint64(actval, &activation);
1032 	nwam_value_free(actval);
1033 	if (err != NWAM_SUCCESS)
1034 		return (err);
1035 
1036 	if (activation == NWAM_ACTIVATION_MODE_MANUAL)
1037 		*manualp = B_TRUE;
1038 	else
1039 		*manualp = B_FALSE;
1040 	return (NWAM_SUCCESS);
1041 }
1042 
1043 /* Determine if location is enabled or not */
1044 static nwam_error_t
1045 nwam_loc_is_enabled(nwam_loc_handle_t loch, boolean_t *enabledp)
1046 {
1047 	nwam_error_t err;
1048 	nwam_value_t enabledval;
1049 
1050 	assert(loch != NULL);
1051 
1052 	if ((err = nwam_loc_get_prop_value(loch, NWAM_LOC_PROP_ENABLED,
1053 	    &enabledval)) != NWAM_SUCCESS)
1054 		return (err);
1055 	err = nwam_value_get_boolean(enabledval, enabledp);
1056 	nwam_value_free(enabledval);
1057 	return (err);
1058 }
1059 
1060 /*
1061  * Callback to disable all locations other than one to enable, the handle
1062  * of which we pass in as an argument. If the argument is NULL, we disable
1063  * all locations.
1064  */
1065 static int
1066 loc_set_enabled(nwam_loc_handle_t loch, void *data)
1067 {
1068 	nwam_value_t enabledval;
1069 	boolean_t enabled = B_FALSE;
1070 	nwam_loc_handle_t testloch = data;
1071 	nwam_error_t err = NWAM_SUCCESS;
1072 
1073 	if (testloch != NULL) {
1074 		char *name, *testname;
1075 
1076 		if (nwam_loc_get_name(loch, &name) == NWAM_SUCCESS &&
1077 		    nwam_loc_get_name(testloch, &testname) == NWAM_SUCCESS &&
1078 		    strcmp(name, testname) == 0) {
1079 			/* We enable this location. */
1080 			enabled = B_TRUE;
1081 		}
1082 	}
1083 	if (nwam_value_create_boolean(enabled, &enabledval) != NWAM_SUCCESS)
1084 		return (0);
1085 	if (nwam_set_prop_value(loch->nwh_data, NWAM_LOC_PROP_ENABLED,
1086 	    enabledval) == NWAM_SUCCESS)
1087 		err = nwam_loc_commit(loch, NWAM_FLAG_ENTITY_ENABLE);
1088 
1089 	nwam_value_free(enabledval);
1090 	return (err);
1091 }
1092 
1093 /*
1094  * Update the enabled property for this location (and for all others
1095  * if necessary.
1096  */
1097 static int
1098 nwam_loc_update_enabled(nwam_loc_handle_t loch, boolean_t enabled)
1099 {
1100 	nwam_error_t err;
1101 	int cb_ret;
1102 
1103 	if (enabled) {
1104 		/*
1105 		 * Disable all other locations that are manually enabled
1106 		 * and enable this one - a maximum of 1 location can be
1107 		 * enabled at once.
1108 		 */
1109 		err = nwam_walk_locs(loc_set_enabled, loch, 0, &cb_ret);
1110 		if (err != NWAM_SUCCESS && err != NWAM_WALK_HALTED)
1111 			cb_ret = err;
1112 	} else {
1113 		cb_ret = loc_set_enabled(loch, NULL);
1114 	}
1115 	return (cb_ret);
1116 }
1117 
1118 nwam_error_t
1119 nwam_loc_enable(nwam_loc_handle_t loch)
1120 {
1121 	nwam_error_t err;
1122 	boolean_t enabled;
1123 
1124 	assert(loch != NULL);
1125 
1126 	/* Make sure location is not enabled */
1127 	if ((err = nwam_loc_is_enabled(loch, &enabled)) != NWAM_SUCCESS)
1128 		return (err);
1129 	if (enabled)
1130 		return (NWAM_SUCCESS);
1131 
1132 	if ((err = nwam_loc_update_enabled(loch, B_TRUE)) != NWAM_SUCCESS)
1133 		return (err);
1134 
1135 	err = nwam_enable(NULL, loch);
1136 
1137 	/* nwamd may not be running, that's okay. */
1138 	if (err == NWAM_ERROR_BIND)
1139 		return (NWAM_SUCCESS);
1140 	else
1141 		return (err);
1142 }
1143 
1144 nwam_error_t
1145 nwam_loc_disable(nwam_loc_handle_t loch)
1146 {
1147 	nwam_error_t err;
1148 	boolean_t enabled;
1149 
1150 	assert(loch != NULL);
1151 
1152 	/* Make sure location is enabled */
1153 	if ((err = nwam_loc_is_enabled(loch, &enabled)) != NWAM_SUCCESS)
1154 		return (err);
1155 	if (!enabled)
1156 		return (NWAM_SUCCESS);
1157 
1158 	if ((err = nwam_loc_update_enabled(loch, B_FALSE)) != NWAM_SUCCESS)
1159 		return (err);
1160 
1161 	err = nwam_disable(NULL, loch);
1162 
1163 	/* nwamd may not be running, that's okay. */
1164 	if (err == NWAM_ERROR_BIND)
1165 		return (NWAM_SUCCESS);
1166 	else
1167 		return (err);
1168 }
1169 
1170 nwam_error_t
1171 nwam_loc_get_default_proplist(const char ***prop_list, uint_t *numvaluesp)
1172 {
1173 	return (nwam_get_default_proplist(loc_prop_table,
1174 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY, prop_list, numvaluesp));
1175 }
1176 
1177 nwam_error_t
1178 nwam_loc_get_state(nwam_loc_handle_t loch, nwam_state_t *statep,
1179     nwam_aux_state_t *auxp)
1180 {
1181 	return (nwam_get_state(NULL, loch, statep, auxp));
1182 }
1183