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