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