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