xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
24  * Copyright 2022 RackTop Systems, Inc.
25  */
26 
27 #include <sys/list.h>
28 #include <assert.h>
29 #include <alloca.h>
30 #include <door.h>
31 #include <errno.h>
32 #include <syslog.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <synch.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <stdlib.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <pthread.h>
42 #include <priv.h>
43 #include <rpcsvc/daemon_utils.h> /* DAEMON_UID */
44 
45 #include <smbsrv/smb_door.h>
46 #include <smbsrv/smb_xdr.h>
47 #include <smbsrv/smb_token.h>
48 #include <smbsrv/libmlsvc.h>
49 #include <smbsrv/libsmbns.h>
50 #include "smbd.h"
51 
52 /*
53  * The list contains asynchronous requests that have been initiated
54  * but have not yet been collected (via smbd_dop_async_response).
55  */
56 typedef struct smbd_doorsvc {
57 	mutex_t		sd_mutex;
58 	cond_t		sd_cv;
59 	list_t		sd_async_list;
60 	uint32_t	sd_async_count;
61 } smbd_doorsvc_t;
62 
63 static int smbd_dop_null(smbd_arg_t *);
64 static int smbd_dop_async_response(smbd_arg_t *);
65 static int smbd_dop_user_auth_logon(smbd_arg_t *);
66 static int smbd_dop_user_nonauth_logon(smbd_arg_t *);
67 static int smbd_dop_user_auth_logoff(smbd_arg_t *);
68 static int smbd_dop_lookup_sid(smbd_arg_t *);
69 static int smbd_dop_lookup_name(smbd_arg_t *);
70 static int smbd_dop_join(smbd_arg_t *);
71 static int smbd_dop_get_dcinfo(smbd_arg_t *);
72 static int smbd_dop_vss_get_count(smbd_arg_t *);
73 static int smbd_dop_vss_get_snapshots(smbd_arg_t *);
74 static int smbd_dop_vss_map_gmttoken(smbd_arg_t *);
75 static int smbd_dop_ads_find_host(smbd_arg_t *);
76 static int smbd_dop_quota_query(smbd_arg_t *);
77 static int smbd_dop_quota_set(smbd_arg_t *);
78 static int smbd_dop_dfs_get_referrals(smbd_arg_t *);
79 static int smbd_dop_shr_hostaccess(smbd_arg_t *);
80 static int smbd_dop_shr_exec(smbd_arg_t *);
81 static int smbd_dop_notify_dc_changed(smbd_arg_t *);
82 
83 typedef int (*smbd_dop_t)(smbd_arg_t *);
84 
85 typedef struct smbd_doorop {
86 	smb_dopcode_t	opcode;
87 	int		opflags;
88 	smbd_dop_t	op;
89 } smbd_doorop_t;
90 
91 /* doorop opflags */
92 #define	DOF_R	1	/* read */
93 #define	DOF_W	2	/* write */
94 #define	DOF_K	4	/* kernel caller */
95 #define	DOF_D	8	/* daemon caller */
96 
97 smbd_doorop_t smbd_doorops[] = {
98 	{ SMB_DR_NULL,			DOF_R,	smbd_dop_null },
99 	{ SMB_DR_ASYNC_RESPONSE,	DOF_K,	smbd_dop_async_response },
100 	{ SMB_DR_USER_AUTH_LOGON,	DOF_W,	smbd_dop_user_auth_logon },
101 	{ SMB_DR_USER_NONAUTH_LOGON,	DOF_W,	smbd_dop_user_nonauth_logon },
102 	{ SMB_DR_USER_AUTH_LOGOFF,	DOF_K,	smbd_dop_user_auth_logoff },
103 	{ SMB_DR_LOOKUP_SID,		DOF_R,	smbd_dop_lookup_sid },
104 	{ SMB_DR_LOOKUP_NAME,		DOF_R,	smbd_dop_lookup_name },
105 	{ SMB_DR_JOIN,			DOF_W,	smbd_dop_join },
106 	{ SMB_DR_GET_DCINFO,		DOF_R,	smbd_dop_get_dcinfo },
107 	{ SMB_DR_VSS_GET_COUNT,		DOF_K,	smbd_dop_vss_get_count },
108 	{ SMB_DR_VSS_GET_SNAPSHOTS,	DOF_K,	smbd_dop_vss_get_snapshots },
109 	{ SMB_DR_VSS_MAP_GMTTOKEN,	DOF_K,	smbd_dop_vss_map_gmttoken },
110 	{ SMB_DR_ADS_FIND_HOST,		DOF_R,	smbd_dop_ads_find_host },
111 	{ SMB_DR_QUOTA_QUERY,		DOF_K,	smbd_dop_quota_query },
112 	{ SMB_DR_QUOTA_SET,		DOF_K,	smbd_dop_quota_set },
113 	{ SMB_DR_DFS_GET_REFERRALS,	DOF_K,	smbd_dop_dfs_get_referrals },
114 	{ SMB_DR_SHR_HOSTACCESS,	DOF_K,	smbd_dop_shr_hostaccess },
115 	{ SMB_DR_SHR_EXEC,		DOF_K,	smbd_dop_shr_exec },
116 	{ SMB_DR_NOTIFY_DC_CHANGED,	DOF_W|DOF_D,
117 						smbd_dop_notify_dc_changed },
118 	{ SMB_DR_LOOKUP_LSID,		DOF_R,	smbd_dop_lookup_sid },
119 	{ SMB_DR_LOOKUP_LNAME,		DOF_R,	smbd_dop_lookup_name }
120 };
121 
122 static int smbd_ndoorop = (sizeof (smbd_doorops) / sizeof (smbd_doorops[0]));
123 
124 static smbd_doorsvc_t smbd_doorsvc;
125 static int smbd_door_fd = -1;
126 static int smbd_door_cookie = 0x534D4244;	/* SMBD */
127 static smbd_door_t smbd_door_sdh;
128 static char *smbd_door_name = NULL;
129 
130 static void smbd_door_dispatch(void *, char *, size_t, door_desc_t *, uint_t);
131 static int smbd_door_dispatch_async(smbd_arg_t *);
132 static void smbd_door_release_async(smbd_arg_t *);
133 
134 /*
135  * Start the smbd door service.  Create and bind to a door.
136  * Returns 0 on success. Otherwise, -1.
137  */
138 int
139 smbd_door_start(void)
140 {
141 	int	newfd;
142 
143 	(void) mutex_lock(&smbd_doorsvc.sd_mutex);
144 
145 	if (smbd_door_fd != -1) {
146 		(void) fprintf(stderr, "smb_doorsrv_start: already started");
147 		(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
148 		return (-1);
149 	}
150 
151 	smbd_door_name = getenv("SMBD_DOOR_NAME");
152 	if (smbd_door_name == NULL)
153 		smbd_door_name = SMBD_DOOR_NAME;
154 
155 	smbd_door_init(&smbd_door_sdh, "doorsrv");
156 
157 	list_create(&smbd_doorsvc.sd_async_list, sizeof (smbd_arg_t),
158 	    offsetof(smbd_arg_t, lnd));
159 	smbd_doorsvc.sd_async_count = 0;
160 
161 	if ((smbd_door_fd = door_create(smbd_door_dispatch,
162 	    &smbd_door_cookie, DOOR_UNREF)) < 0) {
163 		(void) fprintf(stderr, "smb_doorsrv_start: door_create: %s",
164 		    strerror(errno));
165 		smbd_door_fd = -1;
166 		(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
167 		return (-1);
168 	}
169 
170 	(void) unlink(smbd_door_name);
171 
172 	if ((newfd = creat(smbd_door_name, 0644)) < 0) {
173 		(void) fprintf(stderr, "smb_doorsrv_start: open: %s",
174 		    strerror(errno));
175 		(void) door_revoke(smbd_door_fd);
176 		smbd_door_fd = -1;
177 		(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
178 		return (-1);
179 	}
180 
181 	(void) close(newfd);
182 	(void) fdetach(smbd_door_name);
183 
184 	if (fattach(smbd_door_fd, smbd_door_name) < 0) {
185 		(void) fprintf(stderr, "smb_doorsrv_start: fattach: %s",
186 		    strerror(errno));
187 		(void) door_revoke(smbd_door_fd);
188 		smbd_door_fd = -1;
189 		(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
190 		return (-1);
191 	}
192 
193 	(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
194 	return (smbd_door_fd);
195 }
196 
197 /*
198  * Stop the smbd door service.
199  */
200 void
201 smbd_door_stop(void)
202 {
203 	(void) mutex_lock(&smbd_doorsvc.sd_mutex);
204 
205 	smbd_door_fini(&smbd_door_sdh);
206 
207 	if (smbd_door_name)
208 		(void) fdetach(smbd_door_name);
209 
210 	if (smbd_door_fd != -1) {
211 		(void) door_revoke(smbd_door_fd);
212 		smbd_door_fd = -1;
213 	}
214 
215 	(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
216 }
217 
218 static boolean_t
219 have_req_privs(uint32_t opcode, int opflags)
220 {
221 	ucred_t *uc = NULL;
222 	const priv_set_t *ps = NULL;
223 	boolean_t ret = B_FALSE;
224 	pid_t pid;
225 	uid_t uid;
226 
227 	/* If only DOF_R (read), let 'em through */
228 	if ((opflags & ~DOF_R) == 0)
229 		return (B_TRUE);
230 
231 	if (door_ucred(&uc) != 0) {
232 		syslog(LOG_DEBUG, "%s: door_ucred failed", __func__);
233 		goto out;
234 	}
235 
236 	/*
237 	 * in-kernel callers have pid==0
238 	 * If we have pid zero, that's sufficient.
239 	 * If not, allow with sys_smb priv (below)
240 	 */
241 	pid = ucred_getpid(uc);
242 	if ((opflags & DOF_K) != 0) {
243 		if (pid == 0) {
244 			ret = B_TRUE;
245 			goto out;
246 		}
247 	}
248 	uid = ucred_geteuid(uc);
249 	if ((opflags & DOF_D) != 0) {
250 		if (uid == DAEMON_UID) {
251 			ret = B_TRUE;
252 			goto out;
253 		}
254 	}
255 
256 	ps = ucred_getprivset(uc, PRIV_EFFECTIVE);
257 	if (ps == NULL) {
258 		syslog(LOG_DEBUG, "%s: ucred_getprivset failed", __func__);
259 		goto out;
260 	}
261 
262 	if ((opflags & (DOF_W | DOF_K)) != 0) {
263 		/*
264 		 * Modifying operation.  Require sys_smb priv.
265 		 */
266 		if (priv_ismember(ps, PRIV_SYS_SMB)) {
267 			ret = B_TRUE;
268 			goto out;
269 		}
270 	}
271 
272 	syslog(LOG_DEBUG, "smbd_door_dispatch: missing privilege, "
273 	    "OpCode = %d PID = %d UID = %d",
274 	    (int)opcode, (int)pid, (int)uid);
275 
276 out:
277 	/* ps is free'd with the ucred */
278 	if (uc != NULL)
279 		ucred_free(uc);
280 
281 	return (ret);
282 }
283 
284 static smbd_doorop_t *
285 smbd_door_get_opvec(smb_dopcode_t opcode)
286 {
287 	smbd_doorop_t	*doorop;
288 	int i;
289 
290 	for (i = 0, doorop = smbd_doorops;
291 	    i < smbd_ndoorop;
292 	    i++, doorop++) {
293 		if (doorop->opcode == opcode)
294 			return (doorop);
295 	}
296 	return (NULL);
297 }
298 
299 /*ARGSUSED*/
300 static void
301 smbd_door_dispatch(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
302     uint_t n_desc)
303 {
304 	smbd_arg_t	dop_arg;
305 	smb_doorhdr_t	*hdr;
306 	size_t		hdr_size;
307 	char		*rbuf = NULL;
308 	smbd_doorop_t	*doorop;
309 	int		opflags;
310 
311 	smbd_door_enter(&smbd_door_sdh);
312 
313 	if (!smbd_online())
314 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
315 
316 	bzero(&dop_arg, sizeof (smbd_arg_t));
317 	hdr = &dop_arg.hdr;
318 	hdr_size = xdr_sizeof(smb_doorhdr_xdr, hdr);
319 
320 	if ((cookie != &smbd_door_cookie) || (argp == NULL) ||
321 	    (arg_size < hdr_size)) {
322 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
323 	}
324 
325 	if (smb_doorhdr_decode(hdr, (uint8_t *)argp, hdr_size) == -1) {
326 		syslog(LOG_DEBUG, "smbd_door_dispatch: header decode failed");
327 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
328 	}
329 
330 	if ((hdr->dh_magic != SMB_DOOR_HDR_MAGIC) || (hdr->dh_txid == 0)) {
331 		syslog(LOG_DEBUG, "smbd_door_dispatch: invalid header");
332 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
333 	}
334 
335 	if ((doorop = smbd_door_get_opvec(hdr->dh_op)) == NULL) {
336 		/* invalid door op code */
337 		syslog(LOG_DEBUG, "smbd_door_dispatch: invalid op %u",
338 		    hdr->dh_op);
339 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
340 	}
341 
342 	dop_arg.opname = smb_doorhdr_opname(hdr->dh_op);
343 	dop_arg.data = argp + hdr_size;
344 	dop_arg.datalen = hdr->dh_datalen;
345 
346 	/*
347 	 * Opflags tell us the privileges requried for this op.
348 	 * Override them for async operations, which are only
349 	 * requested by the in-kernel door client.
350 	 */
351 	opflags = doorop->opflags;
352 	if ((hdr->dh_flags & SMB_DF_ASYNC) != 0)
353 		opflags |= DOF_K;
354 	if (!have_req_privs(hdr->dh_op, opflags)) {
355 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
356 	}
357 
358 	if (hdr->dh_op == SMB_DR_ASYNC_RESPONSE) {
359 		/*
360 		 * ASYNC_RESPONSE is used to collect the response
361 		 * to an async call; it cannot be an async call.
362 		 */
363 		hdr->dh_flags &= ~SMB_DF_ASYNC;
364 	}
365 
366 	if (hdr->dh_flags & SMB_DF_ASYNC) {
367 		if (smbd_door_dispatch_async(&dop_arg) == 0)
368 			hdr->dh_door_rc = SMB_DOP_SUCCESS;
369 		else
370 			hdr->dh_door_rc = SMB_DOP_NOT_CALLED;
371 	} else {
372 		(void) smbd_door_dispatch_op(&dop_arg);
373 	}
374 
375 	if ((rbuf = (char *)alloca(dop_arg.rsize + hdr_size)) == NULL) {
376 		errno = ENOMEM;
377 		syslog(LOG_DEBUG, "smbd_door_dispatch[%s]: alloca %m",
378 		    dop_arg.opname);
379 		smbd_door_return(&smbd_door_sdh, NULL, 0, NULL, 0);
380 	}
381 
382 	if (dop_arg.rbuf != NULL) {
383 		(void) memcpy(rbuf + hdr_size, dop_arg.rbuf, dop_arg.rsize);
384 		free(dop_arg.rbuf);
385 	}
386 
387 	hdr->dh_datalen = dop_arg.rsize;
388 	(void) smb_doorhdr_encode(hdr, (uint8_t *)rbuf, hdr_size);
389 	dop_arg.rsize += hdr_size;
390 
391 	smbd_door_return(&smbd_door_sdh, rbuf, dop_arg.rsize, NULL, 0);
392 	/*NOTREACHED*/
393 }
394 
395 /*
396  * Launch a thread to process an asynchronous door call.
397  */
398 static int
399 smbd_door_dispatch_async(smbd_arg_t *req_arg)
400 {
401 	smbd_arg_t	*arg = NULL;
402 	char		*data = NULL;
403 	pthread_attr_t	attr;
404 	pthread_t	tid;
405 	int		rc;
406 
407 	if ((req_arg->hdr.dh_flags & SMB_DF_ASYNC) == 0) {
408 		errno = EINVAL;
409 		return (-1);
410 	}
411 
412 	if ((arg = malloc(sizeof (smbd_arg_t))) == NULL) {
413 		syslog(LOG_DEBUG, "smbd_door_dispatch_async[%s]: %m",
414 		    req_arg->opname);
415 		return (-1);
416 	}
417 
418 	(void) memcpy(arg, req_arg, sizeof (smbd_arg_t));
419 	arg->data = NULL;
420 
421 	if (req_arg->datalen != 0) {
422 		if ((data = malloc(req_arg->datalen)) == NULL) {
423 			free(arg);
424 			syslog(LOG_DEBUG, "smbd_door_dispatch_async[%s]: %m",
425 			    req_arg->opname);
426 			return (-1);
427 		}
428 
429 		(void) memcpy(data, req_arg->data, req_arg->datalen);
430 		arg->data = data;
431 	}
432 
433 	(void) mutex_lock(&smbd_doorsvc.sd_mutex);
434 	arg->magic = SMBD_ARG_MAGIC;
435 	list_insert_tail(&smbd_doorsvc.sd_async_list, arg);
436 	++smbd_doorsvc.sd_async_count;
437 	(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
438 
439 	(void) pthread_attr_init(&attr);
440 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
441 	rc = pthread_create(&tid, &attr, smbd_door_dispatch_op, arg);
442 	(void) pthread_attr_destroy(&attr);
443 
444 	if (rc != 0) {
445 		(void) mutex_lock(&smbd_doorsvc.sd_mutex);
446 		smbd_door_release_async(arg);
447 		(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
448 	}
449 
450 	return (rc);
451 }
452 
453 /*
454  * Remove an entry from the async response pending list and free
455  * the arg and associated data.
456  *
457  * Must only be called while holding the smbd_doorsvc mutex.
458  */
459 static void
460 smbd_door_release_async(smbd_arg_t *arg)
461 {
462 	if (arg != NULL) {
463 		assert(arg->magic == SMBD_ARG_MAGIC);
464 		arg->magic = (uint32_t)~SMBD_ARG_MAGIC;
465 
466 		list_remove(&smbd_doorsvc.sd_async_list, arg);
467 		--smbd_doorsvc.sd_async_count;
468 		free(arg->data);
469 		arg->data = NULL;
470 		free(arg);
471 	}
472 }
473 
474 /*
475  * All door calls are processed here: synchronous or asynchronous:
476  * - synchronous calls are invoked by direct function call
477  * - asynchronous calls are invoked from a launched thread
478  *
479  * If the kernel has attempted to collect a response before the op
480  * has completed, the arg will have been marked as response_abort
481  * and we can discard the response data and release the arg.
482  *
483  * We send a notification when asynchronous (ASYNC) door calls
484  * from the kernel (SYSSPACE) have completed.
485  */
486 void *
487 smbd_door_dispatch_op(void *thread_arg)
488 {
489 	smbd_arg_t	*arg = (smbd_arg_t *)thread_arg;
490 	smbd_doorop_t	*doorop;
491 	smb_doorhdr_t	*hdr;
492 
493 	if ((!smbd_online()) || arg == NULL)
494 		return (NULL);
495 
496 	hdr = &arg->hdr;
497 	arg->opname = smb_doorhdr_opname(hdr->dh_op);
498 
499 	doorop = smbd_door_get_opvec(hdr->dh_op);
500 	if (doorop == NULL)
501 		return (NULL);
502 
503 	hdr->dh_door_rc = doorop->op(arg);
504 	hdr->dh_status = arg->status;
505 
506 	if ((hdr->dh_flags & SMB_DF_SYSSPACE) &&
507 	    (hdr->dh_flags & SMB_DF_ASYNC)) {
508 		assert(hdr->dh_op != SMB_DR_ASYNC_RESPONSE);
509 
510 		(void) mutex_lock(&smbd_doorsvc.sd_mutex);
511 		if (arg->response_abort) {
512 			free(arg->rbuf);
513 			arg->rbuf = NULL;
514 			smbd_door_release_async(arg);
515 		} else {
516 			arg->response_ready = B_TRUE;
517 		}
518 		(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
519 
520 		(void) smb_kmod_event_notify(hdr->dh_txid);
521 	}
522 
523 	return (NULL);
524 }
525 
526 /*
527  * Wrapper for door_return.  smbd_door_enter() increments a reference count
528  * when a door call is dispatched and smbd_door_return() decrements the
529  * reference count when it completes.
530  *
531  * The reference counting is used in smbd_door_fini() to wait for active
532  * calls to complete before closing the door.
533  */
534 void
535 smbd_door_init(smbd_door_t *sdh, const char *name)
536 {
537 	(void) strlcpy(sdh->sd_name, name, sizeof (sdh->sd_name));
538 }
539 
540 void
541 smbd_door_enter(smbd_door_t *sdh)
542 {
543 	(void) mutex_lock(&sdh->sd_mutex);
544 	++sdh->sd_ncalls;
545 	(void) mutex_unlock(&sdh->sd_mutex);
546 }
547 
548 /*
549  * We have two calls to door_return because the first call (with data)
550  * can fail, which can leave the door call blocked here.  The second
551  * call (with NULL) is guaranteed to unblock and return to the caller.
552  */
553 void
554 smbd_door_return(smbd_door_t *sdh, char *data_ptr, size_t data_size,
555     door_desc_t *desc_ptr, uint_t num_desc)
556 {
557 	(void) mutex_lock(&sdh->sd_mutex);
558 
559 	if (sdh->sd_ncalls == 0)
560 		syslog(LOG_ERR, "smbd_door_return[%s]: unexpected count=0",
561 		    sdh->sd_name);
562 	else
563 		--sdh->sd_ncalls;
564 
565 	(void) cond_broadcast(&sdh->sd_cv);
566 	(void) mutex_unlock(&sdh->sd_mutex);
567 
568 	(void) door_return(data_ptr, data_size, desc_ptr, num_desc);
569 	(void) door_return(NULL, 0, NULL, 0);
570 	/* NOTREACHED */
571 }
572 
573 /*
574  * A door service is about to terminate.
575  * Give active requests a small grace period to complete.
576  */
577 void
578 smbd_door_fini(smbd_door_t *sdh)
579 {
580 	timestruc_t	delay;
581 	int		rc = 0;
582 
583 	(void) mutex_lock(&sdh->sd_mutex);
584 
585 	while (rc != ETIME && sdh->sd_ncalls != 0) {
586 		delay.tv_sec = 1;
587 		delay.tv_nsec = 0;
588 		rc = cond_reltimedwait(&sdh->sd_cv, &sdh->sd_mutex, &delay);
589 	}
590 
591 	if (sdh->sd_ncalls != 0)
592 		syslog(LOG_NOTICE, "smbd_door_fini[%s]: %d remaining",
593 		    sdh->sd_name, sdh->sd_ncalls);
594 
595 	(void) mutex_unlock(&sdh->sd_mutex);
596 }
597 
598 /*
599  * Null door operation: always returns success.
600  * Assumes no request or response data.
601  */
602 /*ARGSUSED*/
603 static int
604 smbd_dop_null(smbd_arg_t *arg)
605 {
606 	return (SMB_DOP_SUCCESS);
607 }
608 
609 /*
610  * Async response handler: setup the rbuf and rsize for the specified
611  * transaction.  This function is used by the kernel to collect the
612  * response half of an asynchronous door call.
613  *
614  * If a door client attempts to collect a response before the op has
615  * completed (!response_ready), mark the arg as response_abort and
616  * set an error.  The response will be discarded when the op completes.
617  */
618 static int
619 smbd_dop_async_response(smbd_arg_t *rsp_arg)
620 {
621 	list_t		*arg_list = &smbd_doorsvc.sd_async_list;
622 	smbd_arg_t	*arg;
623 
624 	(void) mutex_lock(&smbd_doorsvc.sd_mutex);
625 	arg = list_head(arg_list);
626 
627 	while (arg != NULL) {
628 		assert(arg->magic == SMBD_ARG_MAGIC);
629 
630 		if (arg->hdr.dh_txid == rsp_arg->hdr.dh_txid) {
631 			if (!arg->response_ready) {
632 				arg->response_abort = B_TRUE;
633 				rsp_arg->hdr.dh_door_rc = SMB_DOP_NOT_CALLED;
634 				syslog(LOG_NOTICE, "doorsvc[%s]: %u not ready",
635 				    arg->opname, arg->hdr.dh_txid);
636 				break;
637 			}
638 
639 			rsp_arg->rbuf = arg->rbuf;
640 			rsp_arg->rsize = arg->rsize;
641 			arg->rbuf = NULL;
642 			arg->rsize = 0;
643 			smbd_door_release_async(arg);
644 			break;
645 		}
646 
647 		arg = list_next(arg_list, arg);
648 	}
649 
650 	(void) mutex_unlock(&smbd_doorsvc.sd_mutex);
651 	return (SMB_DOP_SUCCESS);
652 }
653 
654 static int
655 smbd_dop_user_nonauth_logon(smbd_arg_t *arg)
656 {
657 	uint32_t	sid = 0;
658 
659 	if (smb_common_decode(arg->data, arg->datalen,
660 	    xdr_uint32_t, &sid) != 0)
661 		return (SMB_DOP_DECODE_ERROR);
662 
663 	smbd_user_nonauth_logon(sid);
664 	return (SMB_DOP_SUCCESS);
665 }
666 
667 static int
668 smbd_dop_user_auth_logoff(smbd_arg_t *arg)
669 {
670 	uint32_t	sid = 0;
671 
672 	if (smb_common_decode(arg->data, arg->datalen,
673 	    xdr_uint32_t, &sid) != 0)
674 		return (SMB_DOP_DECODE_ERROR);
675 
676 	smbd_user_auth_logoff(sid);
677 	return (SMB_DOP_SUCCESS);
678 }
679 
680 /*
681  * Obtains an access token on successful user authentication.
682  */
683 static int
684 smbd_dop_user_auth_logon(smbd_arg_t *arg __unused)
685 {
686 
687 	/* No longer used */
688 	return (SMB_DOP_EMPTYBUF);
689 }
690 
691 /*
692  * SMB_DR_LOOKUP_NAME,
693  * SMB_DR_LOOKUP_LNAME (local-only, for idmap)
694  */
695 static int
696 smbd_dop_lookup_name(smbd_arg_t *arg)
697 {
698 	smb_domain_t	dinfo;
699 	smb_account_t	ainfo;
700 	lsa_account_t	acct;
701 	char		buf[MAXNAMELEN];
702 
703 	bzero(&acct, sizeof (lsa_account_t));
704 
705 	if (smb_common_decode(arg->data, arg->datalen,
706 	    lsa_account_xdr, &acct) != 0)
707 		return (SMB_DOP_DECODE_ERROR);
708 
709 	if (*acct.a_domain == '\0')
710 		(void) snprintf(buf, MAXNAMELEN, "%s", acct.a_name);
711 	else if (strchr(acct.a_domain, '.') != NULL)
712 		(void) snprintf(buf, MAXNAMELEN, "%s@%s", acct.a_name,
713 		    acct.a_domain);
714 	else
715 		(void) snprintf(buf, MAXNAMELEN, "%s\\%s", acct.a_domain,
716 		    acct.a_name);
717 
718 	switch (arg->hdr.dh_op) {
719 	case SMB_DR_LOOKUP_NAME:
720 		acct.a_status = lsa_lookup_name(buf, acct.a_sidtype, &ainfo);
721 		break;
722 
723 	case SMB_DR_LOOKUP_LNAME:
724 		/*
725 		 * Basically for idmap.  Don't call out to AD.
726 		 */
727 		acct.a_status = lsa_lookup_lname(buf, acct.a_sidtype, &ainfo);
728 		break;
729 
730 	default:
731 		assert(!"arg->hdr.dh_op");
732 		acct.a_status = NT_STATUS_INTERNAL_ERROR;
733 		break;
734 	}
735 
736 	if (acct.a_status == NT_STATUS_SUCCESS) {
737 		acct.a_sidtype = ainfo.a_type;
738 		smb_sid_tostr(ainfo.a_sid, acct.a_sid);
739 		(void) strlcpy(acct.a_name, ainfo.a_name, MAXNAMELEN);
740 
741 		if (smb_domain_lookup_name(ainfo.a_domain, &dinfo))
742 			(void) strlcpy(acct.a_domain, dinfo.di_fqname,
743 			    MAXNAMELEN);
744 		else
745 			(void) strlcpy(acct.a_domain, ainfo.a_domain,
746 			    MAXNAMELEN);
747 		smb_account_free(&ainfo);
748 	}
749 
750 	arg->rbuf = smb_common_encode(&acct, lsa_account_xdr, &arg->rsize);
751 
752 	if (arg->rbuf == NULL)
753 		return (SMB_DOP_ENCODE_ERROR);
754 	return (SMB_DOP_SUCCESS);
755 }
756 
757 /*
758  * SMB_DR_LOOKUP_SID,
759  * SMB_DR_LOOKUP_LSID (local-only, for idmap)
760  */
761 static int
762 smbd_dop_lookup_sid(smbd_arg_t *arg)
763 {
764 	smb_domain_t	dinfo;
765 	smb_account_t	ainfo;
766 	lsa_account_t	acct;
767 	smb_sid_t	*sid;
768 
769 	bzero(&acct, sizeof (lsa_account_t));
770 
771 	if (smb_common_decode(arg->data, arg->datalen,
772 	    lsa_account_xdr, &acct) != 0)
773 		return (SMB_DOP_DECODE_ERROR);
774 
775 	sid = smb_sid_fromstr(acct.a_sid);
776 
777 	switch (arg->hdr.dh_op) {
778 	case SMB_DR_LOOKUP_SID:
779 		acct.a_status = lsa_lookup_sid(sid, &ainfo);
780 		break;
781 
782 	case SMB_DR_LOOKUP_LSID:
783 		/*
784 		 * Basically for idmap.  Don't call out to AD.
785 		 */
786 		acct.a_status = lsa_lookup_lsid(sid, &ainfo);
787 		break;
788 
789 	default:
790 		assert(!"arg->hdr.dh_op");
791 		acct.a_status = NT_STATUS_INTERNAL_ERROR;
792 		break;
793 	}
794 
795 	smb_sid_free(sid);
796 
797 	if (acct.a_status == NT_STATUS_SUCCESS) {
798 		acct.a_sidtype = ainfo.a_type;
799 		smb_sid_tostr(ainfo.a_sid, acct.a_sid);
800 		(void) strlcpy(acct.a_name, ainfo.a_name, MAXNAMELEN);
801 
802 		if (smb_domain_lookup_name(ainfo.a_domain, &dinfo))
803 			(void) strlcpy(acct.a_domain, dinfo.di_fqname,
804 			    MAXNAMELEN);
805 		else
806 			(void) strlcpy(acct.a_domain, ainfo.a_domain,
807 			    MAXNAMELEN);
808 
809 		smb_account_free(&ainfo);
810 	}
811 
812 	arg->rbuf = smb_common_encode(&acct, lsa_account_xdr, &arg->rsize);
813 
814 	if (arg->rbuf == NULL)
815 		return (SMB_DOP_ENCODE_ERROR);
816 	return (SMB_DOP_SUCCESS);
817 }
818 
819 static int
820 smbd_dop_join(smbd_arg_t *arg)
821 {
822 	smb_joininfo_t	jdi;
823 	smb_joinres_t	jdres;
824 
825 	bzero(&jdi, sizeof (smb_joininfo_t));
826 	bzero(&jdres, sizeof (smb_joinres_t));
827 
828 	if (smb_common_decode(arg->data, arg->datalen,
829 	    smb_joininfo_xdr, &jdi) != 0)
830 		return (SMB_DOP_DECODE_ERROR);
831 
832 	smbd_join(&jdi, &jdres);
833 
834 	arg->rbuf = smb_common_encode(&jdres, smb_joinres_xdr, &arg->rsize);
835 
836 	if (arg->rbuf == NULL)
837 		return (SMB_DOP_ENCODE_ERROR);
838 	return (SMB_DOP_SUCCESS);
839 }
840 
841 static int
842 smbd_dop_get_dcinfo(smbd_arg_t *arg)
843 {
844 	smb_domainex_t	dxi;
845 
846 	if (!smb_domain_getinfo(&dxi))
847 		return (SMB_DOP_EMPTYBUF);
848 
849 	arg->rbuf = smb_string_encode(dxi.d_dci.dc_name, &arg->rsize);
850 
851 	if (arg->rbuf == NULL)
852 		return (SMB_DOP_ENCODE_ERROR);
853 	return (SMB_DOP_SUCCESS);
854 }
855 
856 /*
857  * Return the number of snapshots for a dataset
858  */
859 static int
860 smbd_dop_vss_get_count(smbd_arg_t *arg)
861 {
862 	smb_string_t	path;
863 	uint32_t	count;
864 
865 	bzero(&path, sizeof (smb_string_t));
866 	arg->rbuf = NULL;
867 
868 	if (smb_string_decode(&path, arg->data, arg->datalen) != 0)
869 		return (SMB_DOP_DECODE_ERROR);
870 
871 	if (smbd_vss_get_count(path.buf, &count) == 0)
872 		arg->rbuf = smb_common_encode(&count, xdr_uint32_t,
873 		    &arg->rsize);
874 
875 	xdr_free(smb_string_xdr, (char *)&path);
876 
877 	if (arg->rbuf == NULL)
878 		return (SMB_DOP_ENCODE_ERROR);
879 	return (SMB_DOP_SUCCESS);
880 }
881 
882 /*
883  * Return the count and list of snapshots.
884  * The list is in @GMT token format.
885  */
886 static int
887 smbd_dop_vss_get_snapshots(smbd_arg_t *arg)
888 {
889 	char				**gmtp;
890 	smb_gmttoken_query_t		request;
891 	smb_gmttoken_response_t		reply;
892 	uint_t				i;
893 
894 	bzero(&request, sizeof (smb_gmttoken_query_t));
895 	bzero(&reply, sizeof (smb_gmttoken_response_t));
896 
897 	if (smb_common_decode(arg->data, arg->datalen,
898 	    smb_gmttoken_query_xdr, &request) != 0)
899 		return (SMB_DOP_DECODE_ERROR);
900 
901 	reply.gtr_gmttokens.gtr_gmttokens_val = malloc(request.gtq_count *
902 	    sizeof (char *));
903 	bzero(reply.gtr_gmttokens.gtr_gmttokens_val, request.gtq_count *
904 	    sizeof (char *));
905 
906 	if (reply.gtr_gmttokens.gtr_gmttokens_val == NULL) {
907 		xdr_free(smb_gmttoken_query_xdr, (char *)&request);
908 		return (SMB_DOP_EMPTYBUF);
909 	}
910 
911 	smbd_vss_get_snapshots(request.gtq_path, request.gtq_count,
912 	    &reply.gtr_count,
913 	    &reply.gtr_gmttokens.gtr_gmttokens_len,
914 	    reply.gtr_gmttokens.gtr_gmttokens_val);
915 
916 	arg->rbuf = smb_common_encode(&reply, smb_gmttoken_response_xdr,
917 	    &arg->rsize);
918 	if (arg->rbuf == NULL) {
919 		xdr_free(smb_gmttoken_query_xdr, (char *)&request);
920 		return (SMB_DOP_ENCODE_ERROR);
921 	}
922 
923 	for (i = 0, gmtp = reply.gtr_gmttokens.gtr_gmttokens_val;
924 	    (i < request.gtq_count); i++) {
925 		if (*gmtp)
926 			free(*gmtp);
927 		gmtp++;
928 	}
929 
930 	free(reply.gtr_gmttokens.gtr_gmttokens_val);
931 	xdr_free(smb_gmttoken_query_xdr, (char *)&request);
932 	return (SMB_DOP_SUCCESS);
933 }
934 
935 /*
936  * Return the name of the snapshot that matches the dataset path
937  * and @GMT token.
938  */
939 static int
940 smbd_dop_vss_map_gmttoken(smbd_arg_t *arg)
941 {
942 	char			*snapname;
943 	smb_gmttoken_snapname_t	request;
944 
945 	bzero(&request, sizeof (smb_gmttoken_snapname_t));
946 
947 	if (smb_common_decode(arg->data, arg->datalen,
948 	    smb_gmttoken_snapname_xdr, &request) != 0) {
949 		xdr_free(smb_gmttoken_snapname_xdr, (char *)&request);
950 		return (SMB_DOP_DECODE_ERROR);
951 	}
952 
953 	if ((snapname = malloc(MAXPATHLEN)) == NULL) {
954 		xdr_free(smb_gmttoken_snapname_xdr, (char *)&request);
955 		return (SMB_DOP_ENCODE_ERROR);
956 	}
957 
958 	if ((smbd_vss_map_gmttoken(request.gts_path, request.gts_gmttoken,
959 	    request.gts_toktime, snapname) != 0)) {
960 		*snapname = '\0';
961 	}
962 
963 	arg->rbuf = smb_string_encode(snapname, &arg->rsize);
964 	xdr_free(smb_gmttoken_snapname_xdr, (char *)&request);
965 	free(snapname);
966 
967 	if (arg->rbuf == NULL)
968 		return (SMB_DOP_ENCODE_ERROR);
969 	return (SMB_DOP_SUCCESS);
970 }
971 
972 static int
973 smbd_dop_ads_find_host(smbd_arg_t *arg)
974 {
975 	smb_ads_host_info_t	*hinfo = NULL;
976 	char			*hostname = "";
977 	smb_string_t		fqdn;
978 
979 	bzero(&fqdn, sizeof (smb_string_t));
980 
981 	if (smb_string_decode(&fqdn, arg->data, arg->datalen) != 0)
982 		return (SMB_DOP_DECODE_ERROR);
983 
984 	if ((hinfo = smb_ads_find_host(fqdn.buf)) != NULL)
985 		hostname = hinfo->name;
986 
987 	xdr_free(smb_string_xdr, (char *)&fqdn);
988 
989 	arg->rbuf = smb_string_encode(hostname, &arg->rsize);
990 	free(hinfo);
991 
992 	if (arg->rbuf == NULL)
993 		return (SMB_DOP_ENCODE_ERROR);
994 	return (SMB_DOP_SUCCESS);
995 }
996 
997 /*
998  * Query the list of user/group quota entries for a given filesystem.
999  */
1000 static int
1001 smbd_dop_quota_query(smbd_arg_t *arg)
1002 {
1003 	smb_quota_query_t	request;
1004 	smb_quota_response_t	reply;
1005 	uint32_t		status;
1006 
1007 	bzero(&request, sizeof (smb_quota_query_t));
1008 	bzero(&reply, sizeof (smb_quota_response_t));
1009 
1010 	if (smb_common_decode(arg->data, arg->datalen,
1011 	    smb_quota_query_xdr, &request) != 0)
1012 		return (SMB_DOP_DECODE_ERROR);
1013 
1014 	status = smb_quota_query(&request, &reply);
1015 	reply.qr_status = status;
1016 
1017 	arg->rbuf = smb_common_encode(&reply, smb_quota_response_xdr,
1018 	    &arg->rsize);
1019 
1020 	xdr_free(smb_quota_query_xdr, (char *)&request);
1021 	smb_quota_free(&reply);
1022 
1023 	if (arg->rbuf == NULL)
1024 		return (SMB_DOP_ENCODE_ERROR);
1025 	return (SMB_DOP_SUCCESS);
1026 }
1027 
1028 /*
1029  * Set a list of user/group quota entries for a given filesystem.
1030  */
1031 static int
1032 smbd_dop_quota_set(smbd_arg_t *arg)
1033 {
1034 	smb_quota_set_t	request;
1035 	uint32_t	status = 0;
1036 
1037 	bzero(&request, sizeof (smb_quota_set_t));
1038 
1039 	if (smb_common_decode(arg->data, arg->datalen,
1040 	    smb_quota_set_xdr, &request) != 0)
1041 		return (SMB_DOP_DECODE_ERROR);
1042 
1043 	status = smb_quota_set(&request);
1044 
1045 	arg->rbuf = smb_common_encode(&status, xdr_uint32_t, &arg->rsize);
1046 	xdr_free(smb_quota_set_xdr, (char *)&request);
1047 
1048 	if (arg->rbuf == NULL)
1049 		return (SMB_DOP_ENCODE_ERROR);
1050 	return (SMB_DOP_SUCCESS);
1051 }
1052 
1053 static int
1054 smbd_dop_dfs_get_referrals(smbd_arg_t *arg)
1055 {
1056 	dfs_referral_query_t	request;
1057 	dfs_referral_response_t	reply;
1058 
1059 	bzero(&request, sizeof (request));
1060 	bzero(&reply, sizeof (reply));
1061 
1062 	if (smb_common_decode(arg->data, arg->datalen,
1063 	    dfs_referral_query_xdr, &request) != 0)
1064 		return (SMB_DOP_DECODE_ERROR);
1065 
1066 	reply.rp_status = dfs_get_referrals((const char *)request.rq_path,
1067 	    request.rq_type, &reply.rp_referrals);
1068 
1069 	if (reply.rp_status != ERROR_SUCCESS)
1070 		bzero(&reply.rp_referrals, sizeof (dfs_info_t));
1071 
1072 	arg->rbuf = smb_common_encode(&reply, dfs_referral_response_xdr,
1073 	    &arg->rsize);
1074 
1075 	if (reply.rp_status == ERROR_SUCCESS)
1076 		dfs_info_free(&reply.rp_referrals);
1077 
1078 	xdr_free(dfs_referral_query_xdr, (char *)&request);
1079 
1080 	if (arg->rbuf == NULL)
1081 		return (SMB_DOP_ENCODE_ERROR);
1082 	return (SMB_DOP_SUCCESS);
1083 }
1084 
1085 static int
1086 smbd_dop_shr_hostaccess(smbd_arg_t *arg)
1087 {
1088 	smb_shr_hostaccess_query_t request;
1089 	uint32_t reply;
1090 
1091 	bzero(&request, sizeof (request));
1092 	bzero(&reply, sizeof (reply));
1093 
1094 	if (smb_common_decode(arg->data, arg->datalen,
1095 	    smb_shr_hostaccess_query_xdr, &request) != 0)
1096 		return (SMB_DOP_DECODE_ERROR);
1097 
1098 	reply = smb_shr_hostaccess(&request.shq_ipaddr, request.shq_none,
1099 	    request.shq_ro, request.shq_rw, request.shq_flag);
1100 
1101 	arg->rbuf = smb_common_encode(&reply, xdr_uint32_t, &arg->rsize);
1102 
1103 	xdr_free(smb_shr_hostaccess_query_xdr, (char *)&request);
1104 
1105 	if (arg->rbuf == NULL)
1106 		return (SMB_DOP_ENCODE_ERROR);
1107 	return (SMB_DOP_SUCCESS);
1108 }
1109 
1110 static int
1111 smbd_dop_shr_exec(smbd_arg_t *arg)
1112 {
1113 	smb_shr_execinfo_t request;
1114 	int reply;
1115 
1116 	bzero(&request, sizeof (request));
1117 	bzero(&reply, sizeof (reply));
1118 
1119 	if (smb_common_decode(arg->data, arg->datalen,
1120 	    smb_shr_execinfo_xdr, &request) != 0)
1121 		return (SMB_DOP_DECODE_ERROR);
1122 
1123 	reply = smb_shr_exec(&request);
1124 
1125 	if (reply != 0)
1126 		syslog(LOG_NOTICE, "Failed to execute %s command",
1127 		    (request.e_type == SMB_EXEC_MAP) ? "map" : "unmap");
1128 
1129 	arg->rbuf = smb_common_encode(&reply, xdr_int, &arg->rsize);
1130 
1131 	xdr_free(smb_shr_execinfo_xdr, (char *)&request);
1132 
1133 	if (arg->rbuf == NULL)
1134 		return (SMB_DOP_ENCODE_ERROR);
1135 	return (SMB_DOP_SUCCESS);
1136 }
1137 
1138 /* ARGSUSED */
1139 static int
1140 smbd_dop_notify_dc_changed(smbd_arg_t *arg)
1141 {
1142 
1143 	smbd_dc_monitor_refresh();
1144 
1145 	return (SMB_DOP_SUCCESS);
1146 }
1147