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 }