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