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