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
59static char *dup_to_nl(char *);
60
61static 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
75typedef 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
83static 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
110FILE *defptr;		/* default file - fptr */
111
112static const parsent_t *
113scan(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
162struct userdefs *
163getusrdef(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
211static char *
212dup_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
223void
224dispusrdef(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 */
314int
315putusrdef(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 */
405void
406update_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 */
419void
420import_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