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 *
 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 *
 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 *
 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
 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
 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
 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
 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 }