Print this page
    
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libshare/nfs/libshare_nfs.c
          +++ new/usr/src/lib/libshare/nfs/libshare_nfs.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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2016 Nexenta Systems, Inc.
  25   24   * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
       25 + * Copyright 2018 Nexenta Systems, Inc.
  26   26   */
  27   27  
  28   28  /*
  29   29   * NFS specific functions
  30   30   */
       31 +
  31   32  #include <stdio.h>
  32   33  #include <string.h>
  33   34  #include <ctype.h>
  34   35  #include <stdlib.h>
  35   36  #include <unistd.h>
  36      -#include <zone.h>
  37   37  #include <errno.h>
  38   38  #include <locale.h>
  39   39  #include <signal.h>
  40   40  #include <strings.h>
  41   41  #include "libshare.h"
  42   42  #include "libshare_impl.h"
  43   43  #include <nfs/export.h>
  44   44  #include <pwd.h>
  45   45  #include <grp.h>
  46   46  #include <limits.h>
  47   47  #include <libscf.h>
  48   48  #include <syslog.h>
  49   49  #include <rpcsvc/daemon_utils.h>
  50   50  #include "nfslog_config.h"
  51   51  #include "nfslogtab.h"
  52   52  #include "libshare_nfs.h"
  53   53  #include <nfs/nfs.h>
  54   54  #include <nfs/nfssys.h>
  55   55  #include <netconfig.h>
  56   56  #include "smfcfg.h"
  57   57  
  58   58  /* should really be in some global place */
  59   59  #define DEF_WIN 30000
  60   60  #define OPT_CHUNK       1024
  61   61  
  62   62  int debug = 0;
  63   63  
  64   64  #define NFS_SERVER_SVC  "svc:/network/nfs/server:default"
  65   65  #define NFS_CLIENT_SVC  (char *)"svc:/network/nfs/client:default"
  66   66  
  67   67  /* internal functions */
  68   68  static int nfs_init();
  69   69  static void nfs_fini();
  70   70  static int nfs_enable_share(sa_share_t);
  71   71  static int nfs_disable_share(sa_share_t, char *);
  72   72  static int nfs_validate_property(sa_handle_t, sa_property_t, sa_optionset_t);
  73   73  static int nfs_validate_security_mode(char *);
  74   74  static int nfs_is_security_opt(char *);
  75   75  static int nfs_parse_legacy_options(sa_group_t, char *);
  76   76  static char *nfs_format_options(sa_group_t, int);
  77   77  static int nfs_set_proto_prop(sa_property_t);
  78   78  static sa_protocol_properties_t nfs_get_proto_set();
  79   79  static char *nfs_get_status();
  80   80  static char *nfs_space_alias(char *);
  81   81  static uint64_t nfs_features();
  82   82  
  83   83  /*
  84   84   * ops vector that provides the protocol specific info and operations
  85   85   * for share management.
  86   86   */
  87   87  
  88   88  struct sa_plugin_ops sa_plugin_ops = {
  89   89          SA_PLUGIN_VERSION,
  90   90          "nfs",
  91   91          nfs_init,
  92   92          nfs_fini,
  93   93          nfs_enable_share,
  94   94          nfs_disable_share,
  95   95          nfs_validate_property,
  96   96          nfs_validate_security_mode,
  97   97          nfs_is_security_opt,
  98   98          nfs_parse_legacy_options,
  99   99          nfs_format_options,
 100  100          nfs_set_proto_prop,
 101  101          nfs_get_proto_set,
 102  102          nfs_get_status,
 103  103          nfs_space_alias,
 104  104          NULL,   /* update_legacy */
 105  105          NULL,   /* delete_legacy */
 106  106          NULL,   /* change_notify */
 107  107          NULL,   /* enable_resource */
 108  108          NULL,   /* disable_resource */
 109  109          nfs_features,
 110  110          NULL,   /* transient shares */
 111  111          NULL,   /* notify resource */
 112  112          NULL,   /* rename_resource */
 113  113          NULL,   /* run_command */
 114  114          NULL,   /* command_help */
 115  115          NULL    /* delete_proto_section */
 116  116  };
 117  117  
 118  118  /*
 119  119   * list of support services needed
 120  120   * defines should come from head/rpcsvc/daemon_utils.h
 121  121   */
 122  122  
 123  123  static char *service_list_default[] =
 124  124          { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, REPARSED, NULL };
 125  125  static char *service_list_logging[] =
 126  126          { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, REPARSED,
 127  127              NULL };
 128  128  
 129  129  /*
 130  130   * option definitions.  Make sure to keep the #define for the option
 131  131   * index just before the entry it is the index for. Changing the order
 132  132   * can cause breakage.  E.g OPT_RW is index 1 and must precede the
 133  133   * line that includes the SHOPT_RW and OPT_RW entries.
 134  134   */
 135  135  
 136  136  struct option_defs optdefs[] = {
 137  137  #define OPT_RO          0
 138  138          {SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST},
 139  139  #define OPT_RW          1
 140  140          {SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST},
 141  141  #define OPT_ROOT        2
 142  142          {SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST},
 143  143  #define OPT_SECURE      3
 144  144          {SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED},
 145  145  #define OPT_ANON        4
 146  146          {SHOPT_ANON, OPT_ANON, OPT_TYPE_USER},
 147  147  #define OPT_WINDOW      5
 148  148          {SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER},
 149  149  #define OPT_NOSUID      6
 150  150          {SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN},
 151  151  #define OPT_ACLOK       7
 152  152          {SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN},
 153  153  #define OPT_NOSUB       8
 154  154          {SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN},
 155  155  #define OPT_SEC         9
 156  156          {SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY},
 157  157  #define OPT_PUBLIC      10
 158  158          {SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY},
 159  159  #define OPT_INDEX       11
 160  160          {SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE},
 161  161  #define OPT_LOG         12
 162  162          {SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG},
 163  163  #define OPT_CKSUM       13
 164  164          {SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET},
 165  165  #define OPT_NONE        14
 166  166          {SHOPT_NONE, OPT_NONE, OPT_TYPE_ACCLIST},
 167  167  #define OPT_ROOT_MAPPING        15
 168  168          {SHOPT_ROOT_MAPPING, OPT_ROOT_MAPPING, OPT_TYPE_USER},
 169  169  #define OPT_CHARSET_MAP 16
 170  170          {"", OPT_CHARSET_MAP, OPT_TYPE_ACCLIST},
 171  171  #define OPT_NOACLFAB    17
 172  172          {SHOPT_NOACLFAB, OPT_NOACLFAB, OPT_TYPE_BOOLEAN},
 173  173  #define OPT_UIDMAP      18
 174  174          {SHOPT_UIDMAP, OPT_UIDMAP, OPT_TYPE_MAPPING},
 175  175  #define OPT_GIDMAP      19
 176  176          {SHOPT_GIDMAP, OPT_GIDMAP, OPT_TYPE_MAPPING},
 177  177  #define OPT_NOHIDE      20
 178  178          {SHOPT_NOHIDE, OPT_NOHIDE, OPT_TYPE_BOOLEAN},
 179  179  #ifdef VOLATILE_FH_TEST /* XXX added for testing volatile fh's only */
 180  180  #define OPT_VOLFH       21
 181  181          {SHOPT_VOLFH, OPT_VOLFH},
 182  182  #endif /* VOLATILE_FH_TEST */
 183  183          NULL
 184  184  };
 185  185  
 186  186  /*
 187  187   * Codesets that may need to be converted to UTF-8 for file paths.
 188  188   * Add new names here to add new property support. If we ever get a
 189  189   * way to query the kernel for character sets, this should become
 190  190   * dynamically loaded. Make sure changes here are reflected in
 191  191   * cmd/fs.d/nfs/mountd/nfscmd.c
 192  192   */
 193  193  
 194  194  static char *legal_conv[] = {
 195  195          "euc-cn",
 196  196          "euc-jp",
 197  197          "euc-jpms",
 198  198          "euc-kr",
 199  199          "euc-tw",
 200  200          "iso8859-1",
 201  201          "iso8859-2",
 202  202          "iso8859-5",
 203  203          "iso8859-6",
 204  204          "iso8859-7",
 205  205          "iso8859-8",
 206  206          "iso8859-9",
 207  207          "iso8859-13",
 208  208          "iso8859-15",
 209  209          "koi8-r",
 210  210          NULL
 211  211  };
 212  212  
 213  213  /*
 214  214   * list of properties that are related to security flavors.
 215  215   */
 216  216  static char *seclist[] = {
 217  217          SHOPT_RO,
 218  218          SHOPT_RW,
 219  219          SHOPT_ROOT,
 220  220          SHOPT_WINDOW,
 221  221          SHOPT_NONE,
 222  222          SHOPT_ROOT_MAPPING,
 223  223          SHOPT_UIDMAP,
 224  224          SHOPT_GIDMAP,
 225  225          NULL
 226  226  };
 227  227  
 228  228  /* structure for list of securities */
 229  229  struct securities {
 230  230          sa_security_t security;
 231  231          struct securities *next;
 232  232  };
 233  233  
 234  234  /*
 235  235   * findcharset(charset)
 236  236   *
 237  237   * Returns B_TRUE if the charset is a legal conversion otherwise
 238  238   * B_FALSE. This will need to be rewritten to be more efficient when
 239  239   * we have a dynamic list of legal conversions.
 240  240   */
 241  241  
 242  242  static boolean_t
 243  243  findcharset(char *charset)
 244  244  {
 245  245          int i;
 246  246  
 247  247          for (i = 0; legal_conv[i] != NULL; i++)
 248  248                  if (strcmp(charset, legal_conv[i]) == 0)
 249  249                          return (B_TRUE);
 250  250          return (B_FALSE);
 251  251  }
 252  252  
 253  253  /*
 254  254   * findopt(name)
 255  255   *
 256  256   * Lookup option "name" in the option table and return the table
 257  257   * index.
 258  258   */
 259  259  
 260  260  static int
 261  261  findopt(char *name)
 262  262  {
 263  263          int i;
 264  264          if (name != NULL) {
 265  265                  for (i = 0; optdefs[i].tag != NULL; i++) {
 266  266                          if (strcmp(optdefs[i].tag, name) == 0)
 267  267                                  return (optdefs[i].index);
 268  268                  }
 269  269                  if (findcharset(name))
 270  270                          return (OPT_CHARSET_MAP);
 271  271          }
 272  272          return (-1);
 273  273  }
 274  274  
 275  275  /*
 276  276   * gettype(name)
 277  277   *
 278  278   * Return the type of option "name".
 279  279   */
 280  280  
 281  281  static int
 282  282  gettype(char *name)
 283  283  {
 284  284          int optdef;
 285  285  
 286  286          optdef = findopt(name);
 287  287          if (optdef != -1)
 288  288                  return (optdefs[optdef].type);
 289  289          return (OPT_TYPE_ANY);
 290  290  }
 291  291  
 292  292  /*
 293  293   * nfs_validate_security_mode(mode)
 294  294   *
 295  295   * is the specified mode string a valid one for use with NFS?
 296  296   */
 297  297  
 298  298  static int
 299  299  nfs_validate_security_mode(char *mode)
 300  300  {
 301  301          seconfig_t secinfo;
 302  302          int err;
 303  303  
 304  304          (void) memset(&secinfo, '\0', sizeof (secinfo));
 305  305          err = nfs_getseconfig_byname(mode, &secinfo);
 306  306          if (err == SC_NOERROR)
 307  307                  return (1);
 308  308          return (0);
 309  309  }
 310  310  
 311  311  /*
 312  312   * nfs_is_security_opt(tok)
 313  313   *
 314  314   * check to see if tok represents an option that is only valid in some
 315  315   * security flavor.
 316  316   */
 317  317  
 318  318  static int
 319  319  nfs_is_security_opt(char *tok)
 320  320  {
 321  321          int i;
 322  322  
 323  323          for (i = 0; seclist[i] != NULL; i++) {
 324  324                  if (strcmp(tok, seclist[i]) == 0)
 325  325                          return (1);
 326  326          }
 327  327          return (0);
 328  328  }
 329  329  
 330  330  /*
 331  331   * find_security(seclist, sec)
 332  332   *
 333  333   * Walk the current list of security flavors and return true if it is
 334  334   * present, else return false.
 335  335   */
 336  336  
 337  337  static int
 338  338  find_security(struct securities *seclist, sa_security_t sec)
 339  339  {
 340  340          while (seclist != NULL) {
 341  341                  if (seclist->security == sec)
 342  342                          return (1);
 343  343                  seclist = seclist->next;
 344  344          }
 345  345          return (0);
 346  346  }
 347  347  
 348  348  /*
 349  349   * make_security_list(group, securitymodes, proto)
 350  350   *      go through the list of securitymodes and add them to the
 351  351   *      group's list of security optionsets. We also keep a list of
 352  352   *      those optionsets so we don't have to find them later. All of
 353  353   *      these will get copies of the same properties.
 354  354   */
 355  355  
 356  356  static struct securities *
 357  357  make_security_list(sa_group_t group, char *securitymodes, char *proto)
 358  358  {
 359  359          char *tok, *next = NULL;
 360  360          struct securities *curp, *headp = NULL, *prev;
 361  361          sa_security_t check;
 362  362          int freetok = 0;
 363  363  
 364  364          for (tok = securitymodes; tok != NULL; tok = next) {
 365  365                  next = strchr(tok, ':');
 366  366                  if (next != NULL)
 367  367                          *next++ = '\0';
 368  368                  if (strcmp(tok, "default") == 0) {
 369  369                          /* resolve default into the real type */
 370  370                          tok = nfs_space_alias(tok);
 371  371                          freetok = 1;
 372  372                  }
 373  373                  check = sa_get_security(group, tok, proto);
 374  374  
 375  375                  /* add to the security list if it isn't there already */
 376  376                  if (check == NULL || !find_security(headp, check)) {
 377  377                          curp = (struct securities *)calloc(1,
 378  378                              sizeof (struct securities));
 379  379                          if (curp != NULL) {
 380  380                                  if (check == NULL) {
 381  381                                          curp->security = sa_create_security(
 382  382                                              group, tok, proto);
 383  383                                  } else {
 384  384                                          curp->security = check;
 385  385                                  }
 386  386                                  /*
 387  387                                   * note that the first time through the loop,
 388  388                                   * headp will be NULL and prev will be
 389  389                                   * undefined.  Since headp is NULL, we set
 390  390                                   * both it and prev to the curp (first
 391  391                                   * structure to be allocated).
 392  392                                   *
 393  393                                   * later passes through the loop will have
 394  394                                   * headp not being NULL and prev will be used
 395  395                                   * to allocate at the end of the list.
 396  396                                   */
 397  397                                  if (headp == NULL) {
 398  398                                          headp = curp;
 399  399                                          prev = curp;
 400  400                                  } else {
 401  401                                          prev->next = curp;
 402  402                                          prev = curp;
 403  403                                  }
 404  404                          }
 405  405                  }
 406  406  
 407  407                  if (freetok) {
 408  408                          freetok = 0;
 409  409                          sa_free_attr_string(tok);
 410  410                  }
 411  411          }
 412  412          return (headp);
 413  413  }
 414  414  
 415  415  static void
 416  416  free_security_list(struct securities *sec)
 417  417  {
 418  418          struct securities *next;
 419  419          if (sec != NULL) {
 420  420                  for (next = sec->next; sec != NULL; sec = next) {
 421  421                          next = sec->next;
 422  422                          free(sec);
 423  423                  }
 424  424          }
 425  425  }
 426  426  
 427  427  /*
 428  428   * nfs_alistcat(str1, str2, sep)
 429  429   *
 430  430   * concatenate str1 and str2 into a new string using sep as a separate
 431  431   * character. If memory allocation fails, return NULL;
 432  432   */
 433  433  
 434  434  static char *
 435  435  nfs_alistcat(char *str1, char *str2, char sep)
 436  436  {
 437  437          char *newstr;
 438  438          size_t len;
 439  439  
 440  440          len = strlen(str1) + strlen(str2) + 2;
 441  441          newstr = (char *)malloc(len);
 442  442          if (newstr != NULL)
 443  443                  (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2);
 444  444          return (newstr);
 445  445  }
 446  446  
 447  447  /*
 448  448   * add_security_prop(sec, name, value, persist, iszfs)
 449  449   *
 450  450   * Add the property to the securities structure. This accumulates
 451  451   * properties for as part of parsing legacy options.
 452  452   */
 453  453  
 454  454  static int
 455  455  add_security_prop(struct securities *sec, char *name, char *value,
 456  456      int persist, int iszfs)
 457  457  {
 458  458          sa_property_t prop;
 459  459          int ret = SA_OK;
 460  460  
 461  461          for (; sec != NULL; sec = sec->next) {
 462  462                  if (value == NULL) {
 463  463                          if (strcmp(name, SHOPT_RW) == 0 ||
 464  464                              strcmp(name, SHOPT_RO) == 0)
 465  465                                  value = "*";
 466  466                          else
 467  467                                  value = "true";
 468  468                  }
 469  469  
 470  470                  /*
 471  471                   * Get the existing property, if it exists, so we can
 472  472                   * determine what to do with it. The ro/rw/root
 473  473                   * properties can be merged if multiple instances of
 474  474                   * these properies are given. For example, if "rw"
 475  475                   * exists with a value "host1" and a later token of
 476  476                   * rw="host2" is seen, the values are merged into a
 477  477                   * single rw="host1:host2".
 478  478                   */
 479  479                  prop = sa_get_property(sec->security, name);
 480  480  
 481  481                  if (prop != NULL) {
 482  482                          char *oldvalue;
 483  483                          char *newvalue;
 484  484  
 485  485                          /*
 486  486                           * The security options of ro/rw/root/uidmap/gidmap
 487  487                           * might appear multiple times.  If they do, the values
 488  488                           * need to be merged.  If it was previously empty, the
 489  489                           * new value alone is added.
 490  490                           */
 491  491                          oldvalue = sa_get_property_attr(prop, "value");
 492  492                          if (oldvalue != NULL) {
 493  493                                  char sep = ':';
 494  494  
 495  495                                  if (strcmp(name, SHOPT_UIDMAP) == 0 ||
 496  496                                      strcmp(name, SHOPT_GIDMAP) == 0)
 497  497                                          sep = '~';
 498  498  
 499  499                                  /*
 500  500                                   * The general case is to concatenate the new
 501  501                                   * value onto the old value for multiple
 502  502                                   * rw(ro/root/uidmap/gidmap) properties.  For
 503  503                                   * rw/ro/root a special case exists when either
 504  504                                   * the old or new is the "all" case.  In the
 505  505                                   * special case, if both are "all", then it is
 506  506                                   * "all", else if one is an access-list, that
 507  507                                   * replaces the "all".
 508  508                                   */
 509  509                                  if (strcmp(oldvalue, "*") == 0) {
 510  510                                          /* Replace old value with new value. */
 511  511                                          newvalue = strdup(value);
 512  512                                  } else if (strcmp(value, "*") == 0 ||
 513  513                                      strcmp(oldvalue, value) == 0) {
 514  514                                          /*
 515  515                                           * Keep old value and ignore
 516  516                                           * the new value.
 517  517                                           */
 518  518                                          newvalue = NULL;
 519  519                                  } else {
 520  520                                          /*
 521  521                                           * Make a new list of old plus new
 522  522                                           * access-list.
 523  523                                           */
 524  524                                          newvalue = nfs_alistcat(oldvalue,
 525  525                                              value, sep);
 526  526                                  }
 527  527  
 528  528                                  if (newvalue != NULL) {
 529  529                                          (void) sa_remove_property(prop);
 530  530                                          prop = sa_create_property(name,
 531  531                                              newvalue);
 532  532                                          ret = sa_add_property(sec->security,
 533  533                                              prop);
 534  534                                          free(newvalue);
 535  535                                  }
 536  536  
 537  537                                  sa_free_attr_string(oldvalue);
 538  538                          }
 539  539                  } else {
 540  540                          prop = sa_create_property(name, value);
 541  541                          ret = sa_add_property(sec->security, prop);
 542  542                  }
 543  543                  if (ret == SA_OK && !iszfs) {
 544  544                          ret = sa_commit_properties(sec->security, !persist);
 545  545                  }
 546  546          }
 547  547          return (ret);
 548  548  }
 549  549  
 550  550  /*
 551  551   * check to see if group/share is persistent.
 552  552   */
 553  553  static int
 554  554  is_persistent(sa_group_t group)
 555  555  {
 556  556          char *type;
 557  557          int persist = 1;
 558  558  
 559  559          type = sa_get_group_attr(group, "type");
 560  560          if (type != NULL && strcmp(type, "persist") != 0)
 561  561                  persist = 0;
 562  562          if (type != NULL)
 563  563                  sa_free_attr_string(type);
 564  564          return (persist);
 565  565  }
 566  566  
 567  567  /*
 568  568   * invalid_security(options)
 569  569   *
 570  570   * search option string for any invalid sec= type.
 571  571   * return true (1) if any are not valid else false (0)
 572  572   */
 573  573  static int
 574  574  invalid_security(char *options)
 575  575  {
 576  576          char *copy, *base, *token, *value;
 577  577          int ret = 0;
 578  578  
 579  579          copy = strdup(options);
 580  580          token = base = copy;
 581  581          while (token != NULL && ret == 0) {
 582  582                  token = strtok(base, ",");
 583  583                  base = NULL;
 584  584                  if (token != NULL) {
 585  585                          value = strchr(token, '=');
 586  586                          if (value != NULL)
 587  587                                  *value++ = '\0';
 588  588                          if (strcmp(token, SHOPT_SEC) == 0) {
 589  589                                  /* HAVE security flavors so check them */
 590  590                                  char *tok, *next;
 591  591                                  for (next = NULL, tok = value; tok != NULL;
 592  592                                      tok = next) {
 593  593                                          next = strchr(tok, ':');
 594  594                                          if (next != NULL)
 595  595                                                  *next++ = '\0';
 596  596                                          ret = !nfs_validate_security_mode(tok);
 597  597                                          if (ret)
 598  598                                                  break;
 599  599                                  }
 600  600                          }
 601  601                  }
 602  602          }
 603  603          if (copy != NULL)
 604  604                  free(copy);
 605  605          return (ret);
 606  606  }
 607  607  
 608  608  /*
 609  609   * nfs_parse_legacy_options(group, options)
 610  610   *
 611  611   * Parse the old style options into internal format and store on the
 612  612   * specified group.  Group could be a share for full legacy support.
 613  613   */
 614  614  
 615  615  static int
 616  616  nfs_parse_legacy_options(sa_group_t group, char *options)
 617  617  {
 618  618          char *dup;
 619  619          char *base;
 620  620          char *token;
 621  621          sa_optionset_t optionset;
 622  622          struct securities *security_list = NULL;
 623  623          sa_property_t prop;
 624  624          int ret = SA_OK;
 625  625          int iszfs = 0;
 626  626          sa_group_t parent;
 627  627          int persist = 0;
 628  628          char *lasts;
 629  629  
 630  630          /* do we have an existing optionset? */
 631  631          optionset = sa_get_optionset(group, "nfs");
 632  632          if (optionset == NULL) {
 633  633                  /* didn't find existing optionset so create one */
 634  634                  optionset = sa_create_optionset(group, "nfs");
 635  635          } else {
 636  636                  /*
 637  637                   * Have an existing optionset . Ideally, we would need
 638  638                   * to compare options in order to detect errors. For
 639  639                   * now, we assume that the first optionset is the
 640  640                   * correct one and the others will be the same. An
 641  641                   * empty optionset is the same as no optionset so we
 642  642                   * don't want to exit in that case. Getting an empty
 643  643                   * optionset can occur with ZFS property checking.
 644  644                   */
 645  645                  if (sa_get_property(optionset, NULL) != NULL)
 646  646                          return (ret);
 647  647          }
 648  648  
 649  649          if (strcmp(options, SHOPT_RW) == 0) {
 650  650                  /*
 651  651                   * there is a special case of only the option "rw"
 652  652                   * being the default option. We don't have to do
 653  653                   * anything.
 654  654                   */
 655  655                  return (ret);
 656  656          }
 657  657  
 658  658          /*
 659  659           * check if security types are present and validate them. If
 660  660           * any are not legal, fail.
 661  661           */
 662  662  
 663  663          if (invalid_security(options)) {
 664  664                  return (SA_INVALID_SECURITY);
 665  665          }
 666  666  
 667  667          /*
 668  668           * in order to not attempt to change ZFS properties unless
 669  669           * absolutely necessary, we never do it in the legacy parsing.
 670  670           */
 671  671          if (sa_is_share(group)) {
 672  672                  char *zfs;
 673  673                  parent = sa_get_parent_group(group);
 674  674                  if (parent != NULL) {
 675  675                          zfs = sa_get_group_attr(parent, "zfs");
 676  676                          if (zfs != NULL) {
 677  677                                  sa_free_attr_string(zfs);
 678  678                                  iszfs++;
 679  679                          }
 680  680                  }
 681  681          } else {
 682  682                  iszfs = sa_group_is_zfs(group);
 683  683          }
 684  684  
 685  685          /* We need a copy of options for the next part. */
 686  686          dup = strdup(options);
 687  687          if (dup == NULL)
 688  688                  return (SA_NO_MEMORY);
 689  689  
 690  690          /*
 691  691           * we need to step through each option in the string and then
 692  692           * add either the option or the security option as needed. If
 693  693           * this is not a persistent share, don't commit to the
 694  694           * repository. If there is an error, we also want to abort the
 695  695           * processing and report it.
 696  696           */
 697  697          persist = is_persistent(group);
 698  698          base = dup;
 699  699          token = dup;
 700  700          lasts = NULL;
 701  701          while (token != NULL && ret == SA_OK) {
 702  702                  token = strtok_r(base, ",", &lasts);
 703  703                  base = NULL;
 704  704                  if (token != NULL) {
 705  705                          char *value;
 706  706                          /*
 707  707                           * if the option has a value, it will have an '=' to
 708  708                           * separate the name from the value. The following
 709  709                           * code will result in value != NULL and token
 710  710                           * pointing to just the name if there is a value.
 711  711                           */
 712  712                          value = strchr(token, '=');
 713  713                          if (value != NULL) {
 714  714                                  *value++ = '\0';
 715  715                          }
 716  716                          if (strcmp(token, SHOPT_SEC) == 0 ||
 717  717                              strcmp(token, SHOPT_SECURE) == 0) {
 718  718                                  /*
 719  719                                   * Once in security parsing, we only
 720  720                                   * do security. We do need to move
 721  721                                   * between the security node and the
 722  722                                   * toplevel. The security tag goes on
 723  723                                   * the root while the following ones
 724  724                                   * go on the security.
 725  725                                   */
 726  726                                  if (security_list != NULL) {
 727  727                                          /*
 728  728                                           * have an old list so close it and
 729  729                                           * start the new
 730  730                                           */
 731  731                                          free_security_list(security_list);
 732  732                                  }
 733  733                                  if (strcmp(token, SHOPT_SECURE) == 0) {
 734  734                                          value = "dh";
 735  735                                  } else {
 736  736                                          if (value == NULL) {
 737  737                                                  ret = SA_SYNTAX_ERR;
 738  738                                                  break;
 739  739                                          }
 740  740                                  }
 741  741                                  security_list = make_security_list(group,
 742  742                                      value, "nfs");
 743  743                          } else {
 744  744                                  /*
 745  745                                   * Note that the "old" syntax allowed a
 746  746                                   * default security model.  This must be
 747  747                                   * accounted for and internally converted to
 748  748                                   * "standard" security structure.
 749  749                                   */
 750  750                                  if (nfs_is_security_opt(token)) {
 751  751                                          if (security_list == NULL) {
 752  752                                                  /*
 753  753                                                   * need to have a
 754  754                                                   * security
 755  755                                                   * option. This will
 756  756                                                   * be "closed" when a
 757  757                                                   * defined "sec="
 758  758                                                   * option is
 759  759                                                   * seen. This is
 760  760                                                   * technically an
 761  761                                                   * error but will be
 762  762                                                   * allowed with
 763  763                                                   * warning.
 764  764                                                   */
 765  765                                                  security_list =
 766  766                                                      make_security_list(group,
 767  767                                                      "default",
 768  768                                                      "nfs");
 769  769                                          }
 770  770                                          if (security_list != NULL) {
 771  771                                                  ret = add_security_prop(
 772  772                                                      security_list, token,
 773  773                                                      value, persist, iszfs);
 774  774                                          } else {
 775  775                                                  ret = SA_NO_MEMORY;
 776  776                                          }
 777  777                                  } else {
 778  778                                          /* regular options */
 779  779                                          if (value == NULL) {
 780  780                                                  if (strcmp(token, SHOPT_RW) ==
 781  781                                                      0 || strcmp(token,
 782  782                                                      SHOPT_RO) == 0) {
 783  783                                                          value = "*";
 784  784                                                  } else {
 785  785                                                          value = "global";
 786  786                                                          if (strcmp(token,
 787  787                                                              SHOPT_LOG) != 0) {
 788  788                                                                  value = "true";
 789  789                                                          }
 790  790                                                  }
 791  791                                          }
 792  792                                          /*
 793  793                                           * In all cases, create the
 794  794                                           * property specified. If the
 795  795                                           * value was NULL, the default
 796  796                                           * value will have been
 797  797                                           * substituted.
 798  798                                           */
 799  799                                          prop = sa_create_property(token, value);
 800  800                                          ret =  sa_add_property(optionset, prop);
 801  801                                          if (ret != SA_OK)
 802  802                                                  break;
 803  803  
 804  804                                          if (!iszfs) {
 805  805                                                  ret = sa_commit_properties(
 806  806                                                      optionset, !persist);
 807  807                                          }
 808  808                                  }
 809  809                          }
 810  810                  }
 811  811          }
 812  812          if (security_list != NULL)
 813  813                  free_security_list(security_list);
 814  814  
 815  815          free(dup);
 816  816          return (ret);
 817  817  }
 818  818  
 819  819  /*
 820  820   * is_a_number(number)
 821  821   *
 822  822   * is the string a number in one of the forms we want to use?
 823  823   */
 824  824  
 825  825  static int
 826  826  is_a_number(char *number)
 827  827  {
 828  828          int ret = 1;
 829  829          int hex = 0;
 830  830  
 831  831          if (strncmp(number, "0x", 2) == 0) {
 832  832                  number += 2;
 833  833                  hex = 1;
 834  834          } else if (*number == '-') {
 835  835                  number++; /* skip the minus */
 836  836          }
 837  837          while (ret == 1 && *number != '\0') {
 838  838                  if (hex) {
 839  839                          ret = isxdigit(*number++);
 840  840                  } else {
 841  841                          ret = isdigit(*number++);
 842  842                  }
 843  843          }
 844  844          return (ret);
 845  845  }
 846  846  
 847  847  /*
 848  848   * Look for the specified tag in the configuration file. If it is found,
 849  849   * enable logging and set the logging configuration information for exp.
 850  850   */
 851  851  static void
 852  852  configlog(struct exportdata *exp, char *tag)
 853  853  {
 854  854          nfsl_config_t *configlist = NULL, *configp;
 855  855          int error = 0;
 856  856          char globaltag[] = DEFAULTTAG;
 857  857  
 858  858          /*
 859  859           * Sends config errors to stderr
 860  860           */
 861  861          nfsl_errs_to_syslog = B_FALSE;
 862  862  
 863  863          /*
 864  864           * get the list of configuration settings
 865  865           */
 866  866          error = nfsl_getconfig_list(&configlist);
 867  867          if (error) {
 868  868                  (void) fprintf(stderr,
 869  869                      dgettext(TEXT_DOMAIN, "Cannot get log configuration: %s\n"),
 870  870                      strerror(error));
 871  871          }
 872  872  
 873  873          if (tag == NULL)
 874  874                  tag = globaltag;
 875  875          if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) {
 876  876                  nfsl_freeconfig_list(&configlist);
 877  877                  (void) fprintf(stderr,
 878  878                      dgettext(TEXT_DOMAIN, "No tags matching \"%s\"\n"), tag);
 879  879                  /* bad configuration */
 880  880                  error = ENOENT;
 881  881                  goto err;
 882  882          }
 883  883  
 884  884          if ((exp->ex_tag = strdup(tag)) == NULL) {
 885  885                  error = ENOMEM;
 886  886                  goto out;
 887  887          }
 888  888          if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) {
 889  889                  error = ENOMEM;
 890  890                  goto out;
 891  891          }
 892  892          exp->ex_flags |= EX_LOG;
 893  893          if (configp->nc_rpclogpath != NULL)
 894  894                  exp->ex_flags |= EX_LOG_ALLOPS;
 895  895  out:
 896  896          if (configlist != NULL)
 897  897                  nfsl_freeconfig_list(&configlist);
 898  898  
 899  899  err:
 900  900          if (error != 0) {
 901  901                  free(exp->ex_tag);
 902  902                  free(exp->ex_log_buffer);
 903  903                  (void) fprintf(stderr,
 904  904                      dgettext(TEXT_DOMAIN, "Cannot set log configuration: %s\n"),
 905  905                      strerror(error));
 906  906          }
 907  907  }
 908  908  
 909  909  /*
 910  910   * fill_export_from_optionset(export, optionset)
 911  911   *
 912  912   * In order to share, we need to set all the possible general options
 913  913   * into the export structure. Share info will be filled in by the
 914  914   * caller. Various property values get turned into structure specific
 915  915   * values.
 916  916   */
 917  917  
 918  918  static int
 919  919  fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
 920  920  {
 921  921          sa_property_t option;
 922  922          int ret = SA_OK;
 923  923  
 924  924          for (option = sa_get_property(optionset, NULL);
 925  925              option != NULL; option = sa_get_next_property(option)) {
 926  926                  char *name;
 927  927                  char *value;
 928  928                  uint32_t val;
 929  929  
 930  930                  /*
 931  931                   * since options may be set/reset multiple times, always do an
 932  932                   * explicit set or clear of the option. This allows defaults
 933  933                   * to be set and then the protocol specific to override.
 934  934                   */
 935  935  
 936  936                  name = sa_get_property_attr(option, "type");
 937  937                  value = sa_get_property_attr(option, "value");
 938  938                  switch (findopt(name)) {
 939  939                  case OPT_ANON:
 940  940                          if (value != NULL && is_a_number(value)) {
 941  941                                  val = strtoul(value, NULL, 0);
 942  942                          } else {
 943  943                                  struct passwd *pw;
 944  944                                  pw = getpwnam(value != NULL ? value : "nobody");
 945  945                                  if (pw != NULL) {
 946  946                                          val = pw->pw_uid;
 947  947                                  } else {
 948  948                                          val = UID_NOBODY;
 949  949                                  }
 950  950                                  endpwent();
 951  951                          }
 952  952                          export->ex_anon = val;
 953  953                          break;
 954  954                  case OPT_NOSUID:
 955  955                          if (value != NULL && (strcasecmp(value, "true") == 0 ||
 956  956                              strcmp(value, "1") == 0))
 957  957                                  export->ex_flags |= EX_NOSUID;
 958  958                          else
 959  959                                  export->ex_flags &= ~EX_NOSUID;
 960  960                          break;
 961  961                  case OPT_ACLOK:
 962  962                          if (value != NULL && (strcasecmp(value, "true") == 0 ||
 963  963                              strcmp(value, "1") == 0))
 964  964                                  export->ex_flags |= EX_ACLOK;
 965  965                          else
 966  966                                  export->ex_flags &= ~EX_ACLOK;
 967  967                          break;
 968  968                  case OPT_NOSUB:
 969  969                          if (value != NULL && (strcasecmp(value, "true") == 0 ||
 970  970                              strcmp(value, "1") == 0))
 971  971                                  export->ex_flags |= EX_NOSUB;
 972  972                          else
 973  973                                  export->ex_flags &= ~EX_NOSUB;
 974  974                          break;
 975  975                  case OPT_PUBLIC:
 976  976                          if (value != NULL && (strcasecmp(value, "true") == 0 ||
 977  977                              strcmp(value, "1") == 0))
 978  978                                  export->ex_flags |= EX_PUBLIC;
 979  979                          else
 980  980                                  export->ex_flags &= ~EX_PUBLIC;
 981  981                          break;
 982  982                  case OPT_INDEX:
 983  983                          if (value != NULL && (strcmp(value, "..") == 0 ||
 984  984                              strchr(value, '/') != NULL)) {
 985  985                                  /* this is an error */
 986  986                                  (void) printf(dgettext(TEXT_DOMAIN,
 987  987                                      "NFS: index=\"%s\" not valid;"
 988  988                                      "must be a filename.\n"),
 989  989                                      value);
 990  990                                  break;
 991  991                          }
 992  992                          if (value != NULL && *value != '\0' &&
 993  993                              strcmp(value, ".") != 0) {
 994  994                                  /* valid index file string */
 995  995                                  if (export->ex_index != NULL) {
 996  996                                          /* left over from "default" */
 997  997                                          free(export->ex_index);
 998  998                                  }
 999  999                                  /* remember to free */
1000 1000                                  export->ex_index = strdup(value);
1001 1001                                  if (export->ex_index == NULL) {
1002 1002                                          (void) printf(dgettext(TEXT_DOMAIN,
1003 1003                                              "NFS: out of memory setting "
1004 1004                                              "index property\n"));
1005 1005                                          break;
1006 1006                                  }
1007 1007                                  export->ex_flags |= EX_INDEX;
1008 1008                          }
1009 1009                          break;
1010 1010                  case OPT_LOG:
1011 1011                          if (value == NULL)
1012 1012                                  value = strdup("global");
1013 1013                          if (value != NULL)
1014 1014                                  configlog(export,
1015 1015                                      strlen(value) ? value : "global");
1016 1016                          break;
1017 1017                  case OPT_CHARSET_MAP:
1018 1018                          /*
1019 1019                           * Set EX_CHARMAP when there is at least one
1020 1020                           * charmap conversion property. This will get
1021 1021                           * checked by the nfs server when it needs to.
1022 1022                           */
1023 1023                          export->ex_flags |= EX_CHARMAP;
1024 1024                          break;
1025 1025                  case OPT_NOACLFAB:
1026 1026                          if (value != NULL && (strcasecmp(value, "true") == 0 ||
1027 1027                              strcmp(value, "1") == 0))
1028 1028                                  export->ex_flags |= EX_NOACLFAB;
1029 1029                          else
1030 1030                                  export->ex_flags &= ~EX_NOACLFAB;
1031 1031                          break;
1032 1032                  case OPT_NOHIDE:
1033 1033                          if (value != NULL && (strcasecmp(value, "true") == 0 ||
1034 1034                              strcmp(value, "1") == 0))
1035 1035                                  export->ex_flags |= EX_NOHIDE;
1036 1036                          else
1037 1037                                  export->ex_flags &= ~EX_NOHIDE;
1038 1038  
1039 1039                          break;
1040 1040                  default:
1041 1041                          /* have a syntactic error */
1042 1042                          (void) printf(dgettext(TEXT_DOMAIN,
1043 1043                              "NFS: unrecognized option %s=%s\n"),
1044 1044                              name != NULL ? name : "",
1045 1045                              value != NULL ? value : "");
1046 1046                          break;
1047 1047                  }
1048 1048                  if (name != NULL)
1049 1049                          sa_free_attr_string(name);
1050 1050                  if (value != NULL)
1051 1051                          sa_free_attr_string(value);
1052 1052          }
1053 1053          return (ret);
1054 1054  }
1055 1055  
1056 1056  /*
1057 1057   * cleanup_export(export)
1058 1058   *
1059 1059   * Cleanup the allocated areas so we don't leak memory
1060 1060   */
1061 1061  
1062 1062  static void
1063 1063  cleanup_export(struct exportdata *export)
1064 1064  {
1065 1065          int i;
1066 1066  
1067 1067          free(export->ex_index);
1068 1068  
1069 1069          for (i = 0; i < export->ex_seccnt; i++) {
1070 1070                  struct secinfo *s = &export->ex_secinfo[i];
1071 1071  
1072 1072                  while (s->s_rootcnt > 0)
1073 1073                          free(s->s_rootnames[--s->s_rootcnt]);
1074 1074  
1075 1075                  free(s->s_rootnames);
1076 1076          }
1077 1077          free(export->ex_secinfo);
1078 1078  }
1079 1079  
1080 1080  /*
1081 1081   * Given a seconfig entry and a colon-separated
1082 1082   * list of names, allocate an array big enough
1083 1083   * to hold the root list, then convert each name to
1084 1084   * a principal name according to the security
1085 1085   * info and assign it to an array element.
1086 1086   * Return the array and its size.
1087 1087   */
1088 1088  static caddr_t *
1089 1089  get_rootnames(seconfig_t *sec, char *list, int *count)
1090 1090  {
1091 1091          caddr_t *a;
1092 1092          int c, i;
1093 1093          char *host, *p;
1094 1094  
1095 1095          /*
1096 1096           * Count the number of strings in the list.
1097 1097           * This is the number of colon separators + 1.
1098 1098           */
1099 1099          c = 1;
1100 1100          for (p = list; *p; p++)
1101 1101                  if (*p == ':')
1102 1102                          c++;
1103 1103          *count = c;
1104 1104  
1105 1105          a = (caddr_t *)malloc(c * sizeof (char *));
1106 1106          if (a == NULL) {
1107 1107                  (void) printf(dgettext(TEXT_DOMAIN,
1108 1108                      "get_rootnames: no memory\n"));
1109 1109                  *count = 0;
1110 1110          } else {
1111 1111                  for (i = 0; i < c; i++) {
1112 1112                          host = strtok(list, ":");
1113 1113                          if (!nfs_get_root_principal(sec, host, &a[i])) {
1114 1114                                  while (i > 0)
1115 1115                                          free(a[--i]);
1116 1116                                  free(a);
1117 1117                                  a = NULL;
1118 1118                                  *count = 0;
1119 1119                                  break;
1120 1120                          }
1121 1121                          list = NULL;
1122 1122                  }
1123 1123          }
1124 1124  
1125 1125          return (a);
1126 1126  }
1127 1127  
1128 1128  /*
1129 1129   * fill_security_from_secopts(sp, secopts)
1130 1130   *
1131 1131   * Fill the secinfo structure from the secopts optionset.
1132 1132   */
1133 1133  
1134 1134  static int
1135 1135  fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts)
1136 1136  {
1137 1137          sa_property_t prop;
1138 1138          char *type;
1139 1139          int longform;
1140 1140          int err = SC_NOERROR;
1141 1141          uint32_t val;
1142 1142  
1143 1143          type = sa_get_security_attr(secopts, "sectype");
1144 1144          if (type != NULL) {
1145 1145                  /* named security type needs secinfo to be filled in */
1146 1146                  err = nfs_getseconfig_byname(type, &sp->s_secinfo);
1147 1147                  sa_free_attr_string(type);
1148 1148                  if (err != SC_NOERROR)
1149 1149                          return (err);
1150 1150          } else {
1151 1151                  /* default case */
1152 1152                  err = nfs_getseconfig_default(&sp->s_secinfo);
1153 1153                  if (err != SC_NOERROR)
1154 1154                          return (err);
1155 1155          }
1156 1156  
1157 1157          err = SA_OK;
1158 1158          for (prop = sa_get_property(secopts, NULL);
1159 1159              prop != NULL && err == SA_OK;
1160 1160              prop = sa_get_next_property(prop)) {
1161 1161                  char *name;
1162 1162                  char *value;
1163 1163  
1164 1164                  name = sa_get_property_attr(prop, "type");
1165 1165                  value = sa_get_property_attr(prop, "value");
1166 1166  
1167 1167                  longform = value != NULL && strcmp(value, "*") != 0;
1168 1168  
1169 1169                  switch (findopt(name)) {
1170 1170                  case OPT_RO:
1171 1171                          sp->s_flags |= longform ? M_ROL : M_RO;
1172 1172                          break;
1173 1173                  case OPT_RW:
1174 1174                          sp->s_flags |= longform ? M_RWL : M_RW;
1175 1175                          break;
1176 1176                  case OPT_ROOT:
1177 1177                          sp->s_flags |= M_ROOT;
1178 1178                          /*
1179 1179                           * if we are using AUTH_UNIX, handle like other things
1180 1180                           * such as RO/RW
1181 1181                           */
1182 1182                          if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX)
1183 1183                                  break;
1184 1184                          /* not AUTH_UNIX */
1185 1185                          if (value != NULL) {
1186 1186                                  sp->s_rootnames = get_rootnames(&sp->s_secinfo,
1187 1187                                      value, &sp->s_rootcnt);
1188 1188                                  if (sp->s_rootnames == NULL) {
1189 1189                                          err = SA_BAD_VALUE;
1190 1190                                          (void) fprintf(stderr,
1191 1191                                              dgettext(TEXT_DOMAIN,
1192 1192                                              "Bad root list\n"));
1193 1193                                  }
1194 1194                          }
1195 1195                          break;
1196 1196                  case OPT_NONE:
1197 1197                          sp->s_flags |= M_NONE;
1198 1198                          break;
1199 1199                  case OPT_WINDOW:
1200 1200                          if (value != NULL) {
1201 1201                                  sp->s_window = atoi(value);
1202 1202                                  /* just in case */
1203 1203                                  if (sp->s_window < 0)
1204 1204                                          sp->s_window = DEF_WIN;
1205 1205                          }
1206 1206                          break;
1207 1207                  case OPT_ROOT_MAPPING:
1208 1208                          if (value != NULL && is_a_number(value)) {
1209 1209                                  val = strtoul(value, NULL, 0);
1210 1210                          } else {
1211 1211                                  struct passwd *pw;
1212 1212                                  pw = getpwnam(value != NULL ? value : "nobody");
1213 1213                                  if (pw != NULL) {
1214 1214                                          val = pw->pw_uid;
1215 1215                                  } else {
1216 1216                                          val = UID_NOBODY;
1217 1217                                  }
1218 1218                                  endpwent();
1219 1219                          }
1220 1220                          sp->s_rootid = val;
1221 1221                          break;
1222 1222                  case OPT_UIDMAP:
1223 1223                  case OPT_GIDMAP:
1224 1224                          sp->s_flags |= M_MAP;
1225 1225                          break;
1226 1226                  default:
1227 1227                          break;
1228 1228                  }
1229 1229                  if (name != NULL)
1230 1230                          sa_free_attr_string(name);
1231 1231                  if (value != NULL)
1232 1232                          sa_free_attr_string(value);
1233 1233          }
1234 1234          /* if rw/ro options not set, use default of RW */
1235 1235          if ((sp->s_flags & NFS_RWMODES) == 0)
1236 1236                  sp->s_flags |= M_RW;
1237 1237          return (err);
1238 1238  }
1239 1239  
1240 1240  /*
1241 1241   * This is for testing only
1242 1242   * It displays the export structure that
1243 1243   * goes into the kernel.
1244 1244   */
1245 1245  static void
1246 1246  printarg(char *path, struct exportdata *ep)
1247 1247  {
1248 1248          int i, j;
1249 1249          struct secinfo *sp;
1250 1250  
1251 1251          if (debug == 0)
1252 1252                  return;
1253 1253  
1254 1254          (void) printf("%s:\n", path);
1255 1255          (void) printf("\tex_version = %d\n", ep->ex_version);
1256 1256          (void) printf("\tex_path = %s\n", ep->ex_path);
1257 1257          (void) printf("\tex_pathlen = %ld\n", (ulong_t)ep->ex_pathlen);
1258 1258          (void) printf("\tex_flags: (0x%02x) ", ep->ex_flags);
1259 1259          if (ep->ex_flags & EX_NOSUID)
1260 1260                  (void) printf("NOSUID ");
1261 1261          if (ep->ex_flags & EX_ACLOK)
1262 1262                  (void) printf("ACLOK ");
1263 1263          if (ep->ex_flags & EX_PUBLIC)
1264 1264                  (void) printf("PUBLIC ");
1265 1265          if (ep->ex_flags & EX_NOSUB)
1266 1266                  (void) printf("NOSUB ");
1267 1267          if (ep->ex_flags & EX_LOG)
1268 1268                  (void) printf("LOG ");
1269 1269          if (ep->ex_flags & EX_CHARMAP)
1270 1270                  (void) printf("CHARMAP ");
1271 1271          if (ep->ex_flags & EX_LOG_ALLOPS)
1272 1272                  (void) printf("LOG_ALLOPS ");
1273 1273          if (ep->ex_flags == 0)
1274 1274                  (void) printf("(none)");
1275 1275          (void) printf("\n");
1276 1276          if (ep->ex_flags & EX_LOG) {
1277 1277                  (void) printf("\tex_log_buffer = %s\n",
1278 1278                      (ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)"));
1279 1279                  (void) printf("\tex_tag = %s\n",
1280 1280                      (ep->ex_tag ? ep->ex_tag : "(NULL)"));
1281 1281          }
1282 1282          (void) printf("\tex_anon = %d\n", ep->ex_anon);
1283 1283          (void) printf("\tex_seccnt = %d\n", ep->ex_seccnt);
1284 1284          (void) printf("\n");
1285 1285          for (i = 0; i < ep->ex_seccnt; i++) {
1286 1286                  sp = &ep->ex_secinfo[i];
1287 1287                  (void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name);
1288 1288                  (void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags);
1289 1289                  if (sp->s_flags & M_ROOT) (void) printf("M_ROOT ");
1290 1290                  if (sp->s_flags & M_RO) (void) printf("M_RO ");
1291 1291                  if (sp->s_flags & M_ROL) (void) printf("M_ROL ");
1292 1292                  if (sp->s_flags & M_RW) (void) printf("M_RW ");
1293 1293                  if (sp->s_flags & M_RWL) (void) printf("M_RWL ");
1294 1294                  if (sp->s_flags & M_NONE) (void) printf("M_NONE ");
1295 1295                  if (sp->s_flags & M_MAP) (void) printf("M_MAP ");
1296 1296                  if (sp->s_flags == 0) (void) printf("(none)");
1297 1297                  (void) printf("\n");
1298 1298                  (void) printf("\t\ts_window = %d\n", sp->s_window);
1299 1299                  (void) printf("\t\ts_rootid = %d\n", sp->s_rootid);
1300 1300                  (void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt);
1301 1301                  (void) fflush(stdout);
1302 1302                  for (j = 0; j < sp->s_rootcnt; j++)
1303 1303                          (void) printf("%s ", sp->s_rootnames[j] ?
1304 1304                              sp->s_rootnames[j] : "<null>");
1305 1305                  (void) printf("\n\n");
1306 1306          }
1307 1307  }
1308 1308  
1309 1309  /*
1310 1310   * count_security(opts)
1311 1311   *
1312 1312   * Count the number of security types (flavors). The optionset has
1313 1313   * been populated with the security flavors as a holding mechanism.
1314 1314   * We later use this number to allocate data structures.
1315 1315   */
1316 1316  
1317 1317  static int
1318 1318  count_security(sa_optionset_t opts)
1319 1319  {
1320 1320          int count = 0;
1321 1321          sa_property_t prop;
1322 1322          if (opts != NULL) {
1323 1323                  for (prop = sa_get_property(opts, NULL); prop != NULL;
1324 1324                      prop = sa_get_next_property(prop)) {
1325 1325                          count++;
1326 1326                  }
1327 1327          }
1328 1328          return (count);
1329 1329  }
1330 1330  
1331 1331  /*
1332 1332   * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep)
1333 1333   *
1334 1334   * provides a mechanism to format NFS properties into legacy output
1335 1335   * format. If the buffer would overflow, it is reallocated and grown
1336 1336   * as appropriate. Special cases of converting internal form of values
1337 1337   * to those used by "share" are done. this function does one property
1338 1338   * at a time.
1339 1339   */
1340 1340  
1341 1341  static int
1342 1342  nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
1343 1343      sa_property_t prop, int sep)
1344 1344  {
1345 1345          char *name;
1346 1346          char *value;
1347 1347          int curlen;
1348 1348          char *buff = *rbuff;
1349 1349          size_t buffsize = *rbuffsize;
1350 1350          int printed = B_FALSE;
1351 1351  
1352 1352          name = sa_get_property_attr(prop, "type");
1353 1353          value = sa_get_property_attr(prop, "value");
1354 1354          if (buff != NULL)
1355 1355                  curlen = strlen(buff);
1356 1356          else
1357 1357                  curlen = 0;
1358 1358          if (name != NULL) {
1359 1359                  int len;
1360 1360                  len = strlen(name) + sep;
1361 1361  
1362 1362                  /*
1363 1363                   * A future RFE would be to replace this with more
1364 1364                   * generic code and to possibly handle more types.
1365 1365                   */
1366 1366                  switch (gettype(name)) {
1367 1367                  case OPT_TYPE_BOOLEAN:
1368 1368                          /*
1369 1369                           * For NFS, boolean value of FALSE means it
1370 1370                           * doesn't show up in the option list at all.
1371 1371                           */
1372 1372                          if (value != NULL && strcasecmp(value, "false") == 0)
1373 1373                                  goto skip;
1374 1374                          if (value != NULL) {
1375 1375                                  sa_free_attr_string(value);
1376 1376                                  value = NULL;
1377 1377                          }
1378 1378                          break;
1379 1379                  case OPT_TYPE_ACCLIST:
1380 1380                          if (value != NULL && strcmp(value, "*") == 0) {
1381 1381                                  sa_free_attr_string(value);
1382 1382                                  value = NULL;
1383 1383                          } else {
1384 1384                                  if (value != NULL)
1385 1385                                          len += 1 + strlen(value);
1386 1386                          }
1387 1387                          break;
1388 1388                  case OPT_TYPE_LOGTAG:
1389 1389                          if (value != NULL && strlen(value) == 0) {
1390 1390                                  sa_free_attr_string(value);
1391 1391                                  value = NULL;
1392 1392                          } else {
1393 1393                                  if (value != NULL)
1394 1394                                          len += 1 + strlen(value);
1395 1395                          }
1396 1396                          break;
1397 1397                  default:
1398 1398                          if (value != NULL)
1399 1399                                  len += 1 + strlen(value);
1400 1400                          break;
1401 1401                  }
1402 1402                  while (buffsize <= (curlen + len)) {
1403 1403                          /* need more room */
1404 1404                          buffsize += incr;
1405 1405                          buff = realloc(buff, buffsize);
1406 1406                          if (buff == NULL) {
1407 1407                                  /* realloc failed so free everything */
1408 1408                                  if (*rbuff != NULL)
1409 1409                                          free(*rbuff);
1410 1410                          }
1411 1411                          *rbuff = buff;
1412 1412                          *rbuffsize = buffsize;
1413 1413                          if (buff == NULL)
1414 1414                                  goto skip;
1415 1415  
1416 1416                  }
1417 1417  
1418 1418                  if (buff == NULL)
1419 1419                          goto skip;
1420 1420  
1421 1421                  if (value == NULL) {
1422 1422                          (void) snprintf(buff + curlen, buffsize - curlen,
1423 1423                              "%s%s", sep ? "," : "", name);
1424 1424                  } else {
1425 1425                          (void) snprintf(buff + curlen, buffsize - curlen,
1426 1426                              "%s%s=%s", sep ? "," : "",
1427 1427                              name, value != NULL ? value : "");
1428 1428                  }
1429 1429                  printed = B_TRUE;
1430 1430          }
1431 1431  skip:
1432 1432          if (name != NULL)
1433 1433                  sa_free_attr_string(name);
1434 1434          if (value != NULL)
1435 1435                  sa_free_attr_string(value);
1436 1436          return (printed);
1437 1437  }
1438 1438  
1439 1439  /*
1440 1440   * nfs_format_options(group, hier)
1441 1441   *
1442 1442   * format all the options on the group into an old-style option
1443 1443   * string. If hier is non-zero, walk up the tree to get inherited
1444 1444   * options.
1445 1445   */
1446 1446  
1447 1447  static char *
1448 1448  nfs_format_options(sa_group_t group, int hier)
1449 1449  {
1450 1450          sa_optionset_t options = NULL;
1451 1451          sa_optionset_t secoptions = NULL;
1452 1452          sa_property_t prop, secprop;
1453 1453          sa_security_t security = NULL;
1454 1454          char *buff;
1455 1455          size_t buffsize;
1456 1456          char *sectype = NULL;
1457 1457          int sep = 0;
1458 1458  
1459 1459  
1460 1460          buff = malloc(OPT_CHUNK);
1461 1461          if (buff == NULL) {
1462 1462                  return (NULL);
1463 1463          }
1464 1464  
1465 1465          buff[0] = '\0';
1466 1466          buffsize = OPT_CHUNK;
1467 1467  
1468 1468          /*
1469 1469           * We may have a an optionset relative to this item. format
1470 1470           * these if we find them and then add any security definitions.
1471 1471           */
1472 1472  
1473 1473          options = sa_get_derived_optionset(group, "nfs", hier);
1474 1474  
1475 1475          /*
1476 1476           * do the default set first but skip any option that is also
1477 1477           * in the protocol specific optionset.
1478 1478           */
1479 1479          if (options != NULL) {
1480 1480                  for (prop = sa_get_property(options, NULL);
1481 1481                      prop != NULL; prop = sa_get_next_property(prop)) {
1482 1482                          /*
1483 1483                           * use this one since we skipped any
1484 1484                           * of these that were also in
1485 1485                           * optdefault
1486 1486                           */
1487 1487                          if (nfs_sprint_option(&buff, &buffsize, OPT_CHUNK,
1488 1488                              prop, sep))
1489 1489                                  sep = 1;
1490 1490                          if (buff == NULL) {
1491 1491                                  /*
1492 1492                                   * buff could become NULL if there
1493 1493                                   * isn't enough memory for
1494 1494                                   * nfs_sprint_option to realloc()
1495 1495                                   * as necessary. We can't really
1496 1496                                   * do anything about it at this
1497 1497                                   * point so we return NULL.  The
1498 1498                                   * caller should handle the
1499 1499                                   * failure.
1500 1500                                   */
1501 1501                                  if (options != NULL)
1502 1502                                          sa_free_derived_optionset(
1503 1503                                              options);
1504 1504                                  return (buff);
1505 1505                          }
1506 1506                  }
1507 1507          }
1508 1508          secoptions = (sa_optionset_t)sa_get_all_security_types(group,
1509 1509              "nfs", hier);
1510 1510          if (secoptions != NULL) {
1511 1511                  for (secprop = sa_get_property(secoptions, NULL);
1512 1512                      secprop != NULL;
1513 1513                      secprop = sa_get_next_property(secprop)) {
1514 1514                          sectype = sa_get_property_attr(secprop, "type");
1515 1515                          security =
1516 1516                              (sa_security_t)sa_get_derived_security(
1517 1517                              group, sectype, "nfs", hier);
1518 1518                          if (security != NULL) {
1519 1519                                  if (sectype != NULL) {
1520 1520                                          prop = sa_create_property(
1521 1521                                              "sec", sectype);
1522 1522                                          if (prop == NULL)
1523 1523                                                  goto err;
1524 1524                                          if (nfs_sprint_option(&buff,
1525 1525                                              &buffsize, OPT_CHUNK, prop, sep))
1526 1526                                                  sep = 1;
1527 1527                                          (void) sa_remove_property(prop);
1528 1528                                          if (buff == NULL)
1529 1529                                                  goto err;
1530 1530                                  }
1531 1531                                  for (prop = sa_get_property(security,
1532 1532                                      NULL); prop != NULL;
1533 1533                                      prop = sa_get_next_property(prop)) {
1534 1534                                          if (nfs_sprint_option(&buff,
1535 1535                                              &buffsize, OPT_CHUNK, prop, sep))
1536 1536                                                  sep = 1;
1537 1537                                          if (buff == NULL)
1538 1538                                                  goto err;
1539 1539                                  }
1540 1540                                  sa_free_derived_optionset(security);
1541 1541                          }
1542 1542                          if (sectype != NULL)
1543 1543                                  sa_free_attr_string(sectype);
1544 1544                  }
1545 1545                  sa_free_derived_optionset(secoptions);
1546 1546          }
1547 1547  
1548 1548          if (options != NULL)
1549 1549                  sa_free_derived_optionset(options);
1550 1550          return (buff);
1551 1551  
1552 1552  err:
1553 1553          /*
1554 1554           * If we couldn't allocate memory for option printing, we need
1555 1555           * to break out of the nested loops, cleanup and return NULL.
1556 1556           */
1557 1557          if (secoptions != NULL)
1558 1558                  sa_free_derived_optionset(secoptions);
1559 1559          if (security != NULL)
1560 1560                  sa_free_derived_optionset(security);
1561 1561          if (sectype != NULL)
1562 1562                  sa_free_attr_string(sectype);
1563 1563          if (options != NULL)
1564 1564                  sa_free_derived_optionset(options);
1565 1565          return (buff);
1566 1566  }
1567 1567  
1568 1568  /*
1569 1569   * Append an entry to the nfslogtab file
1570 1570   */
1571 1571  static int
1572 1572  nfslogtab_add(char *dir, char *buffer, char *tag)
1573 1573  {
1574 1574          FILE *f;
1575 1575          struct logtab_ent lep;
1576 1576          int error = 0;
1577 1577  
1578 1578          /*
1579 1579           * Open the file for update and create it if necessary.
1580 1580           * This may leave the I/O offset at the end of the file,
1581 1581           * so rewind back to the beginning of the file.
1582 1582           */
1583 1583          f = fopen(NFSLOGTAB, "a+");
1584 1584          if (f == NULL) {
1585 1585                  error = errno;
1586 1586                  goto out;
1587 1587          }
1588 1588          rewind(f);
1589 1589  
1590 1590          if (lockf(fileno(f), F_LOCK, 0L) < 0) {
1591 1591                  (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1592 1592                      "share complete, however failed to lock %s "
1593 1593                      "for update: %s\n"), NFSLOGTAB, strerror(errno));
1594 1594                  error = -1;
1595 1595                  goto out;
1596 1596          }
1597 1597  
1598 1598          if (logtab_deactivate_after_boot(f) == -1) {
1599 1599                  (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1600 1600                      "share complete, however could not deactivate "
1601 1601                      "entries in %s\n"), NFSLOGTAB);
1602 1602                  error = -1;
1603 1603                  goto out;
1604 1604          }
1605 1605  
1606 1606          /*
1607 1607           * Remove entries matching buffer and sharepoint since we're
1608 1608           * going to replace it with perhaps an entry with a new tag.
1609 1609           */
1610 1610          if (logtab_rement(f, buffer, dir, NULL, -1)) {
1611 1611                  (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1612 1612                      "share complete, however could not remove matching "
1613 1613                      "entries in %s\n"), NFSLOGTAB);
1614 1614                  error = -1;
1615 1615                  goto out;
1616 1616          }
1617 1617  
1618 1618          /*
1619 1619           * Deactivate all active entries matching this sharepoint
1620 1620           */
1621 1621          if (logtab_deactivate(f, NULL, dir, NULL)) {
1622 1622                  (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1623 1623                      "share complete, however could not deactivate matching "
1624 1624                      "entries in %s\n"), NFSLOGTAB);
1625 1625                  error = -1;
1626 1626                  goto out;
1627 1627          }
1628 1628  
1629 1629          lep.le_buffer = buffer;
1630 1630          lep.le_path = dir;
1631 1631          lep.le_tag = tag;
1632 1632          lep.le_state = LES_ACTIVE;
1633 1633  
1634 1634          /*
1635 1635           * Add new sharepoint / buffer location to nfslogtab
1636 1636           */
1637 1637          if (logtab_putent(f, &lep) < 0) {
1638 1638                  (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1639 1639                      "share complete, however could not add %s to %s\n"),
1640 1640                      dir, NFSLOGTAB);
1641 1641                  error = -1;
1642 1642          }
1643 1643  
1644 1644  out:
1645 1645          if (f != NULL)
1646 1646                  (void) fclose(f);
1647 1647          return (error);
1648 1648  }
1649 1649  
1650 1650  /*
1651 1651   * Deactivate an entry from the nfslogtab file
1652 1652   */
1653 1653  static int
1654 1654  nfslogtab_deactivate(char *path)
1655 1655  {
1656 1656          FILE *f;
1657 1657          int error = 0;
1658 1658  
1659 1659          f = fopen(NFSLOGTAB, "r+");
1660 1660          if (f == NULL) {
1661 1661                  error = errno;
1662 1662                  goto out;
1663 1663          }
1664 1664          if (lockf(fileno(f), F_LOCK, 0L) < 0) {
1665 1665                  error = errno;
1666 1666                  (void)  fprintf(stderr, dgettext(TEXT_DOMAIN,
1667 1667                      "share complete, however could not lock %s for "
1668 1668                      "update: %s\n"), NFSLOGTAB, strerror(error));
1669 1669                  goto out;
1670 1670          }
1671 1671          if (logtab_deactivate(f, NULL, path, NULL) == -1) {
1672 1672                  error = -1;
1673 1673                  (void) fprintf(stderr,
1674 1674                      dgettext(TEXT_DOMAIN,
1675 1675                      "share complete, however could not "
1676 1676                      "deactivate %s in %s\n"), path, NFSLOGTAB);
1677 1677                  goto out;
1678 1678          }
1679 1679  
1680 1680  out:    if (f != NULL)
1681 1681                  (void) fclose(f);
1682 1682  
1683 1683          return (error);
1684 1684  }
1685 1685  
1686 1686  /*
1687 1687   * check_public(group, skipshare)
1688 1688   *
1689 1689   * Check the group for any shares that have the public property
1690 1690   * enabled. We skip "skipshare" since that is the one we are
1691 1691   * working with. This is a separate function to make handling
1692 1692   * subgroups simpler. Returns true if there is a share with public.
1693 1693   */
1694 1694  static int
1695 1695  check_public(sa_group_t group, sa_share_t skipshare)
1696 1696  {
1697 1697          int exists = B_FALSE;
1698 1698          sa_share_t share;
1699 1699          sa_optionset_t opt;
1700 1700          sa_property_t prop;
1701 1701          char *shared;
1702 1702  
1703 1703          for (share = sa_get_share(group, NULL); share != NULL;
1704 1704              share = sa_get_next_share(share)) {
1705 1705                  if (share == skipshare)
1706 1706                          continue;
1707 1707  
1708 1708                  opt = sa_get_optionset(share, "nfs");
1709 1709                  if (opt == NULL)
1710 1710                          continue;
1711 1711                  prop = sa_get_property(opt, "public");
1712 1712                  if (prop == NULL)
1713 1713                          continue;
1714 1714                  shared = sa_get_share_attr(share, "shared");
1715 1715                  if (shared != NULL) {
1716 1716                          exists = strcmp(shared, "true") == 0;
1717 1717                          sa_free_attr_string(shared);
1718 1718                          if (exists == B_TRUE)
1719 1719                                  break;
1720 1720                  }
1721 1721          }
1722 1722  
1723 1723          return (exists);
1724 1724  }
1725 1725  
1726 1726  /*
1727 1727   * public_exists(handle, skipshare)
1728 1728   *
1729 1729   * check to see if public option is set on any other share than the
1730 1730   * one specified. Need to check zfs sub-groups as well as the top
1731 1731   * level groups.
1732 1732   */
1733 1733  static int
1734 1734  public_exists(sa_handle_t handle, sa_share_t skipshare)
1735 1735  {
1736 1736          sa_group_t group = NULL;
1737 1737  
1738 1738          /*
1739 1739           * If we don't have a handle, we can only do syntax check. We
1740 1740           * can't check against other shares so we assume OK and will
1741 1741           * catch the problem only when we actually try to apply it.
1742 1742           */
1743 1743          if (handle == NULL)
1744 1744                  return (SA_OK);
1745 1745  
1746 1746          if (skipshare != NULL) {
1747 1747                  group = sa_get_parent_group(skipshare);
1748 1748                  if (group == NULL)
1749 1749                          return (SA_NO_SUCH_GROUP);
1750 1750          }
1751 1751  
1752 1752          for (group = sa_get_group(handle, NULL); group != NULL;
1753 1753              group = sa_get_next_group(group)) {
1754 1754                  /* Walk any ZFS subgroups as well as all standard groups */
1755 1755                  if (sa_group_is_zfs(group)) {
1756 1756                          sa_group_t subgroup;
1757 1757                          for (subgroup = sa_get_sub_group(group);
1758 1758                              subgroup != NULL;
1759 1759                              subgroup = sa_get_next_group(subgroup)) {
1760 1760                                  if (check_public(subgroup, skipshare))
1761 1761                                          return (B_TRUE);
1762 1762                          }
1763 1763                  } else {
1764 1764                          if (check_public(group, skipshare))
1765 1765                                  return (B_TRUE);
1766 1766                  }
1767 1767          }
1768 1768          return (B_FALSE);
1769 1769  }
1770 1770  
1771 1771  /*
1772 1772   * sa_enable_share at the protocol level, enable_share must tell the
1773 1773   * implementation that it is to enable the share. This entails
1774 1774   * converting the path and options into the appropriate ioctl
1775 1775   * calls. It is assumed that all error checking of paths, etc. were
1776 1776   * done earlier.
1777 1777   */
1778 1778  static int
1779 1779  nfs_enable_share(sa_share_t share)
1780 1780  {
1781 1781          struct exportdata export;
1782 1782          sa_optionset_t secoptlist;
1783 1783          struct secinfo *sp;
1784 1784          int num_secinfo;
1785 1785          sa_optionset_t opt;
1786 1786          sa_security_t sec;
1787 1787          sa_property_t prop;
1788 1788          char *path;
1789 1789          int err = SA_OK;
1790 1790          int i;
1791 1791          int iszfs;
1792 1792          sa_handle_t handle;
1793 1793  
1794 1794          /* Don't drop core if the NFS module isn't loaded. */
1795 1795          (void) signal(SIGSYS, SIG_IGN);
1796 1796  
1797 1797          /* get the path since it is important in several places */
1798 1798          path = sa_get_share_attr(share, "path");
1799 1799          if (path == NULL)
1800 1800                  return (SA_NO_SUCH_PATH);
1801 1801  
1802 1802          iszfs = sa_path_is_zfs(path);
1803 1803          /*
1804 1804           * find the optionsets and security sets.  There may not be
1805 1805           * any or there could be one or two for each of optionset and
1806 1806           * security may have multiple, one per security type per
1807 1807           * protocol type.
1808 1808           */
1809 1809          opt = sa_get_derived_optionset(share, "nfs", 1);
1810 1810          secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1);
1811 1811          if (secoptlist != NULL)
1812 1812                  num_secinfo = MAX(1, count_security(secoptlist));
1813 1813          else
1814 1814                  num_secinfo = 1;
1815 1815  
1816 1816          /*
1817 1817           * walk through the options and fill in the structure
1818 1818           * appropriately.
1819 1819           */
1820 1820  
1821 1821          (void) memset(&export, '\0', sizeof (export));
1822 1822  
1823 1823          /*
1824 1824           * do non-security options first since there is only one after
1825 1825           * the derived group is constructed.
1826 1826           */
1827 1827          export.ex_version = EX_CURRENT_VERSION;
1828 1828          export.ex_anon = UID_NOBODY; /* this is our default value */
1829 1829          export.ex_index = NULL;
1830 1830          export.ex_path = path;
1831 1831          export.ex_pathlen = strlen(path) + 1;
1832 1832  
1833 1833          if (opt != NULL)
1834 1834                  err = fill_export_from_optionset(&export, opt);
1835 1835  
1836 1836          /*
1837 1837           * check to see if "public" is set. If it is, then make sure
1838 1838           * no other share has it set. If it is already used, fail.
1839 1839           */
1840 1840  
1841 1841          handle = sa_find_group_handle((sa_group_t)share);
1842 1842          if (export.ex_flags & EX_PUBLIC && public_exists(handle, share)) {
1843 1843                  (void) printf(dgettext(TEXT_DOMAIN,
1844 1844                      "NFS: Cannot share more than one file "
1845 1845                      "system with 'public' property\n"));
1846 1846                  err = SA_NOT_ALLOWED;
1847 1847                  goto out;
1848 1848          }
1849 1849  
1850 1850          sp = calloc(num_secinfo, sizeof (struct secinfo));
1851 1851          if (sp == NULL) {
1852 1852                  err = SA_NO_MEMORY;
1853 1853                  (void) printf(dgettext(TEXT_DOMAIN,
1854 1854                      "NFS: NFS: no memory for security\n"));
1855 1855                  goto out;
1856 1856          }
1857 1857          export.ex_secinfo = sp;
1858 1858          /* get default secinfo */
1859 1859          export.ex_seccnt = num_secinfo;
1860 1860          /*
1861 1861           * since we must have one security option defined, we
1862 1862           * init to the default and then override as we find
1863 1863           * defined security options. This handles the case
1864 1864           * where we have no defined options but we need to set
1865 1865           * up one.
1866 1866           */
1867 1867          sp[0].s_window = DEF_WIN;
1868 1868          sp[0].s_rootnames = NULL;
1869 1869          /* setup a default in case no properties defined */
1870 1870          if (nfs_getseconfig_default(&sp[0].s_secinfo)) {
1871 1871                  (void) printf(dgettext(TEXT_DOMAIN,
1872 1872                      "NFS: nfs_getseconfig_default: failed to "
1873 1873                      "get default security mode\n"));
1874 1874                  err = SA_CONFIG_ERR;
1875 1875          }
1876 1876          if (secoptlist != NULL) {
1877 1877                  for (i = 0, prop = sa_get_property(secoptlist, NULL);
1878 1878                      prop != NULL && i < num_secinfo;
1879 1879                      prop = sa_get_next_property(prop), i++) {
1880 1880                          char *sectype;
1881 1881                          sectype = sa_get_property_attr(prop, "type");
1882 1882                          /*
1883 1883                           * if sectype is NULL, we probably
1884 1884                           * have a memory problem and can't get
1885 1885                           * the correct values. Rather than
1886 1886                           * exporting with incorrect security,
1887 1887                           * don't share it.
1888 1888                           */
1889 1889                          if (sectype == NULL) {
1890 1890                                  err = SA_NO_MEMORY;
1891 1891                                  (void) printf(dgettext(TEXT_DOMAIN,
1892 1892                                      "NFS: Cannot share %s: "
1893 1893                                      "no memory\n"), path);
1894 1894                                  goto out;
1895 1895                          }
1896 1896                          sec = (sa_security_t)sa_get_derived_security(
1897 1897                              share, sectype, "nfs", 1);
  
    | 
      ↓ open down ↓ | 
    1851 lines elided | 
    
      ↑ open up ↑ | 
  
1898 1898                          sp[i].s_window = DEF_WIN;
1899 1899                          sp[i].s_rootcnt = 0;
1900 1900                          sp[i].s_rootnames = NULL;
1901 1901                          (void) fill_security_from_secopts(&sp[i], sec);
1902 1902                          if (sec != NULL)
1903 1903                                  sa_free_derived_security(sec);
1904 1904                          if (sectype != NULL)
1905 1905                                  sa_free_attr_string(sectype);
1906 1906                  }
1907 1907          }
1908      -        /*
1909      -         * when we get here, we can do the exportfs system call and
1910      -         * initiate things. We probably want to enable the
1911      -         * svc:/network/nfs/server service first if it isn't running.
1912      -         */
1913      -        /* check svc:/network/nfs/server status and start if needed */
     1908 +
1914 1909          /* now add the share to the internal tables */
1915 1910          printarg(path, &export);
1916 1911          /*
1917 1912           * call the exportfs system call which is implemented
1918 1913           * via the nfssys() call as the EXPORTFS subfunction.
1919 1914           */
1920 1915          if (iszfs) {
1921 1916                  struct exportfs_args ea;
1922 1917                  share_t sh;
1923      -                char *str;
1924      -                priv_set_t *priv_effective;
1925      -                int privileged;
1926 1918  
1927      -                /*
1928      -                 * If we aren't a privileged user
1929      -                 * and NFS server service isn't running
1930      -                 * then print out an error message
1931      -                 * and return EPERM
1932      -                 */
     1919 +                ea.dname = path;
     1920 +                ea.uex = &export;
1933 1921  
1934      -                priv_effective = priv_allocset();
1935      -                (void) getppriv(PRIV_EFFECTIVE, priv_effective);
1936      -
1937      -                privileged = (priv_isfullset(priv_effective) == B_TRUE);
1938      -                priv_freeset(priv_effective);
1939      -
1940      -                if (!privileged &&
1941      -                    (str = smf_get_state(NFS_SERVER_SVC)) != NULL) {
1942      -                        err = 0;
1943      -                        if (strcmp(str, SCF_STATE_STRING_ONLINE) != 0) {
1944      -                                (void) printf(dgettext(TEXT_DOMAIN,
1945      -                                    "NFS: Cannot share remote "
1946      -                                    "filesystem: %s\n"), path);
1947      -                                (void) printf(dgettext(TEXT_DOMAIN,
1948      -                                    "NFS: Service needs to be enabled "
1949      -                                    "by a privileged user\n"));
1950      -                                err = SA_SYSTEM_ERR;
1951      -                                errno = EPERM;
1952      -                        }
1953      -                        free(str);
     1922 +                (void) sa_sharetab_fill_zfs(share, &sh, "nfs");
     1923 +                err = sa_share_zfs(share, NULL, path, &sh, &ea, ZFS_SHARE_NFS);
     1924 +                if (err != SA_OK) {
     1925 +                        errno = err;
     1926 +                        err = -1;
1954 1927                  }
1955      -
1956      -                if (err == 0) {
1957      -                        ea.dname = path;
1958      -                        ea.uex = &export;
1959      -
1960      -                        (void) sa_sharetab_fill_zfs(share, &sh, "nfs");
1961      -                        err = sa_share_zfs(share, NULL, path, &sh,
1962      -                            &ea, ZFS_SHARE_NFS);
1963      -                        if (err != SA_OK) {
1964      -                                errno = err;
1965      -                                err = -1;
1966      -                        }
1967      -                        sa_emptyshare(&sh);
1968      -                }
     1928 +                sa_emptyshare(&sh);
1969 1929          } else {
1970 1930                  err = exportfs(path, &export);
1971 1931          }
1972 1932  
1973 1933          if (err < 0) {
1974 1934                  err = SA_SYSTEM_ERR;
1975 1935                  switch (errno) {
1976      -                case EREMOTE:
1977      -                        (void) printf(dgettext(TEXT_DOMAIN,
1978      -                            "NFS: Cannot share filesystems "
1979      -                            "in non-global zones: %s\n"), path);
1980      -                        err = SA_NOT_SUPPORTED;
1981      -                        break;
1982 1936                  case EPERM:
1983      -                        if (getzoneid() != GLOBAL_ZONEID) {
1984      -                                (void) printf(dgettext(TEXT_DOMAIN,
1985      -                                    "NFS: Cannot share file systems "
1986      -                                    "in non-global zones: %s\n"), path);
1987      -                                err = SA_NOT_SUPPORTED;
1988      -                                break;
1989      -                        }
1990 1937                          err = SA_NO_PERMISSION;
1991 1938                          break;
1992 1939                  case EEXIST:
1993 1940                          err = SA_SHARE_EXISTS;
1994 1941                          break;
1995 1942                  default:
1996 1943                          break;
1997 1944                  }
1998 1945          } else {
1999 1946                  /* update sharetab with an add/modify */
2000 1947                  if (!iszfs) {
2001 1948                          (void) sa_update_sharetab(share, "nfs");
2002 1949                  }
2003 1950          }
2004 1951  
2005 1952          if (err == SA_OK) {
2006 1953                  /*
2007 1954                   * enable services as needed. This should probably be
2008 1955                   * done elsewhere in order to minimize the calls to
2009 1956                   * check services.
2010 1957                   */
2011 1958                  /*
2012 1959                   * check to see if logging and other services need to
2013 1960                   * be triggered, but only if there wasn't an
2014 1961                   * error. This is probably where sharetab should be
2015 1962                   * updated with the NFS specific entry.
2016 1963                   */
2017 1964                  if (export.ex_flags & EX_LOG) {
2018 1965                          /* enable logging */
2019 1966                          if (nfslogtab_add(path, export.ex_log_buffer,
2020 1967                              export.ex_tag) != 0) {
2021 1968                                  (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2022 1969                                      "Could not enable logging for %s\n"),
2023 1970                                      path);
2024 1971                          }
2025 1972                          _check_services(service_list_logging);
2026 1973                  } else {
2027 1974                          /*
2028 1975                           * don't have logging so remove it from file. It might
2029 1976                           * not be thre, but that doesn't matter.
2030 1977                           */
2031 1978                          (void) nfslogtab_deactivate(path);
2032 1979                          _check_services(service_list_default);
2033 1980                  }
2034 1981          }
2035 1982  
2036 1983  out:
2037 1984          if (path != NULL)
2038 1985                  free(path);
2039 1986  
2040 1987          cleanup_export(&export);
2041 1988          if (opt != NULL)
2042 1989                  sa_free_derived_optionset(opt);
2043 1990          if (secoptlist != NULL)
2044 1991                  (void) sa_destroy_optionset(secoptlist);
2045 1992          return (err);
2046 1993  }
2047 1994  
2048 1995  /*
2049 1996   * nfs_disable_share(share, path)
2050 1997   *
2051 1998   * Unshare the specified share. Note that "path" is the same path as
2052 1999   * what is in the "share" object. It is passed in to avoid an
2053 2000   * additional lookup. A missing "path" value makes this a no-op
2054 2001   * function.
2055 2002   */
2056 2003  static int
2057 2004  nfs_disable_share(sa_share_t share, char *path)
2058 2005  {
2059 2006          int err;
2060 2007          int ret = SA_OK;
2061 2008          int iszfs;
2062 2009          sa_group_t parent;
2063 2010          sa_handle_t handle;
2064 2011  
2065 2012          if (path == NULL)
2066 2013                  return (ret);
2067 2014  
2068 2015          /*
2069 2016           * If the share is in a ZFS group we need to handle it
2070 2017           * differently.  Just being on a ZFS file system isn't
2071 2018           * enough since we may be in a legacy share case.
2072 2019           */
2073 2020          parent = sa_get_parent_group(share);
2074 2021          iszfs = sa_group_is_zfs(parent);
2075 2022          if (iszfs) {
2076 2023                  struct exportfs_args ea;
2077 2024                  share_t sh = { 0 };
2078 2025                  ea.dname = path;
2079 2026                  ea.uex = NULL;
2080 2027                  sh.sh_path = path;
2081 2028                  sh.sh_fstype = "nfs";
2082 2029  
2083 2030                  err = sa_share_zfs(share, NULL, path, &sh,
2084 2031                      &ea, ZFS_UNSHARE_NFS);
2085 2032                  if (err != SA_OK) {
2086 2033                          errno = err;
2087 2034                          err = -1;
2088 2035                  }
2089 2036          } else {
2090 2037                  err = exportfs(path, NULL);
  
    | 
      ↓ open down ↓ | 
    91 lines elided | 
    
      ↑ open up ↑ | 
  
2091 2038          }
2092 2039          if (err < 0) {
2093 2040                  /*
2094 2041                   * TBD: only an error in some
2095 2042                   * cases - need better analysis
2096 2043                   */
2097 2044                  switch (errno) {
2098 2045                  case EPERM:
2099 2046                  case EACCES:
2100 2047                          ret = SA_NO_PERMISSION;
2101      -                        if (getzoneid() != GLOBAL_ZONEID) {
2102      -                                ret = SA_NOT_SUPPORTED;
2103      -                        }
2104 2048                          break;
2105 2049                  case EINVAL:
2106 2050                  case ENOENT:
2107 2051                          ret = SA_NO_SUCH_PATH;
2108 2052                          break;
2109 2053                  default:
2110 2054                          ret = SA_SYSTEM_ERR;
2111 2055                          break;
2112 2056                  }
2113 2057          }
2114 2058          if (ret == SA_OK || ret == SA_NO_SUCH_PATH) {
2115 2059                  handle = sa_find_group_handle((sa_group_t)share);
2116 2060                  if (!iszfs)
2117 2061                          (void) sa_delete_sharetab(handle, path, "nfs");
2118 2062                  /* just in case it was logged */
2119 2063                  (void) nfslogtab_deactivate(path);
2120 2064          }
2121 2065          return (ret);
2122 2066  }
2123 2067  
2124 2068  static int
2125 2069  check_user(char *value)
2126 2070  {
2127 2071          int ret = SA_OK;
2128 2072  
2129 2073          if (!is_a_number(value)) {
2130 2074                  struct passwd *pw;
2131 2075                  /*
2132 2076                   * in this case it would have to be a
2133 2077                   * user name
2134 2078                   */
2135 2079                  pw = getpwnam(value);
2136 2080                  if (pw == NULL)
2137 2081                          ret = SA_BAD_VALUE;
2138 2082                  endpwent();
2139 2083          } else {
2140 2084                  uint64_t intval;
2141 2085                  intval = strtoull(value, NULL, 0);
2142 2086                  if (intval > UID_MAX && intval != -1)
2143 2087                          ret = SA_BAD_VALUE;
2144 2088          }
2145 2089  
2146 2090          return (ret);
2147 2091  }
2148 2092  
2149 2093  static int
2150 2094  check_group(char *value)
2151 2095  {
2152 2096          int ret = SA_OK;
2153 2097  
2154 2098          if (!is_a_number(value)) {
2155 2099                  struct group *gr;
2156 2100                  /*
2157 2101                   * in this case it would have to be a
2158 2102                   * group name
2159 2103                   */
2160 2104                  gr = getgrnam(value);
2161 2105                  if (gr == NULL)
2162 2106                          ret = SA_BAD_VALUE;
2163 2107                  endgrent();
2164 2108          } else {
2165 2109                  uint64_t intval;
2166 2110                  intval = strtoull(value, NULL, 0);
2167 2111                  if (intval > UID_MAX && intval != -1)
2168 2112                          ret = SA_BAD_VALUE;
2169 2113          }
2170 2114  
2171 2115          return (ret);
2172 2116  }
2173 2117  
2174 2118  /*
2175 2119   * check_rorwnone(v1, v2, v3)
2176 2120   *
2177 2121   * check ro vs rw vs none values.  Over time this may get beefed up.
2178 2122   * for now it just does simple checks. v1 is never NULL but v2 or v3
2179 2123   * could be.
2180 2124   */
2181 2125  
2182 2126  static int
2183 2127  check_rorwnone(char *v1, char *v2, char *v3)
2184 2128  {
2185 2129          int ret = SA_OK;
2186 2130          if (v2 != NULL && strcmp(v1, v2) == 0)
2187 2131                  ret = SA_VALUE_CONFLICT;
2188 2132          else if (v3 != NULL && strcmp(v1, v3) == 0)
2189 2133                  ret = SA_VALUE_CONFLICT;
2190 2134  
2191 2135          return (ret);
2192 2136  }
2193 2137  
2194 2138  /*
2195 2139   * nfs_validate_property(handle, property, parent)
2196 2140   *
2197 2141   * Check that the property has a legitimate value for its type.
2198 2142   */
2199 2143  
2200 2144  static int
2201 2145  nfs_validate_property(sa_handle_t handle, sa_property_t property,
2202 2146      sa_optionset_t parent)
2203 2147  {
2204 2148          int ret = SA_OK;
2205 2149          char *propname;
2206 2150          char *other1;
2207 2151          char *other2;
2208 2152          int optindex;
2209 2153          nfsl_config_t *configlist;
2210 2154          sa_group_t parent_group;
2211 2155          char *value;
2212 2156  
2213 2157          propname = sa_get_property_attr(property, "type");
2214 2158  
2215 2159          if ((optindex = findopt(propname)) < 0)
2216 2160                  ret = SA_NO_SUCH_PROP;
2217 2161  
2218 2162          /* need to validate value range here as well */
2219 2163  
2220 2164          if (ret == SA_OK) {
2221 2165                  parent_group = sa_get_parent_group((sa_share_t)parent);
2222 2166                  if (optdefs[optindex].share && parent_group != NULL &&
2223 2167                      !sa_is_share(parent_group))
2224 2168                          ret = SA_PROP_SHARE_ONLY;
2225 2169          }
2226 2170          if (ret == SA_OK) {
2227 2171                  if (optdefs[optindex].index == OPT_PUBLIC) {
2228 2172                          /*
2229 2173                           * Public is special in that only one instance can
2230 2174                           * be in the repository at the same time.
2231 2175                           */
2232 2176                          if (public_exists(handle, parent_group)) {
2233 2177                                  sa_free_attr_string(propname);
2234 2178                                  return (SA_VALUE_CONFLICT);
2235 2179                          }
2236 2180                  }
2237 2181                  value = sa_get_property_attr(property, "value");
2238 2182                  if (value != NULL) {
2239 2183                          /* first basic type checking */
2240 2184                          switch (optdefs[optindex].type) {
2241 2185  
2242 2186                          case OPT_TYPE_NUMBER:
2243 2187                                  /* check that the value is all digits */
2244 2188                                  if (!is_a_number(value))
2245 2189                                          ret = SA_BAD_VALUE;
2246 2190                                  break;
2247 2191  
2248 2192                          case OPT_TYPE_BOOLEAN:
2249 2193                                  if (strlen(value) == 0 ||
2250 2194                                      strcasecmp(value, "true") == 0 ||
2251 2195                                      strcmp(value, "1") == 0 ||
2252 2196                                      strcasecmp(value, "false") == 0 ||
2253 2197                                      strcmp(value, "0") == 0) {
2254 2198                                          ret = SA_OK;
2255 2199                                  } else {
2256 2200                                          ret = SA_BAD_VALUE;
2257 2201                                  }
2258 2202                                  break;
2259 2203  
2260 2204                          case OPT_TYPE_USER:
2261 2205                                  ret = check_user(value);
2262 2206                                  break;
2263 2207  
2264 2208                          case OPT_TYPE_FILE:
2265 2209                                  if (strcmp(value, "..") == 0 ||
2266 2210                                      strchr(value, '/') != NULL) {
2267 2211                                          ret = SA_BAD_VALUE;
2268 2212                                  }
2269 2213                                  break;
2270 2214  
2271 2215                          case OPT_TYPE_ACCLIST: {
2272 2216                                  sa_property_t oprop1;
2273 2217                                  sa_property_t oprop2;
2274 2218                                  char *ovalue1 = NULL;
2275 2219                                  char *ovalue2 = NULL;
2276 2220  
2277 2221                                  if (parent == NULL)
2278 2222                                          break;
2279 2223                                  /*
2280 2224                                   * access list handling. Should eventually
2281 2225                                   * validate that all the values make sense.
2282 2226                                   * Also, ro and rw may have cross value
2283 2227                                   * conflicts.
2284 2228                                   */
2285 2229                                  if (strcmp(propname, SHOPT_RO) == 0) {
2286 2230                                          other1 = SHOPT_RW;
2287 2231                                          other2 = SHOPT_NONE;
2288 2232                                  } else if (strcmp(propname, SHOPT_RW) == 0) {
2289 2233                                          other1 = SHOPT_RO;
2290 2234                                          other2 = SHOPT_NONE;
2291 2235                                  } else if (strcmp(propname, SHOPT_NONE) == 0) {
2292 2236                                          other1 = SHOPT_RO;
2293 2237                                          other2 = SHOPT_RW;
2294 2238                                  } else {
2295 2239                                          other1 = NULL;
2296 2240                                          other2 = NULL;
2297 2241                                  }
2298 2242                                  if (other1 == NULL && other2 == NULL)
2299 2243                                          break;
2300 2244  
2301 2245                                  /* compare rw(ro) with ro(rw) */
2302 2246  
2303 2247                                  oprop1 = sa_get_property(parent, other1);
2304 2248                                  oprop2 = sa_get_property(parent, other2);
2305 2249                                  if (oprop1 == NULL && oprop2 == NULL)
2306 2250                                          break;
2307 2251                                  /*
2308 2252                                   * Only potential confusion if other1
2309 2253                                   * or other2 exists. Check the values
2310 2254                                   * and run the check if there is a
2311 2255                                   * value other than the one we are
2312 2256                                   * explicitly looking at.
2313 2257                                   */
2314 2258                                  ovalue1 = sa_get_property_attr(oprop1, "value");
2315 2259                                  ovalue2 = sa_get_property_attr(oprop2, "value");
2316 2260                                  if (ovalue1 != NULL || ovalue2 != NULL)
2317 2261                                          ret = check_rorwnone(value, ovalue1,
2318 2262                                              ovalue2);
2319 2263  
2320 2264                                  if (ovalue1 != NULL)
2321 2265                                          sa_free_attr_string(ovalue1);
2322 2266                                  if (ovalue2 != NULL)
2323 2267                                          sa_free_attr_string(ovalue2);
2324 2268                                  break;
2325 2269                          }
2326 2270  
2327 2271                          case OPT_TYPE_LOGTAG:
2328 2272                                  if (nfsl_getconfig_list(&configlist) == 0) {
2329 2273                                          int error;
2330 2274                                          if (value == NULL ||
2331 2275                                              strlen(value) == 0) {
2332 2276                                                  if (value != NULL)
2333 2277                                                          sa_free_attr_string(
2334 2278                                                              value);
2335 2279                                                  value = strdup("global");
2336 2280                                          }
2337 2281                                          if (value != NULL &&
2338 2282                                              nfsl_findconfig(configlist, value,
2339 2283                                              &error) == NULL) {
2340 2284                                                  ret = SA_BAD_VALUE;
2341 2285                                          }
2342 2286                                          /* Must always free when done */
2343 2287                                          nfsl_freeconfig_list(&configlist);
2344 2288                                  } else {
2345 2289                                          ret = SA_CONFIG_ERR;
2346 2290                                  }
2347 2291                                  break;
2348 2292  
2349 2293                          case OPT_TYPE_STRING:
2350 2294                                  /* whatever is here should be ok */
2351 2295                                  break;
2352 2296  
2353 2297                          case OPT_TYPE_SECURITY:
2354 2298                                  /*
2355 2299                                   * The "sec" property isn't used in the
2356 2300                                   * non-legacy parts of sharemgr. We need to
2357 2301                                   * reject it here. For legacy, it is pulled
2358 2302                                   * out well before we get here.
2359 2303                                   */
2360 2304                                  ret = SA_NO_SUCH_PROP;
2361 2305                                  break;
2362 2306  
2363 2307                          case OPT_TYPE_MAPPING: {
2364 2308                                  char *p;
2365 2309                                  char *n;
2366 2310                                  char *c;
2367 2311                                  int (*f)(char *);
2368 2312  
2369 2313                                  sa_security_t security;
2370 2314  
2371 2315                                  /*
2372 2316                                   * mapping is only supported for sec=sys
2373 2317                                   */
2374 2318                                  ret = SA_CONFIG_ERR;
2375 2319                                  if (parent_group == NULL)
2376 2320                                          break;
2377 2321  
2378 2322                                  for (security = sa_get_security(parent_group,
2379 2323                                      NULL, NULL); security != NULL;
2380 2324                                      security = sa_get_next_security(security)) {
2381 2325                                          char *type;
2382 2326                                          char *sectype;
2383 2327  
2384 2328                                          type = sa_get_security_attr(security,
2385 2329                                              "type");
2386 2330                                          if (type == NULL)
2387 2331                                                  continue;
2388 2332  
2389 2333                                          if (strcmp(type, "nfs") != 0) {
2390 2334                                                  sa_free_attr_string(type);
2391 2335                                                  continue;
2392 2336                                          }
2393 2337                                          sa_free_attr_string(type);
2394 2338  
2395 2339                                          sectype = sa_get_security_attr(security,
2396 2340                                              "sectype");
2397 2341                                          if (sectype == NULL)
2398 2342                                                  continue;
2399 2343  
2400 2344                                          if (strcmp(sectype, "sys") != 0) {
2401 2345                                                  sa_free_attr_string(sectype);
2402 2346                                                  ret = SA_CONFIG_ERR;
2403 2347                                                  break;
2404 2348                                          }
2405 2349                                          sa_free_attr_string(sectype);
2406 2350                                          ret = SA_OK;
2407 2351                                  }
2408 2352  
2409 2353                                  if (ret != SA_OK)
2410 2354                                          break;
2411 2355  
2412 2356                                  assert(optindex == OPT_UIDMAP ||
2413 2357                                      optindex == OPT_GIDMAP);
2414 2358                                  f = optindex == OPT_UIDMAP ? check_user :
2415 2359                                      check_group;
2416 2360  
2417 2361  
2418 2362                                  p = strdup(value);
2419 2363                                  if (p == NULL)
2420 2364                                          ret = SA_BAD_VALUE;
2421 2365  
2422 2366                                  for (c = p; ret == SA_OK && c != NULL; c = n) {
2423 2367                                          char *s;
2424 2368                                          char *t;
2425 2369  
2426 2370                                          n = strchr(c, '~');
2427 2371                                          if (n != NULL)
2428 2372                                                  *n++ = '\0';
2429 2373  
2430 2374                                          s = strchr(c, ':');
2431 2375                                          if (s != NULL) {
2432 2376                                                  *s++ = '\0';
2433 2377                                                  t = strchr(s, ':');
2434 2378                                                  if (t != NULL)
2435 2379                                                          *t = '\0';
2436 2380                                          }
2437 2381  
2438 2382                                          if (s == NULL || t == NULL)
2439 2383                                                  ret = SA_BAD_VALUE;
2440 2384  
2441 2385                                          if (ret == SA_OK && *c != '\0' &&
2442 2386                                              strcmp(c, "*") != 0)
2443 2387                                                  ret = f(c);
2444 2388  
2445 2389                                          if (ret == SA_OK && *s != '\0' &&
2446 2390                                              strcmp(s, "-1") != 0)
2447 2391                                                  ret = f(s);
2448 2392                                  }
2449 2393  
2450 2394                                  free(p);
2451 2395  
2452 2396                                  break;
2453 2397                          }
2454 2398  
2455 2399                          default:
2456 2400                                  break;
2457 2401                          }
2458 2402  
2459 2403                          if (value != NULL)
2460 2404                                  sa_free_attr_string(value);
2461 2405  
2462 2406                          if (ret == SA_OK && optdefs[optindex].check != NULL) {
2463 2407                                  /* do the property specific check */
2464 2408                                  ret = optdefs[optindex].check(handle, property);
2465 2409                          }
2466 2410                  }
2467 2411          }
2468 2412  
2469 2413          if (propname != NULL)
2470 2414                  sa_free_attr_string(propname);
2471 2415          return (ret);
2472 2416  }
2473 2417  
2474 2418  /*
2475 2419   * Protocol management functions
2476 2420   *
2477 2421   * Properties defined in the default files are defined in
2478 2422   * proto_option_defs for parsing and validation. If "other" and
2479 2423   * "compare" are set, then the value for this property should be
2480 2424   * compared against the property specified in "other" using the
2481 2425   * "compare" check (either <= or >=) in order to ensure that the
2482 2426   * values are in the correct range.  E.g. setting server_versmin
2483 2427   * higher than server_versmax should not be allowed.
2484 2428   */
2485 2429  
2486 2430  struct proto_option_defs {
2487 2431          char *tag;
2488 2432          char *name;     /* display name -- remove protocol identifier */
2489 2433          int index;
2490 2434          int type;
2491 2435          union {
2492 2436              int intval;
2493 2437              char *string;
2494 2438          } defvalue;
2495 2439          uint32_t svcs;
2496 2440          int32_t minval;
2497 2441          int32_t maxval;
2498 2442          char *other;
2499 2443          int compare;
2500 2444  #define OPT_CMP_GE      0
2501 2445  #define OPT_CMP_LE      1
2502 2446          int (*check)(char *);
2503 2447  } proto_options[] = {
2504 2448  #define PROTO_OPT_NFSD_SERVERS                  0
2505 2449          {"nfsd_servers",
2506 2450              "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 1024, SVC_NFSD,
2507 2451              1, INT32_MAX},
2508 2452  #define PROTO_OPT_LOCKD_LISTEN_BACKLOG          1
2509 2453          {"lockd_listen_backlog",
2510 2454              "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG,
2511 2455              OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX},
2512 2456  #define PROTO_OPT_LOCKD_SERVERS                 2
2513 2457          {"lockd_servers",
2514 2458              "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 256,
2515 2459              SVC_LOCKD, 1, INT32_MAX},
2516 2460  #define PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT      3
2517 2461          {"lockd_retransmit_timeout",
2518 2462              "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT,
2519 2463              OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX},
2520 2464  #define PROTO_OPT_GRACE_PERIOD                  4
2521 2465          {"grace_period",
2522 2466              "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90,
2523 2467              SVC_LOCKD, 0, INT32_MAX},
2524 2468  #define PROTO_OPT_NFS_SERVER_VERSMIN            5
2525 2469          {"nfs_server_versmin",
2526 2470              "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER,
2527 2471              (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
2528 2472              NFS_VERSMAX, "server_versmax", OPT_CMP_LE},
2529 2473  #define PROTO_OPT_NFS_SERVER_VERSMAX            6
2530 2474          {"nfs_server_versmax",
2531 2475              "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER,
2532 2476              (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
2533 2477              NFS_VERSMAX, "server_versmin", OPT_CMP_GE},
2534 2478  #define PROTO_OPT_NFS_CLIENT_VERSMIN            7
2535 2479          {"nfs_client_versmin",
2536 2480              "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER,
2537 2481              (int)NFS_VERSMIN_DEFAULT, SVC_CLIENT, NFS_VERSMIN, NFS_VERSMAX,
2538 2482              "client_versmax", OPT_CMP_LE},
2539 2483  #define PROTO_OPT_NFS_CLIENT_VERSMAX            8
2540 2484          {"nfs_client_versmax",
2541 2485              "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER,
2542 2486              (int)NFS_VERSMAX_DEFAULT, SVC_CLIENT, NFS_VERSMIN, NFS_VERSMAX,
2543 2487              "client_versmin", OPT_CMP_GE},
2544 2488  #define PROTO_OPT_NFS_SERVER_DELEGATION         9
2545 2489          {"nfs_server_delegation",
2546 2490              "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION,
2547 2491              OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0},
2548 2492  #define PROTO_OPT_NFSMAPID_DOMAIN               10
2549 2493          {"nfsmapid_domain",
2550 2494              "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN,
2551 2495              0, SVC_NFSMAPID, 0, 0},
2552 2496  #define PROTO_OPT_NFSD_MAX_CONNECTIONS          11
2553 2497          {"nfsd_max_connections",
2554 2498              "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS,
2555 2499              OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX},
2556 2500  #define PROTO_OPT_NFSD_PROTOCOL                 12
2557 2501          {"nfsd_protocol",
2558 2502              "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0,
2559 2503              SVC_NFSD, 0, 0},
2560 2504  #define PROTO_OPT_NFSD_LISTEN_BACKLOG           13
2561 2505          {"nfsd_listen_backlog",
2562 2506              "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG,
2563 2507              OPT_TYPE_NUMBER, 0, SVC_NFSD, 0, INT32_MAX},
2564 2508  #define PROTO_OPT_NFSD_DEVICE                   14
2565 2509          {"nfsd_device",
2566 2510              "device", PROTO_OPT_NFSD_DEVICE,
2567 2511              OPT_TYPE_STRING, 0, SVC_NFSD, 0, 0},
2568 2512  #define PROTO_OPT_MOUNTD_LISTEN_BACKLOG         15
2569 2513          {"mountd_listen_backlog",
2570 2514              "mountd_listen_backlog", PROTO_OPT_MOUNTD_LISTEN_BACKLOG,
2571 2515              OPT_TYPE_NUMBER, 64, SVC_NFSD|SVC_MOUNTD, 1, INT32_MAX},
2572 2516  #define PROTO_OPT_MOUNTD_MAX_THREADS            16
2573 2517          {"mountd_max_threads",
2574 2518              "mountd_max_threads", PROTO_OPT_MOUNTD_MAX_THREADS,
2575 2519              OPT_TYPE_NUMBER, 16, SVC_NFSD|SVC_MOUNTD, 1, INT32_MAX},
2576 2520  #define PROTO_OPT_MOUNTD_PORT                   17
2577 2521          {"mountd_port",
2578 2522              "mountd_port", PROTO_OPT_MOUNTD_PORT,
2579 2523              OPT_TYPE_NUMBER, 0, SVC_MOUNTD, 1, UINT16_MAX},
2580 2524  #define PROTO_OPT_STATD_PORT                    18
2581 2525          {"statd_port",
2582 2526              "statd_port", PROTO_OPT_STATD_PORT,
2583 2527              OPT_TYPE_NUMBER, 0, SVC_STATD, 1, UINT16_MAX},
2584 2528          {NULL}
2585 2529  };
2586 2530  
2587 2531  /*
2588 2532   * the protoset holds the defined options so we don't have to read
2589 2533   * them multiple times
2590 2534   */
2591 2535  static sa_protocol_properties_t protoset;
2592 2536  
2593 2537  static int
2594 2538  findprotoopt(char *name, int whichname)
2595 2539  {
2596 2540          int i;
2597 2541          for (i = 0; proto_options[i].tag != NULL; i++) {
2598 2542                  if (whichname == 1) {
2599 2543                          if (strcasecmp(proto_options[i].name, name) == 0)
2600 2544                          return (i);
2601 2545                  } else {
2602 2546                          if (strcasecmp(proto_options[i].tag, name) == 0)
2603 2547                                  return (i);
2604 2548                  }
2605 2549          }
2606 2550          return (-1);
2607 2551  }
2608 2552  
2609 2553  /*
2610 2554   * fixcaselower(str)
2611 2555   *
2612 2556   * convert a string to lower case (inplace).
2613 2557   */
2614 2558  
2615 2559  static void
2616 2560  fixcaselower(char *str)
2617 2561  {
2618 2562          while (*str) {
2619 2563                  *str = tolower(*str);
2620 2564                  str++;
2621 2565          }
2622 2566  }
2623 2567  
2624 2568  /*
2625 2569   * skipwhitespace(str)
2626 2570   *
2627 2571   * Skip leading white space. It is assumed that it is called with a
2628 2572   * valid pointer.
2629 2573   */
2630 2574  
2631 2575  static char *
2632 2576  skipwhitespace(char *str)
2633 2577  {
2634 2578          while (*str && isspace(*str))
2635 2579                  str++;
2636 2580  
2637 2581          return (str);
2638 2582  }
2639 2583  
2640 2584  /*
2641 2585   * extractprop()
2642 2586   *
2643 2587   * Extract the property and value out of the line and create the
2644 2588   * property in the optionset.
2645 2589   */
2646 2590  static int
2647 2591  extractprop(char *name, char *value)
2648 2592  {
2649 2593          sa_property_t prop;
2650 2594          int index;
2651 2595          int ret = SA_OK;
2652 2596          /*
2653 2597           * Remove any leading
2654 2598           * white space.
2655 2599           */
2656 2600          name = skipwhitespace(name);
2657 2601  
2658 2602          index = findprotoopt(name, 1);
2659 2603          if (index >= 0) {
2660 2604                  fixcaselower(name);
2661 2605                  prop = sa_create_property(proto_options[index].name, value);
2662 2606                  if (prop != NULL)
2663 2607                          ret = sa_add_protocol_property(protoset, prop);
2664 2608                  else
2665 2609                          ret = SA_NO_MEMORY;
2666 2610          }
2667 2611          return (ret);
2668 2612  }
2669 2613  
2670 2614  scf_type_t
2671 2615  getscftype(int type)
2672 2616  {
2673 2617          scf_type_t ret;
2674 2618  
2675 2619          switch (type) {
2676 2620          case OPT_TYPE_NUMBER:
2677 2621                  ret = SCF_TYPE_INTEGER;
2678 2622          break;
2679 2623          case OPT_TYPE_BOOLEAN:
2680 2624                  ret = SCF_TYPE_BOOLEAN;
2681 2625          break;
2682 2626          default:
2683 2627                  ret = SCF_TYPE_ASTRING;
2684 2628          }
2685 2629          return (ret);
2686 2630  }
2687 2631  
2688 2632  char *
2689 2633  getsvcname(uint32_t svcs)
2690 2634  {
2691 2635          char *service;
2692 2636          switch (svcs) {
2693 2637                  case SVC_LOCKD:
2694 2638                          service = LOCKD;
2695 2639                          break;
2696 2640                  case SVC_STATD:
2697 2641                          service = STATD;
2698 2642                          break;
2699 2643                  case SVC_NFSD:
2700 2644                          service = NFSD;
2701 2645                          break;
2702 2646                  case SVC_CLIENT:
2703 2647                          service = NFS_CLIENT_SVC;
2704 2648                          break;
2705 2649                  case SVC_NFS4CBD:
2706 2650                          service = NFS4CBD;
2707 2651                          break;
2708 2652                  case SVC_NFSMAPID:
2709 2653                          service = NFSMAPID;
2710 2654                          break;
2711 2655                  case SVC_RQUOTAD:
2712 2656                          service = RQUOTAD;
2713 2657                          break;
2714 2658                  case SVC_NFSLOGD:
2715 2659                          service = NFSLOGD;
2716 2660                          break;
2717 2661                  case SVC_REPARSED:
2718 2662                          service = REPARSED;
2719 2663                          break;
2720 2664                  default:
2721 2665                          service = NFSD;
2722 2666          }
2723 2667          return (service);
2724 2668  }
2725 2669  
2726 2670  /*
2727 2671   * initprotofromsmf()
2728 2672   *
2729 2673   * Read NFS SMF properties and add the defined values to the
2730 2674   * protoset.  Note that default values are known from the built in
2731 2675   * table in case SMF doesn't have a definition. Not having
2732 2676   * SMF properties is OK since we have builtin default
2733 2677   * values.
2734 2678   */
2735 2679  static int
2736 2680  initprotofromsmf()
2737 2681  {
2738 2682          char name[PATH_MAX];
2739 2683          char value[PATH_MAX];
2740 2684          int ret = SA_OK, bufsz = 0, i;
2741 2685  
2742 2686          protoset = sa_create_protocol_properties("nfs");
2743 2687          if (protoset != NULL) {
2744 2688                  for (i = 0; proto_options[i].tag != NULL; i++) {
2745 2689                          scf_type_t ptype;
2746 2690                          char *svc_name;
2747 2691  
2748 2692                          bzero(value, PATH_MAX);
2749 2693                          (void) strncpy(name, proto_options[i].name, PATH_MAX);
2750 2694                          /* Replace NULL with the correct instance */
2751 2695                          ptype = getscftype(proto_options[i].type);
2752 2696                          svc_name = getsvcname(proto_options[i].svcs);
2753 2697                          bufsz = PATH_MAX;
2754 2698                          ret = nfs_smf_get_prop(name, value,
2755 2699                              (char *)DEFAULT_INSTANCE, ptype,
2756 2700                              svc_name, &bufsz);
2757 2701                          if (ret == SA_OK) {
2758 2702                                  ret = extractprop(name, value);
2759 2703                          }
2760 2704                  }
2761 2705          } else {
2762 2706                  ret = SA_NO_MEMORY;
2763 2707          }
2764 2708  
2765 2709          return (ret);
2766 2710  }
2767 2711  
2768 2712  /*
2769 2713   * add_defaults()
2770 2714   *
2771 2715   * Add the default values for any property not defined
2772 2716   * in NFS SMF repository.
2773 2717   * Values are set according to their defined types.
2774 2718   */
2775 2719  
2776 2720  static void
2777 2721  add_defaults()
2778 2722  {
2779 2723          int i;
2780 2724          char number[MAXDIGITS];
2781 2725  
2782 2726          for (i = 0; proto_options[i].tag != NULL; i++) {
2783 2727                  sa_property_t prop;
2784 2728                  prop = sa_get_protocol_property(protoset,
2785 2729                      proto_options[i].name);
2786 2730                  if (prop == NULL) {
2787 2731                          /* add the default value */
2788 2732                          switch (proto_options[i].type) {
2789 2733                          case OPT_TYPE_NUMBER:
2790 2734                                  (void) snprintf(number, sizeof (number), "%d",
2791 2735                                      proto_options[i].defvalue.intval);
2792 2736                                  prop = sa_create_property(proto_options[i].name,
2793 2737                                      number);
2794 2738                                  break;
2795 2739  
2796 2740                          case OPT_TYPE_BOOLEAN:
2797 2741                                  prop = sa_create_property(proto_options[i].name,
2798 2742                                      proto_options[i].defvalue.intval ?
2799 2743                                      "true" : "false");
2800 2744                                  break;
2801 2745  
2802 2746                          case OPT_TYPE_ONOFF:
2803 2747                                  prop = sa_create_property(proto_options[i].name,
2804 2748                                      proto_options[i].defvalue.intval ?
2805 2749                                      "on" : "off");
2806 2750                                  break;
2807 2751  
2808 2752                          default:
2809 2753                                  /* treat as strings of zero length */
2810 2754                                  prop = sa_create_property(proto_options[i].name,
2811 2755                                      "");
2812 2756                                  break;
2813 2757                          }
2814 2758                          if (prop != NULL)
2815 2759                                  (void) sa_add_protocol_property(protoset, prop);
2816 2760                  }
2817 2761          }
2818 2762  }
2819 2763  
2820 2764  static void
2821 2765  free_protoprops()
2822 2766  {
2823 2767          if (protoset != NULL) {
2824 2768                  xmlFreeNode(protoset);
2825 2769                  protoset = NULL;
2826 2770          }
2827 2771  }
2828 2772  
2829 2773  /*
2830 2774   * nfs_init()
2831 2775   *
2832 2776   * Initialize the NFS plugin.
2833 2777   */
2834 2778  
2835 2779  static int
2836 2780  nfs_init()
2837 2781  {
2838 2782          int ret = SA_OK;
2839 2783  
2840 2784          if (sa_plugin_ops.sa_init != nfs_init) {
2841 2785                  (void) printf(dgettext(TEXT_DOMAIN,
2842 2786                      "NFS plugin not properly initialized\n"));
2843 2787                  return (SA_CONFIG_ERR);
2844 2788          }
2845 2789  
2846 2790          ret = initprotofromsmf();
2847 2791          if (ret != SA_OK) {
2848 2792                  (void) printf(dgettext(TEXT_DOMAIN,
2849 2793                      "NFS plugin problem with SMF repository: %s\n"),
2850 2794                      sa_errorstr(ret));
2851 2795                  ret = SA_OK;
2852 2796          }
2853 2797          add_defaults();
2854 2798  
2855 2799          return (ret);
2856 2800  }
2857 2801  
2858 2802  /*
2859 2803   * nfs_fini()
2860 2804   *
2861 2805   * uninitialize the NFS plugin. Want to avoid memory leaks.
2862 2806   */
2863 2807  
2864 2808  static void
2865 2809  nfs_fini()
2866 2810  {
2867 2811          free_protoprops();
2868 2812  }
2869 2813  
2870 2814  /*
2871 2815   * nfs_get_proto_set()
2872 2816   *
2873 2817   * Return an optionset with all the protocol specific properties in
2874 2818   * it.
2875 2819   */
2876 2820  
2877 2821  static sa_protocol_properties_t
2878 2822  nfs_get_proto_set()
2879 2823  {
2880 2824          return (protoset);
2881 2825  }
2882 2826  
2883 2827  /*
2884 2828   * service_in_state(service, chkstate)
2885 2829   *
2886 2830   * Want to know if the specified service is in the desired state
2887 2831   * (chkstate) or not. Return true (1) if it is and false (0) if it
2888 2832   * isn't.
2889 2833   */
2890 2834  static int
2891 2835  service_in_state(char *service, const char *chkstate)
2892 2836  {
2893 2837          char *state;
2894 2838          int ret = B_FALSE;
2895 2839  
2896 2840          state = smf_get_state(service);
2897 2841          if (state != NULL) {
2898 2842                  /* got the state so get the equality for the return value */
2899 2843                  ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
2900 2844                  free(state);
2901 2845          }
2902 2846          return (ret);
2903 2847  }
2904 2848  
2905 2849  /*
2906 2850   * restart_service(svcs)
2907 2851   *
2908 2852   * Walk through the bit mask of services that need to be restarted in
2909 2853   * order to use the new property values. Some properties affect
2910 2854   * multiple daemons. Should only restart a service if it is currently
2911 2855   * enabled (online).
2912 2856   */
2913 2857  
2914 2858  static void
2915 2859  restart_service(uint32_t svcs)
2916 2860  {
2917 2861          uint32_t mask;
2918 2862          int ret;
2919 2863          char *service;
2920 2864  
2921 2865          for (mask = 1; svcs != 0; mask <<= 1) {
2922 2866                  switch (svcs & mask) {
2923 2867                  case SVC_LOCKD:
2924 2868                          service = LOCKD;
2925 2869                          break;
2926 2870                  case SVC_STATD:
2927 2871                          service = STATD;
2928 2872                          break;
2929 2873                  case SVC_NFSD:
2930 2874                          service = NFSD;
2931 2875                          break;
2932 2876                  case SVC_MOUNTD:
2933 2877                          service = MOUNTD;
2934 2878                          break;
2935 2879                  case SVC_NFS4CBD:
2936 2880                          service = NFS4CBD;
2937 2881                          break;
2938 2882                  case SVC_NFSMAPID:
2939 2883                          service = NFSMAPID;
2940 2884                          break;
2941 2885                  case SVC_RQUOTAD:
2942 2886                          service = RQUOTAD;
2943 2887                          break;
2944 2888                  case SVC_NFSLOGD:
2945 2889                          service = NFSLOGD;
2946 2890                          break;
2947 2891                  case SVC_REPARSED:
2948 2892                          service = REPARSED;
2949 2893                          break;
2950 2894                  case SVC_CLIENT:
2951 2895                          service = NFS_CLIENT_SVC;
2952 2896                          break;
2953 2897                  default:
2954 2898                          continue;
2955 2899                  }
2956 2900  
2957 2901                  /*
2958 2902                   * Only attempt to restart the service if it is
2959 2903                   * currently running. In the future, it may be
2960 2904                   * desirable to use smf_refresh_instance if the NFS
2961 2905                   * services ever implement the refresh method.
2962 2906                   */
2963 2907                  if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
2964 2908                          ret = smf_restart_instance(service);
2965 2909                          /*
2966 2910                           * There are only a few SMF errors at this point, but
2967 2911                           * it is also possible that a bad value may have put
2968 2912                           * the service into maintenance if there wasn't an
2969 2913                           * SMF level error.
2970 2914                           */
2971 2915                          if (ret != 0) {
2972 2916                                  (void) fprintf(stderr,
2973 2917                                      dgettext(TEXT_DOMAIN,
2974 2918                                      "%s failed to restart: %s\n"),
2975 2919                                      service, scf_strerror(scf_error()));
2976 2920                          } else {
2977 2921                                  /*
2978 2922                                   * Check whether it has gone to "maintenance"
2979 2923                                   * mode or not. Maintenance implies something
2980 2924                                   * went wrong.
2981 2925                                   */
2982 2926                                  if (service_in_state(service,
2983 2927                                      SCF_STATE_STRING_MAINT)) {
2984 2928                                          (void) fprintf(stderr,
2985 2929                                              dgettext(TEXT_DOMAIN,
2986 2930                                              "%s failed to restart\n"),
2987 2931                                              service);
2988 2932                                  }
2989 2933                          }
2990 2934                  }
2991 2935                  svcs &= ~mask;
2992 2936          }
2993 2937  }
2994 2938  
2995 2939  /*
2996 2940   * nfs_minmax_check(name, value)
2997 2941   *
2998 2942   * Verify that the value for the property specified by index is valid
2999 2943   * relative to the opposite value in the case of a min/max variable.
3000 2944   * Currently, server_minvers/server_maxvers and
3001 2945   * client_minvers/client_maxvers are the only ones to check.
3002 2946   */
3003 2947  
3004 2948  static int
3005 2949  nfs_minmax_check(int index, int value)
3006 2950  {
3007 2951          int val;
3008 2952          char *pval;
3009 2953          sa_property_t prop;
3010 2954          sa_optionset_t opts;
3011 2955          int ret = B_TRUE;
3012 2956  
3013 2957          if (proto_options[index].other != NULL) {
3014 2958                  /* have a property to compare against */
3015 2959                  opts = nfs_get_proto_set();
3016 2960                  prop = sa_get_property(opts, proto_options[index].other);
3017 2961                  /*
3018 2962                   * If we don't find the property, assume default
3019 2963                   * values which will work since the max will be at the
3020 2964                   * max and the min at the min.
3021 2965                   */
3022 2966                  if (prop != NULL) {
3023 2967                          pval = sa_get_property_attr(prop, "value");
3024 2968                          if (pval != NULL) {
3025 2969                                  val = strtoul(pval, NULL, 0);
3026 2970                                  if (proto_options[index].compare ==
3027 2971                                      OPT_CMP_LE) {
3028 2972                                          ret = value <= val ? B_TRUE : B_FALSE;
3029 2973                                  } else if (proto_options[index].compare ==
3030 2974                                      OPT_CMP_GE) {
3031 2975                                          ret = value >= val ? B_TRUE : B_FALSE;
3032 2976                                  }
3033 2977                                  sa_free_attr_string(pval);
3034 2978                          }
3035 2979                  }
3036 2980          }
3037 2981          return (ret);
3038 2982  }
3039 2983  
3040 2984  /*
3041 2985   * nfs_validate_proto_prop(index, name, value)
3042 2986   *
3043 2987   * Verify that the property specified by name can take the new
3044 2988   * value. This is a sanity check to prevent bad values getting into
3045 2989   * the default files. All values need to be checked against what is
3046 2990   * allowed by their defined type. If a type isn't explicitly defined
3047 2991   * here, it is treated as a string.
3048 2992   *
3049 2993   * Note that OPT_TYPE_NUMBER will additionally check that the value is
3050 2994   * within the range specified and potentially against another property
3051 2995   * value as well as specified in the proto_options members other and
3052 2996   * compare.
3053 2997   */
3054 2998  
3055 2999  static int
3056 3000  nfs_validate_proto_prop(int index, char *name, char *value)
3057 3001  {
3058 3002          int ret = SA_OK;
3059 3003          char *cp;
3060 3004  #ifdef lint
3061 3005          name = name;
3062 3006  #endif
3063 3007          switch (proto_options[index].type) {
3064 3008          case OPT_TYPE_NUMBER:
3065 3009                  if (!is_a_number(value))
3066 3010                          ret = SA_BAD_VALUE;
3067 3011                  else {
3068 3012                          int val;
3069 3013                          val = strtoul(value, NULL, 0);
3070 3014                          if (val < proto_options[index].minval ||
3071 3015                              val > proto_options[index].maxval)
3072 3016                                  ret = SA_BAD_VALUE;
3073 3017                          /*
3074 3018                           * For server_versmin/server_versmax and
3075 3019                           * client_versmin/client_versmax, the value of the
3076 3020                           * min(max) should be checked to be correct relative
3077 3021                           * to the current max(min).
3078 3022                           */
3079 3023                          if (!nfs_minmax_check(index, val)) {
3080 3024                                  ret = SA_BAD_VALUE;
3081 3025                          }
3082 3026                  }
3083 3027                  break;
3084 3028  
3085 3029          case OPT_TYPE_DOMAIN:
3086 3030                  /*
3087 3031                   * needs to be a qualified domain so will have at
3088 3032                   * least one period and other characters on either
3089 3033                   * side of it.  A zero length string is also allowed
3090 3034                   * and is the way to turn off the override.
3091 3035                   */
3092 3036                  if (strlen(value) == 0)
3093 3037                          break;
3094 3038                  cp = strchr(value, '.');
3095 3039                  if (cp == NULL || cp == value || strchr(value, '@') != NULL)
3096 3040                          ret = SA_BAD_VALUE;
3097 3041                  break;
3098 3042  
3099 3043          case OPT_TYPE_BOOLEAN:
3100 3044                  if (strlen(value) == 0 ||
3101 3045                      strcasecmp(value, "true") == 0 ||
3102 3046                      strcmp(value, "1") == 0 ||
3103 3047                      strcasecmp(value, "false") == 0 ||
3104 3048                      strcmp(value, "0") == 0) {
3105 3049                          ret = SA_OK;
3106 3050                  } else {
3107 3051                          ret = SA_BAD_VALUE;
3108 3052                  }
3109 3053                  break;
3110 3054  
3111 3055          case OPT_TYPE_ONOFF:
3112 3056                  if (strcasecmp(value, "on") != 0 &&
3113 3057                      strcasecmp(value, "off") != 0) {
3114 3058                          ret = SA_BAD_VALUE;
3115 3059                  }
3116 3060                  break;
3117 3061  
3118 3062          case OPT_TYPE_PROTOCOL: {
3119 3063                  struct netconfig *nconf;
3120 3064                  void *nc;
3121 3065                  boolean_t pfound = B_FALSE;
3122 3066  
3123 3067                  if (strcasecmp(value, "all") == 0)
3124 3068                          break;
3125 3069  
3126 3070                  if ((nc = setnetconfig()) == NULL) {
3127 3071                          (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
3128 3072                              "setnetconfig failed: %s\n"), strerror(errno));
3129 3073                  } else {
3130 3074                          while ((nconf = getnetconfig(nc)) != NULL) {
3131 3075                                  if (strcmp(nconf->nc_proto, value) == 0) {
3132 3076                                          pfound = B_TRUE;
3133 3077                                          break;
3134 3078                                  }
3135 3079                          }
3136 3080                          (void) endnetconfig(nc);
3137 3081                  }
3138 3082  
3139 3083                  if (!pfound)
3140 3084                          ret = SA_BAD_VALUE;
3141 3085                  break;
3142 3086          }
3143 3087  
3144 3088          default:
3145 3089                  /* treat as a string */
3146 3090                  break;
3147 3091          }
3148 3092          return (ret);
3149 3093  }
3150 3094  
3151 3095  /*
3152 3096   * nfs_set_proto_prop(prop)
3153 3097   *
3154 3098   * check that prop is valid.
3155 3099   */
3156 3100  
3157 3101  static int
3158 3102  nfs_set_proto_prop(sa_property_t prop)
3159 3103  {
3160 3104          int ret = SA_OK;
3161 3105          char *name;
3162 3106          char *value;
3163 3107  
3164 3108          name = sa_get_property_attr(prop, "type");
3165 3109          value = sa_get_property_attr(prop, "value");
3166 3110          if (name != NULL && value != NULL) {
3167 3111                  scf_type_t sctype;
3168 3112                  char *svc_name;
3169 3113                  char *instance = NULL;
3170 3114                  int index = findprotoopt(name, 1);
3171 3115  
3172 3116                  ret = nfs_validate_proto_prop(index, name, value);
3173 3117                  if (ret == SA_OK) {
3174 3118                          sctype = getscftype(proto_options[index].type);
3175 3119                          svc_name = getsvcname(proto_options[index].svcs);
3176 3120                          if (sctype == SCF_TYPE_BOOLEAN) {
3177 3121                                  if (value != NULL)
3178 3122                                          sa_free_attr_string(value);
3179 3123                                  if (string_to_boolean(value) == 0)
3180 3124                                          value = strdup("0");
3181 3125                                  else
3182 3126                                          value = strdup("1");
3183 3127                          }
3184 3128                          ret = nfs_smf_set_prop(name, value, instance, sctype,
3185 3129                              svc_name);
3186 3130                          if (ret == SA_OK) {
3187 3131                                  restart_service(proto_options[index].svcs);
3188 3132                          } else {
3189 3133                                  (void) printf(dgettext(TEXT_DOMAIN,
3190 3134                                      "Cannot restart NFS services : %s\n"),
3191 3135                                      sa_errorstr(ret));
3192 3136                          }
3193 3137                  }
3194 3138          }
3195 3139          if (name != NULL)
3196 3140                  sa_free_attr_string(name);
3197 3141          if (value != NULL)
3198 3142                  sa_free_attr_string(value);
3199 3143          return (ret);
3200 3144  }
3201 3145  
3202 3146  /*
3203 3147   * nfs_get_status()
3204 3148   *
3205 3149   * What is the current status of the nfsd? We use the SMF state here.
3206 3150   * Caller must free the returned value.
3207 3151   */
3208 3152  
3209 3153  static char *
3210 3154  nfs_get_status()
3211 3155  {
3212 3156          return (smf_get_state(NFSD));
3213 3157  }
3214 3158  
3215 3159  /*
3216 3160   * nfs_space_alias(alias)
3217 3161   *
3218 3162   * Lookup the space (security) name. If it is default, convert to the
3219 3163   * real name.
3220 3164   */
3221 3165  
3222 3166  static char *
3223 3167  nfs_space_alias(char *space)
3224 3168  {
3225 3169          char *name = space;
3226 3170          seconfig_t secconf;
3227 3171  
3228 3172          /*
3229 3173           * Only the space named "default" is special. If it is used,
3230 3174           * the default needs to be looked up and the real name used.
3231 3175           * This is normally "sys" but could be changed.  We always
3232 3176           * change default to the real name.
3233 3177           */
3234 3178          if (strcmp(space, "default") == 0 &&
3235 3179              nfs_getseconfig_default(&secconf) == 0) {
3236 3180                  if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0)
3237 3181                          name = secconf.sc_name;
3238 3182          }
3239 3183          return (strdup(name));
3240 3184  }
3241 3185  
3242 3186  /*
3243 3187   * nfs_features()
3244 3188   *
3245 3189   * Return a mask of the features required.
3246 3190   */
3247 3191  
3248 3192  static uint64_t
3249 3193  nfs_features()
3250 3194  {
3251 3195          return ((uint64_t)SA_FEATURE_DFSTAB | SA_FEATURE_SERVER);
3252 3196  }
  
    | 
      ↓ open down ↓ | 
    1139 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX