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