xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/door_if.c (revision 72c9c96770c90a8042add81e56bb8a2f9e4a29dc)
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 <auth_attr.h>
28 #include <auth_list.h>
29 #include <bsm/adt.h>
30 #include <bsm/adt_event.h>
31 #include <door.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <libnwam_priv.h>
35 #include <libuutil.h>
36 #include <pthread.h>
37 #include <pwd.h>
38 #include <stdlib.h>
39 #include <sys/stat.h>
40 
41 #include <sys/mman.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 
45 #include "conditions.h"
46 #include "events.h"
47 #include "ncp.h"
48 #include "ncu.h"
49 #include "objects.h"
50 #include "util.h"
51 
52 /*
53  * door_if.c
54  * This file contains functions which implement the command interface to
55  * nwam via the door NWAM_DOOR.  Doors provide a LPC mechanism that allows
56  * for threads in one process to cause code to execute in another process.
57  * Doors also provide the ability to pass data and file descriptors.  See
58  * libdoor(3LIB) for more information.
59  *
60  * This file exports two functions, nwamd_door_initialize() (which sets up
61  * the door) and nwamd_door_fini(), which removes it.
62  *
63  * It sets up the static routine nwamd_door_switch() to be called when a client
64  * calls the door (via door_call(3C)).  The structure nwam_request_t is
65  * passed as data and contains data to specify the type of action requested
66  * and any data need to meet that request.  A table consisting of entries
67  * for each door request, the associated authorization and the function to
68  * process that request is used to handle the various requests.
69  */
70 
71 struct nwamd_door_req_entry
72 {
73 	int ndre_type;
74 	char *ndre_auth;
75 	nwam_error_t (*ndre_fn)(nwamd_door_arg_t *, ucred_t *, struct passwd *);
76 };
77 
78 static nwam_error_t nwamd_door_req_event_register(nwamd_door_arg_t *,
79 	ucred_t *, struct passwd *);
80 static nwam_error_t nwamd_door_req_event_unregister(nwamd_door_arg_t *,
81 	ucred_t *, struct passwd *);
82 static nwam_error_t nwamd_door_req_wlan_scan(nwamd_door_arg_t *,
83 	ucred_t *, struct passwd *);
84 static nwam_error_t nwamd_door_req_wlan_scan_results(nwamd_door_arg_t *,
85 	ucred_t *, struct passwd *);
86 static nwam_error_t nwamd_door_req_wlan_select(nwamd_door_arg_t *,
87 	ucred_t *, struct passwd *);
88 static nwam_error_t nwamd_door_req_wlan_set_key(nwamd_door_arg_t *,
89 	ucred_t *, struct passwd *);
90 static nwam_error_t nwamd_door_req_action(nwamd_door_arg_t *,
91 	ucred_t *, struct passwd *);
92 static nwam_error_t nwamd_door_req_state(nwamd_door_arg_t *,
93 	ucred_t *, struct passwd *);
94 static nwam_error_t nwamd_door_req_priority_group(nwamd_door_arg_t *,
95 	ucred_t *, struct passwd *);
96 
97 /*
98  * This table defines the set of door commands available, the required
99  * authorizations for each command, and the function that carries out
100  * each command.
101  */
102 struct nwamd_door_req_entry door_req_table[] =
103 {
104 
105 	{ NWAM_REQUEST_TYPE_EVENT_REGISTER, AUTOCONF_READ_AUTH,
106 	nwamd_door_req_event_register },
107 	{ NWAM_REQUEST_TYPE_EVENT_UNREGISTER, AUTOCONF_READ_AUTH,
108 	nwamd_door_req_event_unregister },
109 	{ NWAM_REQUEST_TYPE_WLAN_SCAN, AUTOCONF_WLAN_AUTH,
110 	nwamd_door_req_wlan_scan },
111 	{ NWAM_REQUEST_TYPE_WLAN_SCAN_RESULTS, AUTOCONF_READ_AUTH,
112 	nwamd_door_req_wlan_scan_results },
113 	{ NWAM_REQUEST_TYPE_WLAN_SELECT, AUTOCONF_WLAN_AUTH,
114 	nwamd_door_req_wlan_select },
115 	{ NWAM_REQUEST_TYPE_WLAN_SET_KEY, AUTOCONF_WLAN_AUTH,
116 	nwamd_door_req_wlan_set_key },
117 	/* Requires WRITE, SELECT or WLAN auth depending on action */
118 	{ NWAM_REQUEST_TYPE_ACTION, NULL, nwamd_door_req_action },
119 	{ NWAM_REQUEST_TYPE_STATE, AUTOCONF_READ_AUTH,
120 	nwamd_door_req_state },
121 	{ NWAM_REQUEST_TYPE_PRIORITY_GROUP, AUTOCONF_READ_AUTH,
122 	nwamd_door_req_priority_group },
123 };
124 
125 int doorfd = -1;
126 
127 /* ARGSUSED */
128 static nwam_error_t
129 nwamd_door_req_event_register(nwamd_door_arg_t *req, ucred_t *ucr,
130     struct passwd *pwd)
131 {
132 	nwam_error_t err;
133 
134 	err = nwam_event_queue_init
135 	    (req->nwda_data.nwdad_register_info.nwdad_name);
136 	if (err != NWAM_SUCCESS) {
137 		nlog(LOG_ERR, "nwamd_door_req_event_register: "
138 		    "could not register events for %s",
139 		    req->nwda_data.nwdad_register_info.nwdad_name);
140 	}
141 
142 	return (err);
143 }
144 
145 /* ARGSUSED */
146 static nwam_error_t
147 nwamd_door_req_event_unregister(nwamd_door_arg_t *req, ucred_t *ucr,
148     struct passwd *pwd)
149 {
150 	nwam_event_queue_fini(req->nwda_data.nwdad_register_info.nwdad_name);
151 
152 	return (NWAM_SUCCESS);
153 }
154 
155 /* ARGSUSED1 */
156 static nwam_error_t
157 nwamd_door_req_wlan_scan(nwamd_door_arg_t *req, ucred_t *ucr,
158     struct passwd *pwd)
159 {
160 	nlog(LOG_DEBUG,
161 	    "nwamd_door_req_wlan_scan: processing WLAN scan request: "
162 	    "link %s", req->nwda_data.nwdad_wlan_info.nwdad_name);
163 
164 	return (nwamd_wlan_scan(req->nwda_data.nwdad_wlan_info.nwdad_name));
165 }
166 
167 /* ARGSUSED */
168 static nwam_error_t
169 nwamd_door_req_wlan_scan_results(nwamd_door_arg_t *req, ucred_t *ucr,
170     struct passwd *pwd)
171 {
172 	nwamd_object_t obj;
173 	nwamd_ncu_t *ncu;
174 	nwamd_link_t *link;
175 	uint_t num_wlans;
176 
177 	nlog(LOG_DEBUG, "nwamd_door_req_wlan_scan_results: processing WLAN "
178 	    "scan results request: link %s",
179 	    req->nwda_data.nwdad_wlan_info.nwdad_name);
180 
181 	obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK,
182 	    req->nwda_data.nwdad_wlan_info.nwdad_name);
183 	if (obj == NULL) {
184 		nlog(LOG_ERR,
185 		    "nwamd_door_req_wlan_scan_results: link %s not found",
186 		    req->nwda_data.nwdad_wlan_info.nwdad_name);
187 		return (NWAM_ENTITY_NOT_FOUND);
188 	}
189 
190 	ncu = obj->nwamd_object_data;
191 	link = &ncu->ncu_node.u_link;
192 	num_wlans = link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num;
193 
194 	if (num_wlans > 0) {
195 		(void) memcpy
196 		    (req->nwda_data.nwdad_wlan_info.nwdad_wlans,
197 		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
198 		    num_wlans * sizeof (nwam_wlan_t));
199 	}
200 	req->nwda_data.nwdad_wlan_info.nwdad_num_wlans = num_wlans;
201 	nlog(LOG_DEBUG,
202 	    "nwamd_door_req_wlan_scan_results: returning %d scan results",
203 	    num_wlans);
204 	nwamd_object_release(obj);
205 
206 	return (NWAM_SUCCESS);
207 }
208 
209 /* ARGSUSED */
210 static nwam_error_t
211 nwamd_door_req_wlan_select(nwamd_door_arg_t *req, ucred_t *ucr,
212     struct passwd *pwd)
213 {
214 	nlog(LOG_DEBUG,
215 	    "nwamd_door_req_wlan_select: processing WLAN selection : "
216 	    "link %s ESSID %s , BSSID %s",
217 	    req->nwda_data.nwdad_wlan_info.nwdad_name,
218 	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
219 	    req->nwda_data.nwdad_wlan_info.nwdad_bssid);
220 	return (nwamd_wlan_select
221 	    (req->nwda_data.nwdad_wlan_info.nwdad_name,
222 	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
223 	    req->nwda_data.nwdad_wlan_info.nwdad_bssid,
224 	    req->nwda_data.nwdad_wlan_info.nwdad_security_mode,
225 	    req->nwda_data.nwdad_wlan_info.nwdad_add_to_known_wlans));
226 }
227 
228 /* ARGSUSED */
229 static nwam_error_t
230 nwamd_door_req_wlan_set_key(nwamd_door_arg_t *req, ucred_t *ucr,
231     struct passwd *pwd)
232 {
233 	nlog(LOG_DEBUG,
234 	    "nwamd_door_req_wlan_set_key: processing WLAN key input : "
235 	    "link %s ESSID %s BSSID %s",
236 	    req->nwda_data.nwdad_wlan_info.nwdad_name,
237 	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
238 	    req->nwda_data.nwdad_wlan_info.nwdad_bssid);
239 	return (nwamd_wlan_set_key
240 	    (req->nwda_data.nwdad_wlan_info.nwdad_name,
241 	    req->nwda_data.nwdad_wlan_info.nwdad_essid, NULL,
242 	    req->nwda_data.nwdad_wlan_info.nwdad_security_mode,
243 	    req->nwda_data.nwdad_wlan_info.nwdad_keyslot,
244 	    req->nwda_data.nwdad_wlan_info.nwdad_key));
245 }
246 
247 static nwam_error_t
248 nwamd_door_req_action(nwamd_door_arg_t *req, ucred_t *ucr, struct passwd *pwd)
249 {
250 	char name[NWAM_MAX_NAME_LEN];
251 	char parent[NWAM_MAX_NAME_LEN];
252 	nwam_action_t action = req->nwda_data.nwdad_object_action.nwdad_action;
253 	nwam_object_type_t object_type =
254 	    req->nwda_data.nwdad_object_action.nwdad_object_type;
255 	char *obj_type_str  = (char *)nwam_object_type_to_string(object_type);
256 	nwam_error_t err;
257 
258 	/* Check for name, parent overrun */
259 	if (strlcpy(name, req->nwda_data.nwdad_object_action.nwdad_name,
260 	    sizeof (name)) == NWAM_MAX_NAME_LEN ||
261 	    strlcpy(parent, req->nwda_data.nwdad_object_action.nwdad_parent,
262 	    sizeof (parent)) == NWAM_MAX_NAME_LEN)
263 		return (NWAM_INVALID_ARG);
264 
265 	/*
266 	 * Check authorizations against actions.
267 	 * - ENABLE/DISABLE requires SELECT auth
268 	 * - ADD/DESTROY/REFRESH on Known WLANs requires WLAN auth
269 	 * - ADD/DESTROY on other objects requires WRITE auth
270 	 * - REFRESH on other objects requires either WRITE or SELECT auth
271 	 */
272 	if (action == NWAM_ACTION_ENABLE || action == NWAM_ACTION_DISABLE) {
273 		if (chkauthattr(AUTOCONF_SELECT_AUTH, pwd->pw_name) == 0) {
274 			nwam_record_audit_event(ucr,
275 			    action == NWAM_ACTION_ENABLE ?
276 			    ADT_nwam_enable : ADT_nwam_disable, name,
277 			    obj_type_str, ADT_FAILURE, ADT_FAIL_VALUE_AUTH);
278 			nlog(LOG_ERR, "nwamd_door_req_action: "
279 			    "need %s for %s action", AUTOCONF_SELECT_AUTH,
280 			    nwam_action_to_string(action));
281 			return (NWAM_PERMISSION_DENIED);
282 		}
283 	} else if (object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN) {
284 		if (chkauthattr(AUTOCONF_WLAN_AUTH, pwd->pw_name) == 0) {
285 			nlog(LOG_ERR, "nwamd_door_req_action: "
286 			    "need %s for %s action on Known WLAN",
287 			    AUTOCONF_WLAN_AUTH, nwam_action_to_string(action));
288 			return (NWAM_PERMISSION_DENIED);
289 		}
290 	} else if (action == NWAM_ACTION_ADD || action == NWAM_ACTION_DESTROY) {
291 		if (chkauthattr(AUTOCONF_WRITE_AUTH, pwd->pw_name) == 0) {
292 			nlog(LOG_ERR, "nwamd_door_req_action: "
293 			    "need %s for %s action", AUTOCONF_WRITE_AUTH,
294 			    nwam_action_to_string(action));
295 			return (NWAM_PERMISSION_DENIED);
296 		}
297 	} else if (action == NWAM_ACTION_REFRESH) {
298 		if (chkauthattr(AUTOCONF_WRITE_AUTH, pwd->pw_name) == 0 &&
299 		    chkauthattr(AUTOCONF_SELECT_AUTH, pwd->pw_name) == 0) {
300 			nlog(LOG_ERR, "nwamd_door_req_action: "
301 			    "need either %s or %s for %s action",
302 			    AUTOCONF_WRITE_AUTH, AUTOCONF_SELECT_AUTH,
303 			    nwam_action_to_string(action));
304 			return (NWAM_PERMISSION_DENIED);
305 		}
306 	} else {
307 		nlog(LOG_ERR, "nwamd_door_req_action: received unknown "
308 		    "action %d (%s)", action, nwam_action_to_string(action));
309 		return (NWAM_INVALID_ARG);
310 	}
311 
312 	switch (action) {
313 	case NWAM_ACTION_ENABLE:
314 	case NWAM_ACTION_DISABLE:
315 		nwam_record_audit_event(ucr,
316 		    action == NWAM_ACTION_ENABLE ?
317 		    ADT_nwam_enable : ADT_nwam_disable, name,
318 		    obj_type_str, ADT_SUCCESS, ADT_SUCCESS);
319 
320 		nlog(LOG_DEBUG, "nwamd_door_req_action: %s %s",
321 		    action == NWAM_ACTION_ENABLE ? "enabling" : "disabling",
322 		    name);
323 
324 		switch (object_type) {
325 		case NWAM_OBJECT_TYPE_ENM:
326 			err = nwamd_enm_action(name, action);
327 			break;
328 		case NWAM_OBJECT_TYPE_LOC:
329 			err = nwamd_loc_action(name, action);
330 			break;
331 		case NWAM_OBJECT_TYPE_NCU:
332 			err = nwamd_ncu_action(name, parent, action);
333 			break;
334 		case NWAM_OBJECT_TYPE_NCP:
335 			if (action == NWAM_ACTION_DISABLE) {
336 				nlog(LOG_ERR, "nwamd_door_req_action: "
337 				    "NCPs cannot be disabled");
338 				err = NWAM_INVALID_ARG;
339 			} else {
340 				err = nwamd_ncp_action(name, action);
341 			}
342 			break;
343 		default:
344 			nlog(LOG_ERR, "nwamd_door_req_action: received invalid "
345 			    "object type %d (%s)", object_type,
346 			    nwam_object_type_to_string(object_type));
347 			return (NWAM_INVALID_ARG);
348 		}
349 		break;
350 
351 	case NWAM_ACTION_ADD:
352 	case NWAM_ACTION_REFRESH:
353 		/*
354 		 * Called whenever an object is committed in the library.
355 		 * Reread that committed object into nwamd.
356 		 */
357 		nlog(LOG_DEBUG, "door_switch: refreshing %s", name);
358 
359 		switch (object_type) {
360 		case NWAM_OBJECT_TYPE_ENM:
361 			err = nwamd_enm_action(name, action);
362 			break;
363 		case NWAM_OBJECT_TYPE_LOC:
364 			err = nwamd_loc_action(name, action);
365 			break;
366 		case NWAM_OBJECT_TYPE_KNOWN_WLAN:
367 			err = nwamd_known_wlan_action(name, action);
368 			break;
369 		case NWAM_OBJECT_TYPE_NCU:
370 			err = nwamd_ncu_action(name, parent, action);
371 			break;
372 		case NWAM_OBJECT_TYPE_NCP:
373 			err = nwamd_ncp_action(name, action);
374 			break;
375 		default:
376 			nlog(LOG_ERR, "nwamd_door_req_action: received invalid "
377 			    "object type %d (%s)", object_type,
378 			    nwam_object_type_to_string(object_type));
379 			err = NWAM_INVALID_ARG;
380 			break;
381 		}
382 		break;
383 
384 	case NWAM_ACTION_DESTROY:
385 		/* Object was destroyed, remove from nwamd */
386 		nlog(LOG_DEBUG, "door_switch: removing %s", name);
387 
388 		switch (object_type) {
389 		case NWAM_OBJECT_TYPE_ENM:
390 			err = nwamd_enm_action(name, NWAM_ACTION_DESTROY);
391 			break;
392 		case NWAM_OBJECT_TYPE_LOC:
393 			err = nwamd_loc_action(name, NWAM_ACTION_DESTROY);
394 			break;
395 		case NWAM_OBJECT_TYPE_KNOWN_WLAN:
396 			err = nwamd_known_wlan_action(name,
397 			    NWAM_ACTION_DESTROY);
398 			break;
399 		case NWAM_OBJECT_TYPE_NCU:
400 			err = nwamd_ncu_action(name, parent,
401 			    NWAM_ACTION_DESTROY);
402 			break;
403 		case NWAM_OBJECT_TYPE_NCP:
404 			(void) pthread_mutex_lock(&active_ncp_mutex);
405 			if (strcmp(name, active_ncp) == 0) {
406 				nlog(LOG_ERR, "nwamd_door_req_action: %s is "
407 				    "active, cannot destroy", parent);
408 				err = NWAM_ENTITY_IN_USE;
409 			} else {
410 				err = nwamd_ncp_action(name,
411 				    NWAM_ACTION_DESTROY);
412 			}
413 			(void) pthread_mutex_unlock(&active_ncp_mutex);
414 			break;
415 		default:
416 			nlog(LOG_ERR, "nwamd_door_req_action: received invalid "
417 			    "object type %d (%s)", object_type,
418 			    nwam_object_type_to_string(object_type));
419 			err = NWAM_INVALID_ARG;
420 			break;
421 		}
422 		break;
423 
424 	default:
425 		nlog(LOG_ERR, "nwamd_door_req_action: received unknown "
426 		    "action %d (%s)", action, nwam_action_to_string(action));
427 		err = NWAM_INVALID_ARG;
428 		break;
429 	}
430 
431 	if (err == NWAM_SUCCESS) {
432 		/*
433 		 * At this point, we've successfully carried out an action.
434 		 * Configuration may have changed, so we need to recheck
435 		 * conditions, however we want to avoid a flurry of condition
436 		 * check events, so we enqueue a triggered condition check
437 		 * if none is due in the next few seconds.
438 		 */
439 		nwamd_create_triggered_condition_check_event(NEXT_FEW_SECONDS);
440 	} else {
441 		nlog(LOG_ERR, "nwamd_door_req_action: could not carry out "
442 		    "%s action on %s: %s", nwam_action_to_string(action),
443 		    name, nwam_strerror(err));
444 	}
445 
446 	return (err);
447 }
448 
449 /* ARGSUSED */
450 static nwam_error_t
451 nwamd_door_req_state(nwamd_door_arg_t *req, ucred_t *ucr, struct passwd *pwd)
452 {
453 	char name[NWAM_MAX_NAME_LEN];
454 	nwamd_object_t obj;
455 	nwam_object_type_t object_type =
456 	    req->nwda_data.nwdad_object_state.nwdad_object_type;
457 	boolean_t is_active = B_FALSE;
458 
459 	/* Check for name, parent overrun */
460 	if (strlcpy(name, req->nwda_data.nwdad_object_state.nwdad_name,
461 	    sizeof (name)) == NWAM_MAX_NAME_LEN)
462 		return (NWAM_INVALID_ARG);
463 
464 	switch (object_type) {
465 	case NWAM_OBJECT_TYPE_NCP:
466 		(void) pthread_mutex_lock(&active_ncp_mutex);
467 		is_active = (strcmp(active_ncp, name) == 0);
468 		(void) pthread_mutex_unlock(&active_ncp_mutex);
469 		if (is_active) {
470 			req->nwda_data.nwdad_object_state.nwdad_state =
471 			    NWAM_STATE_ONLINE;
472 			req->nwda_data.nwdad_object_state.
473 			    nwdad_aux_state = NWAM_AUX_STATE_ACTIVE;
474 			nlog(LOG_DEBUG,
475 			    "nwamd_door_req_state: NCP %s is active", name);
476 		} else {
477 			req->nwda_data.nwdad_object_state.nwdad_state =
478 			    NWAM_STATE_DISABLED;
479 			req->nwda_data.nwdad_object_state.
480 			    nwdad_aux_state =
481 			    NWAM_AUX_STATE_MANUAL_DISABLE;
482 			nlog(LOG_DEBUG, "nwamd_door_req_state: "
483 			    "NCP %s is inactive", name);
484 		}
485 		break;
486 
487 	case NWAM_OBJECT_TYPE_LOC:
488 	case NWAM_OBJECT_TYPE_NCU:
489 	case NWAM_OBJECT_TYPE_ENM:
490 		obj = nwamd_object_find(object_type, name);
491 		if (obj == NULL) {
492 			nlog(LOG_ERR, "nwamd_door_req_state: %s %s not found",
493 			    nwam_object_type_to_string(object_type), name);
494 			return (NWAM_ENTITY_NOT_FOUND);
495 		}
496 		nlog(LOG_DEBUG, "nwamd_door_req_state: %s %s is %s",
497 		    nwam_object_type_to_string(object_type), name,
498 		    nwam_state_to_string(obj->nwamd_object_state));
499 		req->nwda_data.nwdad_object_state.nwdad_state =
500 		    obj->nwamd_object_state;
501 		req->nwda_data.nwdad_object_state.nwdad_aux_state =
502 		    obj->nwamd_object_aux_state;
503 		nwamd_object_release(obj);
504 		break;
505 
506 	default:
507 		nlog(LOG_ERR, "nwamd_door_req_state: received invalid "
508 		    "object type %d (%s)", object_type,
509 		    nwam_object_type_to_string(object_type));
510 		req->nwda_status = NWAM_REQUEST_STATUS_UNKNOWN;
511 		return (NWAM_INVALID_ARG);
512 	}
513 
514 	return (NWAM_SUCCESS);
515 }
516 
517 /* ARGSUSED */
518 static nwam_error_t
519 nwamd_door_req_priority_group(nwamd_door_arg_t *req, ucred_t *ucr,
520     struct passwd *pwd)
521 {
522 	(void) pthread_mutex_lock(&active_ncp_mutex);
523 	nlog(LOG_DEBUG, "nwamd_door_req_priority_group: "
524 	    "retrieving active priority-group: %d",
525 	    current_ncu_priority_group);
526 	req->nwda_data.nwdad_priority_group_info.nwdad_priority =
527 	    current_ncu_priority_group;
528 	(void) pthread_mutex_unlock(&active_ncp_mutex);
529 
530 	return (NWAM_SUCCESS);
531 }
532 
533 /* ARGSUSED */
534 static void
535 nwamd_door_switch(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
536     uint_t n_desc)
537 {
538 	nwamd_door_arg_t *req;
539 	ucred_t *ucr = NULL;
540 	uid_t uid;
541 	struct passwd *pwd = NULL;
542 	boolean_t found = B_FALSE;
543 	int i;
544 
545 	/* LINTED E_BAD_PTR_CAST_ALIGN */
546 	req = (nwamd_door_arg_t *)argp;
547 	req->nwda_error = NWAM_SUCCESS;
548 
549 	if (door_ucred(&ucr) != 0) {
550 		nlog(LOG_ERR, "nwamd_door_switch: door_ucred failed: %s",
551 		    strerror(errno));
552 		req->nwda_error = NWAM_ERROR_INTERNAL;
553 		req->nwda_status = NWAM_REQUEST_STATUS_FAILED;
554 		goto done;
555 	}
556 	uid = ucred_getruid(ucr);
557 
558 	if ((pwd = getpwuid(uid)) == NULL) {
559 		nlog(LOG_ERR, "nwamd_door_switch: getpwuid failed: %s",
560 		    strerror(errno));
561 		endpwent();
562 		req->nwda_error = NWAM_ERROR_INTERNAL;
563 		req->nwda_status = NWAM_REQUEST_STATUS_FAILED;
564 		goto done;
565 	}
566 
567 	/*
568 	 * Find door request entry in table, check auths and call the function
569 	 * handling the request.
570 	 */
571 	for (i = 0;
572 	    i < sizeof (door_req_table) / sizeof (struct nwamd_door_req_entry);
573 	    i++) {
574 		if (req->nwda_type != door_req_table[i].ndre_type)
575 			continue;
576 
577 		found = B_TRUE;
578 
579 		if (door_req_table[i].ndre_auth != NULL &&
580 		    chkauthattr(door_req_table[i].ndre_auth,
581 		    pwd->pw_name) == 0) {
582 			nlog(LOG_ERR,
583 			    "nwamd_door_switch: need %s for request type %d",
584 			    door_req_table[i].ndre_auth, req->nwda_type);
585 			req->nwda_error = NWAM_PERMISSION_DENIED;
586 			break;
587 		}
588 		req->nwda_error = door_req_table[i].ndre_fn(req, ucr, pwd);
589 		break;
590 	}
591 	if (!found) {
592 		nlog(LOG_ERR,
593 		    "nwamd_door_switch: received unknown request type %d",
594 		    req->nwda_type);
595 		req->nwda_status = NWAM_REQUEST_STATUS_UNKNOWN;
596 	} else {
597 		if (req->nwda_error == NWAM_SUCCESS)
598 			req->nwda_status = NWAM_REQUEST_STATUS_OK;
599 		else
600 			req->nwda_status = NWAM_REQUEST_STATUS_FAILED;
601 	}
602 
603 done:
604 	ucred_free(ucr);
605 	endpwent();
606 
607 	if (door_return((char *)req, sizeof (nwamd_door_arg_t), NULL, 0)
608 	    == -1) {
609 		nlog(LOG_ERR, "door_switch: type %d door_return failed: %s",
610 		    req->nwda_type, strerror(errno));
611 	}
612 }
613 
614 /*
615  * We initialize the nwamd door here.  Failure to have this happen is critical
616  * to the daemon so we log a message and pass up notice to the caller who
617  * will most likely abort trying to start.  This routine is meant to only
618  * be called once.
619  */
620 void
621 nwamd_door_init(void)
622 {
623 	const int door_mode = 0644;
624 	struct stat buf;
625 
626 	if ((doorfd = door_create(nwamd_door_switch, NULL,
627 	    DOOR_NO_CANCEL | DOOR_REFUSE_DESC)) == -1)
628 		pfail("Unable to create door: %s", strerror(errno));
629 
630 	if (stat(NWAM_DOOR, &buf) < 0) {
631 		int nwam_door_fd;
632 
633 		if ((nwam_door_fd = creat(NWAM_DOOR, door_mode)) < 0) {
634 			int err = errno;
635 			(void) door_revoke(doorfd);
636 			doorfd = -1;
637 			pfail("Couldn't create door: %s", strerror(err));
638 		}
639 		(void) close(nwam_door_fd);
640 	} else {
641 		if (buf.st_mode != door_mode) {
642 			if (chmod(NWAM_DOOR, door_mode) == -1) {
643 				nlog(LOG_ERR, "couldn't change mode of %s: %s",
644 				    NWAM_DOOR, strerror(errno));
645 			}
646 		}
647 	}
648 	/* cleanup anything hanging around from a previous invocation */
649 	(void) fdetach(NWAM_DOOR);
650 
651 	/* Place our door in the file system so that others can find us. */
652 	if (fattach(doorfd, NWAM_DOOR) < 0) {
653 		int err = errno;
654 		(void) door_revoke(doorfd);
655 		doorfd = -1;
656 		pfail("Couldn't attach door: %s", strerror(err));
657 	}
658 }
659 
660 void
661 nwamd_door_fini(void)
662 {
663 	if (doorfd != -1) {
664 		nlog(LOG_DEBUG, "nwamd_door_fini: closing door");
665 		(void) door_revoke(doorfd);
666 		doorfd = -1;
667 	}
668 	(void) unlink(NWAM_DOOR);
669 }
670