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