Print this page
    
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/auditreduce/option.c
          +++ new/usr/src/cmd/auditreduce/option.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   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + *
       25 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24   26   */
  25   27  
  26   28  /*
  27   29   * Command line option processing for auditreduce.
  28   30   * The entry point is process_options(), which is called by main().
  29   31   * Process_options() is the only function visible outside this module.
  30   32   */
  31   33  
  32   34  #include <locale.h>
  33   35  #include <sys/zone.h>   /* for max zonename length */
  34   36  #include "auditr.h"
  35   37  
  36   38  /*
  37   39   * Object entry.
  38   40   * Maps object strings specified on the command line to a flag
  39   41   * used when searching by object type.
  40   42   */
  41   43  
  42   44  struct obj_ent {
  43   45          char    *obj_str; /* string specified on the command line */
  44   46          int     obj_flag; /* flag used when searching */
  45   47  };
  46   48  
  47   49  typedef struct obj_ent obj_ent_t;
  48   50  
  49   51  /*
  50   52   * Supports searches by object type.
  51   53   */
  52   54  static obj_ent_t obj_tbl[] = {
  53   55                          { "file", OBJ_PATH },
  54   56                          { "filegroup", OBJ_FGROUP },
  55   57                          { "fileowner", OBJ_FOWNER },
  56   58                          { "fmri", OBJ_FMRI },
  57   59                          { "lp", OBJ_LP   },
  58   60                          { "msgqid", OBJ_MSG  },
  59   61                          { "msgqgroup", OBJ_MSGGROUP },
  60   62                          { "msgqowner", OBJ_MSGOWNER },
  61   63                          { "path", OBJ_PATH },
  
    | 
      ↓ open down ↓ | 
    28 lines elided | 
    
      ↑ open up ↑ | 
  
  62   64                          { "pid", OBJ_PROC },
  63   65                          { "procgroup", OBJ_PGROUP },
  64   66                          { "procowner", OBJ_POWNER },
  65   67                          { "semid", OBJ_SEM  },
  66   68                          { "semgroup", OBJ_SEMGROUP  },
  67   69                          { "semowner", OBJ_SEMOWNER  },
  68   70                          { "shmid", OBJ_SHM  },
  69   71                          { "shmgroup", OBJ_SHMGROUP  },
  70   72                          { "shmowner", OBJ_SHMOWNER  },
  71   73                          { "sock", OBJ_SOCK },
  72      -                        { "user", OBJ_USER } };
       74 +                        { "user", OBJ_USER },
       75 +                        { "wsid", OBJ_WSID } };
  73   76  
  74   77  extern int      derive_date(char *, struct tm *);
  75   78  extern int      parse_time(char *, int);
  76   79  extern char     *re_comp2(char *);
  77   80  extern time_t   tm_to_secs(struct tm *);
  78   81  
  79   82  static int      a_isnum(char *, int);
  80   83  static int      check_file(audit_fcb_t *, int);
  81   84  static int      gather_dir(char *);
  82   85  static audit_pcb_t *get_next_pcb(char *);
  83   86  static obj_ent_t *obj_lkup(char *);
  84   87  static int      proc_class(char *);
  85   88  static int      proc_date(char *, int);
  86   89  static int      proc_file(char *, int);
  87   90  static int      process_fileopt(int, char *argv[], int);
  88   91  static int      proc_group(char *, gid_t *);
  
    | 
      ↓ open down ↓ | 
    6 lines elided | 
    
      ↑ open up ↑ | 
  
  89   92  static int      proc_id(char *, int);
  90   93  static int      proc_object(char *);
  91   94  static void     proc_pcb(audit_pcb_t *, char *, int);
  92   95  static int      proc_label(char *);
  93   96  static int      proc_subject(char *);
  94   97  static int      proc_sid(char *);
  95   98  static int      proc_type(char *);
  96   99  static int      proc_user(char *, uid_t *);
  97  100  static int      proc_zonename(char *);
  98  101  static int      proc_fmri(char *);
      102 +static int      proc_wsid(char *);
  99  103  
 100  104  /*
 101  105   * .func        process_options - process command line options.
 102  106   * .desc        Process the user's command line options. These are of two types:
 103  107   *      single letter flags that are denoted by '-', and filenames. Some
 104  108   *      of the flags have arguments. Getopt() is used to get the flags.
 105  109   *      When this is done it calls process_fileopt() to handle any filenames
 106  110   *      that were there.
 107  111   * .call        ret = process_options(argc, argv).
 108  112   * .arg argc    - the original value.
 109  113   * .arg argv    - the original value.
 110  114   * .ret 0       - no errors detected.
 111  115   * .ret -1      - command line error detected (message already printed).
 112  116   */
 113  117  int
 114  118  process_options(int argc, char **argv)
 115  119  {
 116  120          int     opt;
  
    | 
      ↓ open down ↓ | 
    8 lines elided | 
    
      ↑ open up ↑ | 
  
 117  121          int     error = FALSE;
 118  122          int     error_combo = FALSE;
 119  123          extern int      optind;         /* in getopt() */
 120  124          extern char     *optarg;        /* in getopt() - holds arg to flag */
 121  125  
 122  126          static char     *options = "ACD:M:NQR:S:VO:"
 123  127              "a:b:c:d:e:g:j:l:m:o:r:s:t:u:z:";
 124  128  
 125  129          error_str = gettext("general error");
 126  130  
      131 +        wsid = NULL;
 127  132          zonename = NULL;
 128  133          /*
 129  134           * Big switch to process the flags.
 130  135           * Start_over: is for handling the '-' for standard input. Getopt()
 131  136           * doesn't recognize it.
 132  137           */
 133  138  start_over:
 134  139          while ((opt = getopt(argc, argv, options)) != EOF) {
 135  140                  switch (opt) {
 136  141                  case 'A':               /* all records from the files */
 137  142                          f_all = TRUE;
 138  143                          break;
 139  144                  case 'C':               /* process only completed files */
 140  145                          f_complete = TRUE;
 141  146                          break;
 142  147                  case 'D':               /* delete the files when done */
 143  148                          /* force 'A' 'C' 'O' to be active */
 144  149                          f_all = f_complete = TRUE;
 145  150                          f_outfile = optarg;
 146  151                          f_delete = TRUE;
 147  152                          break;
 148  153                  case 'M':               /* only files from a certain machine */
 149  154                          f_machine = optarg;
 150  155                          break;
 151  156                  case 'N':               /* new object selection mode */
 152  157                          new_mode = TRUE;
 153  158                          break;
 154  159                  case 'Q':               /* no file error reporting */
 155  160                          f_quiet = TRUE;
 156  161                          break;
 157  162                  case 'R':               /* from specified root */
 158  163                          f_root = optarg;
 159  164                          break;
 160  165                  case 'S':               /* from specified server */
 161  166                          f_server = optarg;
 162  167                          break;
 163  168                  case 'V':               /* list all files as they are opened */
 164  169                          f_verbose = TRUE;
 165  170                          break;
 166  171                  case 'O':               /* write to outfile */
 167  172                          f_outfile = optarg;
 168  173                          break;
 169  174                  case 'a':               /* after 'date' */
 170  175                  case 'b':               /* before 'date' */
 171  176                  case 'd':               /* from 'day' */
 172  177                          if (proc_date(optarg, opt))
 173  178                                  error = TRUE;
 174  179                          break;
 175  180                  case 'j':               /* subject */
 176  181                          if (proc_subject(optarg))
 177  182                                  error = TRUE;
 178  183                          break;
 179  184                  case 'm':               /* message 'type' */
 180  185                          if (proc_type(optarg))
 181  186                                  error = TRUE;
 182  187                          break;
 183  188                  case 'o':               /* object type */
 184  189                          if (proc_object(optarg))
 185  190                                  error = TRUE;
 186  191                          break;
 187  192                  case 'c':               /* message class */
 188  193                          if (proc_class(optarg))
 189  194                                  error = TRUE;
 190  195                          break;
 191  196                  case 'u':               /* form audit user */
 192  197                  case 'e':               /* form effective user */
 193  198                  case 'r':               /* form real user */
 194  199                  case 'f':               /* form effective group */
 195  200                  case 'g':               /* form real group */
 196  201                          if (proc_id(optarg, opt))
 197  202                                  error = TRUE;
 198  203                          break;
 199  204                  case 'l':               /* TX label range */
 200  205                          if (!is_system_labeled()) {
 201  206                                  (void) fprintf(stderr,
 202  207                                      gettext("%s option 'l' requires "
 203  208                                      "Trusted Extensions.\n"), ar);
 204  209                                  return (-1);
 205  210                          }
 206  211                          if (proc_label(optarg))
 207  212                                  error = TRUE;
 208  213                          break;
 209  214                  case 's':               /* session ID */
 210  215                          if (proc_sid(optarg))
 211  216                                  error = TRUE;
 212  217                          break;
 213  218                  case 'z':               /* zone name */
 214  219                          if (proc_zonename(optarg))
 215  220                                  error = TRUE;
 216  221                          break;
 217  222                  case 't':               /* termial ID reserved for later */
 218  223                  default:
 219  224                          return (-1);
 220  225                  }
 221  226                  if (error) {
 222  227                          (void) fprintf(stderr,
 223  228                              gettext("%s command line error - %s.\n"),
 224  229                              ar, error_str);
 225  230                          return (-1);
 226  231                  }
 227  232          }
 228  233          /* catch '-' option for stdin processing - getopt() won't see it */
 229  234          if (optind < argc) {
 230  235                  if (argv[optind][0] == '-' && argv[optind][1] == '\0') {
 231  236                          optind++;
 232  237                          f_stdin = TRUE;
 233  238                          goto start_over;
 234  239                  }
 235  240          }
 236  241          /*
 237  242           * Give a default value for 'b' option if not specified.
 238  243           */
 239  244          if (m_before == 0)
 240  245                  m_before = MAXLONG;     /* forever */
 241  246          /*
 242  247           * Validate combinations of options.
 243  248           * The following are done:
 244  249           *      1. Can't have 'M' or 'S' or 'R' with filenames.
 245  250           *      2. Can't have an after ('a') time after a before ('b') time.
 246  251           *      3. Delete ('D') must have 'C' and 'A' and 'O' with it.
 247  252           *      4. Input from stdin ('-') can't have filenames too.
 248  253           */
 249  254          if ((f_machine || f_server || f_root) && (argc != optind)) {
 250  255                  error_str = gettext(
 251  256                      "no filenames allowed with 'M' or 'S' or 'R' options");
 252  257                  error_combo = TRUE;
 253  258          }
 254  259          if (m_after >= m_before) {
 255  260                  error_str =
 256  261                      gettext("'a' parameter must be before 'b' parameter");
 257  262                  error_combo = TRUE;
 258  263          }
 259  264          if (f_delete &&
 260  265              (!f_complete || !f_all || !f_outfile)) {
 261  266                  error_str = gettext(
 262  267                      "'C', 'A', and 'O' must be specified with 'D'");
 263  268                  error_combo = TRUE;
 264  269          }
 265  270          if (f_stdin && (argc != optind)) {
 266  271                  error_str = gettext("no filenames allowed with '-' option");
 267  272                  error_combo = TRUE;
 268  273          }
 269  274          /*
 270  275           * If error with option combos then print message and exit.
 271  276           * If there was an error with just an option then exit.
 272  277           */
 273  278          if (error_combo) {
 274  279                  (void) fprintf(stderr,
 275  280                      gettext("%s command line error - %s.\n"), ar, error_str);
 276  281                  return (-1);
 277  282          }
 278  283          if (f_root == NULL)
 279  284                  f_root = "/etc/security/audit";
 280  285          /*
 281  286           * Now handle any filenames included in the command line.
 282  287           */
 283  288          return (process_fileopt(argc, argv, optind));
 284  289  }
 285  290  
 286  291  int
 287  292  proc_subject(char *optarg)
 288  293  {
 289  294          if (flags & M_SUBJECT) {
 290  295                  error_str = gettext("'j' option specified multiple times");
 291  296                  return (-1);
 292  297          }
 293  298          flags |= M_SUBJECT;
 294  299          subj_id = atol(optarg);
 295  300          return (0);
 296  301  }
 297  302  
 298  303  int
 299  304  proc_sid(char *optarg)
 300  305  {
 301  306          if (flags & M_SID) {
 302  307                  error_str = gettext("'s' option specified multiple times");
 303  308                  return (-1);
 304  309          }
 305  310          flags |= M_SID;
 306  311          m_sid = (au_asid_t)atol(optarg);
 307  312          return (0);
 308  313  }
 309  314  
 310  315  int
 311  316  proc_object(char *optarg)
 312  317  {
 313  318          char    *obj_str;
 314  319          char    *obj_val;
 315  320          char    *obj_arg;
 316  321          int     err;
 317  322  
 318  323          obj_ent_t *oep;
 319  324          struct hostent *he;
 320  325  
 321  326          if (flags & M_OBJECT) {
 322  327                  error_str = gettext("'o' option specified multiple times");
 323  328                  return (-1);
 324  329          }
 325  330          flags |= M_OBJECT;
 326  331          if ((obj_arg = strdup(optarg)) == (char *)0)
 327  332                  return (-1);
 328  333          if ((obj_str = strtok(optarg, "=")) == (char *)0 ||
 329  334              (oep = obj_lkup(obj_str)) == (obj_ent_t *)0 ||
 330  335              (obj_val = strtok((char *)0, "=")) == (char *)0) {
 331  336                  (void) sprintf(errbuf, gettext("invalid object arg (%s)"),
 332  337                      obj_arg);
 333  338                  error_str = errbuf;
 334  339                  return (-1);
 335  340          }
 336  341  
 337  342          obj_flag = oep->obj_flag;
 338  343  
 339  344          switch (obj_flag) {
 340  345          case OBJ_PATH:
 341  346                  if ((error_str = re_comp2(obj_val)) != (char *)NULL) {
 342  347                          return (-1);
 343  348                  }
 344  349                  return (0);
 345  350          case OBJ_SOCK:
 346  351                  if (!a_isnum(obj_val, TRUE)) {
 347  352                          obj_id = atol(obj_val);
 348  353                          socket_flag = SOCKFLG_PORT;
 349  354                          return (0);
 350  355                  }
 351  356                  if (*obj_val == '0') {
 352  357                          (void) sscanf(obj_val, "%x", (uint_t *)&obj_id);
 353  358                          socket_flag = SOCKFLG_PORT;
 354  359                          return (0);
 355  360                  }
 356  361  
 357  362                  he = getipnodebyname((const void *)obj_val, AF_INET6, 0, &err);
 358  363                  if (he == 0) {
 359  364                          he = getipnodebyname((const void *)obj_val, AF_INET,
 360  365                              0, &err);
 361  366                          if (he == 0) {
 362  367                                  (void) sprintf(errbuf,
 363  368                                      gettext("invalid machine name (%s)"),
 364  369                                      obj_val);
 365  370                                  error_str = errbuf;
 366  371                                  return (-1);
 367  372                          }
 368  373                  }
 369  374  
 370  375                  if (he->h_addrtype == AF_INET6) {
 371  376                          /* LINTED */
 372  377                          if (IN6_IS_ADDR_V4MAPPED(
 373  378                              (in6_addr_t *)he->h_addr_list[0])) {
 374  379                                  /* address is IPv4 (32 bits) */
 375  380                                  (void) memcpy(&obj_id,
 376  381                                      he->h_addr_list[0] + 12, 4);
 377  382                                  ip_type = AU_IPv4;
 378  383                          } else {
 379  384                                  (void) memcpy(ip_ipv6, he->h_addr_list[0], 16);
 380  385                                  ip_type = AU_IPv6;
 381  386                          }
 382  387                  } else {
 383  388                          /* address is IPv4 (32 bits) */
 384  389                          (void) memcpy(&obj_id, he->h_addr_list[0], 4);
 385  390                          ip_type = AU_IPv4;
 386  391                  }
 387  392  
 388  393                  freehostent(he);
 389  394                  socket_flag = SOCKFLG_MACHINE;
 390  395                  return (0);
 391  396          case OBJ_MSG:
 392  397          case OBJ_SEM:
 393  398          case OBJ_SHM:
 394  399          case OBJ_PROC:
 395  400                  obj_id = atol(obj_val);
 396  401                  return (0);
 397  402          case OBJ_FGROUP:
 398  403          case OBJ_MSGGROUP:
 399  404          case OBJ_SEMGROUP:
 400  405          case OBJ_SHMGROUP:
 401  406          case OBJ_PGROUP:
 402  407                  return (proc_group(obj_val, &obj_group));
  
    | 
      ↓ open down ↓ | 
    266 lines elided | 
    
      ↑ open up ↑ | 
  
 403  408          case OBJ_FOWNER:
 404  409          case OBJ_MSGOWNER:
 405  410          case OBJ_SEMOWNER:
 406  411          case OBJ_SHMOWNER:
 407  412          case OBJ_POWNER:
 408  413                  return (proc_user(obj_val, &obj_owner));
 409  414          case OBJ_FMRI:
 410  415                  return (proc_fmri(obj_val));
 411  416          case OBJ_USER:
 412  417                  return (proc_user(obj_val, &obj_user));
      418 +        case OBJ_WSID:
      419 +                return (proc_wsid(obj_val));
 413  420          case OBJ_LP: /* lp objects have not yet been defined */
 414  421          default: /* impossible */
 415  422                  (void) sprintf(errbuf, gettext("invalid object type (%s)"),
 416  423                      obj_str);
 417  424                  error_str = errbuf;
 418  425                  return (-1);
 419  426          } /* switch */
 420  427          /*NOTREACHED*/
 421  428  }
 422  429  
 423  430  
 424  431  obj_ent_t *
 425  432  obj_lkup(char *obj_str)
 426  433  {
 427  434          int     i;
 428  435  
 429  436          for (i = 0; i < sizeof (obj_tbl) / sizeof (obj_ent_t); i++)
 430  437                  if (strcmp(obj_str, obj_tbl[i].obj_str) == 0)
 431  438                          return (&obj_tbl[i]);
 432  439  
 433  440          /* not in table */
 434  441          return (NULL);
 435  442  }
 436  443  
 437  444  
 438  445  /*
 439  446   * .func        proc_type - process record type.
 440  447   * .desc        Process a record type. It is either as a number or a mnemonic.
 441  448   * .call        ret = proc_type(optstr).
 442  449   * .arg optstr  - ptr to name or number.
 443  450   * .ret 0       - no errors detected.
 444  451   * .ret -1      - error detected (error_str contains description).
 445  452   */
 446  453  int
 447  454  proc_type(char *optstr)
 448  455  {
 449  456          struct au_event_ent *aep;
 450  457  
 451  458          /*
 452  459           * Either a number or a name.
 453  460           */
 454  461  
 455  462          if (flags & M_TYPE) {
 456  463                  error_str = gettext("'m' option specified multiple times");
 457  464                  return (-1);
 458  465          }
 459  466          flags |= M_TYPE;
 460  467          m_type = 0;
 461  468          if (a_isnum(optstr, TRUE)) {
 462  469                  if ((aep = getauevnam(optstr)) != NULL)
 463  470                          m_type = aep->ae_number;
 464  471          } else {
 465  472                  if ((aep = getauevnum((au_event_t)atoi(optstr))) !=
 466  473                      (struct au_event_ent *)NULL)
 467  474                          m_type = aep->ae_number;
 468  475          }
 469  476          if ((m_type == 0)) {
 470  477                  (void) sprintf(errbuf, gettext("invalid event (%s)"), optstr);
 471  478                  error_str = errbuf;
 472  479                  return (-1);
 473  480          }
 474  481          return (0);
 475  482  }
 476  483  
 477  484  
 478  485  /*
 479  486   * .func        a_isnum - is it a number?
 480  487   * .desc        Determine if a string is a number or a name.
 481  488   *      A number may have a leading '+' or '-', but then must be
 482  489   *      all digits.
 483  490   * .call        ret = a_isnum(str).
 484  491   * .arg str - ptr to the string.
 485  492   * .arg leading - TRUE if leading '+-' allowed.
 486  493   * .ret 0       - is a number.
 487  494   * .ret 1       - is not a number.
 488  495   */
 489  496  int
 490  497  a_isnum(char *str, int leading)
 491  498  {
 492  499          char    *strs;
 493  500  
 494  501          if ((leading == TRUE) && (*str == '-' || *str == '+'))
 495  502                  strs = str + 1;
 496  503          else
 497  504                  strs = str;
 498  505  
 499  506          if (strlen(strs) == strspn(strs, "0123456789"))
 500  507                  return (0);
 501  508          else
 502  509                  return (1);
 503  510  }
 504  511  
 505  512  
 506  513  /*
 507  514   * .func        proc_id - process user/group id's/
 508  515   * .desc        Process either a user number/name or group number/name.
 509  516   *      For names check to see if the name is active in the system
 510  517   *      to derive the number. If it is not active then fail. For a number
 511  518   *      also check to see if it is active, but only print a warning if it
 512  519   *      is not. An administrator may be looking at activity of a 'phantom'
 513  520   *      user.
 514  521   * .call        ret = proc_id(optstr, opt).
 515  522   * .arg optstr  - ptr to name or number.
 516  523   * .arg opt     - 'u' - audit user, 'e' - effective user, 'r' - real user,
 517  524   *                'g' - group, 'f' - effective group.
 518  525   * .ret 0       - no errors detected.
 519  526   * .ret -1      - error detected (error_str contains description).
 520  527   */
 521  528  int
 522  529  proc_id(char *optstr, int opt)
 523  530  {
 524  531          switch (opt) {
 525  532          case 'e':               /* effective user id */
 526  533                  if (flags & M_USERE) {
 527  534                          error_str = gettext(
 528  535                              "'e' option specified multiple times");
 529  536                          return (-1);
 530  537                  }
 531  538                  flags |= M_USERE;
 532  539                  return (proc_user(optstr, &m_usere));
 533  540          case 'f':               /* effective group id */
 534  541                  if (flags & M_GROUPE) {
 535  542                          error_str = gettext(
 536  543                              "'f' option specified multiple times");
 537  544                          return (-1);
 538  545                  }
 539  546                  flags |= M_GROUPE;
 540  547                  return (proc_group(optstr, &m_groupe));
 541  548          case 'r':               /* real user id */
 542  549                  if (flags & M_USERR) {
 543  550                          error_str = gettext(
 544  551                              "'r' option specified multiple times");
 545  552                          return (-1);
 546  553                  }
 547  554                  flags |= M_USERR;
 548  555                  return (proc_user(optstr, &m_userr));
 549  556          case 'u':               /* audit user id */
 550  557                  if (flags & M_USERA) {
 551  558                          error_str = gettext(
 552  559                              "'u' option specified multiple times");
 553  560                          return (-1);
 554  561                  }
 555  562                  flags |= M_USERA;
 556  563                  return (proc_user(optstr, &m_usera));
 557  564          case 'g':               /* real group id */
 558  565                  if (flags & M_GROUPR) {
 559  566                          error_str = gettext(
 560  567                              "'g' option specified multiple times");
 561  568                          return (-1);
 562  569                  }
 563  570                  flags |= M_GROUPR;
 564  571                  return (proc_group(optstr, &m_groupr));
 565  572          default:                /* impossible */
 566  573                  (void) sprintf(errbuf, gettext("'%c' unknown option"), opt);
 567  574                  error_str = errbuf;
 568  575                  return (-1);
 569  576          }
 570  577          /*NOTREACHED*/
 571  578  }
 572  579  
 573  580  
 574  581  int
 575  582  proc_group(char *optstr, gid_t *gid)
 576  583  {
 577  584          struct group *grp;
 578  585  
 579  586          if ((grp = getgrnam(optstr)) == NULL) {
 580  587                  if (!a_isnum(optstr, TRUE)) {
 581  588                          *gid = (gid_t)atoi(optstr);
 582  589                          return (0);
 583  590                  }
 584  591                  (void) sprintf(errbuf, gettext("group name invalid (%s)"),
 585  592                      optstr);
 586  593                  error_str = errbuf;
 587  594                  return (-1);
 588  595          }
 589  596          *gid = grp->gr_gid;
 590  597          return (0);
 591  598  }
 592  599  
 593  600  
 594  601  int
 595  602  proc_user(char *optstr, uid_t *uid)
 596  603  {
 597  604          struct passwd *usr;
 598  605  
 599  606          if ((usr = getpwnam(optstr)) == NULL) {
 600  607                  if (!a_isnum(optstr, TRUE)) {
 601  608                          *uid = (uid_t)atoi(optstr);
 602  609                          return (0);
 603  610                  }
 604  611                  (void) sprintf(errbuf, gettext("user name invalid (%s)"),
 605  612                      optstr);
 606  613                  error_str = errbuf;
 607  614                  return (-1);
 608  615          }
 609  616          *uid = usr->pw_uid;
 610  617          return (0);
 611  618  }
 612  619  
 613  620  
 614  621  /*
 615  622   * .func proc_date - process date argument.
 616  623   * .desc Handle a date/time argument. See if the user has erred in combining
 617  624   *      the types of date arguments. Then parse the string and check for
 618  625   *      validity of each part.
 619  626   * .call        ret = proc_date(optstr, opt).
 620  627   * .arg optstr  - ptr to date/time string.
 621  628   * .arg opt     - 'd' for day, 'a' for after, or 'b' for before.
 622  629   * .ret 0       - no errors detected.
 623  630   * .ret -1      - errors detected (error_str knows what it is).
 624  631   */
 625  632  int
 626  633  proc_date(char *optstr, int opt)
 627  634  {
 628  635          static int      m_day = FALSE;
 629  636  
 630  637          if (opt == 'd') {
 631  638                  if (m_day == TRUE) {
 632  639                          error_str = gettext(
 633  640                              "'d' option may not be used with 'a' or 'b'");
 634  641                          return (-1);
 635  642                  }
 636  643                  m_day = TRUE;
 637  644          }
 638  645          if ((opt == 'd') && (m_before || m_after)) {
 639  646                  error_str = gettext(
 640  647                      "'d' option may not be used with 'a' or 'b'");
 641  648                  return (-1);
 642  649          }
 643  650          if ((opt == 'a' || opt == 'b') && m_day) {
 644  651                  error_str = gettext(
 645  652                      "'a' or 'b' option may not be used with 'd'");
 646  653                  return (-1);
 647  654          }
 648  655          if ((opt == 'a') && (m_after != 0)) {
 649  656                  error_str = gettext("'a' option specified multiple times");
 650  657                  return (-1);
 651  658          }
 652  659          if ((opt == 'b') && (m_before != 0)) {
 653  660                  error_str = gettext("'b' option specified multiple times");
 654  661                  return (-1);
 655  662          }
 656  663          if (parse_time(optstr, opt))
 657  664                  return (-1);
 658  665          return (0);
 659  666  }
 660  667  
 661  668  
 662  669  /*
 663  670   * .func        proc_class - process message class argument.
 664  671   * .desc        Process class type and see if it is for real.
 665  672   * .call        ret = proc_class(optstr).
 666  673   * .arg optstr  - ptr to class.
 667  674   * .ret 0       - class has class.
 668  675   * .ret -1      - class in no good.
 669  676   */
 670  677  int
 671  678  proc_class(char *optstr)
 672  679  {
 673  680          if (flags & M_CLASS) {
 674  681                  error_str = gettext("'c' option specified multiple times");
 675  682                  return (-1);
 676  683          }
 677  684          flags |= M_CLASS;
 678  685  
 679  686          if (getauditflagsbin(optstr, &mask) != 0) {
 680  687                  (void) sprintf(errbuf, gettext("unknown class (%s)"), optstr);
 681  688                  error_str = errbuf;
 682  689                  return (-1);
 683  690          }
 684  691  
 685  692          if (mask.am_success != mask.am_failure) {
 686  693                  flags |= M_SORF;
 687  694          }
 688  695  
 689  696          return (0);
 690  697  }
 691  698  
 692  699  
 693  700  /*
 694  701   * .func process_fileopt - process command line file options.
 695  702   * .desc Process the command line file options and gather the specified files
 696  703   *      together in file groups based upon file name suffix. The user can
 697  704   *      specify files explicitly on the command line or via a directory.
 698  705   *      This is called after the command line flags are processed (as
 699  706   *      denoted by '-').
 700  707   * .call        ret = process_fileopt(argc, argv, optindex).
 701  708   * .arg argc    - current value of argc.
 702  709   * .arg argv    - current value of argv.
 703  710   * .arg optindex- current index into argv (as setup by getopt()).
 704  711   * .ret 0       - no errors detected.
 705  712   * .ret -1      - error detected (message already printed).
 706  713   */
 707  714  int
 708  715  process_fileopt(int argc, char **argv, int optindex)
 709  716  {
 710  717          int     f_mode = FM_ALLDIR;
 711  718          char    f_dr[MAXNAMLEN+1];
 712  719          char    *f_dir = f_dr;
 713  720          char    *fname;
 714  721          static char     *std = "standard input";
 715  722          audit_fcb_t *fcb;
 716  723          DIR * dirp;
 717  724          struct dirent *dp;
 718  725          audit_pcb_t *pcb;
 719  726  
 720  727          /*
 721  728           * Take input from stdin, not any files.
 722  729           * Use a single fcb to do this.
 723  730           */
 724  731          if (f_stdin) {
 725  732                  fcb = (audit_fcb_t *)a_calloc(1, sizeof (*fcb) + strlen(std));
 726  733                  (void) strcpy(fcb->fcb_file, std);
 727  734                  fcb->fcb_suffix = fcb->fcb_name = fcb->fcb_file;
 728  735                  fcb->fcb_next = NULL;
 729  736                  fcb->fcb_start = 0;
 730  737                  fcb->fcb_end = MAXLONG;         /* forever */
 731  738                  if ((pcb = get_next_pcb((char *)NULL)) == (audit_pcb_t *)NULL)
 732  739                          return (-1);
 733  740                  pcb->pcb_suffix = fcb->fcb_file;
 734  741                  pcb->pcb_dfirst = pcb->pcb_first = fcb; /* one-item list */
 735  742                  pcb->pcb_dlast = pcb->pcb_last = fcb;
 736  743                  pcb->pcb_cur = fcb;
 737  744          }
 738  745          /*
 739  746           * No files specified on the command line.
 740  747           * Process a directory of files or subdirectories.
 741  748           */
 742  749          else if (argc == optindex) {
 743  750                  /*
 744  751                   * A specific server directory was requested.
 745  752                   */
 746  753                  if (f_server) {
 747  754                          if (strchr(f_server, '/')) {    /* given full path */
 748  755                                  f_dir = f_server;
 749  756                                  f_mode = FM_ALLFILE;    /* all files here */
 750  757                          } else {                /* directory off audit root */
 751  758                                  f_dir[0] = '\0';
 752  759                                  (void) strcat(f_dir, f_root);
 753  760                                  (void) strcat(f_dir, "/");
 754  761                                  (void) strcat(f_dir, f_server);
 755  762                                  f_mode = FM_ALLFILE;
 756  763                          }
 757  764                  }
 758  765                  /*
 759  766                   * Gather all of the files in the directory 'f_dir'.
 760  767                   */
 761  768                  if (f_mode == FM_ALLFILE) {
 762  769                          if (gather_dir(f_dir)) { /* get those files together */
 763  770                                  return (-1);
 764  771                          }
 765  772                  } else {
 766  773                          /*
 767  774                           * Gather all of the files in all of the
 768  775                           * directories in 'f_root'.
 769  776                           */
 770  777                          if ((dirp = opendir(f_root)) == NULL) {
 771  778                                  (void) sprintf(errbuf, gettext(
 772  779                                      "%s can't open directory %s"), ar, f_root);
 773  780                                  perror(errbuf);
 774  781                                  return (-1);
 775  782                          }
 776  783                          /* read the directory and process all of the subs */
 777  784                          for (dp = readdir(dirp);
 778  785                              dp != NULL; dp = readdir(dirp)) {
 779  786                                  if (dp->d_name[0] == '.')
 780  787                                          continue;
 781  788                                  f_dir[0] = '\0';
 782  789                                  (void) strcat(f_dir, f_root);
 783  790                                  (void) strcat(f_dir, "/");
 784  791                                  (void) strcat(f_dir, dp->d_name);
 785  792                                  if (gather_dir(f_dir))  /* process a sub */
 786  793                                          return (-1);
 787  794                          }
 788  795                          (void) closedir(dirp);
 789  796                  }
 790  797          } else {
 791  798                  /*
 792  799                   * User specified filenames on the comm and line.
 793  800                   */
 794  801                  f_cmdline = TRUE;
 795  802                  for (; optindex < argc; optindex++) {
 796  803                          fname = argv[optindex];         /* get a filename */
 797  804                          if (proc_file(fname, FALSE))
 798  805                                  return (-1);
 799  806                  }
 800  807          }
 801  808          return (0);
 802  809  }
 803  810  
 804  811  
 805  812  /*
 806  813   * .func        gather_dir - gather a directory's files together.
 807  814   * .desc        Process all of the files in a specific directory. The files may
 808  815   *      be checked for adherence to the file name form at.
 809  816   *      If the directory can't be opened that is ok - just print
 810  817   *      a message and continue.
 811  818   * .call        ret = gather_dir(dir).
 812  819   * .arg dir     - ptr to full pathname of directory.
 813  820   * .ret 0       - no errors detected.
 814  821   * .ret -1      - error detected (message already printed).
 815  822   */
 816  823  int
 817  824  gather_dir(char *dir)
 818  825  {
 819  826          char    dname[MAXNAMLEN+1];
 820  827          char    fname[MAXNAMLEN+1];
 821  828          DIR * dirp;
 822  829          struct dirent *dp;
 823  830  
 824  831          (void) snprintf(dname, sizeof (dname), "%s/files", dir);
 825  832  
 826  833          if ((dirp = opendir(dname)) == NULL) {
 827  834                  if (errno != ENOTDIR) {
 828  835                          (void) sprintf(errbuf,
 829  836                              gettext("%s can't open directory - %s"), ar, dname);
 830  837                          perror(errbuf);
 831  838                  }
 832  839                  return (0);
 833  840          }
 834  841          for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
 835  842                  if (dp->d_name[0] == '.')       /* can't see hidden files */
 836  843                          continue;
 837  844                  fname[0] = '\0';
 838  845                  (void) strcat(fname, dname);    /* create pathname of file */
 839  846                  (void) strcat(fname, "/");
 840  847                  (void) strcat(fname, dp->d_name);
 841  848                  if (proc_file(fname, TRUE))
 842  849                          return (-1);
 843  850          }
 844  851          (void) closedir(dirp);
 845  852          return (0);
 846  853  }
 847  854  
 848  855  
 849  856  /*
 850  857   * .func        proc_file - process a single candidate file.
 851  858   * .desc        Check out a file to see if it should be used in the merge.
 852  859   *      This includes checking the name (mode is TRUE) against the
 853  860   *      file format, checking access rights to the file, and thence
 854  861   *      getting and fcb and installing the fcb into the correct pcb.
 855  862   *      If the file fails then the fcb is not installed into a pcb
 856  863   *      and the file dissapears from view.
 857  864   * .call        proc_file(fname, mode).
 858  865   * .arg fname   - ptr to full pathna me of file.
 859  866   * .arg mode    - TRUE if checking adherence to file name format.
 860  867   * .ret 0       - no fatal errors detected.
 861  868   * .ret -1      - fatal error detected - quit altogether
 862  869   *                (message already printed).
 863  870   */
 864  871  int
 865  872  proc_file(char *fname, int mode)
 866  873  {
 867  874          int reject = FALSE;
 868  875          size_t len;
 869  876          struct stat stat_buf;
 870  877          audit_fcb_t *fcb, *fcbp, *fcbprev;
 871  878          audit_pcb_t *pcb;
 872  879  
 873  880          /*
 874  881           * See if it is a weird file like a directory or
 875  882           * character special (around here?).
 876  883           */
 877  884          if (stat(fname, &stat_buf)) {
 878  885                  return (0);
 879  886          }
 880  887          if (!S_ISREG(stat_buf.st_mode))
 881  888                  return (0);
 882  889          /*
 883  890           * Allocate a new fcb to hold fcb and full filename.
 884  891           */
 885  892          len = sizeof (audit_fcb_t) + strlen(fname);
 886  893          fcb = (audit_fcb_t *)a_calloc(1, len);
 887  894          (void) strcpy(fcb->fcb_file, fname);
 888  895          if (check_file(fcb, mode)) { /* check file name */
 889  896                  if (!f_quiet) {
 890  897                          (void) fprintf(stderr, "%s %s:\n  %s.\n", ar,
 891  898                              error_str, fname);
 892  899                  }
 893  900                  reject = TRUE;
 894  901          } else {
 895  902                  /*
 896  903                   * Check against file criteria.
 897  904                   * Check finish-time here, and start-time later on
 898  905                   * while processing.
 899  906                   * This is because the start time on a file can be after
 900  907                   * the first record(s).
 901  908                   */
 902  909                  if (f_complete && (fcb->fcb_flags & FF_NOTTERM) && !f_cmdline)
 903  910                          reject = TRUE;
 904  911                  if (!f_all && (fcb->fcb_end < m_after))
 905  912                          reject = TRUE;
 906  913                  if (f_machine) {
 907  914                          if (strlen(fcb->fcb_suffix) != strlen(f_machine) ||
 908  915                              (strcmp(fcb->fcb_suffix, f_machine) != 0)) {
 909  916                                  reject = TRUE;
 910  917                          }
 911  918                  }
 912  919          }
 913  920          if (reject == FALSE) {
 914  921                  filenum++;      /* count of total files to be processed */
 915  922                  fcb->fcb_next = NULL;
 916  923                  if ((pcb = get_next_pcb(fcb->fcb_suffix)) == NULL) {
 917  924                          return (-1);
 918  925                  }
 919  926                  /* Place FCB into the PCB in order - oldest first.  */
 920  927                  fcbp = pcb->pcb_first;
 921  928                  fcbprev = NULL;
 922  929                  while (fcbp != NULL) {
 923  930                          if (fcb->fcb_start < fcbp->fcb_start) {
 924  931                                  if (fcbprev)
 925  932                                          fcbprev->fcb_next = fcb;
 926  933                                  else
 927  934                                          pcb->pcb_dfirst = pcb->pcb_first = fcb;
 928  935                                  fcb->fcb_next = fcbp;
 929  936                                  break;
 930  937                          }
 931  938                          fcbprev = fcbp;
 932  939                          fcbp = fcbp->fcb_next;
 933  940                  }
 934  941                  /* younger than all || empty list */
 935  942                  if (!fcb->fcb_next) {
 936  943                          if (pcb->pcb_first == NULL)
 937  944                                  pcb->pcb_dfirst = pcb->pcb_first = fcb;
 938  945                          pcb->pcb_dlast = pcb->pcb_last = fcb;
 939  946                          if (fcbprev)
 940  947                                  fcbprev->fcb_next = fcb;
 941  948                  }
 942  949          } else {
 943  950                  free((char *)fcb);      /* rejected */
 944  951          }
 945  952          return (0);
 946  953  }
 947  954  
 948  955  
 949  956  /*
 950  957   * .func        check_file - check filename and setup fcb.
 951  958   * .desc        Check adherence to the file format (do_check is TRUE) and setup
 952  959   *      the fcb with useful information.
 953  960   *      filename format: yyyymmddhhmmss.yyyymmddhhmmss.suffix
 954  961   *                       yyyymmddhhmmss.not_terminated.suffix
 955  962   *      If do_check is FALSE then still see if the filename does confirm
 956  963   *      to the format. If it does then extract useful information from
 957  964   *      it (start time and end time).  But if it doesn't then don't print
 958  965   *      any error messages.
 959  966   * .call        ret = check_file(fcb, do_check).
 960  967   * .arg fcb     - ptr to fcb that holds the file.
 961  968   * .arg do_check - if TRUE do check adherence to file format.
 962  969   * .ret 0       - no errors detected.
 963  970   * .ret -1      - file failed somehow (error_str tells why).
 964  971   */
 965  972  int
 966  973  check_file(audit_fcb_t *fcb, int do_check)
 967  974  {
 968  975          int     ret;
 969  976          char    *namep, *slp;
 970  977          char    errb[256];              /* build error message */
 971  978          struct tm tme;
 972  979  
 973  980          errb[0] = '\0';
 974  981          /* get just the filename */
 975  982          for (slp = namep = fcb->fcb_file; *namep; namep++) {
 976  983                  if (*namep == '/')
 977  984                          slp = namep + 1; /* slp -> the filename itself */
 978  985          }
 979  986          if (do_check == FALSE) {
 980  987                  fcb->fcb_end = MAXLONG;         /* forever */
 981  988                  fcb->fcb_suffix = NULL;
 982  989                  fcb->fcb_name = slp;
 983  990                  ret = 0;
 984  991          } else {
 985  992                  ret = -1;
 986  993          }
 987  994          if ((int)strlen(slp) < 31) {
 988  995                  (void) sprintf(errbuf, gettext("filename too short (%d)"),
 989  996                      strlen(slp));
 990  997                  error_str = errbuf;
 991  998                  return (ret);
 992  999          }
 993 1000          /*
 994 1001           * Get working copy of filename.
 995 1002           */
 996 1003          namep = (char *)a_calloc(1, strlen(slp) + 1);
 997 1004          (void) strcpy(namep, slp);
 998 1005          if (namep[14] != '.' || namep[29] != '.') {
 999 1006                  (void) sprintf(errbuf,
1000 1007                      gettext("invalid filename format (%c or %c)"), namep[14],
1001 1008                      namep[29]);
1002 1009                  error_str = errbuf;
1003 1010                  free(namep);
1004 1011                  return (ret);
1005 1012          }
1006 1013          namep[14] = '\0';                       /* mark off start time */
1007 1014          namep[29] = '\0';                       /* mark off finish time */
1008 1015          if (derive_date(namep, &tme)) {
1009 1016                  (void) strcat(errb, gettext("starting time-stamp invalid - "));
1010 1017                  (void) strcat(errb, error_str);
1011 1018                  (void) strcpy(errbuf, errb);
1012 1019                  error_str = errbuf;
1013 1020                  free(namep);
1014 1021                  return (ret);
1015 1022          }
1016 1023          /*
1017 1024           * Keep start time from filename. Use it to order files in
1018 1025           * the file list. Later we will update this when we read
1019 1026           * the first record from the file.
1020 1027           */
1021 1028          fcb->fcb_start = tm_to_secs(&tme);
1022 1029  
1023 1030          if (strcmp(&namep[15], "not_terminated") == 0) {
1024 1031                  fcb->fcb_end = MAXLONG;         /* forever */
1025 1032                  /*
1026 1033                   * Only treat a 'not_terminated' file as such if
1027 1034                   * it is not on the command line.
1028 1035                   */
1029 1036                  if (do_check == TRUE)
1030 1037                          fcb->fcb_flags |= FF_NOTTERM;
1031 1038          } else if (derive_date(&namep[15], &tme)) {
1032 1039                  (void) strcat(errb, gettext("ending time-stamp invalid - "));
1033 1040                  (void) strcat(errb, error_str);
1034 1041                  (void) strcpy(errbuf, errb);
1035 1042                  error_str = errbuf;
1036 1043                  free(namep);
1037 1044                  return (ret);
1038 1045          } else {
1039 1046                  fcb->fcb_end = tm_to_secs(&tme);
1040 1047          }
1041 1048          fcb->fcb_name = slp;
1042 1049          fcb->fcb_suffix = &slp[30];
1043 1050          free(namep);
1044 1051          return (0);
1045 1052  }
1046 1053  
1047 1054  
1048 1055  /*
1049 1056   * .func get_next_pcb - get a pcb to use.
1050 1057   * .desc        The pcb's in the array audit_pcbs are used to hold single file
1051 1058   *      groups in the form of a linked list. Each pcb holds files that
1052 1059   *      are tied together by a common suffix in the file name. Here we
1053 1060   *      get either 1. the existing pcb holding a specified sufix or
1054 1061   *      2. a new pcb if we can't find an existing one.
1055 1062   * .call        pcb = get_next_pcb(suffix).
1056 1063   * .arg suffix  - ptr to suffix we are seeking.
1057 1064   * .ret pcb     - ptr to pcb that hold s the sought suffix.
1058 1065   * .ret NULL- serious failure in memory allocation. Quit processing.
1059 1066   */
1060 1067  audit_pcb_t *
1061 1068  get_next_pcb(char *suffix)
1062 1069  {
1063 1070          int     i = 0;
1064 1071          int     zerosize;
1065 1072          unsigned int    size;
1066 1073          audit_pcb_t *pcb;
1067 1074  
1068 1075          /* Search through (maybe) entire array. */
1069 1076          while (i < pcbsize) {
1070 1077                  pcb = &audit_pcbs[i++];
1071 1078                  if (pcb->pcb_first == NULL) {
1072 1079                          proc_pcb(pcb, suffix, i);
1073 1080                          return (pcb);   /* came to an unused one */
1074 1081                  }
1075 1082                  if (suffix) {
1076 1083                          if (strcmp(pcb->pcb_suffix, suffix) == 0)
1077 1084                                  return (pcb);   /* matched one with suffix */
1078 1085                  }
1079 1086          }
1080 1087          /*
1081 1088           * Uh-oh, the entire array is used and we haven't gotten one yet.
1082 1089           * Allocate a bigger array.
1083 1090           */
1084 1091          pcbsize += PCB_INC;
1085 1092          size = pcbsize * sizeof (audit_pcb_t);
1086 1093          zerosize = size - ((pcbsize - PCB_INC) * sizeof (audit_pcb_t));
1087 1094          if ((audit_pcbs = (audit_pcb_t *)realloc((char *)audit_pcbs, size)) ==
1088 1095              NULL) {
1089 1096                  (void) sprintf(errbuf,
1090 1097                      gettext("%s memory reallocation failed (%d bytes)"), ar,
1091 1098                      size);
1092 1099                  perror(errbuf);
1093 1100                  audit_stats();          /* give user statistics on usage */
1094 1101                  return (NULL);          /* really bad thing to have happen */
1095 1102          }
1096 1103          /*
1097 1104           * Don't know if realloc clears the new memory like calloc would.
1098 1105           */
1099 1106          (void) memset((void *) & audit_pcbs[pcbsize-PCB_INC], 0,
1100 1107              (size_t)zerosize);
1101 1108          pcb = &audit_pcbs[pcbsize-PCB_INC];     /* allocate the first new one */
1102 1109          proc_pcb(pcb, suffix, pcbsize - PCB_INC);
1103 1110          return (pcb);
1104 1111  }
1105 1112  
1106 1113  
1107 1114  /*
1108 1115   * .func proc_pcb - process pcb.
1109 1116   * .desc        Common pcb processing for above routine.
1110 1117   * .call        proc_pcb(pcb, suffix, i).
1111 1118   * .arg pcb     - ptr to pcb.
1112 1119   * .arg suffix  - prt to suffix tha t ties this group together.
1113 1120   * .arg i       - index into audit_pcbs[ ].
1114 1121   * .ret void.
1115 1122   */
1116 1123  void
1117 1124  proc_pcb(audit_pcb_t *pcb, char *suffix, int i)
1118 1125  {
1119 1126          if (suffix)
1120 1127                  pcb->pcb_suffix = suffix;
1121 1128          pcbnum++;       /* one more pcb in use */
1122 1129          pcb->pcb_size = AUDITBUFSIZE;
1123 1130          pcb->pcb_rec = (char *)a_calloc(1, AUDITBUFSIZE);
1124 1131          pcb->pcb_time = -1;
1125 1132          pcb->pcb_flags |= PF_USEFILE;   /* note this one controls files */
1126 1133          pcb->pcb_procno = i;    /* save index into audit_pcbs [] for id */
1127 1134  }
1128 1135  
1129 1136  
1130 1137  /*
1131 1138   * .func        proc_label - process label range argument.
1132 1139   * .desc        Parse label range lower-bound[;upper-bound]
1133 1140   * .call        ret = proc_label(optstr).
1134 1141   * .arg opstr   - ptr to label range string
1135 1142   * .ret 0       - no errors detected.
1136 1143   * .ret -1      - errors detected (error_str set).
1137 1144   */
1138 1145  
1139 1146  int
1140 1147  proc_label(char *optstr)
1141 1148  {
1142 1149          char    *p;
1143 1150          int     error;
1144 1151  
1145 1152          if (flags & M_LABEL) {
1146 1153                  error_str = gettext("'l' option specified multiple times");
1147 1154                  return (-1);
1148 1155          }
1149 1156          flags |= M_LABEL;
1150 1157  
1151 1158          if ((m_label = malloc(sizeof (m_range_t))) == NULL) {
1152 1159                  return (-1);
1153 1160          }
1154 1161          m_label->lower_bound = NULL;
1155 1162          m_label->upper_bound = NULL;
1156 1163  
1157 1164          p = strchr(optstr, ';');
1158 1165          if (p == NULL) {
1159 1166                  /* exact label match, lower and upper range bounds the same */
1160 1167                  if (str_to_label(optstr, &m_label->lower_bound, MAC_LABEL,
1161 1168                      L_NO_CORRECTION, &error) == -1) {
1162 1169                          (void) sprintf(errbuf,
1163 1170                              gettext("invalid sensitivity label (%s) err %d"),
1164 1171                              optstr, error);
1165 1172                          error_str = errbuf;
1166 1173                          goto errout;
1167 1174                  }
1168 1175                  m_label->upper_bound = m_label->lower_bound;
1169 1176                  return (0);
1170 1177          }
1171 1178          if (p == optstr) {
1172 1179                  /* lower bound is not specified .. default is admin_low */
1173 1180                  if (str_to_label(ADMIN_LOW, &m_label->lower_bound, MAC_LABEL,
1174 1181                      L_NO_CORRECTION, &error) == -1) {
1175 1182                          goto errout;
1176 1183                  }
1177 1184  
1178 1185                  p++;
1179 1186                  if (*p == '\0') {
1180 1187                          /* upper bound not specified .. default is admin_high */
1181 1188                          if (str_to_label(ADMIN_HIGH, &m_label->upper_bound,
1182 1189                              MAC_LABEL, L_NO_CORRECTION, &error) == -1) {
1183 1190                                  goto errout;
1184 1191                          }
1185 1192                  } else {
1186 1193                          if (str_to_label(p, &m_label->upper_bound, MAC_LABEL,
1187 1194                              L_NO_CORRECTION, &error) == -1) {
1188 1195                                  (void) sprintf(errbuf, gettext(
1189 1196                                      "invalid sensitivity label (%s) err %d"),
1190 1197                                      p, error);
1191 1198                                  error_str = errbuf;
1192 1199                                  goto errout;
1193 1200                          }
1194 1201                  }
1195 1202                  return (0);
1196 1203          }
1197 1204          *p++ = '\0';
1198 1205          if (str_to_label(optstr, &m_label->lower_bound, MAC_LABEL,
1199 1206              L_NO_CORRECTION, &error) == -1) {
1200 1207                  (void) sprintf(errbuf,
1201 1208                      gettext("invalid sensitivity label (%s) err %d"), optstr,
1202 1209                      error);
1203 1210                  error_str = errbuf;
1204 1211                  goto errout;
1205 1212          }
1206 1213          if (*p == '\0') {
1207 1214                  /* upper bound is not specified .. default is admin_high */
1208 1215                  if (str_to_label(ADMIN_HIGH, &m_label->upper_bound,
1209 1216                      MAC_LABEL, L_NO_CORRECTION, &error) == -1) {
1210 1217                          goto errout;
1211 1218                  }
1212 1219          } else {
1213 1220                  if (str_to_label(p, &m_label->upper_bound, MAC_LABEL,
1214 1221                      L_NO_CORRECTION, &error) == -1) {
1215 1222                          (void) sprintf(errbuf,
1216 1223                              gettext("invalid sensitivity label (%s) err %d"),
1217 1224                              p, error);
1218 1225                          error_str = errbuf;
1219 1226                          goto errout;
1220 1227                  }
1221 1228          }
1222 1229          /* make sure that upper bound dominates the lower bound */
1223 1230          if (!bldominates(m_label->upper_bound, m_label->lower_bound)) {
1224 1231                  *--p = ';';
1225 1232                  (void) sprintf(errbuf,
1226 1233                      gettext("invalid sensitivity label range (%s)"), optstr);
1227 1234                  error_str = errbuf;
1228 1235                  goto errout;
1229 1236          }
1230 1237          return (0);
1231 1238  
1232 1239  errout:
1233 1240          m_label_free(m_label->upper_bound);
1234 1241          m_label_free(m_label->lower_bound);
1235 1242          free(m_label);
1236 1243  
1237 1244          return (-1);
1238 1245  }
1239 1246  
1240 1247  /*
1241 1248   * proc_zonename - pick up zone name.
1242 1249   *
1243 1250   * all non-empty and not-too-long strings are valid since any name
1244 1251   * may be valid.
1245 1252   *
1246 1253   * ret 0:       non-empty string
1247 1254   * ret -1:      empty string or string is too long.
1248 1255   */
1249 1256  static int
1250 1257  proc_zonename(char *optstr)
1251 1258  {
1252 1259          size_t  length = strlen(optstr);
1253 1260          if ((length < 1) || (length > ZONENAME_MAX)) {
1254 1261                  (void) sprintf(errbuf,
1255 1262                      gettext("invalid zone name: %s"), optstr);
1256 1263                  error_str = errbuf;
1257 1264                  return (-1);
1258 1265          }
1259 1266          zonename = strdup(optstr);
1260 1267          flags |= M_ZONENAME;
1261 1268          return (0);
1262 1269  }
1263 1270  
1264 1271  /*
1265 1272   * proc_frmi - set up frmi for pattern matching.
1266 1273   *      Logic ripped off of scf_walk_fmri()
1267 1274   *              Thanks to the smf team.
1268 1275   *
1269 1276   * ret 0:       OK
1270 1277   * ret -1:      error
1271 1278   */
1272 1279  static int
1273 1280  proc_fmri(char *optstr)
1274 1281  {
1275 1282          if (strpbrk(optstr, "*?[") != NULL) {
1276 1283                  /* have a pattern to glob for */
1277 1284  
1278 1285                  fmri.sp_type = PATTERN_GLOB;
1279 1286                  if (optstr[0] == '*' ||
1280 1287                      (strlen(optstr) >= 4 && optstr[3] == ':')) {
1281 1288                          fmri.sp_arg = strdup(optstr);
1282 1289                  } else if ((fmri.sp_arg = malloc(strlen(optstr) + 6)) != NULL) {
1283 1290                          (void) snprintf(fmri.sp_arg, strlen(optstr) + 6,
1284 1291                              "svc:/%s", optstr);
  
    | 
      ↓ open down ↓ | 
    862 lines elided | 
    
      ↑ open up ↑ | 
  
1285 1292                  }
1286 1293          } else {
1287 1294                  fmri.sp_type = PATTERN_PARTIAL;
1288 1295                  fmri.sp_arg = strdup(optstr);
1289 1296          }
1290 1297          if (fmri.sp_arg == NULL)
1291 1298                  return (-1);
1292 1299  
1293 1300          return (0);
1294 1301  }
     1302 +
     1303 +/*
     1304 + * proc_wsid - pick up Windows SID.
     1305 + *
     1306 + * ret 0:       non-empty string
     1307 + * ret -1:      empty string or string is too long.
     1308 + */
     1309 +static int
     1310 +proc_wsid(char *optstr)
     1311 +{
     1312 +        size_t  length = strlen(optstr);
     1313 +        if ((length < 1) || (length > 256) ||
     1314 +            strncmp(optstr, "S-1-", 4) != 0) { /* SMB_SID_STRSZ */
     1315 +                (void) snprintf(errbuf, ERRBUF_SZ,
     1316 +                    gettext("bad Windows SID: %s"), optstr);
     1317 +                error_str = errbuf;
     1318 +                return (-1);
     1319 +        }
     1320 +        wsid = strdup(optstr);
     1321 +        return (0);
     1322 +}
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX