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
60 static char *dup_to_nl(char *);
61
62 static 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
76 typedef 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
84 static 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
111 FILE *defptr; /* default file - fptr */
112
113 static const parsent_t *
scan(char ** start_p)114 scan(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
163 struct userdefs *
getusrdef(char * usertype)164 getusrdef(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
212 static char *
dup_to_nl(char * from)213 dup_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
224 void
dispusrdef(FILE * fptr,unsigned flags,char * usertype)225 dispusrdef(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 */
315 int
putusrdef(struct userdefs * defs,char * usertype)316 putusrdef(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 */
406 void
update_def(struct userdefs * ud)407 update_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 */
420 void
import_def(struct userdefs * ud)421 import_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