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