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