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