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 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
34 */
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) == '\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, DEFROLEAUTH
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 { ROLEAUTHSTR, sizeof (ROLEAUTHSTR) - 1, STR, DEFOFF(defroleauth),
107 USERATTR_ROLEAUTH_KW },
108 };
109
110 #define NDEF (sizeof (tab) / sizeof (parsent_t))
111
112 FILE *defptr; /* default file - fptr */
113
114 static const parsent_t *
scan(char ** start_p)115 scan(char **start_p)
116 {
117 static int ind = NDEF - 1;
118 char *cur_p = *start_p;
119 int lastind = ind;
120
121 if (!*cur_p || *cur_p == '\n' || *cur_p == '#')
122 return (NULL);
123
124 /*
125 * The magic in this loop is remembering the last index when
126 * reentering the function; the entries above are also used to
127 * order the output to the default file.
128 */
129 do {
130 ind++;
131 ind %= NDEF;
132
133 if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) {
134 *start_p = cur_p + tab[ind].nmsz;
135 return (&tab[ind]);
136 }
137 } while (ind != lastind);
138
139 return (NULL);
140 }
141
142 /*
143 * getusrdef - access the user defaults file. If it doesn't exist,
144 * then returns default values of (values in userdefs.h):
145 * defrid = 100
146 * defgroup = 1
147 * defgname = other
148 * defparent = /home
149 * defskel = /usr/sadm/skel
150 * defshell = /bin/sh
151 * definact = 0
152 * defexpire = 0
153 * defauth = 0
154 * defprof = 0
155 * defrole = 0
156 * defroleauth = role
157 *
158 * If getusrdef() is unable to access the defaults file, it
159 * returns a NULL pointer.
160 *
161 * If user defaults file exists, then getusrdef uses values
162 * in it to override the above values.
163 */
164
165 struct userdefs *
getusrdef(char * usertype)166 getusrdef(char *usertype)
167 {
168 char instr[512], *ptr;
169 const parsent_t *pe;
170
171 if (is_role(usertype)) {
172 if ((defptr = fopen(DEFROLEFILE, "r")) == NULL) {
173 defaults.defshell = DEFROLESHL;
174 defaults.defprof = DEFROLEPROF;
175 defaults.defroleauth = DEFROLEROLEAUTH;
176 return (&defaults);
177 }
178 } else {
179 if ((defptr = fopen(DEFFILE, "r")) == NULL)
180 return (&defaults);
181 }
182
183 while (fgets(instr, sizeof (instr), defptr) != NULL) {
184 ptr = instr;
185
186 SKIPWS(ptr);
187
188 if (*ptr == '#')
189 continue;
190
191 pe = scan(&ptr);
192
193 if (pe != NULL) {
194 switch (pe->type) {
195 case INT:
196 FIELD(&defaults, pe, int) =
197 (int)strtol(ptr, NULL, 10);
198 break;
199 case PROJID:
200 FIELD(&defaults, pe, projid_t) =
201 (projid_t)strtol(ptr, NULL, 10);
202 break;
203 case STR:
204 FIELD(&defaults, pe, char *) = dup_to_nl(ptr);
205 break;
206 }
207 }
208 }
209
210 (void) fclose(defptr);
211
212 return (&defaults);
213 }
214
215 static char *
dup_to_nl(char * from)216 dup_to_nl(char *from)
217 {
218 char *res = strdup(from);
219
220 char *p = strchr(res, '\n');
221 if (p)
222 *p = '\0';
223
224 return (res);
225 }
226
227 void
dispusrdef(FILE * fptr,unsigned flags,char * usertype)228 dispusrdef(FILE *fptr, unsigned flags, char *usertype)
229 {
230 struct userdefs *deflts = getusrdef(usertype);
231 int outcount = 0;
232
233 /* Print out values */
234
235 if (flags & D_GROUP) {
236 outcount += fprintf(fptr, "group=%s,%ld ",
237 deflts->defgname, deflts->defgroup);
238 PRINTNL();
239 }
240
241 if (flags & D_PROJ) {
242 outcount += fprintf(fptr, "project=%s,%ld ",
243 deflts->defprojname, deflts->defproj);
244 PRINTNL();
245 }
246
247 if (flags & D_BASEDIR) {
248 outcount += fprintf(fptr, "basedir=%s ", deflts->defparent);
249 PRINTNL();
250 }
251
252 if (flags & D_RID) {
253 outcount += fprintf(fptr, "rid=%ld ", deflts->defrid);
254 PRINTNL();
255 }
256
257 if (flags & D_SKEL) {
258 outcount += fprintf(fptr, "skel=%s ", deflts->defskel);
259 PRINTNL();
260 }
261
262 if (flags & D_SHELL) {
263 outcount += fprintf(fptr, "shell=%s ", deflts->defshell);
264 PRINTNL();
265 }
266
267 if (flags & D_INACT) {
268 outcount += fprintf(fptr, "inactive=%d ", deflts->definact);
269 PRINTNL();
270 }
271
272 if (flags & D_EXPIRE) {
273 outcount += fprintf(fptr, "expire=%s ", deflts->defexpire);
274 PRINTNL();
275 }
276
277 if (flags & D_AUTH) {
278 outcount += fprintf(fptr, "auths=%s ", deflts->defauth);
279 PRINTNL();
280 }
281
282 if (flags & D_PROF) {
283 outcount += fprintf(fptr, "profiles=%s ", deflts->defprof);
284 PRINTNL();
285 }
286
287 if ((flags & D_ROLE) &&
288 (!is_role(usertype))) {
289 outcount += fprintf(fptr, "roles=%s ", deflts->defrole);
290 PRINTNL();
291 }
292
293 if (flags & D_LPRIV) {
294 outcount += fprintf(fptr, "limitpriv=%s ", 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 PRINTNL();
308 }
309
310 if ((flags & D_ROLEAUTH) && is_role(usertype)) {
311 outcount += fprintf(fptr, "roleauth=%s ",
312 deflts->defroleauth);
313 }
314
315 if (outcount > 0)
316 (void) fprintf(fptr, "\n");
317 }
318
319 /*
320 * putusrdef -
321 * changes default values in defadduser file
322 */
323 int
putusrdef(struct userdefs * defs,char * usertype)324 putusrdef(struct userdefs *defs, char *usertype)
325 {
326 time_t timeval; /* time value from time */
327 int i;
328 ptrdiff_t skip;
329 char *hdr;
330
331 /*
332 * file format is:
333 * #<tab>Default values for adduser. Changed mm/dd/yy hh:mm:ss.
334 * defgroup=m (m=default group id)
335 * defgname=str1 (str1=default group name)
336 * defparent=str2 (str2=default base directory)
337 * definactive=x (x=default inactive)
338 * defexpire=y (y=default expire)
339 * defproj=z (z=numeric project id)
340 * defprojname=str3 (str3=default project name)
341 * ... etc ...
342 */
343
344 if (is_role(usertype)) {
345 if ((defptr = fopen(DEFROLEFILE, "w")) == NULL) {
346 errmsg(M_FAILED);
347 return (EX_UPDATE);
348 }
349 } else {
350 if ((defptr = fopen(DEFFILE, "w")) == NULL) {
351 errmsg(M_FAILED);
352 return (EX_UPDATE);
353 }
354 }
355
356 if (lockf(fileno(defptr), F_LOCK, 0) != 0) {
357 /* print error if can't lock whole of DEFFILE */
358 errmsg(M_UPDATE, "created");
359 return (EX_UPDATE);
360 }
361
362 if (is_role(usertype)) {
363 /* If it's a role, we must skip the defrole field */
364 skip = DEFOFF(defrole);
365 hdr = FHEADER_ROLE;
366 } else {
367 /* If it's a user, we must skip the defroleauth field */
368 skip = DEFOFF(defroleauth);
369 hdr = FHEADER;
370 }
371
372 /* get time */
373 timeval = time(NULL);
374
375 /* write it to file */
376 if (fprintf(defptr, "%s%s\n", hdr, ctime(&timeval)) <= 0) {
377 errmsg(M_UPDATE, "created");
378 return (EX_UPDATE);
379 }
380
381 for (i = 0; i < NDEF; i++) {
382 int res = 0;
383
384 if (tab[i].off == skip)
385 continue;
386
387 switch (tab[i].type) {
388 case INT:
389 res = fprintf(defptr, "%s%d\n", tab[i].name,
390 FIELD(defs, &tab[i], int));
391 break;
392 case STR:
393 res = fprintf(defptr, "%s%s\n", tab[i].name,
394 FIELD(defs, &tab[i], char *));
395 break;
396 case PROJID:
397 res = fprintf(defptr, "%s%d\n", tab[i].name,
398 (int)FIELD(defs, &tab[i], projid_t));
399 break;
400 }
401
402 if (res <= 0) {
403 errmsg(M_UPDATE, "created");
404 return (EX_UPDATE);
405 }
406 }
407
408 (void) lockf(fileno(defptr), F_ULOCK, 0);
409 (void) fclose(defptr);
410
411 return (EX_SUCCESS);
412 }
413
414 /* Export command line keys to defaults for useradd -D */
415 void
update_def(struct userdefs * ud)416 update_def(struct userdefs *ud)
417 {
418 int i;
419
420 for (i = 0; i < NDEF; i++) {
421 char *val;
422 if (tab[i].uakey != NULL &&
423 (val = getsetdefval(tab[i].uakey, NULL)) != NULL)
424 FIELD(ud, &tab[i], char *) = val;
425 }
426 }
427
428 /* Import default keys for ordinary useradd */
429 void
import_def(struct userdefs * ud)430 import_def(struct userdefs *ud)
431 {
432 int i;
433
434 for (i = 0; i < NDEF; i++) {
435 if (tab[i].uakey != NULL && tab[i].type == STR) {
436 char *val = FIELD(ud, &tab[i], char *);
437 if (val == getsetdefval(tab[i].uakey, val))
438 nkeys ++;
439 }
440 }
441 }
442