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