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 }