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