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 *
scan(char ** start_p)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 *
getusrdef(char * usertype)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 *
dup_to_nl(char * from)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
dispusrdef(FILE * fptr,unsigned flags,char * usertype)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
putusrdef(struct userdefs * defs,char * usertype)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
update_def(struct userdefs * ud)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
import_def(struct userdefs * ud)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