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