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