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