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