1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2013 Gary Mills
  23  *
  24  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 
  32 #include        <sys/types.h>
  33 #include        <sys/stat.h>
  34 #include        <sys/param.h>
  35 #include        <stdio.h>
  36 #include        <stdlib.h>
  37 #include        <ctype.h>
  38 #include        <limits.h>
  39 #include        <string.h>
  40 #include        <userdefs.h>
  41 #include        <errno.h>
  42 #include        <project.h>
  43 #include        <unistd.h>
  44 #include        <user_attr.h>
  45 #include        "users.h"
  46 #include        "messages.h"
  47 #include        "userdisp.h"
  48 #include        "funcs.h"
  49 
  50 /*
  51  *  useradd [-u uid [-o] | -g group | -G group [[, group]...] | -d dir [-m]
  52  *              | -s shell | -c comment | -k skel_dir | -b base_dir] ]
  53  *              [ -A authorization [, authorization ...]]
  54  *              [ -P profile [, profile ...]]
  55  *              [ -K key=value ]
  56  *              [ -R role [, role ...]] [-p project [, project ...]] login
  57  *  useradd -D [ -g group ] [ -b base_dir | -f inactive | -e expire |
  58  *              -s shell | -k skel_dir ]
  59  *              [ -A authorization [, authorization ...]]
  60  *              [ -P profile [, profile ...]] [ -K key=value ]
  61  *              [ -R role [, role ...]] [-p project [, project ...]] login
  62  *
  63  *      This command adds new user logins to the system.  Arguments are:
  64  *
  65  *      uid - an integer
  66  *      group - an existing group's integer ID or char string name
  67  *      dir - home directory
  68  *      shell - a program to be used as a shell
  69  *      comment - any text string
  70  *      skel_dir - a skeleton directory
  71  *      base_dir - a directory
  72  *      login - a string of printable chars except colon(:)
  73  *      authorization - One or more comma separated authorizations defined
  74  *                      in auth_attr(4).
  75  *      profile - One or more comma separated execution profiles defined
  76  *                in prof_attr(4)
  77  *      role - One or more comma-separated role names defined in user_attr(4)
  78  *      project - One or more comma-separated project names or numbers
  79  *
  80  */
  81 
  82 extern struct userdefs *getusrdef();
  83 extern void dispusrdef();
  84 
  85 static void cleanup();
  86 
  87 extern uid_t findnextuid(void);
  88 extern int check_perm(), valid_expire();
  89 extern int putusrdef(), valid_uid();
  90 extern int call_passmgmt(), edit_group(), create_home();
  91 extern int edit_project();
  92 extern int **valid_lgroup();
  93 extern projid_t **valid_lproject();
  94 extern void update_def(struct userdefs *);
  95 extern void import_def(struct userdefs *);
  96 
  97 static uid_t uid;                       /* new uid */
  98 static char *logname;                   /* login name to add */
  99 static struct userdefs *usrdefs;        /* defaults for useradd */
 100 
 101 char *cmdname;
 102 
 103 static char homedir[ PATH_MAX + 1 ];    /* home directory */
 104 static char gidstring[32];              /* group id string representation */
 105 static gid_t gid;                       /* gid of new login */
 106 static char uidstring[32];              /* user id string representation */
 107 static char *uidstr = NULL;             /* uid from command line */
 108 static char *base_dir = NULL;           /* base_dir from command line */
 109 static char *group = NULL;              /* group from command line */
 110 static char *grps = NULL;               /* multi groups from command line */
 111 static char *dir = NULL;                /* home dir from command line */
 112 static char *shell = NULL;              /* shell from command line */
 113 static char *comment = NULL;            /* comment from command line */
 114 static char *skel_dir = NULL;           /* skel dir from command line */
 115 static long inact;                      /* inactive days */
 116 static char *inactstr = NULL;           /* inactive from command line */
 117 static char inactstring[10];            /* inactivity string representation */
 118 static char *expirestr = NULL;          /* expiration date from command line */
 119 static char *projects = NULL;           /* project id's from command line */
 120 
 121 static char *usertype = NULL;   /* type of user, either role or normal */
 122 
 123 typedef enum {
 124         BASEDIR = 0,
 125         SKELDIR,
 126         SHELL
 127 } path_opt_t;
 128 
 129 
 130 static void valid_input(path_opt_t, const char *);
 131 
 132 int
 133 main(argc, argv)
 134 int argc;
 135 char *argv[];
 136 {
 137         int ch, ret, mflag = 0, oflag = 0, Dflag = 0, **gidlist;
 138         projid_t **projlist;
 139         char *ptr;                      /* loc in a str, may be set by strtol */
 140         struct group *g_ptr;
 141         struct project p_ptr;
 142         char mybuf[PROJECT_BUFSZ];
 143         struct stat statbuf;            /* status buffer for stat */
 144         int warning;
 145         int busy = 0;
 146         char **nargv;                   /* arguments for execvp of passmgmt */
 147         int argindex;                   /* argument index into nargv */
 148 
 149         cmdname = argv[0];
 150 
 151         if (geteuid() != 0) {
 152                 errmsg(M_PERM_DENIED);
 153                 exit(EX_NO_PERM);
 154         }
 155 
 156         opterr = 0;                     /* no print errors from getopt */
 157         usertype = getusertype(argv[0]);
 158 
 159         change_key(USERATTR_TYPE_KW, usertype);
 160 
 161         while ((ch = getopt(argc, argv,
 162                     "b:c:Dd:e:f:G:g:k:mop:s:u:A:P:R:K:")) != EOF)
 163                 switch (ch) {
 164                 case 'b':
 165                         base_dir = optarg;
 166                         break;
 167 
 168                 case 'c':
 169                         comment = optarg;
 170                         break;
 171 
 172                 case 'D':
 173                         Dflag++;
 174                         break;
 175 
 176                 case 'd':
 177                         dir = optarg;
 178                         break;
 179 
 180                 case 'e':
 181                         expirestr = optarg;
 182                         break;
 183 
 184                 case 'f':
 185                         inactstr = optarg;
 186                         break;
 187 
 188                 case 'G':
 189                         grps = optarg;
 190                         break;
 191 
 192                 case 'g':
 193                         group = optarg;
 194                         break;
 195 
 196                 case 'k':
 197                         skel_dir = optarg;
 198                         break;
 199 
 200                 case 'm':
 201                         mflag++;
 202                         break;
 203 
 204                 case 'o':
 205                         oflag++;
 206                         break;
 207 
 208                 case 'p':
 209                         projects = optarg;
 210                         break;
 211 
 212                 case 's':
 213                         shell = optarg;
 214                         break;
 215 
 216                 case 'u':
 217                         uidstr = optarg;
 218                         break;
 219 
 220                 case 'A':
 221                         change_key(USERATTR_AUTHS_KW, optarg);
 222                         break;
 223 
 224                 case 'P':
 225                         change_key(USERATTR_PROFILES_KW, optarg);
 226                         break;
 227 
 228                 case 'R':
 229                         if (is_role(usertype)) {
 230                                 errmsg(M_ARUSAGE);
 231                                 exit(EX_SYNTAX);
 232                         }
 233                         change_key(USERATTR_ROLES_KW, optarg);
 234                         break;
 235 
 236                 case 'K':
 237                         change_key(NULL, optarg);
 238                         break;
 239 
 240                 default:
 241                 case '?':
 242                         if (is_role(usertype))
 243                                 errmsg(M_ARUSAGE);
 244                         else
 245                                 errmsg(M_AUSAGE);
 246                         exit(EX_SYNTAX);
 247                 }
 248 
 249         /* get defaults for adding new users */
 250         usrdefs = getusrdef(usertype);
 251 
 252         if (Dflag) {
 253                 /* DISPLAY mode */
 254 
 255                 /* check syntax */
 256                 if (optind != argc) {
 257                         if (is_role(usertype))
 258                                 errmsg(M_ARUSAGE);
 259                         else
 260                                 errmsg(M_AUSAGE);
 261                         exit(EX_SYNTAX);
 262                 }
 263 
 264                 if (uidstr != NULL || oflag || grps != NULL ||
 265                     dir != NULL || mflag || comment != NULL) {
 266                         if (is_role(usertype))
 267                                 errmsg(M_ARUSAGE);
 268                         else
 269                                 errmsg(M_AUSAGE);
 270                         exit(EX_SYNTAX);
 271                 }
 272 
 273                 /* Group must be an existing group */
 274                 if (group != NULL) {
 275                         switch (valid_group(group, &g_ptr, &warning)) {
 276                         case INVALID:
 277                                 errmsg(M_INVALID, group, "group id");
 278                                 exit(EX_BADARG);
 279                                 /*NOTREACHED*/
 280                         case TOOBIG:
 281                                 errmsg(M_TOOBIG, "gid", group);
 282                                 exit(EX_BADARG);
 283                                 /*NOTREACHED*/
 284                         case RESERVED:
 285                         case UNIQUE:
 286                                 errmsg(M_GRP_NOTUSED, group);
 287                                 exit(EX_NAME_NOT_EXIST);
 288                         }
 289                         if (warning)
 290                                 warningmsg(warning, group);
 291 
 292                         usrdefs->defgroup = g_ptr->gr_gid;
 293                         usrdefs->defgname = g_ptr->gr_name;
 294 
 295                 }
 296 
 297                 /* project must be an existing project */
 298                 if (projects != NULL) {
 299                         switch (valid_project(projects, &p_ptr, mybuf,
 300                             sizeof (mybuf), &warning)) {
 301                         case INVALID:
 302                                 errmsg(M_INVALID, projects, "project id");
 303                                 exit(EX_BADARG);
 304                                 /*NOTREACHED*/
 305                         case TOOBIG:
 306                                 errmsg(M_TOOBIG, "projid", projects);
 307                                 exit(EX_BADARG);
 308                                 /*NOTREACHED*/
 309                         case UNIQUE:
 310                                 errmsg(M_PROJ_NOTUSED, projects);
 311                                 exit(EX_NAME_NOT_EXIST);
 312                         }
 313                         if (warning)
 314                                 warningmsg(warning, projects);
 315 
 316                         usrdefs->defproj = p_ptr.pj_projid;
 317                         usrdefs->defprojname = p_ptr.pj_name;
 318                 }
 319 
 320                 /* base_dir must be an existing directory */
 321                 if (base_dir != NULL) {
 322                         valid_input(BASEDIR, base_dir);
 323                         usrdefs->defparent = base_dir;
 324                 }
 325 
 326                 /* inactivity period is an integer */
 327                 if (inactstr != NULL) {
 328                         /* convert inactstr to integer */
 329                         inact = strtol(inactstr, &ptr, 10);
 330                         if (*ptr || inact < 0) {
 331                                 errmsg(M_INVALID, inactstr,
 332                                     "inactivity period");
 333                                 exit(EX_BADARG);
 334                         }
 335 
 336                         usrdefs->definact = inact;
 337                 }
 338 
 339                 /* expiration string is a date, newer than today */
 340                 if (expirestr != NULL) {
 341                         if (*expirestr) {
 342                                 if (valid_expire(expirestr, (time_t *)0)
 343                                     == INVALID) {
 344                                         errmsg(M_INVALID, expirestr,
 345                                             "expiration date");
 346                                         exit(EX_BADARG);
 347                                 }
 348                                 usrdefs->defexpire = expirestr;
 349                         } else
 350                                 /* Unset the expiration date */
 351                                 usrdefs->defexpire = "";
 352                 }
 353 
 354                 if (shell != NULL) {
 355                         valid_input(SHELL, shell);
 356                         usrdefs->defshell = shell;
 357                 }
 358                 if (skel_dir != NULL) {
 359                         valid_input(SKELDIR, skel_dir);
 360                         usrdefs->defskel = skel_dir;
 361                 }
 362                 update_def(usrdefs);
 363 
 364                 /* change defaults for useradd */
 365                 if (putusrdef(usrdefs, usertype) < 0) {
 366                         errmsg(M_UPDATE, "created");
 367                         exit(EX_UPDATE);
 368                 }
 369 
 370                 /* Now, display */
 371                 dispusrdef(stdout, (D_ALL & ~D_RID), usertype);
 372                 exit(EX_SUCCESS);
 373 
 374         }
 375 
 376         /* ADD mode */
 377 
 378         /* check syntax */
 379         if (optind != argc - 1 || (skel_dir != NULL && !mflag)) {
 380                 if (is_role(usertype))
 381                         errmsg(M_ARUSAGE);
 382                 else
 383                         errmsg(M_AUSAGE);
 384                 exit(EX_SYNTAX);
 385         }
 386 
 387         logname = argv[optind];
 388         switch (valid_login(logname, (struct passwd **)NULL, &warning)) {
 389         case INVALID:
 390                 errmsg(M_INVALID, logname, "login name");
 391                 exit(EX_BADARG);
 392                 /*NOTREACHED*/
 393 
 394         case NOTUNIQUE:
 395                 errmsg(M_USED, logname);
 396                 exit(EX_NAME_EXISTS);
 397                 /*NOTREACHED*/
 398 
 399         case LONGNAME:
 400                 errmsg(M_TOO_LONG, logname);
 401                 exit(EX_BADARG);
 402                 /*NOTREACHED*/
 403         }
 404 
 405         if (warning)
 406                 warningmsg(warning, logname);
 407         if (uidstr != NULL) {
 408                 /* convert uidstr to integer */
 409                 errno = 0;
 410                 uid = (uid_t)strtol(uidstr, &ptr, (int)10);
 411                 if (*ptr || errno == ERANGE) {
 412                         errmsg(M_INVALID, uidstr, "user id");
 413                         exit(EX_BADARG);
 414                 }
 415 
 416                 switch (valid_uid(uid, NULL)) {
 417                 case NOTUNIQUE:
 418                         if (!oflag) {
 419                                 /* override not specified */
 420                                 errmsg(M_UID_USED, uid);
 421                                 exit(EX_ID_EXISTS);
 422                         }
 423                         break;
 424                 case RESERVED:
 425                         errmsg(M_RESERVED, uid);
 426                         break;
 427                 case TOOBIG:
 428                         errmsg(M_TOOBIG, "uid", uid);
 429                         exit(EX_BADARG);
 430                         break;
 431                 }
 432 
 433         } else {
 434 
 435                 if ((uid = findnextuid()) < 0) {
 436                         errmsg(M_INVALID, "default id", "user id");
 437                         exit(EX_ID_EXISTS);
 438                 }
 439         }
 440 
 441         if (group != NULL) {
 442                 switch (valid_group(group, &g_ptr, &warning)) {
 443                 case INVALID:
 444                         errmsg(M_INVALID, group, "group id");
 445                         exit(EX_BADARG);
 446                         /*NOTREACHED*/
 447                 case TOOBIG:
 448                         errmsg(M_TOOBIG, "gid", group);
 449                         exit(EX_BADARG);
 450                         /*NOTREACHED*/
 451                 case RESERVED:
 452                 case UNIQUE:
 453                         errmsg(M_GRP_NOTUSED, group);
 454                         exit(EX_NAME_NOT_EXIST);
 455                         /*NOTREACHED*/
 456                 }
 457 
 458                 if (warning)
 459                         warningmsg(warning, group);
 460                 gid = g_ptr->gr_gid;
 461 
 462         } else gid = usrdefs->defgroup;
 463 
 464         if (grps != NULL) {
 465                 if (!*grps)
 466                         /* ignore -G "" */
 467                         grps = (char *)0;
 468                 else if (!(gidlist = valid_lgroup(grps, gid)))
 469                         exit(EX_BADARG);
 470         }
 471 
 472         if (projects != NULL) {
 473                 if (! *projects)
 474                         projects = (char *)0;
 475                 else if (! (projlist = valid_lproject(projects)))
 476                         exit(EX_BADARG);
 477         }
 478 
 479         /* if base_dir is provided, check its validity; otherwise default */
 480         if (base_dir != NULL)
 481                 valid_input(BASEDIR, base_dir);
 482         else
 483                 base_dir = usrdefs->defparent;
 484 
 485         if (dir == NULL) {
 486                 /* set homedir to home directory made from base_dir */
 487                 (void) sprintf(homedir, "%s/%s", base_dir, logname);
 488 
 489         } else if (REL_PATH(dir)) {
 490                 errmsg(M_RELPATH, dir);
 491                 exit(EX_BADARG);
 492 
 493         } else
 494                 (void) strcpy(homedir, dir);
 495 
 496         if (mflag) {
 497                 /* Does home dir. already exist? */
 498                 if (stat(homedir, &statbuf) == 0) {
 499                         /* directory exists - don't try to create */
 500                         mflag = 0;
 501 
 502                         if (check_perm(statbuf, uid, gid, S_IXOTH) != 0)
 503                                 errmsg(M_NO_PERM, logname, homedir);
 504                 }
 505         }
 506         /*
 507          * if shell, skel_dir are provided, check their validity.
 508          * Otherwise default.
 509          */
 510         if (shell != NULL)
 511                 valid_input(SHELL, shell);
 512         else
 513                 shell = usrdefs->defshell;
 514 
 515         if (skel_dir != NULL)
 516                 valid_input(SKELDIR, skel_dir);
 517         else
 518                 skel_dir = usrdefs->defskel;
 519 
 520         if (inactstr != NULL) {
 521                 /* convert inactstr to integer */
 522                 inact = strtol(inactstr, &ptr, 10);
 523                 if (*ptr || inact < 0) {
 524                         errmsg(M_INVALID, inactstr, "inactivity period");
 525                         exit(EX_BADARG);
 526                 }
 527         } else inact = usrdefs->definact;
 528 
 529         /* expiration string is a date, newer than today */
 530         if (expirestr != NULL) {
 531                 if (*expirestr) {
 532                         if (valid_expire(expirestr, (time_t *)0) == INVALID) {
 533                                 errmsg(M_INVALID, expirestr, "expiration date");
 534                                 exit(EX_BADARG);
 535                         }
 536                         usrdefs->defexpire = expirestr;
 537                 } else
 538                         /* Unset the expiration date */
 539                         expirestr = (char *)0;
 540 
 541         } else expirestr = usrdefs->defexpire;
 542 
 543         import_def(usrdefs);
 544 
 545         /* must now call passmgmt */
 546 
 547         /* set up arguments to  passmgmt in nargv array */
 548         nargv = malloc((30 + nkeys * 2) * sizeof (char *));
 549         argindex = 0;
 550         nargv[argindex++] = PASSMGMT;
 551         nargv[argindex++] = "-a";       /* add */
 552 
 553         if (comment != NULL) {
 554                 /* comment */
 555                 nargv[argindex++] = "-c";
 556                 nargv[argindex++] = comment;
 557         }
 558 
 559         /* flags for home directory */
 560         nargv[argindex++] = "-h";
 561         nargv[argindex++] = homedir;
 562 
 563         /* set gid flag */
 564         nargv[argindex++] = "-g";
 565         (void) sprintf(gidstring, "%u", gid);
 566         nargv[argindex++] = gidstring;
 567 
 568         /* shell */
 569         nargv[argindex++] = "-s";
 570         nargv[argindex++] = shell;
 571 
 572         /* set inactive */
 573         nargv[argindex++] = "-f";
 574         (void) sprintf(inactstring, "%ld", inact);
 575         nargv[argindex++] = inactstring;
 576 
 577         /* set expiration date */
 578         if (expirestr != NULL) {
 579                 nargv[argindex++] = "-e";
 580                 nargv[argindex++] = expirestr;
 581         }
 582 
 583         /* set uid flag */
 584         nargv[argindex++] = "-u";
 585         (void) sprintf(uidstring, "%u", uid);
 586         nargv[argindex++] = uidstring;
 587 
 588         if (oflag) nargv[argindex++] = "-o";
 589 
 590         if (nkeys > 1)
 591                 addkey_args(nargv, &argindex);
 592 
 593         /* finally - login name */
 594         nargv[argindex++] = logname;
 595 
 596         /* set the last to null */
 597         nargv[argindex++] = NULL;
 598 
 599         /* now call passmgmt */
 600         ret = PEX_FAILED;
 601         /*
 602          * If call_passmgmt fails for any reason other than PEX_BADUID, exit
 603          * is invoked with an appropriate error message. If PEX_BADUID is
 604          * returned, then if the user specified the ID, exit is invoked
 605          * with an appropriate error message. Otherwise we try to pick a
 606          * different ID and try again. If we run out of IDs, i.e. no more
 607          * users can be created, then -1 is returned and we terminate via exit.
 608          * If PEX_BUSY is returned we increment a count, since we will stop
 609          * trying if PEX_BUSY reaches 3. For PEX_SUCCESS we immediately
 610          * terminate the loop.
 611          */
 612         while (busy < 3 && ret != PEX_SUCCESS) {
 613                 switch (ret = call_passmgmt(nargv)) {
 614                 case PEX_SUCCESS:
 615                         break;
 616                 case PEX_BUSY:
 617                         busy++;
 618                         break;
 619                 case PEX_HOSED_FILES:
 620                         errmsg(M_HOSED_FILES);
 621                         exit(EX_INCONSISTENT);
 622                         break;
 623 
 624                 case PEX_SYNTAX:
 625                 case PEX_BADARG:
 626                         /* should NEVER occur that passmgmt usage is wrong */
 627                         if (is_role(usertype))
 628                                 errmsg(M_ARUSAGE);
 629                         else
 630                                 errmsg(M_AUSAGE);
 631                         exit(EX_SYNTAX);
 632                         break;
 633 
 634                 case PEX_BADUID:
 635                         /*
 636                          * The uid has been taken. If it was specified by a
 637                          * user, then we must fail. Otherwise, keep trying
 638                          * to get a good uid until we run out of IDs.
 639                          */
 640                         if (uidstr != NULL) {
 641                                 errmsg(M_UID_USED, uid);
 642                                 exit(EX_ID_EXISTS);
 643                         } else {
 644                                 if ((uid = findnextuid()) < 0) {
 645                                         errmsg(M_INVALID, "default id",
 646                                             "user id");
 647                                         exit(EX_ID_EXISTS);
 648                                 }
 649                                 (void) sprintf(uidstring, "%u", uid);
 650                         }
 651                         break;
 652 
 653                 case PEX_BADNAME:
 654                         /* invalid loname */
 655                         errmsg(M_USED, logname);
 656                         exit(EX_NAME_EXISTS);
 657                         break;
 658 
 659                 default:
 660                         errmsg(M_UPDATE, "created");
 661                         exit(ret);
 662                         break;
 663                 }
 664         }
 665         if (busy == 3) {
 666                 errmsg(M_UPDATE, "created");
 667                 exit(ret);
 668         }
 669 
 670         /* add group entry */
 671         if ((grps != NULL) && edit_group(logname, (char *)0, gidlist, 0)) {
 672                 errmsg(M_UPDATE, "created");
 673                 cleanup(logname);
 674                 exit(EX_UPDATE);
 675         }
 676 
 677         /* update project database */
 678         if ((projects != NULL) &&
 679             edit_project(logname, (char *)NULL, projlist, 0)) {
 680                 errmsg(M_UPDATE, "created");
 681                 cleanup(logname);
 682                 exit(EX_UPDATE);
 683         }
 684 
 685         /* create home directory */
 686         if (mflag &&
 687             (create_home(homedir, skel_dir, uid, gid) != EX_SUCCESS)) {
 688                 (void) edit_group(logname, (char *)0, (int **)0, 1);
 689                 cleanup(logname);
 690                 exit(EX_HOMEDIR);
 691         }
 692 
 693         return (ret);
 694 }
 695 
 696 static void
 697 cleanup(logname)
 698 char *logname;
 699 {
 700         char *nargv[4];
 701 
 702         nargv[0] = PASSMGMT;
 703         nargv[1] = "-d";
 704         nargv[2] = logname;
 705         nargv[3] = NULL;
 706 
 707         switch (call_passmgmt(nargv)) {
 708         case PEX_SUCCESS:
 709                 break;
 710 
 711         case PEX_SYNTAX:
 712                 /* should NEVER occur that passmgmt usage is wrong */
 713                 if (is_role(usertype))
 714                         errmsg(M_ARUSAGE);
 715                 else
 716                         errmsg(M_AUSAGE);
 717                 break;
 718 
 719         case PEX_BADUID:
 720                 /* uid is used - shouldn't happen but print message anyway */
 721                 errmsg(M_UID_USED, uid);
 722                 break;
 723 
 724         case PEX_BADNAME:
 725                 /* invalid loname */
 726                 errmsg(M_USED, logname);
 727                 break;
 728 
 729         default:
 730                 errmsg(M_UPDATE, "created");
 731                 break;
 732         }
 733 }
 734 
 735 /* Check the validity for shell, base_dir and skel_dir */
 736 
 737 void
 738 valid_input(path_opt_t opt, const char *input)
 739 {
 740         struct stat     statbuf;
 741 
 742         if (REL_PATH(input)) {
 743                 errmsg(M_RELPATH, input);
 744                 exit(EX_BADARG);
 745         }
 746         if (stat(input, &statbuf) == -1) {
 747                 errmsg(M_INVALID, input, "path");
 748                 exit(EX_BADARG);
 749         }
 750         if (opt == SHELL) {
 751                 if (!S_ISREG(statbuf.st_mode) ||
 752                     (statbuf.st_mode & 0555) != 0555) {
 753                         errmsg(M_INVALID, input, "shell");
 754                         exit(EX_BADARG);
 755                 }
 756         } else {
 757                 if (!S_ISDIR(statbuf.st_mode)) {
 758                         errmsg(M_INVALID, input, "directory");
 759                         exit(EX_BADARG);
 760                 }
 761         }
 762 }