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 * Copyright 2016 Gordon W. Ross
35 */
36
37 /*
38 * Get values for things that were historically constants in userdefs.h
39 * i.e. DEFRID, DEFSHL
40 *
41 * Several things copied or moved from:
42 * $SRC/cmd/oamuser/user/userdefs.c
43 */
44
45 /*LINTLIBRARY*/
46 #define _USERDEFS_INTERNAL 1
47
48 #include <sys/types.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <userdefs.h>
52 #include <user_attr.h>
53 #include <limits.h>
54 #include <stdlib.h>
55 #include <stddef.h>
56 #include <time.h>
57 #include <unistd.h>
58
59 #define STR_SZ 512
60 #define SKIPWS(ptr) while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++
61
62 static char *zap_nl(char *);
63 static int fwrite_defs(FILE *, struct userdefs *, char *, ptrdiff_t);
64
65 static char user_defgname[STR_SZ] = DEFGNAME;
66 static char user_defparent[STR_SZ] = DEFPARENT;
67 static char user_defskel[STR_SZ] = DEFSKL;
68 static char user_defshell[STR_SZ] = DEFSHL;
69 static char user_defexpire[STR_SZ] = DEFEXPIRE;
70 static char user_defauth[STR_SZ] = DEFAUTH;
71 static char user_defprof[STR_SZ] = DEFPROF;
72 static char user_defrole[STR_SZ] = DEFROLE;
73 static char user_defprojname[STR_SZ] = DEFPROJNAME;
74 static char user_deflimpriv[STR_SZ] = DEFLIMPRIV;
75 static char user_defdfltpriv[STR_SZ] = DEFDFLTPRIV;
76 static char user_deflock_a_r[STR_SZ] = DEFLOCK_AFTER_RETRIES;
77
78 static struct userdefs userdefs = {
79 DEFRID,
80 DEFGROUP,
81 user_defgname,
82 user_defparent,
83 user_defskel,
84 user_defshell,
85 DEFINACT,
86 user_defexpire,
87 user_defauth,
88 user_defprof,
89 user_defrole,
90 DEFPROJ,
91 user_defprojname,
92 user_deflimpriv,
93 user_defdfltpriv,
94 user_deflock_a_r
95 };
96
97 static char role_defgname[STR_SZ] = DEFGNAME;
98 static char role_defparent[STR_SZ] = DEFPARENT;
99 static char role_defskel[STR_SZ] = DEFSKL;
100 static char role_defshell[STR_SZ] = DEFROLESHL; /* role! */
101 static char role_defexpire[STR_SZ] = DEFEXPIRE;
102 static char role_defauth[STR_SZ] = DEFAUTH;
103 static char role_defprof[STR_SZ] = DEFROLEPROF; /* role! */
104 static char role_defprojname[STR_SZ] = DEFPROJNAME;
105 static char role_deflimpriv[STR_SZ] = DEFLIMPRIV;
106 static char role_defdfltpriv[STR_SZ] = DEFDFLTPRIV;
107 static char role_deflock_a_r[STR_SZ] = DEFLOCK_AFTER_RETRIES;
108
109 static struct userdefs roledefs = {
110 DEFRID,
111 DEFGROUP,
112 role_defgname,
113 role_defparent,
114 role_defskel,
115 role_defshell,
116 DEFINACT,
117 role_defexpire,
118 role_defauth,
119 role_defprof,
120 "", /* not changeable */
121 DEFPROJ,
122 role_defprojname,
123 role_deflimpriv,
124 role_defdfltpriv,
125 role_deflock_a_r
126 };
127
128 #define INT 0
129 #define STR 1
130 #define PROJID 2
131
132 #define DEFOFF(field) offsetof(struct userdefs, field)
133 #define FIELD(up, pe, type) (*(type *)((char *)(up) + (pe)->off))
134
135 typedef struct parsent {
136 const char *name; /* deffoo= */
137 const size_t nmsz; /* length of def= string (excluding \0) */
138 const int type; /* type of entry */
139 const ptrdiff_t off; /* offset in userdefs structure */
140 const char *uakey; /* user_attr key, if defined */
141 } parsent_t;
142
143 /* BEGIN CSTYLED */
144 static const parsent_t tab[] = {
145 { RIDSTR, sizeof (RIDSTR) - 1, INT, DEFOFF(defrid) }, /* DEFRID */
146 { GIDSTR, sizeof (GIDSTR) - 1, INT, DEFOFF(defgroup) }, /* DEFGROUP */
147 { GNAMSTR, sizeof (GNAMSTR) - 1, STR, DEFOFF(defgname) }, /* DEFGNAME */
148 { PARSTR, sizeof (PARSTR) - 1, STR, DEFOFF(defparent) }, /* DEFPARENT */
149 { SKLSTR, sizeof (SKLSTR) - 1, STR, DEFOFF(defskel) }, /* DEFSKL */
150 { SHELLSTR, sizeof (SHELLSTR) - 1, STR, DEFOFF(defshell) }, /* DEFSHL, DEFROLESHL */
151 { INACTSTR, sizeof (INACTSTR) - 1, INT, DEFOFF(definact) }, /* DEFINACT */
152 { EXPIRESTR, sizeof (EXPIRESTR) - 1, STR, DEFOFF(defexpire) }, /* DEFEXPIRE */
153 { AUTHSTR, sizeof (AUTHSTR) - 1, STR, DEFOFF(defauth), /* DEFAUTH */
154 USERATTR_AUTHS_KW },
155 { PROFSTR, sizeof (PROFSTR) - 1, STR, DEFOFF(defprof), /* DEFPROF, DEFROLEPROF */
156 USERATTR_PROFILES_KW },
157 { ROLESTR, sizeof (ROLESTR) - 1, STR, DEFOFF(defrole), /* DEFROLE */
158 USERATTR_ROLES_KW },
159 { PROJSTR, sizeof (PROJSTR) - 1, PROJID, DEFOFF(defproj) }, /* DEFPROJ */
160 { PROJNMSTR, sizeof (PROJNMSTR) - 1, STR, DEFOFF(defprojname) }, /* DEFPROJNAME */
161 { LIMPRSTR, sizeof (LIMPRSTR) - 1, STR, DEFOFF(deflimpriv), /* DEFLIMPRIV */
162 USERATTR_LIMPRIV_KW },
163 { DFLTPRSTR, sizeof (DFLTPRSTR) - 1, STR, DEFOFF(defdfltpriv), /* DEFDFLTPRIV */
164 USERATTR_DFLTPRIV_KW },
165 { LOCK_AFTER_RETRIESSTR, sizeof (LOCK_AFTER_RETRIESSTR) - 1, /* DEFLOCK_AFTER_RETRIES */
166 STR, DEFOFF(deflock_after_retries),
167 USERATTR_LOCK_AFTER_RETRIES_KW },
168 };
169 /* END CSTYLED */
170
171 #define NDEF (sizeof (tab) / sizeof (parsent_t))
172
173 static const parsent_t *
174 scan(char **start_p)
175 {
176 static int ind = NDEF - 1;
177 char *cur_p = *start_p;
178 int lastind = ind;
179
180 if (!*cur_p || *cur_p == '\n' || *cur_p == '#')
181 return (NULL);
182
183 /*
184 * The magic in this loop is remembering the last index when
185 * reentering the function; the entries above are also used to
186 * order the output to the default file.
187 */
188 do {
189 ind++;
190 ind %= NDEF;
191
192 if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) {
193 *start_p = cur_p + tab[ind].nmsz;
194 return (&tab[ind]);
195 }
196 } while (ind != lastind);
197
198 return (NULL);
199 }
200
201 /*
202 * getusrdef - access the user defaults file. If it doesn't exist,
203 * then returns default values of (values in userdefs.h):
204 * defrid = 100
205 * defgroup = 1
206 * defgname = other
207 * defparent = /home
208 * defskel = /usr/sadm/skel
209 * defshell = /bin/sh
210 * definact = 0
211 * defexpire = 0
212 * defauth = 0
213 * defprof = 0
214 * defrole = 0
215 *
216 * If getusrdef() is unable to access the defaults file, it
217 * returns a NULL pointer.
218 *
219 * If user defaults file exists, then getusrdef uses values
220 * in it to override the above values.
221 *
222 * Note that the userdefs_loaded, roledefs_loaded flags are
223 * more than an optimization. Once we've return the struct
224 * to the caller, they may change any of the string members
225 * with pointers to constant strings etc. If we were to run
226 * fread_defs() after that, it could segv trying to copy the
227 * strings from the scanner onto those constant strings.
228 */
229
230 static int roledefs_loaded = 0;
231
232 struct userdefs *
233 _get_roledefs()
234 {
235 FILE *fp;
236
237 if (roledefs_loaded == 0) {
238
239 fp = fopen(ODEFROLEFILE, "r");
240 if (fp != NULL) {
241 fread_defs(fp, &roledefs, B_TRUE);
242 (void) fclose(fp);
243 }
244
245 fp = fopen(DEFROLEFILE, "r");
246 if (fp != NULL) {
247 fread_defs(fp, &roledefs, B_TRUE);
248 (void) fclose(fp);
249 }
250
251 roledefs_loaded = 1;
252 }
253 return (&roledefs);
254 }
255
256 static int userdefs_loaded = 0;
257
258 struct userdefs *
259 _get_userdefs()
260 {
261 FILE *fp;
262
263 if (userdefs_loaded == 0) {
264
265 fp = fopen(ODEFFILE, "r");
266 if (fp != NULL) {
267 fread_defs(fp, &userdefs, B_FALSE);
268 (void) fclose(fp);
269 }
270
271 fp = fopen(DEFFILE, "r");
272 if (fp != NULL) {
273 fread_defs(fp, &userdefs, B_FALSE);
274 (void) fclose(fp);
275 }
276
277 userdefs_loaded = 1;
278 }
279 return (&userdefs);
280 }
281
282 void
283 fread_defs(FILE *fp, struct userdefs *ud, boolean_t role)
284 {
285 char instr[STR_SZ], *ptr;
286 const parsent_t *pe;
287
288 while (fgets(instr, sizeof (instr), fp) != NULL) {
289 ptr = instr;
290
291 SKIPWS(ptr);
292
293 if (*ptr == '#')
294 continue;
295
296 pe = scan(&ptr);
297
298 if (pe != NULL) {
299 /*
300 * If reading a role file, should not see defrole,
301 * but in case we do, just skip it.
302 */
303 if (role && pe->off == DEFOFF(defrole))
304 continue;
305
306 switch (pe->type) {
307 case INT:
308 FIELD(ud, pe, int) =
309 (int)strtol(ptr, NULL, 10);
310 break;
311 case PROJID:
312 FIELD(ud, pe, projid_t) =
313 (projid_t)strtol(ptr, NULL, 10);
314 break;
315 case STR:
316 /*
317 * Copy into static storage here (avoiding
318 * strdup) so _get_userdefs() doesn't leak.
319 * In here we know the userdefs struct has
320 * all STR struct members pointing to our
321 * static buffers of size STR_SZ.
322 */
323 (void) strlcpy(FIELD(ud, pe, char *),
324 zap_nl(ptr), STR_SZ);
325 break;
326 }
327 }
328 }
329 }
330
331 static char *
332 zap_nl(char *s)
333 {
334 char *p = strchr(s, '\n');
335 if (p != NULL)
336 *p = '\0';
337
338 return (s);
339 }
340
341 extern int
342 fwrite_roledefs(struct __FILE *fp, struct userdefs *defs)
343 {
344 ptrdiff_t skip;
345 char *hdr;
346
347 /* This is a role, so we must skip the defrole field */
348 skip = offsetof(struct userdefs, defrole);
349 hdr = FHEADER_ROLE;
350
351 return (fwrite_defs(fp, defs, hdr, skip));
352 }
353
354 extern int
355 fwrite_userdefs(struct __FILE *fp, struct userdefs *defs)
356 {
357 ptrdiff_t skip;
358 char *hdr;
359
360 skip = -1;
361 hdr = FHEADER;
362
363 return (fwrite_defs(fp, defs, hdr, skip));
364 }
365
366 /*
367 * fwrite_defs
368 * changes default values in defadduser file
369 * Returns:
370 * <= 0: error
371 * > 0: success
372 */
373 static int
374 fwrite_defs(FILE *fp, struct userdefs *defs, char *hdr, ptrdiff_t skip)
375 {
376 time_t timeval; /* time value from time */
377 int i, res;
378
379 /*
380 * file format is:
381 * #<tab>Default values for adduser. Changed mm/dd/yy hh:mm:ss.
382 * defgroup=m (m=default group id)
383 * defgname=str1 (str1=default group name)
384 * defparent=str2 (str2=default base directory)
385 * definactive=x (x=default inactive)
386 * defexpire=y (y=default expire)
387 * defproj=z (z=numeric project id)
388 * defprojname=str3 (str3=default project name)
389 * ... etc ...
390 */
391
392 /* get time */
393 timeval = time(NULL);
394
395 /* write it to file */
396 res = fprintf(fp, "%s%s\n", hdr, ctime(&timeval));
397 if (res <= 0)
398 return (res);
399
400 for (i = 0; i < NDEF; i++) {
401 res = 0;
402
403 if (tab[i].off == skip)
404 continue;
405
406 switch (tab[i].type) {
407 case INT:
408 res = fprintf(fp, "%s%d\n", tab[i].name,
409 FIELD(defs, &tab[i], int));
410 break;
411 case STR:
412 res = fprintf(fp, "%s%s\n", tab[i].name,
413 FIELD(defs, &tab[i], char *));
414 break;
415 case PROJID:
416 res = fprintf(fp, "%s%d\n", tab[i].name,
417 (int)FIELD(defs, &tab[i], projid_t));
418 break;
419 }
420
421 if (res <= 0) {
422 return (res);
423 }
424 }
425
426 return (1);
427 }
428
429 /*
430 * Import a default key for ordinary useradd.
431 * Caller already did: ud = getusrdef();
432 */
433 char *
434 userdef_get_by_uakey(struct userdefs *ud, const char *key)
435 {
436 int i;
437
438 for (i = 0; i < NDEF; i++) {
439 if (tab[i].uakey != NULL &&
440 tab[i].type == STR &&
441 strcmp(tab[i].uakey, key) == 0)
442 return (FIELD(ud, &tab[i], char *));
443 }
444 return (NULL);
445 }
446
447 /* Export a command line key to defaults for useradd -D */
448 void
449 userdef_set_by_uakey(struct userdefs *ud, const char *key, char *val)
450 {
451 int i;
452
453 for (i = 0; i < NDEF; i++) {
454 if (tab[i].uakey != NULL &&
455 tab[i].type == STR &&
456 strcmp(tab[i].uakey, key) == 0) {
457 /*
458 * Don't strlcpy here because the calling program
459 * may have changed the struct member to point to
460 * something other than our static buffers.
461 * If this leaks, it's the caller's fault.
462 */
463 FIELD(ud, &tab[i], char *) = val;
464 }
465 }
466 }