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