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 (NULL);
 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 }