xref: /illumos-gate/usr/src/cmd/oamuser/user/userdefs.c (revision 49335bde)
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 
23 /*
24  * Copyright 2005 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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(FILE *fptr, unsigned flags, char *usertype)
225 {
226 	struct userdefs *deflts = getusrdef(usertype);
227 	int outcount = 0;
228 
229 	/* Print out values */
230 
231 	if (flags & D_GROUP) {
232 		outcount += fprintf(fptr, "group=%s,%ld  ",
233 			deflts->defgname, deflts->defgroup);
234 		PRINTNL();
235 	}
236 
237 	if (flags & D_PROJ) {
238 		outcount += fprintf(fptr, "project=%s,%ld  ",
239 		    deflts->defprojname, deflts->defproj);
240 		PRINTNL();
241 	}
242 
243 	if (flags & D_BASEDIR) {
244 		outcount += fprintf(fptr, "basedir=%s  ", deflts->defparent);
245 		PRINTNL();
246 	}
247 
248 	if (flags & D_RID) {
249 		outcount += fprintf(fptr, "rid=%ld  ", deflts->defrid);
250 		PRINTNL();
251 	}
252 
253 	if (flags & D_SKEL) {
254 		outcount += fprintf(fptr, "skel=%s  ", deflts->defskel);
255 		PRINTNL();
256 	}
257 
258 	if (flags & D_SHELL) {
259 		outcount += fprintf(fptr, "shell=%s  ", deflts->defshell);
260 		PRINTNL();
261 	}
262 
263 	if (flags & D_INACT) {
264 		outcount += fprintf(fptr, "inactive=%d  ", deflts->definact);
265 		PRINTNL();
266 	}
267 
268 	if (flags & D_EXPIRE) {
269 		outcount += fprintf(fptr, "expire=%s  ", deflts->defexpire);
270 		PRINTNL();
271 	}
272 
273 	if (flags & D_AUTH) {
274 		outcount += fprintf(fptr, "auths=%s  ", deflts->defauth);
275 		PRINTNL();
276 	}
277 
278 	if (flags & D_PROF) {
279 		outcount += fprintf(fptr, "profiles=%s  ", deflts->defprof);
280 		PRINTNL();
281 	}
282 
283 	if ((flags & D_ROLE) &&
284 	    (!is_role(usertype))) {
285 		outcount += fprintf(fptr, "roles=%s  ", deflts->defrole);
286 		PRINTNL();
287 	}
288 
289 	if (flags & D_LPRIV) {
290 		outcount += fprintf(fptr, "limitpriv=%s  ",
291 			deflts->deflimpriv);
292 		PRINTNL();
293 	}
294 
295 	if (flags & D_DPRIV) {
296 		outcount += fprintf(fptr, "defaultpriv=%s  ",
297 			deflts->defdfltpriv);
298 		PRINTNL();
299 	}
300 
301 	if (flags & D_LOCK) {
302 		outcount += fprintf(fptr, "lock_after_retries=%s  ",
303 		    deflts->deflock_after_retries);
304 	}
305 
306 	if (outcount > 0)
307 		(void) fprintf(fptr, "\n");
308 }
309 
310 /*
311  * putusrdef -
312  * 	changes default values in defadduser file
313  */
314 int
315 putusrdef(struct userdefs *defs, char *usertype)
316 {
317 	time_t timeval;		/* time value from time */
318 	int i;
319 	ptrdiff_t skip;
320 	char *hdr;
321 
322 	/*
323 	 * file format is:
324 	 * #<tab>Default values for adduser.  Changed mm/dd/yy hh:mm:ss.
325 	 * defgroup=m	(m=default group id)
326 	 * defgname=str1	(str1=default group name)
327 	 * defparent=str2	(str2=default base directory)
328 	 * definactive=x	(x=default inactive)
329 	 * defexpire=y		(y=default expire)
330 	 * defproj=z		(z=numeric project id)
331 	 * defprojname=str3	(str3=default project name)
332 	 * ... etc ...
333 	 */
334 
335 	if (is_role(usertype)) {
336 		if ((defptr = fopen(DEFROLEFILE, "w")) == NULL) {
337 			errmsg(M_FAILED);
338 			return (EX_UPDATE);
339 		}
340 	} else {
341 		if ((defptr = fopen(DEFFILE, "w")) == NULL) {
342 			errmsg(M_FAILED);
343 			return (EX_UPDATE);
344 		}
345 	}
346 
347 	if (lockf(fileno(defptr), F_LOCK, 0) != 0) {
348 		/* print error if can't lock whole of DEFFILE */
349 		errmsg(M_UPDATE, "created");
350 		return (EX_UPDATE);
351 	}
352 
353 	if (is_role(usertype)) {
354 		/* If it's a role, we must skip the defrole field */
355 		skip = offsetof(struct userdefs, defrole);
356 		hdr = FHEADER_ROLE;
357 	} else {
358 		skip = -1;
359 		hdr = FHEADER;
360 	}
361 
362 	/* get time */
363 	timeval = time(NULL);
364 
365 	/* write it to file */
366 	if (fprintf(defptr, "%s%s\n", hdr, ctime(&timeval)) <= 0) {
367 		errmsg(M_UPDATE, "created");
368 		return (EX_UPDATE);
369 	}
370 
371 	for (i = 0; i < NDEF; i++) {
372 		int res = 0;
373 
374 		if (tab[i].off == skip)
375 			continue;
376 
377 		switch (tab[i].type) {
378 		case INT:
379 			res = fprintf(defptr, "%s%d\n", tab[i].name,
380 					FIELD(defs, &tab[i], int));
381 			break;
382 		case STR:
383 			res = fprintf(defptr, "%s%s\n", tab[i].name,
384 					FIELD(defs, &tab[i], char *));
385 			break;
386 		case PROJID:
387 			res = fprintf(defptr, "%s%d\n", tab[i].name,
388 					(int)FIELD(defs, &tab[i], projid_t));
389 			break;
390 		}
391 
392 		if (res <= 0) {
393 			errmsg(M_UPDATE, "created");
394 			return (EX_UPDATE);
395 		}
396 	}
397 
398 	(void) lockf(fileno(defptr), F_ULOCK, 0);
399 	(void) fclose(defptr);
400 
401 	return (EX_SUCCESS);
402 }
403 
404 /* Export command line keys to defaults for useradd -D */
405 void
406 update_def(struct userdefs *ud)
407 {
408 	int i;
409 
410 	for (i = 0; i < NDEF; i++) {
411 		char *val;
412 		if (tab[i].uakey != NULL &&
413 		    (val = getsetdefval(tab[i].uakey, NULL)) != NULL)
414 			FIELD(ud, &tab[i], char *) = val;
415 	}
416 }
417 
418 /* Import default keys for ordinary useradd */
419 void
420 import_def(struct userdefs *ud)
421 {
422 	int i;
423 
424 	for (i = 0; i < NDEF; i++) {
425 		if (tab[i].uakey != NULL && tab[i].type == STR) {
426 			char *val = FIELD(ud, &tab[i], char *);
427 			if (val == getsetdefval(tab[i].uakey, val))
428 				nkeys ++;
429 		}
430 	}
431 }
432