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