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