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 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Server Service RPC (SRVSVC) server-side interface definition.
  29  * The server service provides a remote administration interface.
  30  *
  31  * This service uses NERR/Win32 error codes rather than NT status
  32  * values.
  33  */
  34 
  35 #include <sys/errno.h>
  36 #include <sys/tzfile.h>
  37 #include <unistd.h>
  38 #include <netdb.h>
  39 #include <strings.h>
  40 #include <time.h>
  41 #include <thread.h>
  42 #include <ctype.h>
  43 #include <stdlib.h>
  44 #include <string.h>
  45 #include <sys/types.h>
  46 #include <sys/socket.h>
  47 #include <netinet/in.h>
  48 #include <arpa/inet.h>
  49 #include <libshare.h>
  50 #include <libnvpair.h>
  51 #include <sys/idmap.h>
  52 #include <pwd.h>
  53 #include <nss_dbdefs.h>
  54 #include <smbsrv/libsmb.h>
  55 #include <smbsrv/libmlsvc.h>
  56 #include <smbsrv/nmpipes.h>
  57 #include <smbsrv/smb.h>
  58 #include <smbsrv/netrauth.h>
  59 #include <smbsrv/ndl/srvsvc.ndl>
  60 #include "mlsvc.h"
  61 
  62 /*
  63  * Qualifier types for NetConnectEnum.
  64  */
  65 #define SRVSVC_CONNECT_ENUM_NULL        0
  66 #define SRVSVC_CONNECT_ENUM_SHARE       1
  67 #define SRVSVC_CONNECT_ENUM_WKSTN       2
  68 
  69 #define SMB_SRVSVC_MAXBUFLEN            (8 * 1024 * 1024)
  70 #define SMB_SRVSVC_MAXPREFLEN           ((uint32_t)(-1))
  71 
  72 typedef struct srvsvc_sd {
  73         uint8_t *sd_buf;
  74         uint32_t sd_size;
  75 } srvsvc_sd_t;
  76 
  77 typedef struct srvsvc_netshare_setinfo {
  78         char *nss_netname;
  79         char *nss_comment;
  80         char *nss_path;
  81         uint32_t nss_type;
  82         srvsvc_sd_t nss_sd;
  83 } srvsvc_netshare_setinfo_t;
  84 
  85 typedef union srvsvc_netshare_getinfo {
  86         struct mslm_NetShareInfo_0 nsg_info0;
  87         struct mslm_NetShareInfo_1 nsg_info1;
  88         struct mslm_NetShareInfo_2 nsg_info2;
  89         struct mslm_NetShareInfo_501 nsg_info501;
  90         struct mslm_NetShareInfo_502 nsg_info502;
  91         struct mslm_NetShareInfo_503 nsg_info503;
  92         struct mslm_NetShareInfo_1004 nsg_info1004;
  93         struct mslm_NetShareInfo_1005 nsg_info1005;
  94         struct mslm_NetShareInfo_1006 nsg_info1006;
  95         struct mslm_NetShareInfo_1501 nsg_info1501;
  96 } srvsvc_netshare_getinfo_t;
  97 
  98 typedef struct mslm_infonres srvsvc_infonres_t;
  99 typedef struct mslm_NetConnectEnum srvsvc_NetConnectEnum_t;
 100 
 101 static uint32_t srvsvc_netconnectenum_level0(ndr_xa_t *, smb_svcenum_t *,
 102     srvsvc_NetConnectEnum_t *);
 103 static uint32_t srvsvc_netconnectenum_level1(ndr_xa_t *, smb_svcenum_t *,
 104     srvsvc_NetConnectEnum_t *);
 105 static uint32_t srvsvc_netconnectenum_common(ndr_xa_t *,
 106     srvsvc_NetConnectInfo_t *, smb_netsvc_t *, smb_svcenum_t *);
 107 
 108 static DWORD srvsvc_NetFileEnum2(ndr_xa_t *, struct mslm_NetFileEnum *,
 109     smb_svcenum_t *se);
 110 static DWORD srvsvc_NetFileEnum3(ndr_xa_t *, struct mslm_NetFileEnum *,
 111     smb_svcenum_t *se);
 112 
 113 static uint32_t srvsvc_NetSessionEnumCommon(ndr_xa_t *, srvsvc_infonres_t *,
 114     smb_netsvc_t *, smb_svcenum_t *);
 115 
 116 static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *, srvsvc_infonres_t *,
 117     smb_svcenum_t *, int);
 118 static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *, srvsvc_infonres_t *,
 119     smb_svcenum_t *, int);
 120 static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *, srvsvc_infonres_t *,
 121     smb_svcenum_t *, int);
 122 static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *, srvsvc_infonres_t *,
 123     smb_svcenum_t *, int);
 124 static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *, srvsvc_infonres_t *,
 125     smb_svcenum_t *, int);
 126 static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *, smb_svcenum_t *,
 127     smb_share_t *, void *);
 128 static boolean_t srvsvc_add_autohome(ndr_xa_t *, smb_svcenum_t *, void *);
 129 static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
 130 static uint32_t srvsvc_share_getsd(ndr_xa_t *, smb_share_t *, srvsvc_sd_t *);
 131 
 132 static int srvsvc_netconnect_qualifier(const char *);
 133 static void srvsvc_estimate_limit(smb_svcenum_t *, uint32_t);
 134 static uint32_t srvsvc_open_sessions(void);
 135 static uint32_t srvsvc_open_connections(uint32_t, const char *);
 136 static uint32_t srvsvc_open_files(void);
 137 
 138 static uint32_t srvsvc_modify_share(smb_share_t *,
 139     srvsvc_netshare_setinfo_t *);
 140 static uint32_t srvsvc_modify_transient_share(smb_share_t *,
 141     srvsvc_netshare_setinfo_t *);
 142 static uint32_t srvsvc_update_share_flags(smb_share_t *, uint32_t);
 143 static uint32_t srvsvc_get_share_flags(smb_share_t *);
 144 
 145 static uint32_t srvsvc_sa_add(char *, char *, char *);
 146 static uint32_t srvsvc_sa_delete(char *);
 147 static uint32_t srvsvc_sa_modify(smb_share_t *, srvsvc_netshare_setinfo_t *);
 148 static uint32_t srvsvc_sa_setprop(smb_share_t *, nvlist_t *);
 149 
 150 static char empty_string[1];
 151 
 152 static ndr_stub_table_t srvsvc_stub_table[];
 153 
 154 static ndr_service_t srvsvc_service = {
 155         "SRVSVC",                       /* name */
 156         "Server services",              /* desc */
 157         "\\srvsvc",                     /* endpoint */
 158         PIPE_NTSVCS,                    /* sec_addr_port */
 159         "4b324fc8-1670-01d3-1278-5a47bf6ee188", 3,      /* abstract */
 160         NDR_TRANSFER_SYNTAX_UUID,               2,      /* transfer */
 161         0,                              /* no bind_instance_size */
 162         0,                              /* no bind_req() */
 163         0,                              /* no unbind_and_close() */
 164         0,                              /* use generic_call_stub() */
 165         &TYPEINFO(srvsvc_interface),        /* interface ti */
 166         srvsvc_stub_table               /* stub_table */
 167 };
 168 
 169 /*
 170  * srvsvc_initialize
 171  *
 172  * This function registers the SRVSVC RPC interface with the RPC runtime
 173  * library. It must be called in order to use either the client side
 174  * or the server side functions.
 175  */
 176 void
 177 srvsvc_initialize(void)
 178 {
 179         (void) ndr_svc_register(&srvsvc_service);
 180 }
 181 
 182 /*
 183  * Turn "dfsroot" property on/off for the specified
 184  * share and save it.
 185  *
 186  * If the requested value is the same as what is already
 187  * set then no change is required and the function returns.
 188  */
 189 uint32_t
 190 srvsvc_shr_setdfsroot(smb_share_t *si, boolean_t on)
 191 {
 192         char *dfs = NULL;
 193         nvlist_t *nvl;
 194         uint32_t nerr;
 195 
 196         if (on && ((si->shr_flags & SMB_SHRF_DFSROOT) == 0)) {
 197                 si->shr_flags |= SMB_SHRF_DFSROOT;
 198                 dfs = "true";
 199         } else if (!on && (si->shr_flags & SMB_SHRF_DFSROOT)) {
 200                 si->shr_flags &= ~SMB_SHRF_DFSROOT;
 201                 dfs = "false";
 202         }
 203 
 204         if (dfs == NULL)
 205                 return (ERROR_SUCCESS);
 206 
 207         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
 208                 return (NERR_InternalError);
 209 
 210         if (nvlist_add_string(nvl, SHOPT_DFSROOT, dfs) != 0) {
 211                 nvlist_free(nvl);
 212                 return (NERR_InternalError);
 213         }
 214 
 215         nerr = srvsvc_sa_setprop(si, nvl);
 216         nvlist_free(nvl);
 217 
 218         if (nerr != NERR_Success)
 219                 return (nerr);
 220 
 221         return (smb_shr_modify(si));
 222 }
 223 
 224 /*
 225  * srvsvc_s_NetConnectEnum
 226  *
 227  * List tree connections made to a share on this server or all tree
 228  * connections established from a specific client.  Administrator,
 229  * Server Operator, Print Operator or Power User group membership
 230  * is required to use this interface.
 231  *
 232  * There are three information levels:  0, 1, and 50.  We don't support
 233  * level 50, which is only used by Windows 9x clients.
 234  *
 235  * It seems Server Manger (srvmgr) only sends workstation as the qualifier
 236  * and the Computer Management Interface on Windows 2000 doesn't request
 237  * a list of connections.
 238  *
 239  * Return Values:
 240  * ERROR_SUCCESS            Success
 241  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
 242  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
 243  * ERROR_INVALID_LEVEL      Unknown information level specified.
 244  * ERROR_MORE_DATA          Partial date returned, more entries available.
 245  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
 246  * NERR_NetNameNotFound     The share qualifier cannot be found.
 247  * NERR_BufTooSmall         The supplied buffer is too small.
 248  */
 249 static int
 250 srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa)
 251 {
 252         srvsvc_NetConnectEnum_t         *param = arg;
 253         smb_netsvc_t                    *ns;
 254         smb_svcenum_t                   se;
 255         char                            *qualifier;
 256         int                             qualtype;
 257         DWORD                           status = ERROR_SUCCESS;
 258 
 259         if (!ndr_is_poweruser(mxa)) {
 260                 status = ERROR_ACCESS_DENIED;
 261                 goto srvsvc_netconnectenum_error;
 262         }
 263 
 264         qualifier = (char *)param->qualifier;
 265         qualtype = srvsvc_netconnect_qualifier(qualifier);
 266         if (qualtype == SRVSVC_CONNECT_ENUM_NULL) {
 267                 status = NERR_NetNameNotFound;
 268                 goto srvsvc_netconnectenum_error;
 269         }
 270 
 271         param->total_entries = srvsvc_open_connections(qualtype, qualifier);
 272         if (param->total_entries == 0) {
 273                 bzero(param, sizeof (srvsvc_NetConnectEnum_t));
 274                 param->status = ERROR_SUCCESS;
 275                 return (NDR_DRC_OK);
 276         }
 277 
 278         bzero(&se, sizeof (smb_svcenum_t));
 279         se.se_type = SMB_SVCENUM_TYPE_TREE;
 280         se.se_level = param->info.level;
 281         se.se_ntotal = param->total_entries;
 282         se.se_nlimit = se.se_ntotal;
 283 
 284         if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
 285             param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
 286                 se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
 287         else
 288                 se.se_prefmaxlen = param->pref_max_len;
 289 
 290         if (param->resume_handle) {
 291                 se.se_resume = *param->resume_handle;
 292                 se.se_nskip = se.se_resume;
 293                 *param->resume_handle = 0;
 294         }
 295 
 296         switch (param->info.level) {
 297         case 0:
 298                 status = srvsvc_netconnectenum_level0(mxa, &se, param);
 299                 break;
 300         case 1:
 301                 status = srvsvc_netconnectenum_level1(mxa, &se, param);
 302                 break;
 303         case 50:
 304                 status = ERROR_NOT_SUPPORTED;
 305                 break;
 306         default:
 307                 status = ERROR_INVALID_LEVEL;
 308                 break;
 309         }
 310 
 311         if (status != ERROR_SUCCESS)
 312                 goto srvsvc_netconnectenum_error;
 313 
 314         if ((ns = smb_kmod_enum_init(&se)) == NULL) {
 315                 status = ERROR_NOT_ENOUGH_MEMORY;
 316                 goto srvsvc_netconnectenum_error;
 317         }
 318 
 319         status = srvsvc_netconnectenum_common(mxa, &param->info, ns, &se);
 320         smb_kmod_enum_fini(ns);
 321 
 322         if (status != ERROR_SUCCESS)
 323                 goto srvsvc_netconnectenum_error;
 324 
 325         if (param->resume_handle &&
 326             param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
 327                 if (se.se_resume < param->total_entries) {
 328                         *param->resume_handle = se.se_resume;
 329                         status = ERROR_MORE_DATA;
 330                 }
 331         }
 332 
 333         param->status = status;
 334         return (NDR_DRC_OK);
 335 
 336 srvsvc_netconnectenum_error:
 337         bzero(param, sizeof (srvsvc_NetConnectEnum_t));
 338         param->status = status;
 339         return (NDR_DRC_OK);
 340 }
 341 
 342 /*
 343  * Allocate memory and estimate the number of objects that can
 344  * be returned for NetConnectEnum level 0.
 345  */
 346 static uint32_t
 347 srvsvc_netconnectenum_level0(ndr_xa_t *mxa, smb_svcenum_t *se,
 348     srvsvc_NetConnectEnum_t *param)
 349 {
 350         srvsvc_NetConnectInfo0_t        *info0;
 351         srvsvc_NetConnectInfoBuf0_t     *ci0;
 352 
 353         if ((info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t)) == NULL)
 354                 return (ERROR_NOT_ENOUGH_MEMORY);
 355 
 356         bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
 357         param->info.ru.info0 = info0;
 358 
 359         srvsvc_estimate_limit(se, sizeof (srvsvc_NetConnectInfoBuf0_t));
 360         if (se->se_nlimit == 0)
 361                 return (NERR_BufTooSmall);
 362 
 363         do {
 364                 ci0 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf0_t, se->se_nlimit);
 365                 if (ci0 == NULL)
 366                         se->se_nlimit >>= 1;
 367         } while ((se->se_nlimit > 0) && (ci0 == NULL));
 368 
 369         if (ci0 == NULL)
 370                 return (ERROR_NOT_ENOUGH_MEMORY);
 371 
 372         info0->ci0 = ci0;
 373         info0->entries_read = 0;
 374         return (ERROR_SUCCESS);
 375 }
 376 
 377 /*
 378  * Allocate memory and estimate the number of objects that can
 379  * be returned for NetConnectEnum level 1.
 380  */
 381 static uint32_t
 382 srvsvc_netconnectenum_level1(ndr_xa_t *mxa, smb_svcenum_t *se,
 383     srvsvc_NetConnectEnum_t *param)
 384 {
 385         srvsvc_NetConnectInfo1_t        *info1;
 386         srvsvc_NetConnectInfoBuf1_t     *ci1;
 387 
 388         if ((info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t)) == NULL)
 389                 return (ERROR_NOT_ENOUGH_MEMORY);
 390 
 391         bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
 392         param->info.ru.info1 = info1;
 393 
 394         srvsvc_estimate_limit(se,
 395             sizeof (srvsvc_NetConnectInfoBuf1_t) + MAXNAMELEN);
 396         if (se->se_nlimit == 0)
 397                 return (NERR_BufTooSmall);
 398 
 399         do {
 400                 ci1 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf1_t, se->se_nlimit);
 401                 if (ci1 == NULL)
 402                         se->se_nlimit >>= 1;
 403         } while ((se->se_nlimit > 0) && (ci1 == NULL));
 404 
 405         if (ci1 == NULL)
 406                 return (ERROR_NOT_ENOUGH_MEMORY);
 407 
 408         info1->ci1 = ci1;
 409         info1->entries_read = 0;
 410         return (ERROR_SUCCESS);
 411 }
 412 
 413 /*
 414  * Request a list of connections from the kernel and set up
 415  * the connection information to be returned to the client.
 416  */
 417 static uint32_t
 418 srvsvc_netconnectenum_common(ndr_xa_t *mxa, srvsvc_NetConnectInfo_t *info,
 419     smb_netsvc_t *ns, smb_svcenum_t *se)
 420 {
 421         srvsvc_NetConnectInfo0_t        *info0;
 422         srvsvc_NetConnectInfo1_t        *info1;
 423         srvsvc_NetConnectInfoBuf0_t     *ci0;
 424         srvsvc_NetConnectInfoBuf1_t     *ci1;
 425         smb_netsvcitem_t                *item;
 426         smb_netconnectinfo_t            *tree;
 427 
 428         if (smb_kmod_enum(ns) != 0)
 429                 return (ERROR_INTERNAL_ERROR);
 430 
 431         info0 = info->ru.info0;
 432         ci0 = info0->ci0;
 433 
 434         info1 = info->ru.info1;
 435         ci1 = info1->ci1;
 436 
 437         item = list_head(&ns->ns_list);
 438         while (item != NULL) {
 439                 tree = &item->nsi_un.nsi_tree;
 440 
 441                 switch (se->se_level) {
 442                 case 0:
 443                         ci0->coni0_id = tree->ci_id;
 444                         ++ci0;
 445                         ++info0->entries_read;
 446                         break;
 447                 case 1:
 448                         ci1->coni1_id = tree->ci_id;
 449                         ci1->coni1_type = tree->ci_type;
 450                         ci1->coni1_num_opens = tree->ci_numopens;
 451                         ci1->coni1_num_users = tree->ci_numusers;
 452                         ci1->coni1_time = tree->ci_time;
 453                         ci1->coni1_username = (uint8_t *)
 454                             NDR_STRDUP(mxa, tree->ci_username);
 455                         ci1->coni1_netname = (uint8_t *)
 456                             NDR_STRDUP(mxa, tree->ci_share);
 457                         ++ci1;
 458                         ++info1->entries_read;
 459                         break;
 460                 default:
 461                         return (ERROR_INVALID_LEVEL);
 462                 }
 463 
 464                 ++se->se_resume;
 465                 item = list_next(&ns->ns_list, item);
 466         }
 467 
 468         return (ERROR_SUCCESS);
 469 }
 470 
 471 /*
 472  * srvsvc_netconnect_qualifier
 473  *
 474  * The qualifier is a string that specifies a share name or computer name
 475  * for the connections of interest.  If it is a share name then all the
 476  * connections made to that share name are listed.  If it is a computer
 477  * name (it starts with two backslash characters), then NetConnectEnum
 478  * lists all connections made from that computer to the specified server.
 479  */
 480 static int
 481 srvsvc_netconnect_qualifier(const char *qualifier)
 482 {
 483         if (qualifier == NULL || *qualifier == '\0')
 484                 return (SRVSVC_CONNECT_ENUM_NULL);
 485 
 486         if (strlen(qualifier) > MAXHOSTNAMELEN)
 487                 return (SRVSVC_CONNECT_ENUM_NULL);
 488 
 489         if (qualifier[0] == '\\' && qualifier[1] == '\\') {
 490                 return (SRVSVC_CONNECT_ENUM_WKSTN);
 491         } else {
 492                 if (!smb_shr_exists((char *)qualifier))
 493                         return (SRVSVC_CONNECT_ENUM_NULL);
 494 
 495                 return (SRVSVC_CONNECT_ENUM_SHARE);
 496         }
 497 }
 498 
 499 static uint32_t
 500 srvsvc_open_sessions(void)
 501 {
 502         smb_opennum_t   opennum;
 503 
 504         bzero(&opennum, sizeof (smb_opennum_t));
 505         if (smb_kmod_get_open_num(&opennum) != 0)
 506                 return (0);
 507 
 508         return (opennum.open_users);
 509 }
 510 
 511 static uint32_t
 512 srvsvc_open_connections(uint32_t qualtype, const char *qualifier)
 513 {
 514         smb_opennum_t   opennum;
 515 
 516         bzero(&opennum, sizeof (smb_opennum_t));
 517         opennum.qualtype = qualtype;
 518         (void) strlcpy(opennum.qualifier, qualifier, MAXNAMELEN);
 519 
 520         if (smb_kmod_get_open_num(&opennum) != 0)
 521                 return (0);
 522 
 523         return (opennum.open_trees);
 524 }
 525 
 526 static uint32_t
 527 srvsvc_open_files(void)
 528 {
 529         smb_opennum_t   opennum;
 530 
 531         bzero(&opennum, sizeof (smb_opennum_t));
 532         if (smb_kmod_get_open_num(&opennum) != 0)
 533                 return (0);
 534 
 535         return (opennum.open_files);
 536 }
 537 
 538 /*
 539  * srvsvc_s_NetFileEnum
 540  *
 541  * Return information on open files or named pipes. Only members of the
 542  * Administrators or Server Operators local groups are allowed to make
 543  * this call. Currently, we only support Administrators.
 544  *
 545  * If basepath is null, all open resources are enumerated. If basepath
 546  * is non-null, only resources that have basepath as a prefix should
 547  * be returned.
 548  *
 549  * If username is specified (non-null), only files opened by username
 550  * should be returned.
 551  *
 552  * Notes:
 553  * 1. We don't validate the servername because we would have to check
 554  * all primary IPs and the ROI seems unlikely to be worth it.
 555  * 2. Both basepath and username are currently ignored because both
 556  * Server Manger (NT 4.0) and CMI (Windows 2000) always set them to null.
 557  *
 558  * The level of information requested may be one of:
 559  *
 560  *  2   Return the file identification number.
 561  *      This level is not supported on Windows Me/98/95.
 562  *
 563  *  3   Return information about the file.
 564  *      This level is not supported on Windows Me/98/95.
 565  *
 566  *  50  Windows Me/98/95:  Return information about the file.
 567  *
 568  * Note:
 569  * If pref_max_len is unlimited and resume_handle is null, the client
 570  * expects to receive all data in a single call.
 571  * If we are unable to do fit all data in a single response, we would
 572  * normally return ERROR_MORE_DATA with a partial list.
 573  *
 574  * Unfortunately, when both of these conditions occur, Server Manager
 575  * pops up an error box with the message "more data available" and
 576  * doesn't display any of the returned data. In this case, it is
 577  * probably better to return ERROR_SUCCESS with the partial list.
 578  * Windows 2000 doesn't have this problem because it always sends a
 579  * non-null resume_handle.
 580  *
 581  * Return Values:
 582  * ERROR_SUCCESS            Success
 583  * ERROR_ACCESS_DENIED      Caller does not have access to this call.
 584  * ERROR_INVALID_PARAMETER  One of the parameters is invalid.
 585  * ERROR_INVALID_LEVEL      Unknown information level specified.
 586  * ERROR_MORE_DATA          Partial date returned, more entries available.
 587  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
 588  * NERR_BufTooSmall         The supplied buffer is too small.
 589  */
 590 static int
 591 srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa)
 592 {
 593         struct mslm_NetFileEnum *param = arg;
 594         smb_svcenum_t           se;
 595         DWORD                   status;
 596 
 597         if (!ndr_is_admin(mxa)) {
 598                 bzero(param, sizeof (struct mslm_NetFileEnum));
 599                 param->status = ERROR_ACCESS_DENIED;
 600                 return (NDR_DRC_OK);
 601         }
 602 
 603         if ((param->total_entries = srvsvc_open_files()) == 0) {
 604                 bzero(param, sizeof (struct mslm_NetFileEnum));
 605                 param->status = ERROR_SUCCESS;
 606                 return (NDR_DRC_OK);
 607         }
 608 
 609         bzero(&se, sizeof (smb_svcenum_t));
 610         se.se_type = SMB_SVCENUM_TYPE_FILE;
 611         se.se_level = param->info.switch_value;
 612         se.se_ntotal = param->total_entries;
 613         se.se_nlimit = se.se_ntotal;
 614 
 615         if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
 616             param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
 617                 se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
 618         else
 619                 se.se_prefmaxlen = param->pref_max_len;
 620 
 621         if (param->resume_handle) {
 622                 se.se_resume = *param->resume_handle;
 623                 se.se_nskip = se.se_resume;
 624                 *param->resume_handle = 0;
 625         }
 626 
 627         switch (param->info.switch_value) {
 628         case 2:
 629                 status = srvsvc_NetFileEnum2(mxa, param, &se);
 630                 break;
 631 
 632         case 3:
 633                 status = srvsvc_NetFileEnum3(mxa, param, &se);
 634                 break;
 635 
 636         case 50:
 637                 status = ERROR_NOT_SUPPORTED;
 638                 break;
 639 
 640         default:
 641                 status = ERROR_INVALID_LEVEL;
 642                 break;
 643         }
 644 
 645         if (status != ERROR_SUCCESS) {
 646                 bzero(param, sizeof (struct mslm_NetFileEnum));
 647                 param->status = status;
 648                 return (NDR_DRC_OK);
 649         }
 650 
 651         if (param->resume_handle &&
 652             param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
 653                 if (se.se_resume < param->total_entries) {
 654                         *param->resume_handle = se.se_resume;
 655                         status = ERROR_MORE_DATA;
 656                 }
 657         }
 658 
 659         param->status = status;
 660         return (NDR_DRC_OK);
 661 }
 662 
 663 /*
 664  * Build level 2 file information.
 665  *
 666  * SMB fids are 16-bit values but this interface expects 32-bit file ids.
 667  * So we use the uniqid here.
 668  *
 669  * On success, the caller expects that the info2, fi2 and entries_read
 670  * fields have been set up.
 671  */
 672 static DWORD
 673 srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
 674     smb_svcenum_t *se)
 675 {
 676         struct mslm_NetFileInfoBuf2     *fi2;
 677         smb_netsvc_t                    *ns;
 678         smb_netsvcitem_t                *item;
 679         smb_netfileinfo_t               *ofile;
 680         uint32_t                        entries_read = 0;
 681 
 682         param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
 683         if (param->info.ru.info2 == NULL)
 684                 return (ERROR_NOT_ENOUGH_MEMORY);
 685 
 686         srvsvc_estimate_limit(se, sizeof (struct mslm_NetFileInfoBuf2));
 687         if (se->se_nlimit == 0)
 688                 return (NERR_BufTooSmall);
 689 
 690         do {
 691                 fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, se->se_nlimit);
 692                 if (fi2 == NULL)
 693                         se->se_nlimit >>= 1;
 694         } while ((se->se_nlimit > 0) && (fi2 == NULL));
 695 
 696         if (fi2 == NULL)
 697                 return (ERROR_NOT_ENOUGH_MEMORY);
 698 
 699         param->info.ru.info2->fi2 = fi2;
 700 
 701         if ((ns = smb_kmod_enum_init(se)) == NULL)
 702                 return (ERROR_NOT_ENOUGH_MEMORY);
 703 
 704         if (smb_kmod_enum(ns) != 0) {
 705                 smb_kmod_enum_fini(ns);
 706                 return (ERROR_INTERNAL_ERROR);
 707         }
 708 
 709         item = list_head(&ns->ns_list);
 710         while (item != NULL) {
 711                 ofile = &item->nsi_un.nsi_ofile;
 712                 fi2->fi2_id = ofile->fi_uniqid;
 713 
 714                 ++entries_read;
 715                 ++fi2;
 716                 item = list_next(&ns->ns_list, item);
 717         }
 718 
 719         se->se_resume += entries_read;
 720         param->info.ru.info2->entries_read = entries_read;
 721         smb_kmod_enum_fini(ns);
 722         return (ERROR_SUCCESS);
 723 }
 724 
 725 /*
 726  * Build level 3 file information.
 727  *
 728  * SMB fids are 16-bit values but this interface expects 32-bit file ids.
 729  * So we use the uniqid here.
 730  *
 731  * On success, the caller expects that the info3, fi3 and entries_read
 732  * fields have been set up.
 733  */
 734 static DWORD
 735 srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
 736     smb_svcenum_t *se)
 737 {
 738         struct mslm_NetFileInfoBuf3     *fi3;
 739         smb_netsvc_t                    *ns;
 740         smb_netsvcitem_t                *item;
 741         smb_netfileinfo_t               *ofile;
 742         uint32_t                        entries_read = 0;
 743 
 744         param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3);
 745         if (param->info.ru.info3 == NULL)
 746                 return (ERROR_NOT_ENOUGH_MEMORY);
 747 
 748         srvsvc_estimate_limit(se,
 749             sizeof (struct mslm_NetFileInfoBuf3) + MAXNAMELEN);
 750         if (se->se_nlimit == 0)
 751                 return (NERR_BufTooSmall);
 752 
 753         do {
 754                 fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, se->se_nlimit);
 755                 if (fi3 == NULL)
 756                         se->se_nlimit >>= 1;
 757         } while ((se->se_nlimit > 0) && (fi3 == NULL));
 758 
 759         if (fi3 == NULL)
 760                 return (ERROR_NOT_ENOUGH_MEMORY);
 761 
 762         param->info.ru.info3->fi3 = fi3;
 763 
 764         if ((ns = smb_kmod_enum_init(se)) == NULL)
 765                 return (ERROR_NOT_ENOUGH_MEMORY);
 766 
 767         if (smb_kmod_enum(ns) != 0) {
 768                 smb_kmod_enum_fini(ns);
 769                 return (ERROR_INTERNAL_ERROR);
 770         }
 771 
 772         item = list_head(&ns->ns_list);
 773         while (item != NULL) {
 774                 ofile = &item->nsi_un.nsi_ofile;
 775                 fi3->fi3_id = ofile->fi_uniqid;
 776                 fi3->fi3_permissions = ofile->fi_permissions;
 777                 fi3->fi3_num_locks = ofile->fi_numlocks;
 778                 fi3->fi3_pathname = (uint8_t *)
 779                     NDR_STRDUP(mxa, ofile->fi_path);
 780                 fi3->fi3_username = (uint8_t *)
 781                     NDR_STRDUP(mxa, ofile->fi_username);
 782 
 783                 ++entries_read;
 784                 ++fi3;
 785                 item = list_next(&ns->ns_list, item);
 786         }
 787 
 788         se->se_resume += entries_read;
 789         param->info.ru.info3->entries_read = entries_read;
 790         param->total_entries = entries_read;
 791         smb_kmod_enum_fini(ns);
 792         return (ERROR_SUCCESS);
 793 }
 794 
 795 /*
 796  * srvsvc_s_NetFileClose
 797  *
 798  * NetFileClose forces a file to close. This function can be used when
 799  * an error prevents closure by other means.  Use NetFileClose with
 800  * caution because it does not flush data, cached on a client, to the
 801  * file before closing the file.
 802  *
 803  * SMB fids are 16-bit values but this interface expects 32-bit file ids.
 804  * So we use the uniqid here.
 805  *
 806  * Return Values
 807  * ERROR_SUCCESS            Operation succeeded.
 808  * ERROR_ACCESS_DENIED      Operation denied.
 809  * NERR_FileIdNotFound      No open file with the specified id.
 810  *
 811  * Note: MSDN suggests ERROR_FILE_NOT_FOUND for NetFileClose but network
 812  * captures using NT show NERR_FileIdNotFound, which is consistent with
 813  * the NetFileClose2 page on MSDN.
 814  */
 815 static int
 816 srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa)
 817 {
 818         static struct {
 819                 int errnum;
 820                 int nerr;
 821         } errmap[] = {
 822                 0,      ERROR_SUCCESS,
 823                 EACCES, ERROR_ACCESS_DENIED,
 824                 EPERM,  ERROR_ACCESS_DENIED,
 825                 EINVAL, ERROR_INVALID_PARAMETER,
 826                 ENOMEM, ERROR_NOT_ENOUGH_MEMORY,
 827                 ENOENT, NERR_FileIdNotFound
 828         };
 829 
 830         struct mslm_NetFileClose *param = arg;
 831         int             i;
 832         int             rc;
 833 
 834         if (!ndr_is_admin(mxa)) {
 835                 param->status = ERROR_ACCESS_DENIED;
 836                 return (NDR_DRC_OK);
 837         }
 838 
 839         rc = smb_kmod_file_close(param->file_id);
 840 
 841         for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
 842                 if (rc == errmap[i].errnum) {
 843                         param->status = errmap[i].nerr;
 844                         return (NDR_DRC_OK);
 845                 }
 846         }
 847 
 848         param->status = ERROR_INTERNAL_ERROR;
 849         return (NDR_DRC_OK);
 850 }
 851 
 852 /*
 853  * srvsvc_s_NetShareGetInfo
 854  *
 855  * Returns Win32 error codes.
 856  */
 857 static int
 858 srvsvc_s_NetShareGetInfo(void *arg, ndr_xa_t *mxa)
 859 {
 860         struct mlsm_NetShareGetInfo *param = arg;
 861         struct mslm_NetShareInfo_0 *info0;
 862         struct mslm_NetShareInfo_1 *info1;
 863         struct mslm_NetShareInfo_2 *info2;
 864         struct mslm_NetShareInfo_501 *info501;
 865         struct mslm_NetShareInfo_502 *info502;
 866         struct mslm_NetShareInfo_503 *info503;
 867         struct mslm_NetShareInfo_1004 *info1004;
 868         struct mslm_NetShareInfo_1005 *info1005;
 869         struct mslm_NetShareInfo_1006 *info1006;
 870         struct mslm_NetShareInfo_1501 *info1501;
 871         srvsvc_netshare_getinfo_t *info;
 872         uint8_t *netname;
 873         uint8_t *comment;
 874         smb_share_t si;
 875         srvsvc_sd_t sd;
 876         DWORD status;
 877 
 878         status = smb_shr_get((char *)param->netname, &si);
 879         if (status != NERR_Success) {
 880                 bzero(param, sizeof (struct mlsm_NetShareGetInfo));
 881                 param->status = status;
 882                 return (NDR_DRC_OK);
 883         }
 884 
 885         netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
 886         comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
 887         info = NDR_NEW(mxa, srvsvc_netshare_getinfo_t);
 888 
 889         if (netname == NULL || comment == NULL || info == NULL) {
 890                 bzero(param, sizeof (struct mlsm_NetShareGetInfo));
 891                 param->status = ERROR_NOT_ENOUGH_MEMORY;
 892                 return (NDR_DRC_OK);
 893         }
 894 
 895         switch (param->level) {
 896         case 0:
 897                 info0 = &info->nsg_info0;
 898                 info0->shi0_netname = netname;
 899                 param->result.ru.info0 = info0;
 900                 break;
 901 
 902         case 1:
 903                 info1 = &info->nsg_info1;
 904                 info1->shi1_netname = netname;
 905                 info1->shi1_comment = comment;
 906                 info1->shi1_type = si.shr_type;
 907                 param->result.ru.info1 = info1;
 908                 break;
 909 
 910         case 2:
 911                 info2 = &info->nsg_info2;
 912                 info2->shi2_netname = netname;
 913                 info2->shi2_comment = comment;
 914                 info2->shi2_path =
 915                     (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
 916                 info2->shi2_passwd = 0;
 917                 info2->shi2_type = si.shr_type;
 918                 info2->shi2_permissions = 0;
 919                 info2->shi2_max_uses = SHI_USES_UNLIMITED;
 920                 info2->shi2_current_uses = 0;
 921                 param->result.ru.info2 = info2;
 922                 break;
 923 
 924         case 501:
 925                 info501 = &info->nsg_info501;
 926                 info501->shi501_netname = netname;
 927                 info501->shi501_comment = comment;
 928                 info501->shi501_type = si.shr_type;
 929                 info501->shi501_flags = srvsvc_get_share_flags(&si);
 930                 param->result.ru.info501 = info501;
 931                 break;
 932 
 933         case 502:
 934                 info502 = &info->nsg_info502;
 935                 info502->shi502_netname = netname;
 936                 info502->shi502_comment = comment;
 937                 info502->shi502_path =
 938                     (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
 939                 info502->shi502_passwd = 0;
 940                 info502->shi502_type = si.shr_type;
 941                 info502->shi502_permissions = 0;
 942                 info502->shi502_max_uses = SHI_USES_UNLIMITED;
 943                 info502->shi502_current_uses = 0;
 944 
 945                 status = srvsvc_share_getsd(mxa, &si, &sd);
 946                 if (status == ERROR_SUCCESS) {
 947                         info502->shi502_reserved = sd.sd_size;
 948                         info502->shi502_security_descriptor = sd.sd_buf;
 949                 } else {
 950                         info502->shi502_reserved = 0;
 951                         info502->shi502_security_descriptor = NULL;
 952                 }
 953 
 954                 param->result.ru.info502 = info502;
 955                 break;
 956 
 957         case 503:
 958                 info503 = &info->nsg_info503;
 959                 info503->shi503_netname = netname;
 960                 info503->shi503_comment = comment;
 961                 info503->shi503_path =
 962                     (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
 963                 info503->shi503_passwd = NULL;
 964                 info503->shi503_type = si.shr_type;
 965                 info503->shi503_permissions = 0;
 966                 info503->shi503_max_uses = SHI_USES_UNLIMITED;
 967                 info503->shi503_current_uses = 0;
 968                 info503->shi503_servername = NULL;
 969 
 970                 status = srvsvc_share_getsd(mxa, &si, &sd);
 971                 if (status == ERROR_SUCCESS) {
 972                         info503->shi503_reserved = sd.sd_size;
 973                         info503->shi503_security_descriptor = sd.sd_buf;
 974                 } else {
 975                         info503->shi503_reserved = 0;
 976                         info503->shi503_security_descriptor = NULL;
 977                 }
 978 
 979                 param->result.ru.info503 = info503;
 980                 break;
 981 
 982         case 1004:
 983                 info1004 = &info->nsg_info1004;
 984                 info1004->shi1004_comment = comment;
 985                 param->result.ru.info1004 = info1004;
 986                 break;
 987 
 988         case 1005:
 989                 info1005 = &info->nsg_info1005;
 990                 info1005->shi1005_flags = srvsvc_get_share_flags(&si);
 991                 param->result.ru.info1005 = info1005;
 992                 break;
 993 
 994         case 1006:
 995                 info1006 = &info->nsg_info1006;
 996                 info1006->shi1006_max_uses = SHI_USES_UNLIMITED;
 997                 param->result.ru.info1006 = info1006;
 998                 break;
 999 
1000         case 1501:
1001                 info1501 = &info->nsg_info1501;
1002 
1003                 status = srvsvc_share_getsd(mxa, &si, &sd);
1004                 if (status == ERROR_SUCCESS) {
1005                         info503->shi503_reserved = sd.sd_size;
1006                         info503->shi503_security_descriptor = sd.sd_buf;
1007                 } else {
1008                         info503->shi503_reserved = 0;
1009                         info503->shi503_security_descriptor = NULL;
1010                 }
1011 
1012                 param->result.ru.info1501 = info1501;
1013                 break;
1014 
1015         default:
1016                 status = ERROR_ACCESS_DENIED;
1017                 break;
1018         }
1019 
1020         if (status != ERROR_SUCCESS)
1021                 bzero(param, sizeof (struct mlsm_NetShareGetInfo));
1022         else
1023                 param->result.switch_value = param->level;
1024 
1025         param->status = status;
1026         return (NDR_DRC_OK);
1027 }
1028 
1029 static uint32_t
1030 srvsvc_share_getsd(ndr_xa_t *mxa, smb_share_t *si, srvsvc_sd_t *sd)
1031 {
1032         uint32_t status;
1033 
1034         status = srvsvc_sd_get(si, NULL, &sd->sd_size);
1035         if (status != ERROR_SUCCESS) {
1036                 if (status == ERROR_PATH_NOT_FOUND) {
1037                         bzero(sd, sizeof (srvsvc_sd_t));
1038                         status = ERROR_SUCCESS;
1039                 }
1040 
1041                 return (status);
1042         }
1043 
1044         if ((sd->sd_buf = NDR_MALLOC(mxa, sd->sd_size)) == NULL)
1045                 return (ERROR_NOT_ENOUGH_MEMORY);
1046 
1047         status = srvsvc_sd_get(si, sd->sd_buf, NULL);
1048         if (status == ERROR_PATH_NOT_FOUND) {
1049                 bzero(sd, sizeof (srvsvc_sd_t));
1050                 status = ERROR_SUCCESS;
1051         }
1052 
1053         return (status);
1054 }
1055 
1056 /*
1057  * srvsvc_s_NetShareSetInfo
1058  *
1059  * This call is made by SrvMgr to set share information.
1060  * Only power users groups can manage shares.
1061  *
1062  * To avoid misleading errors, we don't report an error
1063  * when a FS doesn't support ACLs on shares.
1064  *
1065  * Returns Win32 error codes.
1066  */
1067 static int
1068 srvsvc_s_NetShareSetInfo(void *arg, ndr_xa_t *mxa)
1069 {
1070         struct mlsm_NetShareSetInfo *param = arg;
1071         struct mslm_NetShareInfo_0 *info0;
1072         struct mslm_NetShareInfo_1 *info1;
1073         struct mslm_NetShareInfo_2 *info2;
1074         struct mslm_NetShareInfo_501 *info501;
1075         struct mslm_NetShareInfo_502 *info502;
1076         struct mslm_NetShareInfo_503 *info503;
1077         struct mslm_NetShareInfo_1004 *info1004;
1078         struct mslm_NetShareInfo_1005 *info1005;
1079         struct mslm_NetShareInfo_1501 *info1501;
1080         static DWORD parm_err = 0;
1081         srvsvc_netshare_setinfo_t info;
1082         smb_share_t si;
1083         uint8_t *sdbuf;
1084         int32_t native_os;
1085         DWORD status;
1086 
1087         native_os = ndr_native_os(mxa);
1088 
1089         if (!ndr_is_poweruser(mxa)) {
1090                 status = ERROR_ACCESS_DENIED;
1091                 goto netsharesetinfo_exit;
1092         }
1093 
1094         if (smb_shr_get((char *)param->netname, &si) != NERR_Success) {
1095                 status = ERROR_INVALID_NETNAME;
1096                 goto netsharesetinfo_exit;
1097         }
1098 
1099         if (param->result.ru.nullptr == NULL) {
1100                 status = ERROR_INVALID_PARAMETER;
1101                 goto netsharesetinfo_exit;
1102         }
1103 
1104         bzero(&info, sizeof (srvsvc_netshare_setinfo_t));
1105 
1106         switch (param->level) {
1107         case 0:
1108                 info0 = (struct mslm_NetShareInfo_0 *)param->result.ru.info0;
1109                 info.nss_netname = (char *)info0->shi0_netname;
1110                 status = srvsvc_modify_share(&si, &info);
1111                 break;
1112 
1113         case 1:
1114                 info1 = (struct mslm_NetShareInfo_1 *)param->result.ru.info1;
1115                 info.nss_netname = (char *)info1->shi1_netname;
1116                 info.nss_comment = (char *)info1->shi1_comment;
1117                 info.nss_type = info1->shi1_type;
1118                 status = srvsvc_modify_share(&si, &info);
1119                 break;
1120 
1121         case 2:
1122                 info2 = (struct mslm_NetShareInfo_2 *)param->result.ru.info2;
1123                 info.nss_netname = (char *)info2->shi2_netname;
1124                 info.nss_comment = (char *)info2->shi2_comment;
1125                 info.nss_path = (char *)info2->shi2_path;
1126                 info.nss_type = info2->shi2_type;
1127                 status = srvsvc_modify_share(&si, &info);
1128                 break;
1129 
1130         case 501:
1131                 info501 = (struct mslm_NetShareInfo_501 *)
1132                     param->result.ru.info501;
1133                 info.nss_netname = (char *)info501->shi501_netname;
1134                 info.nss_comment = (char *)info501->shi501_comment;
1135                 info.nss_type = info501->shi501_type;
1136                 status = srvsvc_modify_share(&si, &info);
1137                 if (status == ERROR_SUCCESS)
1138                         status = srvsvc_update_share_flags(&si,
1139                             info501->shi501_flags);
1140                 break;
1141 
1142         case 502:
1143                 info502 = (struct mslm_NetShareInfo_502 *)
1144                     param->result.ru.info502;
1145                 info.nss_netname = (char *)info502->shi502_netname;
1146                 info.nss_comment = (char *)info502->shi502_comment;
1147                 info.nss_path = (char *)info502->shi502_path;
1148                 info.nss_type = info502->shi502_type;
1149                 info.nss_sd.sd_buf = info502->shi502_security_descriptor;
1150                 status = srvsvc_modify_share(&si, &info);
1151                 break;
1152 
1153         case 503:
1154                 info503 = (struct mslm_NetShareInfo_503 *)
1155                     param->result.ru.info503;
1156                 info.nss_netname = (char *)info503->shi503_netname;
1157                 info.nss_comment = (char *)info503->shi503_comment;
1158                 info.nss_path = (char *)info503->shi503_path;
1159                 info.nss_type = info503->shi503_type;
1160                 info.nss_sd.sd_buf = info503->shi503_security_descriptor;
1161                 status = srvsvc_modify_share(&si, &info);
1162                 break;
1163 
1164         case 1004:
1165                 info1004 = (struct mslm_NetShareInfo_1004 *)
1166                     param->result.ru.info1004;
1167                 info.nss_comment = (char *)info1004->shi1004_comment;
1168                 status = srvsvc_modify_share(&si, &info);
1169                 break;
1170 
1171         case 1005:
1172                 info1005 = (struct mslm_NetShareInfo_1005 *)
1173                     param->result.ru.info1005;
1174                 status = srvsvc_update_share_flags(&si,
1175                     info1005->shi1005_flags);
1176                 break;
1177 
1178         case 1006:
1179                 /*
1180                  * We don't limit the maximum number of concurrent
1181                  * connections to a share.
1182                  */
1183                 status = ERROR_SUCCESS;
1184                 break;
1185 
1186         case 1501:
1187                 info1501 = (struct mslm_NetShareInfo_1501 *)
1188                     param->result.ru.info1501;
1189                 sdbuf = info1501->shi1501_security_descriptor;
1190                 status = ERROR_SUCCESS;
1191 
1192                 if (sdbuf != NULL) {
1193                         status = srvsvc_sd_set(&si, sdbuf);
1194                         if (status == ERROR_PATH_NOT_FOUND)
1195                                 status = ERROR_SUCCESS;
1196                 }
1197                 break;
1198 
1199         default:
1200                 status = ERROR_ACCESS_DENIED;
1201                 break;
1202         }
1203 
1204 netsharesetinfo_exit:
1205         if (status != ERROR_SUCCESS)
1206                 bzero(param, sizeof (struct mlsm_NetShareSetInfo));
1207 
1208         param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
1209         param->status = status;
1210         return (NDR_DRC_OK);
1211 }
1212 
1213 static uint32_t
1214 srvsvc_modify_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
1215 {
1216         uint32_t nerr = NERR_Success;
1217 
1218         if (si->shr_flags & SMB_SHRF_TRANS)
1219                 return (srvsvc_modify_transient_share(si, info));
1220 
1221         if (info->nss_sd.sd_buf != NULL) {
1222                 nerr = srvsvc_sd_set(si, info->nss_sd.sd_buf);
1223                 if (nerr == ERROR_PATH_NOT_FOUND)
1224                         nerr = NERR_Success;
1225         }
1226 
1227         if ((nerr = srvsvc_sa_modify(si, info)) == NERR_Success)
1228                 nerr = smb_shr_modify(si);
1229 
1230         return (nerr);
1231 }
1232 
1233 /*
1234  * Update transient shares.  This includes autohome shares.
1235  */
1236 static uint32_t
1237 srvsvc_modify_transient_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
1238 {
1239         uint32_t nerr;
1240 
1241         if (info->nss_netname != NULL && info->nss_netname[0] != '\0' &&
1242             smb_strcasecmp(info->nss_netname, si->shr_name, 0) != 0) {
1243                 nerr = smb_shr_rename(si->shr_name, info->nss_netname);
1244                 if (nerr != NERR_Success)
1245                         return (nerr);
1246 
1247                 (void) strlcpy(si->shr_name, info->nss_netname, MAXNAMELEN);
1248         }
1249 
1250         if ((info->nss_comment != NULL) &&
1251             (strcmp(info->nss_comment, si->shr_cmnt) != 0)) {
1252                 (void) strlcpy(si->shr_cmnt, info->nss_comment,
1253                     SMB_SHARE_CMNT_MAX);
1254 
1255                 if ((nerr = smb_shr_modify(si)) != NERR_Success)
1256                         return (nerr);
1257         }
1258 
1259         return (NERR_Success);
1260 }
1261 
1262 /*
1263  * srvsvc_update_share_flags
1264  *
1265  * This function updates flags for shares.
1266  * Flags for Persistent shares are updated in both libshare and the local cache.
1267  * Flags for Transient shares are updated only in the local cache.
1268  */
1269 static uint32_t
1270 srvsvc_update_share_flags(smb_share_t *si, uint32_t shi_flags)
1271 {
1272         uint32_t nerr = NERR_Success;
1273         uint32_t flag = 0;
1274         char *csc_value;
1275         char *abe_value = "false";
1276         nvlist_t *nvl;
1277         int err = 0;
1278 
1279         if (shi_flags & SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM) {
1280                 flag = SMB_SHRF_ABE;
1281                 abe_value = "true";
1282         }
1283 
1284         si->shr_flags &= ~SMB_SHRF_ABE;
1285         si->shr_flags |= flag;
1286 
1287         switch ((shi_flags & CSC_MASK)) {
1288         case CSC_CACHE_AUTO_REINT:
1289                 flag = SMB_SHRF_CSC_AUTO;
1290                 break;
1291         case CSC_CACHE_VDO:
1292                 flag = SMB_SHRF_CSC_VDO;
1293                 break;
1294         case CSC_CACHE_NONE:
1295                 flag = SMB_SHRF_CSC_DISABLED;
1296                 break;
1297         case CSC_CACHE_MANUAL_REINT:
1298                 flag = SMB_SHRF_CSC_MANUAL;
1299                 break;
1300         default:
1301                 return (NERR_InternalError);
1302         }
1303 
1304         si->shr_flags &= ~SMB_SHRF_CSC_MASK;
1305         si->shr_flags |= flag;
1306 
1307         if ((si->shr_flags & SMB_SHRF_TRANS) == 0) {
1308                 csc_value = smb_shr_sa_csc_name(si);
1309 
1310                 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1311                         return (NERR_InternalError);
1312 
1313                 err |= nvlist_add_string(nvl, SHOPT_CSC, csc_value);
1314                 err |= nvlist_add_string(nvl, SHOPT_ABE, abe_value);
1315                 if (err) {
1316                         nvlist_free(nvl);
1317                         return (NERR_InternalError);
1318                 }
1319 
1320                 nerr = srvsvc_sa_setprop(si, nvl);
1321                 nvlist_free(nvl);
1322 
1323                 if (nerr != NERR_Success)
1324                         return (nerr);
1325         }
1326 
1327         return (smb_shr_modify(si));
1328 }
1329 
1330 static uint32_t
1331 srvsvc_get_share_flags(smb_share_t *si)
1332 {
1333         uint32_t flags = 0;
1334         boolean_t shortnames = B_TRUE;
1335 
1336         switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
1337         case SMB_SHRF_CSC_DISABLED:
1338                 flags |= CSC_CACHE_NONE;
1339                 break;
1340         case SMB_SHRF_CSC_AUTO:
1341                 flags |= CSC_CACHE_AUTO_REINT;
1342                 break;
1343         case SMB_SHRF_CSC_VDO:
1344                 flags |= CSC_CACHE_VDO;
1345                 break;
1346         case SMB_SHRF_CSC_MANUAL:
1347         default:
1348                 /*
1349                  * Default to CSC_CACHE_MANUAL_REINT.
1350                  */
1351                 break;
1352         }
1353 
1354         if (si->shr_flags & SMB_SHRF_ABE)
1355                 flags |= SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
1356 
1357         /* if 'smb' zfs property: shortnames=disabled */
1358         if ((smb_kmod_shareinfo(si->shr_name, &shortnames) == 0) &&
1359             (shortnames == B_FALSE)) {
1360                 flags |= SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING;
1361         }
1362 
1363         return (flags);
1364 }
1365 
1366 /*
1367  * srvsvc_s_NetSessionEnum
1368  *
1369  * Level 1 request is made by (Server Manager (srvmgr) on NT Server when
1370  * the user info icon is selected.
1371  *
1372  * On success, the return value is NERR_Success.
1373  * On error, the return value can be one of the following error codes:
1374  *
1375  * ERROR_ACCESS_DENIED      The user does not have access to the requested
1376  *                          information.
1377  * ERROR_INVALID_LEVEL      The value specified for the level is invalid.
1378  * ERROR_INVALID_PARAMETER  The specified parameter is invalid.
1379  * ERROR_MORE_DATA          More entries are available. Specify a large
1380  *                          enough buffer to receive all entries.
1381  * ERROR_NOT_ENOUGH_MEMORY  Insufficient memory is available.
1382  * NERR_ClientNameNotFound  A session does not exist with the computer name.
1383  * NERR_InvalidComputer     The computer name is invalid.
1384  * NERR_UserNotFound        The user name could not be found.
1385  */
1386 static int
1387 srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa)
1388 {
1389         struct mslm_NetSessionEnum      *param = arg;
1390         srvsvc_infonres_t               *info;
1391         smb_netsvc_t                    *ns;
1392         smb_svcenum_t                   se;
1393         DWORD                           status = ERROR_SUCCESS;
1394 
1395         if (!ndr_is_admin(mxa)) {
1396                 status = ERROR_ACCESS_DENIED;
1397                 goto srvsvc_netsessionenum_error;
1398         }
1399 
1400         if ((info = NDR_NEW(mxa, srvsvc_infonres_t)) == NULL) {
1401                 status = ERROR_NOT_ENOUGH_MEMORY;
1402                 goto srvsvc_netsessionenum_error;
1403         }
1404 
1405         info->entriesread = 0;
1406         info->entries = NULL;
1407         param->result.level = param->level;
1408         param->result.bufptr.p = info;
1409 
1410         if ((param->total_entries = srvsvc_open_sessions()) == 0) {
1411                 param->resume_handle = NULL;
1412                 param->status = ERROR_SUCCESS;
1413                 return (NDR_DRC_OK);
1414         }
1415 
1416         bzero(&se, sizeof (smb_svcenum_t));
1417         se.se_type = SMB_SVCENUM_TYPE_USER;
1418         se.se_level = param->level;
1419         se.se_ntotal = param->total_entries;
1420         se.se_nlimit = se.se_ntotal;
1421 
1422         if (param->resume_handle) {
1423                 se.se_resume = *param->resume_handle;
1424                 se.se_nskip = se.se_resume;
1425                 *param->resume_handle = 0;
1426         }
1427 
1428         switch (param->level) {
1429         case 0:
1430                 info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0,
1431                     se.se_nlimit);
1432                 break;
1433         case 1:
1434                 info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1,
1435                     se.se_nlimit);
1436                 break;
1437         case 2:
1438                 info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2,
1439                     se.se_nlimit);
1440                 break;
1441         case 10:
1442                 info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10,
1443                     se.se_nlimit);
1444                 break;
1445         case 502:
1446                 info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502,
1447                     se.se_nlimit);
1448                 break;
1449         default:
1450                 bzero(param, sizeof (struct mslm_NetSessionEnum));
1451                 param->status = ERROR_INVALID_LEVEL;
1452                 return (NDR_DRC_OK);
1453         }
1454 
1455         if (info->entries == NULL) {
1456                 status = ERROR_NOT_ENOUGH_MEMORY;
1457                 goto srvsvc_netsessionenum_error;
1458         }
1459 
1460         if ((ns = smb_kmod_enum_init(&se)) == NULL) {
1461                 status = ERROR_NOT_ENOUGH_MEMORY;
1462                 goto srvsvc_netsessionenum_error;
1463         }
1464 
1465         status = srvsvc_NetSessionEnumCommon(mxa, info, ns, &se);
1466         smb_kmod_enum_fini(ns);
1467 
1468         if (status != ERROR_SUCCESS)
1469                 goto srvsvc_netsessionenum_error;
1470 
1471         if (param->resume_handle &&
1472             param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
1473                 if (se.se_resume < param->total_entries) {
1474                         *param->resume_handle = se.se_resume;
1475                         status = ERROR_MORE_DATA;
1476                 }
1477         }
1478 
1479         param->total_entries = info->entriesread;
1480         param->status = status;
1481         return (NDR_DRC_OK);
1482 
1483 srvsvc_netsessionenum_error:
1484         bzero(param, sizeof (struct mslm_NetSessionEnum));
1485         param->status = status;
1486         return (NDR_DRC_OK);
1487 }
1488 
1489 static uint32_t
1490 srvsvc_NetSessionEnumCommon(ndr_xa_t *mxa, srvsvc_infonres_t *info,
1491     smb_netsvc_t *ns, smb_svcenum_t *se)
1492 {
1493         struct mslm_SESSION_INFO_0      *info0 = info->entries;
1494         struct mslm_SESSION_INFO_1      *info1 = info->entries;
1495         struct mslm_SESSION_INFO_2      *info2 = info->entries;
1496         struct mslm_SESSION_INFO_10     *info10 = info->entries;
1497         struct mslm_SESSION_INFO_502    *info502 = info->entries;
1498         smb_netsvcitem_t                *item;
1499         smb_netuserinfo_t               *user;
1500         char                            *workstation;
1501         char                            account[MAXNAMELEN];
1502         char                            ipaddr_buf[INET6_ADDRSTRLEN];
1503         uint32_t                        logon_time;
1504         uint32_t                        flags;
1505         uint32_t                        entries_read = 0;
1506 
1507         if (smb_kmod_enum(ns) != 0)
1508                 return (ERROR_INTERNAL_ERROR);
1509 
1510         item = list_head(&ns->ns_list);
1511         while (item != NULL) {
1512                 user = &item->nsi_un.nsi_user;
1513 
1514                 workstation = user->ui_workstation;
1515                 if (workstation == NULL || *workstation == '\0') {
1516                         (void) smb_inet_ntop(&user->ui_ipaddr, ipaddr_buf,
1517                             SMB_IPSTRLEN(user->ui_ipaddr.a_family));
1518                         workstation = ipaddr_buf;
1519                 }
1520 
1521                 (void) snprintf(account, MAXNAMELEN, "%s\\%s",
1522                     user->ui_domain, user->ui_account);
1523 
1524                 logon_time = time(0) - user->ui_logon_time;
1525                 flags = (user->ui_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
1526 
1527                 switch (se->se_level) {
1528                 case 0:
1529                         info0->sesi0_cname = NDR_STRDUP(mxa, workstation);
1530                         if (info0->sesi0_cname == NULL)
1531                                 return (ERROR_NOT_ENOUGH_MEMORY);
1532                         ++info0;
1533                         break;
1534 
1535                 case 1:
1536                         info1->sesi1_cname = NDR_STRDUP(mxa, workstation);
1537                         info1->sesi1_uname = NDR_STRDUP(mxa, account);
1538 
1539                         if (info1->sesi1_cname == NULL ||
1540                             info1->sesi1_uname == NULL)
1541                                 return (ERROR_NOT_ENOUGH_MEMORY);
1542 
1543                         info1->sesi1_nopens = user->ui_numopens;
1544                         info1->sesi1_time = logon_time;
1545                         info1->sesi1_itime = 0;
1546                         info1->sesi1_uflags = flags;
1547                         ++info1;
1548                         break;
1549 
1550                 case 2:
1551                         info2->sesi2_cname = NDR_STRDUP(mxa, workstation);
1552                         info2->sesi2_uname = NDR_STRDUP(mxa, account);
1553 
1554                         if (info2->sesi2_cname == NULL ||
1555                             info2->sesi2_uname == NULL)
1556                                 return (ERROR_NOT_ENOUGH_MEMORY);
1557 
1558                         info2->sesi2_nopens = user->ui_numopens;
1559                         info2->sesi2_time = logon_time;
1560                         info2->sesi2_itime = 0;
1561                         info2->sesi2_uflags = flags;
1562                         info2->sesi2_cltype_name = (uint8_t *)"";
1563                         ++info2;
1564                         break;
1565 
1566                 case 10:
1567                         info10->sesi10_cname = NDR_STRDUP(mxa, workstation);
1568                         info10->sesi10_uname = NDR_STRDUP(mxa, account);
1569 
1570                         if (info10->sesi10_cname == NULL ||
1571                             info10->sesi10_uname == NULL)
1572                                 return (ERROR_NOT_ENOUGH_MEMORY);
1573 
1574                         info10->sesi10_time = logon_time;
1575                         info10->sesi10_itime = 0;
1576                         ++info10;
1577                         break;
1578 
1579                 case 502:
1580                         info502->sesi502_cname = NDR_STRDUP(mxa, workstation);
1581                         info502->sesi502_uname = NDR_STRDUP(mxa, account);
1582 
1583                         if (info502->sesi502_cname == NULL ||
1584                             info502->sesi502_uname == NULL)
1585                                 return (ERROR_NOT_ENOUGH_MEMORY);
1586 
1587                         info502->sesi502_nopens = user->ui_numopens;
1588                         info502->sesi502_time = logon_time;
1589                         info502->sesi502_itime = 0;
1590                         info502->sesi502_uflags = flags;
1591                         info502->sesi502_cltype_name = (uint8_t *)"";
1592                         info502->sesi502_transport = (uint8_t *)"";
1593                         ++info502;
1594                         break;
1595 
1596                 default:
1597                         return (ERROR_INVALID_LEVEL);
1598                 }
1599 
1600                 ++entries_read;
1601                 item = list_next(&ns->ns_list, item);
1602         }
1603 
1604         info->entriesread = entries_read;
1605         return (ERROR_SUCCESS);
1606 }
1607 
1608 /*
1609  * srvsvc_s_NetSessionDel
1610  *
1611  * Ends a network session between a server and a workstation.
1612  * On NT only members of the Administrators or Account Operators
1613  * local groups are permitted to use NetSessionDel.
1614  *
1615  * If unc_clientname is NULL, all sessions associated with the
1616  * specified user will be disconnected.
1617  *
1618  * If username is NULL, all sessions from the specified client
1619  * will be disconnected.
1620  *
1621  * Return Values
1622  * On success, the return value is NERR_Success/ERROR_SUCCESS.
1623  * On failure, the return value can be one of the following errors:
1624  *
1625  * ERROR_ACCESS_DENIED          The user does not have access to the
1626  *                              requested information.
1627  * ERROR_INVALID_PARAMETER      The specified parameter is invalid.
1628  * ERROR_NOT_ENOUGH_MEMORY      Insufficient memory is available.
1629  * NERR_ClientNameNotFound      A session does not exist with that
1630  *                              computer name.
1631  */
1632 static int
1633 srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa)
1634 {
1635         static struct {
1636                 int errnum;
1637                 int nerr;
1638         } errmap[] = {
1639                 0,      ERROR_SUCCESS,
1640                 EACCES, ERROR_ACCESS_DENIED,
1641                 EPERM,  ERROR_ACCESS_DENIED,
1642                 EINVAL, ERROR_INVALID_PARAMETER,
1643                 ENOMEM, ERROR_NOT_ENOUGH_MEMORY,
1644                 ENOENT, NERR_ClientNameNotFound
1645         };
1646 
1647         struct mslm_NetSessionDel *param = arg;
1648         int     i;
1649         int     rc;
1650 
1651         if (!ndr_is_admin(mxa)) {
1652                 param->status = ERROR_ACCESS_DENIED;
1653                 return (NDR_DRC_OK);
1654         }
1655 
1656         rc = smb_kmod_session_close((char *)param->unc_clientname,
1657             (char *)param->username);
1658 
1659         for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
1660                 if (rc == errmap[i].errnum) {
1661                         param->status = errmap[i].nerr;
1662                         return (NDR_DRC_OK);
1663                 }
1664         }
1665 
1666         param->status = ERROR_INTERNAL_ERROR;
1667         return (NDR_DRC_OK);
1668 }
1669 
1670 static int
1671 srvsvc_s_NetServerGetInfo(void *arg, ndr_xa_t *mxa)
1672 {
1673         struct mslm_NetServerGetInfo *param = arg;
1674         struct mslm_SERVER_INFO_100 *info100;
1675         struct mslm_SERVER_INFO_101 *info101;
1676         struct mslm_SERVER_INFO_102 *info102;
1677         struct mslm_SERVER_INFO_502 *info502;
1678         struct mslm_SERVER_INFO_503 *info503;
1679         char sys_comment[SMB_PI_MAX_COMMENT];
1680         char hostname[NETBIOS_NAME_SZ];
1681         smb_version_t version;
1682 
1683         if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) {
1684 netservergetinfo_no_memory:
1685                 bzero(param, sizeof (struct mslm_NetServerGetInfo));
1686                 return (ERROR_NOT_ENOUGH_MEMORY);
1687         }
1688 
1689         (void) smb_config_getstr(SMB_CI_SYS_CMNT, sys_comment,
1690             sizeof (sys_comment));
1691         if (*sys_comment == '\0')
1692                 (void) strcpy(sys_comment, " ");
1693 
1694         smb_config_get_version(&version);
1695 
1696         switch (param->level) {
1697         case 100:
1698                 info100 = NDR_NEW(mxa, struct mslm_SERVER_INFO_100);
1699                 if (info100 == NULL)
1700                         goto netservergetinfo_no_memory;
1701 
1702                 bzero(info100, sizeof (struct mslm_SERVER_INFO_100));
1703                 info100->sv100_platform_id = SV_PLATFORM_ID_NT;
1704                 info100->sv100_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1705                 if (info100->sv100_name == NULL)
1706                         goto netservergetinfo_no_memory;
1707 
1708                 param->result.bufptr.bufptr100 = info100;
1709                 break;
1710 
1711         case 101:
1712                 info101 = NDR_NEW(mxa, struct mslm_SERVER_INFO_101);
1713                 if (info101 == NULL)
1714                         goto netservergetinfo_no_memory;
1715 
1716                 bzero(info101, sizeof (struct mslm_SERVER_INFO_101));
1717                 info101->sv101_platform_id = SV_PLATFORM_ID_NT;
1718                 info101->sv101_version_major = version.sv_major;
1719                 info101->sv101_version_minor = version.sv_minor;
1720                 info101->sv101_type = SV_TYPE_DEFAULT;
1721                 info101->sv101_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1722                 info101->sv101_comment
1723                     = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1724 
1725                 if (info101->sv101_name == NULL ||
1726                     info101->sv101_comment == NULL)
1727                         goto netservergetinfo_no_memory;
1728 
1729                 param->result.bufptr.bufptr101 = info101;
1730                 break;
1731 
1732         case 102:
1733                 info102 = NDR_NEW(mxa, struct mslm_SERVER_INFO_102);
1734                 if (info102 == NULL)
1735                         goto netservergetinfo_no_memory;
1736 
1737                 bzero(info102, sizeof (struct mslm_SERVER_INFO_102));
1738                 info102->sv102_platform_id = SV_PLATFORM_ID_NT;
1739                 info102->sv102_version_major = version.sv_major;
1740                 info102->sv102_version_minor = version.sv_minor;
1741                 info102->sv102_type = SV_TYPE_DEFAULT;
1742                 info102->sv102_name = (uint8_t *)NDR_STRDUP(mxa, hostname);
1743                 info102->sv102_comment
1744                     = (uint8_t *)NDR_STRDUP(mxa, sys_comment);
1745 
1746                 /*
1747                  * The following level 102 fields are defaulted to zero
1748                  * by virtue of the call to bzero above.
1749                  *
1750                  * sv102_users
1751                  * sv102_disc
1752                  * sv102_hidden
1753                  * sv102_announce
1754                  * sv102_anndelta
1755                  * sv102_licenses
1756                  * sv102_userpath
1757                  */
1758                 if (info102->sv102_name == NULL ||
1759                     info102->sv102_comment == NULL)
1760                         goto netservergetinfo_no_memory;
1761 
1762                 param->result.bufptr.bufptr102 = info102;
1763                 break;
1764 
1765         case 502:
1766                 info502 = NDR_NEW(mxa, struct mslm_SERVER_INFO_502);
1767                 if (info502 == NULL)
1768                         goto netservergetinfo_no_memory;
1769 
1770                 bzero(info502, sizeof (struct mslm_SERVER_INFO_502));
1771                 param->result.bufptr.bufptr502 = info502;
1772 #ifdef SRVSVC_SATISFY_SMBTORTURE
1773                 break;
1774 #else
1775                 param->result.level = param->level;
1776                 param->status = ERROR_ACCESS_DENIED;
1777                 return (NDR_DRC_OK);
1778 #endif /* SRVSVC_SATISFY_SMBTORTURE */
1779 
1780         case 503:
1781                 info503 = NDR_NEW(mxa, struct mslm_SERVER_INFO_503);
1782                 if (info503 == NULL)
1783                         goto netservergetinfo_no_memory;
1784 
1785                 bzero(info503, sizeof (struct mslm_SERVER_INFO_503));
1786                 param->result.bufptr.bufptr503 = info503;
1787 #ifdef SRVSVC_SATISFY_SMBTORTURE
1788                 break;
1789 #else
1790                 param->result.level = param->level;
1791                 param->status = ERROR_ACCESS_DENIED;
1792                 return (NDR_DRC_OK);
1793 #endif /* SRVSVC_SATISFY_SMBTORTURE */
1794 
1795         default:
1796                 bzero(&param->result,
1797                     sizeof (struct mslm_NetServerGetInfo_result));
1798                 param->status = ERROR_ACCESS_DENIED;
1799                 return (NDR_DRC_OK);
1800         }
1801 
1802         param->result.level = param->level;
1803         param->status = ERROR_SUCCESS;
1804         return (NDR_DRC_OK);
1805 }
1806 
1807 /*
1808  * NetRemoteTOD
1809  *
1810  * Returns information about the time of day on this server.
1811  *
1812  * typedef struct _TIME_OF_DAY_INFO {
1813  *      DWORD tod_elapsedt;  // seconds since 00:00:00 January 1 1970 GMT
1814  *      DWORD tod_msecs;     // arbitrary milliseconds (since reset)
1815  *      DWORD tod_hours;     // current hour [0-23]
1816  *      DWORD tod_mins;      // current minute [0-59]
1817  *      DWORD tod_secs;      // current second [0-59]
1818  *      DWORD tod_hunds;     // current hundredth (0.01) second [0-99]
1819  *      LONG tod_timezone;   // time zone of the server
1820  *      DWORD tod_tinterval; // clock tick time interval
1821  *      DWORD tod_day;       // day of the month [1-31]
1822  *      DWORD tod_month;     // month of the year [1-12]
1823  *      DWORD tod_year;      // current year
1824  *      DWORD tod_weekday;   // day of the week since Sunday [0-6]
1825  * } TIME_OF_DAY_INFO;
1826  *
1827  * The time zone of the server is calculated in minutes from Greenwich
1828  * Mean Time (GMT). For time zones west of Greenwich, the value is
1829  * positive; for time zones east of Greenwich, the value is negative.
1830  * A value of -1 indicates that the time zone is undefined.
1831  *
1832  * Determine offset from GMT. If daylight saving time use altzone,
1833  * otherwise use timezone.
1834  *
1835  * The clock tick value represents a resolution of one ten-thousandth
1836  * (0.0001) second.
1837  */
1838 static int
1839 srvsvc_s_NetRemoteTOD(void *arg, ndr_xa_t *mxa)
1840 {
1841         struct mslm_NetRemoteTOD *param = arg;
1842         struct mslm_TIME_OF_DAY_INFO *tod;
1843         struct timeval          time_val;
1844         struct tm               tm;
1845         time_t                  gmtoff;
1846 
1847 
1848         (void) gettimeofday(&time_val, 0);
1849         (void) gmtime_r(&time_val.tv_sec, &tm);
1850 
1851         tod = NDR_NEW(mxa, struct mslm_TIME_OF_DAY_INFO);
1852         if (tod == NULL) {
1853                 bzero(param, sizeof (struct mslm_NetRemoteTOD));
1854                 return (ERROR_NOT_ENOUGH_MEMORY);
1855         }
1856 
1857         bzero(tod, sizeof (struct mslm_TIME_OF_DAY_INFO));
1858 
1859         tod->tod_elapsedt = time_val.tv_sec;
1860         tod->tod_msecs = time_val.tv_usec;
1861         tod->tod_hours = tm.tm_hour;
1862         tod->tod_mins = tm.tm_min;
1863         tod->tod_secs = tm.tm_sec;
1864         tod->tod_hunds = 0;
1865         tod->tod_tinterval = 1000;
1866         tod->tod_day = tm.tm_mday;
1867         tod->tod_month = tm.tm_mon+1;
1868         tod->tod_year = tm.tm_year+1900;
1869         tod->tod_weekday = tm.tm_wday;
1870 
1871         (void) localtime_r(&time_val.tv_sec, &tm);
1872         gmtoff = (tm.tm_isdst) ? altzone : timezone;
1873         tod->tod_timezone = gmtoff / SECSPERMIN;
1874 
1875         param->bufptr = tod;
1876         param->status = ERROR_SUCCESS;
1877         return (NDR_DRC_OK);
1878 }
1879 
1880 /*
1881  * srvsvc_s_NetNameValidate
1882  *
1883  * Perform name validation.
1884  *
1885  * Returns Win32 error codes.
1886  */
1887 /*ARGSUSED*/
1888 static int
1889 srvsvc_s_NetNameValidate(void *arg, ndr_xa_t *mxa)
1890 {
1891         struct mslm_NetNameValidate *param = arg;
1892         char *name;
1893         int maxlen;
1894         int len;
1895 
1896         if ((name = (char *)param->pathname) == NULL) {
1897                 param->status = ERROR_INVALID_PARAMETER;
1898                 return (NDR_DRC_OK);
1899         }
1900 
1901         switch (param->type) {
1902         case NAMETYPE_SHARE:
1903                 len = strlen(name);
1904                 maxlen = (param->flags & NAMEFLAG_LM2) ?
1905                     SMB_SHARE_OEMNAME_MAX : SMB_SHARE_NTNAME_MAX;
1906 
1907                 if (len > maxlen) {
1908                         param->status = ERROR_INVALID_NAME;
1909                         return (NDR_DRC_OK);
1910                 }
1911 
1912                 param->status = smb_name_validate_share(name);
1913                 break;
1914 
1915         case NAMETYPE_USER:
1916         case NAMETYPE_GROUP:
1917                 param->status = smb_name_validate_account(name);
1918                 break;
1919 
1920         case NAMETYPE_DOMAIN:   /* NetBIOS domain name */
1921                 param->status = smb_name_validate_nbdomain(name);
1922                 break;
1923 
1924         case NAMETYPE_WORKGROUP:
1925                 param->status = smb_name_validate_workgroup(name);
1926                 break;
1927 
1928         case NAMETYPE_PASSWORD:
1929         case NAMETYPE_COMPUTER:
1930         case NAMETYPE_EVENT:
1931         case NAMETYPE_SERVICE:
1932         case NAMETYPE_NET:
1933         case NAMETYPE_MESSAGE:
1934         case NAMETYPE_MESSAGEDEST:
1935         case NAMETYPE_SHAREPASSWORD:
1936                 param->status = ERROR_NOT_SUPPORTED;
1937                 break;
1938 
1939         default:
1940                 param->status = ERROR_INVALID_PARAMETER;
1941                 break;
1942         }
1943 
1944         return (NDR_DRC_OK);
1945 }
1946 
1947 /*
1948  * srvsvc_s_NetShareAdd
1949  *
1950  * Add a new share. Only power users groups can manage shares.
1951  *
1952  * This interface is used by the rmtshare command from the NT resource
1953  * kit. Rmtshare allows a client to add or remove shares on a server
1954  * from the client's command line.
1955  *
1956  * Returns Win32 error codes.
1957  */
1958 static int
1959 srvsvc_s_NetShareAdd(void *arg, ndr_xa_t *mxa)
1960 {
1961         static DWORD parm_err = 0;
1962         DWORD parm_stat;
1963         struct mslm_NetShareAdd *param = arg;
1964         struct mslm_NetShareInfo_2 *info2;
1965         struct mslm_NetShareInfo_502 *info502;
1966         char realpath[MAXPATHLEN];
1967         int32_t native_os;
1968         uint8_t *sdbuf = NULL;
1969         uint32_t status;
1970         smb_share_t si;
1971 
1972         native_os = ndr_native_os(mxa);
1973 
1974         if (!ndr_is_poweruser(mxa)) {
1975                 bzero(param, sizeof (struct mslm_NetShareAdd));
1976                 param->status = ERROR_ACCESS_DENIED;
1977                 return (NDR_DRC_OK);
1978         }
1979 
1980         switch (param->level) {
1981         case 2:
1982                 info2 = (struct mslm_NetShareInfo_2 *)param->info.un.info2;
1983                 break;
1984 
1985         case 502:
1986                 info502 = (struct mslm_NetShareInfo_502 *)
1987                     param->info.un.info502;
1988                 sdbuf = info502->shi502_security_descriptor;
1989                 info2 = (struct mslm_NetShareInfo_2 *)info502;
1990                 break;
1991 
1992         default:
1993                 bzero(param, sizeof (struct mslm_NetShareAdd));
1994                 param->status = ERROR_ACCESS_DENIED;
1995                 return (NDR_DRC_OK);
1996         }
1997 
1998         if (info2->shi2_netname == NULL || info2->shi2_path == NULL) {
1999                 bzero(param, sizeof (struct mslm_NetShareAdd));
2000                 param->status = NERR_NetNameNotFound;
2001                 return (NDR_DRC_OK);
2002         }
2003 
2004         if (smb_shr_is_restricted((char *)info2->shi2_netname)) {
2005                 bzero(param, sizeof (struct mslm_NetShareAdd));
2006                 param->status = ERROR_ACCESS_DENIED;
2007                 return (NDR_DRC_OK);
2008         }
2009 
2010         if (info2->shi2_comment == NULL)
2011                 info2->shi2_comment = (uint8_t *)"";
2012 
2013         /*
2014          * Derive the real path which will be stored in the
2015          * directory field of the smb_share_t structure
2016          * from the path field in this RPC request.
2017          */
2018         parm_stat = smb_shr_get_realpath((const char *)info2->shi2_path,
2019             realpath, MAXPATHLEN);
2020 
2021         if (parm_stat != NERR_Success) {
2022                 bzero(param, sizeof (struct mslm_NetShareAdd));
2023                 param->status = parm_stat;
2024                 param->parm_err
2025                     = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
2026                 return (NDR_DRC_OK);
2027         }
2028 
2029         param->status = srvsvc_sa_add((char *)info2->shi2_netname, realpath,
2030             (char *)info2->shi2_comment);
2031         if (param->status == NERR_Success) {
2032                 status = smb_shr_get((char *)info2->shi2_netname, &si);
2033 
2034                 if ((sdbuf != NULL) && (status == NERR_Success))
2035                         (void) srvsvc_sd_set(&si, sdbuf);
2036         }
2037         param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
2038         return (NDR_DRC_OK);
2039 }
2040 
2041 /*
2042  * srvsvc_estimate_limit
2043  *
2044  * Estimate the number of objects that will fit in prefmaxlen.
2045  * nlimit is adjusted here.
2046  */
2047 static void
2048 srvsvc_estimate_limit(smb_svcenum_t *se, uint32_t obj_size)
2049 {
2050         DWORD max_cnt;
2051 
2052         if (obj_size == 0) {
2053                 se->se_nlimit = 0;
2054                 return;
2055         }
2056 
2057         if ((max_cnt = (se->se_prefmaxlen / obj_size)) == 0) {
2058                 se->se_nlimit = 0;
2059                 return;
2060         }
2061 
2062         if (se->se_ntotal > max_cnt)
2063                 se->se_nlimit = max_cnt;
2064         else
2065                 se->se_nlimit = se->se_ntotal;
2066 }
2067 
2068 /*
2069  * srvsvc_s_NetShareEnum
2070  *
2071  * Enumerate all shares (see also NetShareEnumSticky).
2072  *
2073  * Request for various levels of information about our shares.
2074  * Level 0: share names.
2075  * Level 1: share name, share type and comment field.
2076  * Level 2: everything that we know about the shares.
2077  * Level 501: level 1 + flags.
2078  * Level 502: level 2 + security descriptor.
2079  */
2080 static int
2081 srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa)
2082 {
2083         struct mslm_NetShareEnum *param = arg;
2084         srvsvc_infonres_t *infonres;
2085         smb_svcenum_t se;
2086         DWORD status;
2087 
2088         infonres = NDR_NEW(mxa, srvsvc_infonres_t);
2089         if (infonres == NULL) {
2090                 bzero(param, sizeof (struct mslm_NetShareEnum));
2091                 param->status = ERROR_NOT_ENOUGH_MEMORY;
2092                 return (NDR_DRC_OK);
2093         }
2094 
2095         infonres->entriesread = 0;
2096         infonres->entries = NULL;
2097         param->result.level = param->level;
2098         param->result.bufptr.p = infonres;
2099 
2100         bzero(&se, sizeof (smb_svcenum_t));
2101         se.se_type = SMB_SVCENUM_TYPE_SHARE;
2102         se.se_level = param->level;
2103         se.se_ntotal = smb_shr_count();
2104         se.se_nlimit = se.se_ntotal;
2105 
2106         if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
2107             param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
2108                 se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
2109         else
2110                 se.se_prefmaxlen = param->prefmaxlen;
2111 
2112         if (param->resume_handle) {
2113                 se.se_resume = *param->resume_handle;
2114                 se.se_nskip = se.se_resume;
2115                 *param->resume_handle = 0;
2116         }
2117 
2118         switch (param->level) {
2119         case 0:
2120                 status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 0);
2121                 break;
2122 
2123         case 1:
2124                 status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 0);
2125                 break;
2126 
2127         case 2:
2128                 status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 0);
2129                 break;
2130 
2131         case 501:
2132                 status = mlsvc_NetShareEnumLevel501(mxa, infonres, &se, 0);
2133                 break;
2134 
2135         case 502:
2136                 status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 0);
2137                 break;
2138 
2139         default:
2140                 status = ERROR_INVALID_LEVEL;
2141                 break;
2142         }
2143 
2144         if (status != 0) {
2145                 bzero(param, sizeof (struct mslm_NetShareEnum));
2146                 param->status = status;
2147                 return (NDR_DRC_OK);
2148         }
2149 
2150         if (se.se_nlimit == 0) {
2151                 param->status = ERROR_SUCCESS;
2152                 return (NDR_DRC_OK);
2153         }
2154 
2155         if (param->resume_handle &&
2156             param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
2157                 if (se.se_resume < se.se_ntotal) {
2158                         *param->resume_handle = se.se_resume;
2159                         status = ERROR_MORE_DATA;
2160                 }
2161         }
2162 
2163         param->totalentries = se.se_ntotal;
2164         param->status = status;
2165         return (NDR_DRC_OK);
2166 }
2167 
2168 /*
2169  * srvsvc_s_NetShareEnumSticky
2170  *
2171  * Enumerate sticky shares: all shares except those marked STYPE_SPECIAL.
2172  * Except for excluding STYPE_SPECIAL shares, NetShareEnumSticky is the
2173  * same as NetShareEnum.
2174  *
2175  * Request for various levels of information about our shares.
2176  * Level 0: share names.
2177  * Level 1: share name, share type and comment field.
2178  * Level 2: everything that we know about the shares.
2179  * Level 501: not valid for this request.
2180  * Level 502: level 2 + security descriptor.
2181  *
2182  * We set n_skip to resume_handle, which is used to find the appropriate
2183  * place to resume.  The resume_handle is similar to the readdir cookie.
2184  */
2185 static int
2186 srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa)
2187 {
2188         struct mslm_NetShareEnum *param = arg;
2189         srvsvc_infonres_t *infonres;
2190         smb_svcenum_t se;
2191         DWORD status;
2192 
2193         infonres = NDR_NEW(mxa, srvsvc_infonres_t);
2194         if (infonres == NULL) {
2195                 bzero(param, sizeof (struct mslm_NetShareEnum));
2196                 param->status = ERROR_NOT_ENOUGH_MEMORY;
2197                 return (NDR_DRC_OK);
2198         }
2199 
2200         infonres->entriesread = 0;
2201         infonres->entries = NULL;
2202         param->result.level = param->level;
2203         param->result.bufptr.p = infonres;
2204 
2205         bzero(&se, sizeof (smb_svcenum_t));
2206         se.se_type = SMB_SVCENUM_TYPE_SHARE;
2207         se.se_level = param->level;
2208         se.se_ntotal = smb_shr_count();
2209         se.se_nlimit = se.se_ntotal;
2210 
2211         if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
2212             param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
2213                 se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
2214         else
2215                 se.se_prefmaxlen = param->prefmaxlen;
2216 
2217         if (param->resume_handle) {
2218                 se.se_resume = *param->resume_handle;
2219                 se.se_nskip = se.se_resume;
2220                 *param->resume_handle = 0;
2221         }
2222 
2223         switch (param->level) {
2224         case 0:
2225                 status = mlsvc_NetShareEnumLevel0(mxa, infonres, &se, 1);
2226                 break;
2227 
2228         case 1:
2229                 status = mlsvc_NetShareEnumLevel1(mxa, infonres, &se, 1);
2230                 break;
2231 
2232         case 2:
2233                 status = mlsvc_NetShareEnumLevel2(mxa, infonres, &se, 1);
2234                 break;
2235 
2236         case 502:
2237                 status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 1);
2238                 break;
2239 
2240         case 501:
2241         default:
2242                 status = ERROR_INVALID_LEVEL;
2243                 break;
2244         }
2245 
2246         if (status != ERROR_SUCCESS) {
2247                 bzero(param, sizeof (struct mslm_NetShareEnum));
2248                 param->status = status;
2249                 return (NDR_DRC_OK);
2250         }
2251 
2252         if (se.se_nlimit == 0) {
2253                 param->status = ERROR_SUCCESS;
2254                 return (NDR_DRC_OK);
2255         }
2256 
2257         if (param->resume_handle &&
2258             param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
2259                 if (se.se_resume < se.se_ntotal) {
2260                         *param->resume_handle = se.se_resume;
2261                         status = ERROR_MORE_DATA;
2262                 }
2263         }
2264 
2265         param->totalentries = se.se_ntotal;
2266         param->status = status;
2267         return (NDR_DRC_OK);
2268 }
2269 
2270 /*
2271  * NetShareEnum Level 0
2272  */
2273 static DWORD
2274 mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2275     smb_svcenum_t *se, int sticky)
2276 {
2277         struct mslm_NetShareInfo_0 *info0;
2278         smb_shriter_t iterator;
2279         smb_share_t *si;
2280         DWORD status;
2281 
2282         srvsvc_estimate_limit(se,
2283             sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
2284         if (se->se_nlimit == 0)
2285                 return (ERROR_SUCCESS);
2286 
2287         info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_nlimit);
2288         if (info0 == NULL)
2289                 return (ERROR_NOT_ENOUGH_MEMORY);
2290 
2291         smb_shr_iterinit(&iterator);
2292 
2293         se->se_nitems = 0;
2294         while ((si = smb_shr_iterate(&iterator)) != NULL) {
2295                 if (se->se_nskip > 0) {
2296                         --se->se_nskip;
2297                         continue;
2298                 }
2299 
2300                 ++se->se_resume;
2301 
2302                 if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2303                         continue;
2304 
2305                 if (si->shr_flags & SMB_SHRF_AUTOHOME)
2306                         continue;
2307 
2308                 if (se->se_nitems >= se->se_nlimit) {
2309                         se->se_nitems = se->se_nlimit;
2310                         break;
2311                 }
2312 
2313                 status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info0);
2314                 if (status != ERROR_SUCCESS)
2315                         break;
2316 
2317                 ++se->se_nitems;
2318         }
2319 
2320         if (se->se_nitems < se->se_nlimit) {
2321                 if (srvsvc_add_autohome(mxa, se, (void *)info0))
2322                         ++se->se_nitems;
2323         }
2324 
2325         infonres->entriesread = se->se_nitems;
2326         infonres->entries = info0;
2327         return (ERROR_SUCCESS);
2328 }
2329 
2330 /*
2331  * NetShareEnum Level 1
2332  */
2333 static DWORD
2334 mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2335     smb_svcenum_t *se, int sticky)
2336 {
2337         struct mslm_NetShareInfo_1 *info1;
2338         smb_shriter_t iterator;
2339         smb_share_t *si;
2340         DWORD status;
2341 
2342         srvsvc_estimate_limit(se,
2343             sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
2344         if (se->se_nlimit == 0)
2345                 return (ERROR_SUCCESS);
2346 
2347         info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_nlimit);
2348         if (info1 == NULL)
2349                 return (ERROR_NOT_ENOUGH_MEMORY);
2350 
2351         smb_shr_iterinit(&iterator);
2352 
2353         se->se_nitems = 0;
2354         while ((si = smb_shr_iterate(&iterator)) != 0) {
2355                 if (se->se_nskip > 0) {
2356                         --se->se_nskip;
2357                         continue;
2358                 }
2359 
2360                 ++se->se_resume;
2361 
2362                 if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2363                         continue;
2364 
2365                 if (si->shr_flags & SMB_SHRF_AUTOHOME)
2366                         continue;
2367 
2368                 if (se->se_nitems >= se->se_nlimit) {
2369                         se->se_nitems = se->se_nlimit;
2370                         break;
2371                 }
2372 
2373                 status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info1);
2374                 if (status != ERROR_SUCCESS)
2375                         break;
2376 
2377                 ++se->se_nitems;
2378         }
2379 
2380         if (se->se_nitems < se->se_nlimit) {
2381                 if (srvsvc_add_autohome(mxa, se, (void *)info1))
2382                         ++se->se_nitems;
2383         }
2384 
2385         infonres->entriesread = se->se_nitems;
2386         infonres->entries = info1;
2387         return (ERROR_SUCCESS);
2388 }
2389 
2390 /*
2391  * NetShareEnum Level 2
2392  */
2393 static DWORD
2394 mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2395     smb_svcenum_t *se, int sticky)
2396 {
2397         struct mslm_NetShareInfo_2 *info2;
2398         smb_shriter_t iterator;
2399         smb_share_t *si;
2400         DWORD status;
2401 
2402         srvsvc_estimate_limit(se,
2403             sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
2404         if (se->se_nlimit == 0)
2405                 return (ERROR_SUCCESS);
2406 
2407         info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_nlimit);
2408         if (info2 == NULL)
2409                 return (ERROR_NOT_ENOUGH_MEMORY);
2410 
2411         smb_shr_iterinit(&iterator);
2412 
2413         se->se_nitems = 0;
2414         while ((si = smb_shr_iterate(&iterator)) != 0) {
2415                 if (se->se_nskip > 0) {
2416                         --se->se_nskip;
2417                         continue;
2418                 }
2419 
2420                 ++se->se_resume;
2421 
2422                 if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2423                         continue;
2424 
2425                 if (si->shr_flags & SMB_SHRF_AUTOHOME)
2426                         continue;
2427 
2428                 if (se->se_nitems >= se->se_nlimit) {
2429                         se->se_nitems = se->se_nlimit;
2430                         break;
2431                 }
2432 
2433                 status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info2);
2434                 if (status != ERROR_SUCCESS)
2435                         break;
2436 
2437                 ++se->se_nitems;
2438         }
2439 
2440         if (se->se_nitems < se->se_nlimit) {
2441                 if (srvsvc_add_autohome(mxa, se, (void *)info2))
2442                         ++se->se_nitems;
2443         }
2444 
2445         infonres->entriesread = se->se_nitems;
2446         infonres->entries = info2;
2447         return (ERROR_SUCCESS);
2448 }
2449 
2450 /*
2451  * NetShareEnum Level 501
2452  */
2453 static DWORD
2454 mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2455     smb_svcenum_t *se, int sticky)
2456 {
2457         struct mslm_NetShareInfo_501 *info501;
2458         smb_shriter_t iterator;
2459         smb_share_t *si;
2460         DWORD status;
2461 
2462         srvsvc_estimate_limit(se,
2463             sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
2464         if (se->se_nlimit == 0)
2465                 return (ERROR_SUCCESS);
2466 
2467         info501 = NDR_NEWN(mxa, struct mslm_NetShareInfo_501,
2468             se->se_nlimit);
2469         if (info501 == NULL)
2470                 return (ERROR_NOT_ENOUGH_MEMORY);
2471 
2472         smb_shr_iterinit(&iterator);
2473 
2474         se->se_nitems = 0;
2475         while ((si = smb_shr_iterate(&iterator)) != 0) {
2476                 if (se->se_nskip > 0) {
2477                         --se->se_nskip;
2478                         continue;
2479                 }
2480 
2481                 ++se->se_resume;
2482 
2483                 if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2484                         continue;
2485 
2486                 if (si->shr_flags & SMB_SHRF_AUTOHOME)
2487                         continue;
2488 
2489                 if (se->se_nitems >= se->se_nlimit) {
2490                         se->se_nitems = se->se_nlimit;
2491                         break;
2492                 }
2493 
2494                 status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info501);
2495                 if (status != ERROR_SUCCESS)
2496                         break;
2497 
2498                 ++se->se_nitems;
2499         }
2500 
2501         if (se->se_nitems < se->se_nlimit) {
2502                 if (srvsvc_add_autohome(mxa, se, (void *)info501))
2503                         ++se->se_nitems;
2504         }
2505 
2506         infonres->entriesread = se->se_nitems;
2507         infonres->entries = info501;
2508         return (ERROR_SUCCESS);
2509 }
2510 
2511 /*
2512  * NetShareEnum Level 502
2513  */
2514 static DWORD
2515 mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
2516     smb_svcenum_t *se, int sticky)
2517 {
2518         struct mslm_NetShareInfo_502 *info502;
2519         smb_shriter_t iterator;
2520         smb_share_t *si;
2521         DWORD status;
2522 
2523         srvsvc_estimate_limit(se,
2524             sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
2525         if (se->se_nlimit == 0)
2526                 return (ERROR_SUCCESS);
2527 
2528         info502 = NDR_NEWN(mxa, struct mslm_NetShareInfo_502,
2529             se->se_nlimit);
2530         if (info502 == NULL)
2531                 return (ERROR_NOT_ENOUGH_MEMORY);
2532 
2533         smb_shr_iterinit(&iterator);
2534 
2535         se->se_nitems = 0;
2536         while ((si = smb_shr_iterate(&iterator)) != NULL) {
2537                 if (se->se_nskip > 0) {
2538                         --se->se_nskip;
2539                         continue;
2540                 }
2541 
2542                 ++se->se_resume;
2543 
2544                 if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
2545                         continue;
2546 
2547                 if (si->shr_flags & SMB_SHRF_AUTOHOME)
2548                         continue;
2549 
2550                 if (se->se_nitems >= se->se_nlimit) {
2551                         se->se_nitems = se->se_nlimit;
2552                         break;
2553                 }
2554 
2555                 status = mlsvc_NetShareEnumCommon(mxa, se, si, (void *)info502);
2556                 if (status != ERROR_SUCCESS)
2557                         break;
2558 
2559                 ++se->se_nitems;
2560         }
2561 
2562         if (se->se_nitems < se->se_nlimit) {
2563                 if (srvsvc_add_autohome(mxa, se, (void *)info502))
2564                         ++se->se_nitems;
2565         }
2566 
2567         infonres->entriesread = se->se_nitems;
2568         infonres->entries = info502;
2569         return (ERROR_SUCCESS);
2570 }
2571 
2572 /*
2573  * mlsvc_NetShareEnumCommon
2574  *
2575  * Build the levels 0, 1, 2, 501 and 502 share information. This function
2576  * is called by the various NetShareEnum levels for each share. If
2577  * we cannot build the share data for some reason, we return an error
2578  * but the actual value of the error is not important to the caller.
2579  * The caller just needs to know not to include this info in the RPC
2580  * response.
2581  *
2582  * Returns:
2583  *      ERROR_SUCCESS
2584  *      ERROR_NOT_ENOUGH_MEMORY
2585  *      ERROR_INVALID_LEVEL
2586  */
2587 static DWORD
2588 mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se,
2589     smb_share_t *si, void *infop)
2590 {
2591         struct mslm_NetShareInfo_0 *info0;
2592         struct mslm_NetShareInfo_1 *info1;
2593         struct mslm_NetShareInfo_2 *info2;
2594         struct mslm_NetShareInfo_501 *info501;
2595         struct mslm_NetShareInfo_502 *info502;
2596         srvsvc_sd_t sd;
2597         uint8_t *netname;
2598         uint8_t *comment;
2599         uint8_t *passwd;
2600         uint8_t *path;
2601         int i = se->se_nitems;
2602 
2603         netname = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
2604         comment = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
2605         passwd = (uint8_t *)NDR_STRDUP(mxa, empty_string);
2606         path = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
2607 
2608         if (!netname || !comment || !passwd || !path)
2609                 return (ERROR_NOT_ENOUGH_MEMORY);
2610 
2611         switch (se->se_level) {
2612         case 0:
2613                 info0 = (struct mslm_NetShareInfo_0 *)infop;
2614                 info0[i].shi0_netname = netname;
2615                 break;
2616 
2617         case 1:
2618                 info1 = (struct mslm_NetShareInfo_1 *)infop;
2619                 info1[i].shi1_netname = netname;
2620                 info1[i].shi1_comment = comment;
2621                 info1[i].shi1_type = si->shr_type;
2622                 break;
2623 
2624         case 2:
2625                 info2 = (struct mslm_NetShareInfo_2 *)infop;
2626                 info2[i].shi2_netname = netname;
2627                 info2[i].shi2_comment = comment;
2628                 info2[i].shi2_path = path;
2629                 info2[i].shi2_type = si->shr_type;
2630                 info2[i].shi2_permissions = 0;
2631                 info2[i].shi2_max_uses = SHI_USES_UNLIMITED;
2632                 info2[i].shi2_current_uses = 0;
2633                 info2[i].shi2_passwd = passwd;
2634                 break;
2635 
2636         case 501:
2637                 info501 = (struct mslm_NetShareInfo_501 *)infop;
2638                 info501[i].shi501_netname = netname;
2639                 info501[i].shi501_comment = comment;
2640                 info501[i].shi501_type = si->shr_type;
2641                 info501[i].shi501_flags = srvsvc_get_share_flags(si);
2642                 break;
2643 
2644         case 502:
2645                 info502 = (struct mslm_NetShareInfo_502 *)infop;
2646                 info502[i].shi502_netname = netname;
2647                 info502[i].shi502_comment = comment;
2648                 info502[i].shi502_path = path;
2649                 info502[i].shi502_type = si->shr_type;
2650                 info502[i].shi502_permissions = 0;
2651                 info502[i].shi502_max_uses = SHI_USES_UNLIMITED;
2652                 info502[i].shi502_current_uses = 0;
2653                 info502[i].shi502_passwd = passwd;
2654 
2655                 if (srvsvc_share_getsd(mxa, si, &sd) == ERROR_SUCCESS) {
2656                         info502[i].shi502_reserved = sd.sd_size;
2657                         info502[i].shi502_security_descriptor = sd.sd_buf;
2658                 } else {
2659                         info502[i].shi502_reserved = 0;
2660                         info502[i].shi502_security_descriptor = NULL;
2661                 }
2662 
2663                 break;
2664 
2665         default:
2666                 return (ERROR_INVALID_LEVEL);
2667         }
2668 
2669         return (ERROR_SUCCESS);
2670 }
2671 
2672 /*
2673  * srvsvc_add_autohome
2674  *
2675  * Add the autohome share for the user. The share must not be a permanent
2676  * share to avoid duplicates.
2677  */
2678 static boolean_t
2679 srvsvc_add_autohome(ndr_xa_t *mxa, smb_svcenum_t *se, void *infop)
2680 {
2681         smb_netuserinfo_t *user = mxa->pipe->np_user;
2682         char *username;
2683         smb_share_t si;
2684         DWORD status;
2685         struct passwd pw;
2686         char buf[NSS_LINELEN_PASSWD];
2687 
2688         if (IDMAP_ID_IS_EPHEMERAL(user->ui_posix_uid)) {
2689                 username = user->ui_account;
2690         } else {
2691                 if (getpwuid_r(user->ui_posix_uid, &pw, buf, sizeof (buf)) ==
2692                     NULL)
2693                         return (B_FALSE);
2694 
2695                 username = pw.pw_name;
2696         }
2697 
2698         if (smb_shr_get(username, &si) != NERR_Success)
2699                 return (B_FALSE);
2700 
2701         if ((si.shr_flags & SMB_SHRF_AUTOHOME) == 0)
2702                 return (B_FALSE);
2703 
2704         status = mlsvc_NetShareEnumCommon(mxa, se, &si, infop);
2705         return (status == ERROR_SUCCESS);
2706 }
2707 
2708 /*
2709  * srvsvc_share_mkpath
2710  *
2711  * Create the share path required by the share enum calls. The path
2712  * is created in a heap buffer ready for use by the caller.
2713  *
2714  * Some Windows over-the-wire backup applications do not work unless a
2715  * drive letter is present in the share path.  We don't care about the
2716  * drive letter since the path is fully qualified with the volume name.
2717  *
2718  * Windows clients seem to be mostly okay with forward slashes in
2719  * share paths but they cannot handle one immediately after the drive
2720  * letter, i.e. B:/.  For consistency we convert all the slashes in
2721  * the path.
2722  *
2723  * Returns a pointer to a heap buffer containing the share path, which
2724  * could be a null pointer if the heap allocation fails.
2725  */
2726 static char *
2727 srvsvc_share_mkpath(ndr_xa_t *mxa, char *path)
2728 {
2729         char tmpbuf[MAXPATHLEN];
2730         char *p;
2731         char drive_letter;
2732 
2733         if (strlen(path) == 0)
2734                 return (NDR_STRDUP(mxa, path));
2735 
2736         drive_letter = smb_shr_drive_letter(path);
2737         if (drive_letter != '\0') {
2738                 (void) snprintf(tmpbuf, MAXPATHLEN, "%c:\\", drive_letter);
2739                 return (NDR_STRDUP(mxa, tmpbuf));
2740         }
2741 
2742         /*
2743          * Strip the volume name from the path (/vol1/home -> /home).
2744          */
2745         p = path;
2746         p += strspn(p, "/");
2747         p += strcspn(p, "/");
2748         p += strspn(p, "/");
2749         (void) snprintf(tmpbuf, MAXPATHLEN, "%c:/%s", 'B', p);
2750         (void) strsubst(tmpbuf, '/', '\\');
2751 
2752         return (NDR_STRDUP(mxa, tmpbuf));
2753 }
2754 
2755 static int
2756 srvsvc_s_NetShareCheck(void *arg, ndr_xa_t *mxa)
2757 {
2758         struct mslm_NetShareCheck *param = arg;
2759         smb_shriter_t iterator;
2760         smb_share_t *si;
2761         char *path;
2762 
2763         if (param->path == NULL) {
2764                 param->stype = STYPE_DISKTREE;
2765                 param->status = NERR_NetNameNotFound;
2766                 return (NDR_DRC_OK);
2767         }
2768 
2769         (void) strsubst((char *)param->path, '/', '\\');
2770 
2771         smb_shr_iterinit(&iterator);
2772 
2773         while ((si = smb_shr_iterate(&iterator)) != NULL) {
2774                 path = srvsvc_share_mkpath(mxa, si->shr_path);
2775 
2776                 if (smb_strcasecmp(path, (char *)param->path, 0) == 0) {
2777                         param->stype = (si->shr_type & STYPE_MASK);
2778                         param->status = NERR_Success;
2779                         return (NDR_DRC_OK);
2780                 }
2781         }
2782 
2783         param->stype = STYPE_DISKTREE;
2784         param->status = NERR_NetNameNotFound;
2785         return (NDR_DRC_OK);
2786 }
2787 
2788 /*
2789  * Delete a share.  Only members of the Administrators, Server Operators
2790  * or Power Users local groups are allowed to delete shares.
2791  *
2792  * This interface is used by the rmtshare command from the NT resource
2793  * kit. Rmtshare allows a client to add or remove shares on a server
2794  * from the client's command line.
2795  *
2796  * Returns Win32 error codes.
2797  */
2798 static int
2799 srvsvc_s_NetShareDel(void *arg, ndr_xa_t *mxa)
2800 {
2801         struct mslm_NetShareDel *param = arg;
2802         smb_share_t si;
2803 
2804         if (!ndr_is_poweruser(mxa) ||
2805             smb_shr_is_restricted((char *)param->netname)) {
2806                 param->status = ERROR_ACCESS_DENIED;
2807                 return (NDR_DRC_OK);
2808         }
2809 
2810         if (smb_shr_get((char *)param->netname, &si) == NERR_Success) {
2811                 if (si.shr_flags & SMB_SHRF_DFSROOT) {
2812                         param->status = NERR_IsDfsShare;
2813                         return (NDR_DRC_OK);
2814                 }
2815         }
2816 
2817         param->status = srvsvc_sa_delete((char *)param->netname);
2818         return (NDR_DRC_OK);
2819 }
2820 
2821 /*
2822  * srvsvc_s_NetGetFileSecurity
2823  *
2824  * Get security descriptor of the requested file/folder
2825  *
2826  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2827  * get the requested SD here in RPC code.
2828  */
2829 /*ARGSUSED*/
2830 static int
2831 srvsvc_s_NetGetFileSecurity(void *arg, ndr_xa_t *mxa)
2832 {
2833         struct mslm_NetGetFileSecurity *param = arg;
2834 
2835         param->length = 0;
2836         param->status = ERROR_ACCESS_DENIED;
2837         return (NDR_DRC_OK);
2838 }
2839 
2840 /*
2841  * srvsvc_s_NetSetFileSecurity
2842  *
2843  * Set the given security descriptor for the requested file/folder
2844  *
2845  * Right now, just returns ERROR_ACCESS_DENIED, because we cannot
2846  * set the requested SD here in RPC code.
2847  */
2848 /*ARGSUSED*/
2849 static int
2850 srvsvc_s_NetSetFileSecurity(void *arg, ndr_xa_t *mxa)
2851 {
2852         struct mslm_NetSetFileSecurity *param = arg;
2853 
2854         param->status = ERROR_ACCESS_DENIED;
2855         return (NDR_DRC_OK);
2856 }
2857 
2858 /*
2859  * If the default "smb" share group exists then return the group
2860  * handle, otherwise create the group and return the handle.
2861  *
2862  * All shares created via the srvsvc will be added to the "smb"
2863  * group.
2864  */
2865 static sa_group_t
2866 srvsvc_sa_get_smbgrp(sa_handle_t handle)
2867 {
2868         sa_group_t group = NULL;
2869         int err;
2870 
2871         group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
2872         if (group != NULL)
2873                 return (group);
2874 
2875         group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
2876         if (group == NULL)
2877                 return (NULL);
2878 
2879         if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
2880                 (void) sa_remove_group(group);
2881                 group = NULL;
2882         }
2883 
2884         return (group);
2885 }
2886 
2887 /*
2888  * Stores the given share in sharemgr
2889  */
2890 static uint32_t
2891 srvsvc_sa_add(char *sharename, char *path, char *cmnt)
2892 {
2893         sa_handle_t handle;
2894         sa_share_t share;
2895         sa_group_t group;
2896         sa_resource_t resource;
2897         boolean_t new_share = B_FALSE;
2898         uint32_t status = NERR_Success;
2899         int err;
2900 
2901         if ((handle = smb_shr_sa_enter()) == NULL)
2902                 return (NERR_InternalError);
2903 
2904         share = sa_find_share(handle, path);
2905         if (share == NULL) {
2906                 group = srvsvc_sa_get_smbgrp(handle);
2907                 if (group == NULL) {
2908                         smb_shr_sa_exit();
2909                         return (NERR_InternalError);
2910                 }
2911 
2912                 share = sa_add_share(group, path, SA_SHARE_PERMANENT, &err);
2913                 if (share == NULL) {
2914                         smb_shr_sa_exit();
2915                         return (NERR_InternalError);
2916                 }
2917                 new_share = B_TRUE;
2918         }
2919 
2920         resource = sa_get_share_resource(share, sharename);
2921         if (resource == NULL) {
2922                 resource = sa_add_resource(share, sharename,
2923                     SA_SHARE_PERMANENT, &err);
2924                 if (resource == NULL) {
2925                         if (new_share)
2926                                 (void) sa_remove_share(share);
2927                         smb_shr_sa_exit();
2928                         return (NERR_InternalError);
2929                 }
2930         }
2931 
2932         (void) sa_set_resource_description(resource, cmnt);
2933 
2934         smb_shr_sa_exit();
2935         return (status);
2936 }
2937 
2938 /*
2939  * Removes the share from sharemgr
2940  */
2941 static uint32_t
2942 srvsvc_sa_delete(char *sharename)
2943 {
2944         sa_handle_t handle;
2945         sa_resource_t resource;
2946         uint32_t status;
2947 
2948         if ((handle = smb_shr_sa_enter()) == NULL)
2949                 return (NERR_InternalError);
2950 
2951         status = NERR_InternalError;
2952         if ((resource = sa_find_resource(handle, sharename)) != NULL) {
2953                 if (sa_remove_resource(resource) == SA_OK)
2954                         status = NERR_Success;
2955         }
2956 
2957         smb_shr_sa_exit();
2958         return (status);
2959 }
2960 
2961 /*
2962  * Update the share information.
2963  */
2964 static uint32_t
2965 srvsvc_sa_modify(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
2966 {
2967         sa_handle_t handle;
2968         sa_share_t share;
2969         sa_resource_t resource;
2970         boolean_t renamed = B_FALSE, is_zfs = B_FALSE;
2971         nvlist_t *nvl;
2972         uint32_t nerr = NERR_Success;
2973 
2974         if ((handle = smb_shr_sa_enter()) == NULL)
2975                 return (NERR_InternalError);
2976 
2977         if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
2978                 smb_shr_sa_exit();
2979                 return (NERR_InternalError);
2980         }
2981 
2982         if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
2983                 smb_shr_sa_exit();
2984                 return (NERR_InternalError);
2985         }
2986 
2987         if (sa_group_is_zfs(sa_get_parent_group(share))) {
2988                 is_zfs = B_TRUE;
2989                 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
2990                         smb_shr_sa_exit();
2991                         return (NERR_InternalError);
2992                 }
2993         }
2994 
2995         if (info->nss_netname != NULL && info->nss_netname[0] != '\0' &&
2996             smb_strcasecmp(info->nss_netname, si->shr_name, 0) != 0) {
2997                 if (is_zfs)
2998                         (void) nvlist_add_string(nvl, SHOPT_NAME,
2999                             info->nss_netname);
3000                 else
3001                         (void) sa_set_resource_attr(resource, SHOPT_NAME,
3002                             info->nss_netname);
3003                 renamed = B_TRUE;
3004         }
3005 
3006         if ((info->nss_comment != NULL) &&
3007             (strcmp(info->nss_comment, si->shr_cmnt) != 0)) {
3008                 if (is_zfs)
3009                         (void) nvlist_add_string(nvl, SHOPT_DESCRIPTION,
3010                             info->nss_comment);
3011                 else
3012                         (void) sa_set_resource_description(resource,
3013                             info->nss_comment);
3014                 (void) strlcpy(si->shr_cmnt, info->nss_comment,
3015                     SMB_SHARE_CMNT_MAX);
3016         }
3017 
3018         if (is_zfs) {
3019                 if (sa_zfs_setprop(handle, si->shr_path, nvl) != 0) {
3020                         smb_shr_sa_exit();
3021                         nvlist_free(nvl);
3022                         return (NERR_InternalError);
3023                 }
3024                 nvlist_free(nvl);
3025         }
3026         smb_shr_sa_exit();
3027 
3028         if (renamed) {
3029                 nerr = smb_shr_rename(si->shr_name, info->nss_netname);
3030                 if (nerr != NERR_Success)
3031                         return (nerr);
3032 
3033                 (void) strlcpy(si->shr_name, info->nss_netname, MAXNAMELEN);
3034         }
3035 
3036         return (nerr);
3037 }
3038 
3039 /*
3040  * Sets the share properties.
3041  *
3042  * This method sets share properties. If its a ZFS share, then properties
3043  * are set by calling the sa_zfs_setprop method. Else the optionset properties
3044  * of the share resource are set.The properties to be set are given as a list
3045  * of name-value pair.
3046  */
3047 static uint32_t
3048 srvsvc_sa_setprop(smb_share_t *si, nvlist_t *nvl)
3049 {
3050         sa_handle_t handle;
3051         sa_share_t share;
3052         sa_resource_t resource;
3053         sa_property_t prop;
3054         sa_optionset_t opts;
3055         uint32_t nerr = NERR_Success;
3056         nvpair_t *cur;
3057         int err = 0;
3058         char *name, *val;
3059 
3060         if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
3061                 return (NERR_InternalError);
3062 
3063         if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
3064                 sa_fini(handle);
3065                 return (NERR_InternalError);
3066         }
3067 
3068         if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
3069                 sa_fini(handle);
3070                 return (NERR_InternalError);
3071         }
3072 
3073         if (sa_group_is_zfs(sa_get_parent_group(share))) {
3074                 if (sa_zfs_setprop(handle, si->shr_path, nvl) != 0)
3075                         nerr = NERR_InternalError;
3076                 sa_fini(handle);
3077                 return (nerr);
3078         }
3079 
3080         if ((opts = sa_get_optionset(resource, SMB_PROTOCOL_NAME)) == NULL) {
3081                 opts = sa_create_optionset(resource, SMB_PROTOCOL_NAME);
3082                 if (opts == NULL) {
3083                         sa_fini(handle);
3084                         return (NERR_InternalError);
3085                 }
3086         }
3087 
3088         cur = nvlist_next_nvpair(nvl, NULL);
3089         while (cur != NULL) {
3090                 name = nvpair_name(cur);
3091                 err = nvpair_value_string(cur, &val);
3092                 if ((err != 0) || (name == NULL) || (val == NULL)) {
3093                         nerr = NERR_InternalError;
3094                         break;
3095                 }
3096 
3097                 prop = NULL;
3098                 if ((prop = sa_get_property(opts, name)) == NULL) {
3099                         prop = sa_create_property(name, val);
3100                         if (prop != NULL) {
3101                                 nerr = sa_valid_property(handle, opts,
3102                                     SMB_PROTOCOL_NAME, prop);
3103                                 if (nerr != NERR_Success) {
3104                                         (void) sa_remove_property(prop);
3105                                         break;
3106                                 }
3107                         }
3108                         nerr = sa_add_property(opts, prop);
3109                         if (nerr != NERR_Success)
3110                                 break;
3111                 } else {
3112                         nerr = sa_update_property(prop, val);
3113                         if (nerr != NERR_Success)
3114                                 break;
3115                 }
3116 
3117                 cur = nvlist_next_nvpair(nvl, cur);
3118         }
3119 
3120         if (nerr == NERR_Success)
3121                 nerr = sa_commit_properties(opts, 0);
3122 
3123         sa_fini(handle);
3124         return (nerr);
3125 }
3126 
3127 static ndr_stub_table_t srvsvc_stub_table[] = {
3128         { srvsvc_s_NetConnectEnum,      SRVSVC_OPNUM_NetConnectEnum },
3129         { srvsvc_s_NetFileEnum,         SRVSVC_OPNUM_NetFileEnum },
3130         { srvsvc_s_NetFileClose,        SRVSVC_OPNUM_NetFileClose },
3131         { srvsvc_s_NetShareGetInfo,     SRVSVC_OPNUM_NetShareGetInfo },
3132         { srvsvc_s_NetShareSetInfo,     SRVSVC_OPNUM_NetShareSetInfo },
3133         { srvsvc_s_NetSessionEnum,      SRVSVC_OPNUM_NetSessionEnum },
3134         { srvsvc_s_NetSessionDel,       SRVSVC_OPNUM_NetSessionDel },
3135         { srvsvc_s_NetServerGetInfo,    SRVSVC_OPNUM_NetServerGetInfo },
3136         { srvsvc_s_NetRemoteTOD,        SRVSVC_OPNUM_NetRemoteTOD },
3137         { srvsvc_s_NetNameValidate,     SRVSVC_OPNUM_NetNameValidate },
3138         { srvsvc_s_NetShareAdd,         SRVSVC_OPNUM_NetShareAdd },
3139         { srvsvc_s_NetShareDel,         SRVSVC_OPNUM_NetShareDel },
3140         { srvsvc_s_NetShareEnum,        SRVSVC_OPNUM_NetShareEnum },
3141         { srvsvc_s_NetShareEnumSticky,  SRVSVC_OPNUM_NetShareEnumSticky },
3142         { srvsvc_s_NetShareCheck,       SRVSVC_OPNUM_NetShareCheck },
3143         { srvsvc_s_NetGetFileSecurity,  SRVSVC_OPNUM_NetGetFileSecurity },
3144         { srvsvc_s_NetSetFileSecurity,  SRVSVC_OPNUM_NetSetFileSecurity },
3145         {0}
3146 };