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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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