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