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