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