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