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