xref: /illumos-gate/usr/src/cmd/oamuser/user/userdefs.c (revision 7c478bd9)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI" /* SVr4.0 1.4 */
32 
33 
34 /*LINTLIBRARY*/
35 
36 #include	<sys/types.h>
37 #include	<stdio.h>
38 #include	<string.h>
39 #include	<userdefs.h>
40 #include	<user_attr.h>
41 #include	<limits.h>
42 #include	<stdlib.h>
43 #include	<stddef.h>
44 #include	<time.h>
45 #include	<unistd.h>
46 #include	"userdisp.h"
47 #include	"funcs.h"
48 #include	"messages.h"
49 
50 /* Print out a NL when the line gets too long */
51 #define	PRINTNL()	\
52 	if (outcount > 40) { \
53 		outcount = 0; \
54 		(void) fprintf(fptr, "\n"); \
55 	}
56 
57 #define	SKIPWS(ptr)	while (*ptr && *ptr == ' ' || *ptr == '\t') ptr++
58 
59 static char *dup_to_nl(char *);
60 
61 static struct userdefs defaults = {
62 	DEFRID, DEFGROUP, DEFGNAME, DEFPARENT, DEFSKL,
63 	DEFSHL, DEFINACT, DEFEXPIRE, DEFAUTH, DEFPROF,
64 	DEFROLE, DEFPROJ, DEFPROJNAME, DEFLIMPRIV,
65 	DEFDFLTPRIV, DEFLOCK_AFTER_RETRIES
66 };
67 
68 #define	INT	0
69 #define	STR	1
70 #define	PROJID	2
71 
72 #define	DEFOFF(field)		offsetof(struct userdefs, field)
73 #define	FIELD(up, pe, type)	(*(type *)((char *)(up) + (pe)->off))
74 
75 typedef struct parsent {
76 	const char *name;	/* deffoo= */
77 	const size_t nmsz;	/* length of def= string (excluding \0) */
78 	const int type;		/* type of entry */
79 	const ptrdiff_t off;	/* offset in userdefs structure */
80 	const char *uakey;	/* user_attr key, if defined */
81 } parsent_t;
82 
83 static const parsent_t tab[] = {
84 	{ GIDSTR,	sizeof (GIDSTR) - 1,	INT,	DEFOFF(defgroup) },
85 	{ GNAMSTR,	sizeof (GNAMSTR) - 1,	STR,	DEFOFF(defgname) },
86 	{ PARSTR,	sizeof (PARSTR) - 1,	STR,	DEFOFF(defparent) },
87 	{ SKLSTR,	sizeof (SKLSTR) - 1,	STR,	DEFOFF(defskel) },
88 	{ SHELLSTR,	sizeof (SHELLSTR) - 1,	STR,	DEFOFF(defshell) },
89 	{ INACTSTR,	sizeof (INACTSTR) - 1,	INT,	DEFOFF(definact) },
90 	{ EXPIRESTR,	sizeof (EXPIRESTR) - 1,	STR,	DEFOFF(defexpire) },
91 	{ AUTHSTR,	sizeof (AUTHSTR) - 1,	STR,	DEFOFF(defauth),
92 		USERATTR_AUTHS_KW },
93 	{ ROLESTR,	sizeof (ROLESTR) - 1,	STR,	DEFOFF(defrole),
94 		USERATTR_ROLES_KW },
95 	{ PROFSTR,	sizeof (PROFSTR) - 1,	STR,	DEFOFF(defprof),
96 		USERATTR_PROFILES_KW },
97 	{ PROJSTR,	sizeof (PROJSTR) - 1,	PROJID,	DEFOFF(defproj) },
98 	{ PROJNMSTR,	sizeof (PROJNMSTR) - 1,	STR,	DEFOFF(defprojname) },
99 	{ LIMPRSTR,	sizeof (LIMPRSTR) - 1,	STR,	DEFOFF(deflimpriv),
100 		USERATTR_LIMPRIV_KW },
101 	{ DFLTPRSTR,	sizeof (DFLTPRSTR) - 1,	STR,	DEFOFF(defdfltpriv),
102 		USERATTR_DFLTPRIV_KW },
103 	{ LOCK_AFTER_RETRIESSTR,	sizeof (LOCK_AFTER_RETRIESSTR) - 1,
104 		STR,	DEFOFF(deflock_after_retries),
105 		USERATTR_LOCK_AFTER_RETRIES_KW },
106 };
107 
108 #define	NDEF	(sizeof (tab) / sizeof (parsent_t))
109 
110 FILE *defptr;		/* default file - fptr */
111 
112 static const parsent_t *
113 scan(char **start_p)
114 {
115 	static int ind = NDEF - 1;
116 	char *cur_p = *start_p;
117 	int lastind = ind;
118 
119 	if (!*cur_p || *cur_p == '\n' || *cur_p == '#')
120 		return (NULL);
121 
122 	/*
123 	 * The magic in this loop is remembering the last index when
124 	 * reentering the function; the entries above are also used to
125 	 * order the output to the default file.
126 	 */
127 	do {
128 		ind++;
129 		ind %= NDEF;
130 
131 		if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) {
132 			*start_p = cur_p + tab[ind].nmsz;
133 			return (&tab[ind]);
134 		}
135 	} while (ind != lastind);
136 
137 	return (NULL);
138 }
139 
140 /*
141  * getusrdef - access the user defaults file.  If it doesn't exist,
142  *		then returns default values of (values in userdefs.h):
143  *		defrid = 100
144  *		defgroup = 1
145  *		defgname = other
146  *		defparent = /home
147  *		defskel	= /usr/sadm/skel
148  *		defshell = /bin/sh
149  *		definact = 0
150  *		defexpire = 0
151  *		defauth = 0
152  *		defprof = 0
153  *		defrole = 0
154  *
155  *	If getusrdef() is unable to access the defaults file, it
156  *	returns a NULL pointer.
157  *
158  * 	If user defaults file exists, then getusrdef uses values
159  *  in it to override the above values.
160  */
161 
162 struct userdefs *
163 getusrdef(char *usertype)
164 {
165 	char instr[512], *ptr;
166 	const parsent_t *pe;
167 
168 	if (is_role(usertype)) {
169 		if ((defptr = fopen(DEFROLEFILE, "r")) == NULL) {
170 			defaults.defshell = DEFROLESHL;
171 			defaults.defprof = DEFROLEPROF;
172 			return (&defaults);
173 		}
174 	} else {
175 		if ((defptr = fopen(DEFFILE, "r")) == NULL)
176 			return (&defaults);
177 	}
178 
179 	while (fgets(instr, sizeof (instr), defptr) != NULL) {
180 		ptr = instr;
181 
182 		SKIPWS(ptr);
183 
184 		if (*ptr == '#')
185 			continue;
186 
187 		pe = scan(&ptr);
188 
189 		if (pe != NULL) {
190 			switch (pe->type) {
191 			case INT:
192 				FIELD(&defaults, pe, int) =
193 					(int)strtol(ptr, NULL, 10);
194 				break;
195 			case PROJID:
196 				FIELD(&defaults, pe, projid_t) =
197 					(projid_t)strtol(ptr, NULL, 10);
198 				break;
199 			case STR:
200 				FIELD(&defaults, pe, char *) = dup_to_nl(ptr);
201 				break;
202 			}
203 		}
204 	}
205 
206 	(void) fclose(defptr);
207 
208 	return (&defaults);
209 }
210 
211 static char *
212 dup_to_nl(char *from)
213 {
214 	char *res = strdup(from);
215 
216 	char *p = strchr(res, '\n');
217 	if (p)
218 		*p = '\0';
219 
220 	return (res);
221 }
222 
223 void
224 dispusrdef(fptr, flags, usertype)
225 FILE *fptr;
226 unsigned flags;
227 char *usertype;
228 {
229 	struct userdefs *deflts = getusrdef(usertype);
230 	register outcount = 0;
231 
232 	/* Print out values */
233 
234 	if (flags & D_GROUP) {
235 		outcount += fprintf(fptr, "group=%s,%ld  ",
236 			deflts->defgname, deflts->defgroup);
237 		PRINTNL();
238 	}
239 
240 	if (flags & D_PROJ) {
241 		outcount += fprintf(fptr, "project=%s,%ld  ",
242 		    deflts->defprojname, deflts->defproj);
243 		PRINTNL();
244 	}
245 
246 	if (flags & D_BASEDIR) {
247 		outcount += fprintf(fptr, "basedir=%s  ", deflts->defparent);
248 		PRINTNL();
249 	}
250 
251 	if (flags & D_RID) {
252 		outcount += fprintf(fptr, "rid=%ld  ", deflts->defrid);
253 		PRINTNL();
254 	}
255 
256 	if (flags & D_SKEL) {
257 		outcount += fprintf(fptr, "skel=%s  ", deflts->defskel);
258 		PRINTNL();
259 	}
260 
261 	if (flags & D_SHELL) {
262 		outcount += fprintf(fptr, "shell=%s  ", deflts->defshell);
263 		PRINTNL();
264 	}
265 
266 	if (flags & D_INACT) {
267 		outcount += fprintf(fptr, "inactive=%d  ", deflts->definact);
268 		PRINTNL();
269 	}
270 
271 	if (flags & D_EXPIRE) {
272 		outcount += fprintf(fptr, "expire=%s  ", deflts->defexpire);
273 		PRINTNL();
274 	}
275 
276 	if (flags & D_AUTH) {
277 		outcount += fprintf(fptr, "auths=%s  ", deflts->defauth);
278 		PRINTNL();
279 	}
280 
281 	if (flags & D_PROF) {
282 		outcount += fprintf(fptr, "profiles=%s  ", deflts->defprof);
283 		PRINTNL();
284 	}
285 
286 	if ((flags & D_ROLE) &&
287 	    (!is_role(usertype))) {
288 		outcount += fprintf(fptr, "roles=%s  ", deflts->defrole);
289 		PRINTNL();
290 	}
291 
292 	if (flags & D_LPRIV) {
293 		outcount += fprintf(fptr, "limitpriv=%s  ",
294 			deflts->deflimpriv);
295 		PRINTNL();
296 	}
297 
298 	if (flags & D_DPRIV) {
299 		outcount += fprintf(fptr, "defaultpriv=%s  ",
300 			deflts->defdfltpriv);
301 		PRINTNL();
302 	}
303 
304 	if (flags & D_LOCK) {
305 		outcount += fprintf(fptr, "lock_after_retries=%s  ",
306 		    deflts->deflock_after_retries);
307 	}
308 
309 	if (outcount > 0)
310 		(void) fprintf(fptr, "\n");
311 }
312 
313 /*
314  * putusrdef -
315  * 	changes default values in defadduser file
316  */
317 int
318 putusrdef(struct userdefs *defs, char *usertype)
319 {
320 	time_t timeval;		/* time value from time */
321 	int i;
322 	ptrdiff_t skip;
323 	char *hdr;
324 
325 	/*
326 	 * file format is:
327 	 * #<tab>Default values for adduser.  Changed mm/dd/yy hh:mm:ss.
328 	 * defgroup=m	(m=default group id)
329 	 * defgname=str1	(str1=default group name)
330 	 * defparent=str2	(str2=default base directory)
331 	 * definactive=x	(x=default inactive)
332 	 * defexpire=y		(y=default expire)
333 	 * defproj=z		(z=numeric project id)
334 	 * defprojname=str3	(str3=default project name)
335 	 * ... etc ...
336 	 */
337 
338 	if (is_role(usertype)) {
339 		if ((defptr = fopen(DEFROLEFILE, "w")) == NULL) {
340 			errmsg(M_FAILED);
341 			return (EX_UPDATE);
342 		}
343 	} else {
344 		if ((defptr = fopen(DEFFILE, "w")) == NULL) {
345 			errmsg(M_FAILED);
346 			return (EX_UPDATE);
347 		}
348 	}
349 
350 	if (lockf(fileno(defptr), F_LOCK, 0) != 0) {
351 		/* print error if can't lock whole of DEFFILE */
352 		errmsg(M_UPDATE, "created");
353 		return (EX_UPDATE);
354 	}
355 
356 	if (is_role(usertype)) {
357 		/* If it's a role, we must skip the defrole field */
358 		skip = offsetof(struct userdefs, defrole);
359 		hdr = FHEADER_ROLE;
360 	} else {
361 		skip = -1;
362 		hdr = FHEADER;
363 	}
364 
365 	/* get time */
366 	timeval = time(NULL);
367 
368 	/* write it to file */
369 	if (fprintf(defptr, "%s%s\n", hdr, ctime(&timeval)) <= 0) {
370 		errmsg(M_UPDATE, "created");
371 		return (EX_UPDATE);
372 	}
373 
374 	for (i = 0; i < NDEF; i++) {
375 		int res = 0;
376 
377 		if (tab[i].off == skip)
378 			continue;
379 
380 		switch (tab[i].type) {
381 		case INT:
382 			res = fprintf(defptr, "%s%d\n", tab[i].name,
383 					FIELD(defs, &tab[i], int));
384 			break;
385 		case STR:
386 			res = fprintf(defptr, "%s%s\n", tab[i].name,
387 					FIELD(defs, &tab[i], char *));
388 			break;
389 		case PROJID:
390 			res = fprintf(defptr, "%s%d\n", tab[i].name,
391 					(int)FIELD(defs, &tab[i], projid_t));
392 			break;
393 		}
394 
395 		if (res <= 0) {
396 			errmsg(M_UPDATE, "created");
397 			return (EX_UPDATE);
398 		}
399 	}
400 
401 	(void) lockf(fileno(defptr), F_ULOCK, 0);
402 	(void) fclose(defptr);
403 
404 	return (EX_SUCCESS);
405 }
406 
407 /* Export command line keys to defaults for useradd -D */
408 void
409 update_def(struct userdefs *ud)
410 {
411 	int i;
412 
413 	for (i = 0; i < NDEF; i++) {
414 		char *val;
415 		if (tab[i].uakey != NULL &&
416 		    (val = getsetdefval(tab[i].uakey, NULL)) != NULL)
417 			FIELD(ud, &tab[i], char *) = val;
418 	}
419 }
420 
421 /* Import default keys for ordinary useradd */
422 void
423 import_def(struct userdefs *ud)
424 {
425 	int i;
426 
427 	for (i = 0; i < NDEF; i++) {
428 		if (tab[i].uakey != NULL && tab[i].type == STR) {
429 			char *val = FIELD(ud, &tab[i], char *);
430 			if (val == getsetdefval(tab[i].uakey, val))
431 				nkeys ++;
432 		}
433 	}
434 }
435