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