/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 RackTop Systems. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include #include #include #include #include "userdisp.h" #include "funcs.h" #include "messages.h" /* Print out a NL when the line gets too long */ #define PRINTNL() \ if (outcount > 40) { \ outcount = 0; \ (void) fprintf(fptr, "\n"); \ } #define SKIPWS(ptr) while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++ static char *dup_to_nl(char *); static struct userdefs defaults = { DEFRID, DEFGROUP, DEFGNAME, DEFPARENT, DEFSKL, DEFSHL, DEFINACT, DEFEXPIRE, DEFAUTH, DEFPROF, DEFROLE, DEFPROJ, DEFPROJNAME, DEFLIMPRIV, DEFDFLTPRIV, DEFLOCK_AFTER_RETRIES }; #define INT 0 #define STR 1 #define PROJID 2 #define DEFOFF(field) offsetof(struct userdefs, field) #define FIELD(up, pe, type) (*(type *)((char *)(up) + (pe)->off)) typedef struct parsent { const char *name; /* deffoo= */ const size_t nmsz; /* length of def= string (excluding \0) */ const int type; /* type of entry */ const ptrdiff_t off; /* offset in userdefs structure */ const char *uakey; /* user_attr key, if defined */ } parsent_t; static const parsent_t tab[] = { { GIDSTR, sizeof (GIDSTR) - 1, INT, DEFOFF(defgroup) }, { GNAMSTR, sizeof (GNAMSTR) - 1, STR, DEFOFF(defgname) }, { PARSTR, sizeof (PARSTR) - 1, STR, DEFOFF(defparent) }, { SKLSTR, sizeof (SKLSTR) - 1, STR, DEFOFF(defskel) }, { SHELLSTR, sizeof (SHELLSTR) - 1, STR, DEFOFF(defshell) }, { INACTSTR, sizeof (INACTSTR) - 1, INT, DEFOFF(definact) }, { EXPIRESTR, sizeof (EXPIRESTR) - 1, STR, DEFOFF(defexpire) }, { AUTHSTR, sizeof (AUTHSTR) - 1, STR, DEFOFF(defauth), USERATTR_AUTHS_KW }, { ROLESTR, sizeof (ROLESTR) - 1, STR, DEFOFF(defrole), USERATTR_ROLES_KW }, { PROFSTR, sizeof (PROFSTR) - 1, STR, DEFOFF(defprof), USERATTR_PROFILES_KW }, { PROJSTR, sizeof (PROJSTR) - 1, PROJID, DEFOFF(defproj) }, { PROJNMSTR, sizeof (PROJNMSTR) - 1, STR, DEFOFF(defprojname) }, { LIMPRSTR, sizeof (LIMPRSTR) - 1, STR, DEFOFF(deflimpriv), USERATTR_LIMPRIV_KW }, { DFLTPRSTR, sizeof (DFLTPRSTR) - 1, STR, DEFOFF(defdfltpriv), USERATTR_DFLTPRIV_KW }, { LOCK_AFTER_RETRIESSTR, sizeof (LOCK_AFTER_RETRIESSTR) - 1, STR, DEFOFF(deflock_after_retries), USERATTR_LOCK_AFTER_RETRIES_KW }, }; #define NDEF (sizeof (tab) / sizeof (parsent_t)) FILE *defptr; /* default file - fptr */ static const parsent_t * scan(char **start_p) { static int ind = NDEF - 1; char *cur_p = *start_p; int lastind = ind; if (!*cur_p || *cur_p == '\n' || *cur_p == '#') return (NULL); /* * The magic in this loop is remembering the last index when * reentering the function; the entries above are also used to * order the output to the default file. */ do { ind++; ind %= NDEF; if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) { *start_p = cur_p + tab[ind].nmsz; return (&tab[ind]); } } while (ind != lastind); return (NULL); } /* * getusrdef - access the user defaults file. If it doesn't exist, * then returns default values of (values in userdefs.h): * defrid = 100 * defgroup = 1 * defgname = other * defparent = /home * defskel = /usr/sadm/skel * defshell = /bin/sh * definact = 0 * defexpire = 0 * defauth = 0 * defprof = 0 * defrole = 0 * * If getusrdef() is unable to access the defaults file, it * returns a NULL pointer. * * If user defaults file exists, then getusrdef uses values * in it to override the above values. */ struct userdefs * getusrdef(char *usertype) { char instr[512], *ptr; const parsent_t *pe; if (is_role(usertype)) { if ((defptr = fopen(DEFROLEFILE, "r")) == NULL) { defaults.defshell = DEFROLESHL; defaults.defprof = DEFROLEPROF; return (&defaults); } } else { if ((defptr = fopen(DEFFILE, "r")) == NULL) return (&defaults); } while (fgets(instr, sizeof (instr), defptr) != NULL) { ptr = instr; SKIPWS(ptr); if (*ptr == '#') continue; pe = scan(&ptr); if (pe != NULL) { switch (pe->type) { case INT: FIELD(&defaults, pe, int) = (int)strtol(ptr, NULL, 10); break; case PROJID: FIELD(&defaults, pe, projid_t) = (projid_t)strtol(ptr, NULL, 10); break; case STR: FIELD(&defaults, pe, char *) = dup_to_nl(ptr); break; } } } (void) fclose(defptr); return (&defaults); } static char * dup_to_nl(char *from) { char *res = strdup(from); char *p = strchr(res, '\n'); if (p) *p = '\0'; return (res); } void dispusrdef(FILE *fptr, unsigned flags, char *usertype) { struct userdefs *deflts = getusrdef(usertype); int outcount = 0; /* Print out values */ if (flags & D_GROUP) { outcount += fprintf(fptr, "group=%s,%ld ", deflts->defgname, deflts->defgroup); PRINTNL(); } if (flags & D_PROJ) { outcount += fprintf(fptr, "project=%s,%ld ", deflts->defprojname, deflts->defproj); PRINTNL(); } if (flags & D_BASEDIR) { outcount += fprintf(fptr, "basedir=%s ", deflts->defparent); PRINTNL(); } if (flags & D_RID) { outcount += fprintf(fptr, "rid=%ld ", deflts->defrid); PRINTNL(); } if (flags & D_SKEL) { outcount += fprintf(fptr, "skel=%s ", deflts->defskel); PRINTNL(); } if (flags & D_SHELL) { outcount += fprintf(fptr, "shell=%s ", deflts->defshell); PRINTNL(); } if (flags & D_INACT) { outcount += fprintf(fptr, "inactive=%d ", deflts->definact); PRINTNL(); } if (flags & D_EXPIRE) { outcount += fprintf(fptr, "expire=%s ", deflts->defexpire); PRINTNL(); } if (flags & D_AUTH) { outcount += fprintf(fptr, "auths=%s ", deflts->defauth); PRINTNL(); } if (flags & D_PROF) { outcount += fprintf(fptr, "profiles=%s ", deflts->defprof); PRINTNL(); } if ((flags & D_ROLE) && (!is_role(usertype))) { outcount += fprintf(fptr, "roles=%s ", deflts->defrole); PRINTNL(); } if (flags & D_LPRIV) { outcount += fprintf(fptr, "limitpriv=%s ", deflts->deflimpriv); PRINTNL(); } if (flags & D_DPRIV) { outcount += fprintf(fptr, "defaultpriv=%s ", deflts->defdfltpriv); PRINTNL(); } if (flags & D_LOCK) { outcount += fprintf(fptr, "lock_after_retries=%s ", deflts->deflock_after_retries); } if (outcount > 0) (void) fprintf(fptr, "\n"); } /* * putusrdef - * changes default values in defadduser file */ int putusrdef(struct userdefs *defs, char *usertype) { time_t timeval; /* time value from time */ int i; ptrdiff_t skip; char *hdr; /* * file format is: * #Default values for adduser. Changed mm/dd/yy hh:mm:ss. * defgroup=m (m=default group id) * defgname=str1 (str1=default group name) * defparent=str2 (str2=default base directory) * definactive=x (x=default inactive) * defexpire=y (y=default expire) * defproj=z (z=numeric project id) * defprojname=str3 (str3=default project name) * ... etc ... */ if (is_role(usertype)) { if ((defptr = fopen(DEFROLEFILE, "w")) == NULL) { errmsg(M_FAILED); return (EX_UPDATE); } } else { if ((defptr = fopen(DEFFILE, "w")) == NULL) { errmsg(M_FAILED); return (EX_UPDATE); } } if (lockf(fileno(defptr), F_LOCK, 0) != 0) { /* print error if can't lock whole of DEFFILE */ errmsg(M_UPDATE, "created"); return (EX_UPDATE); } if (is_role(usertype)) { /* If it's a role, we must skip the defrole field */ skip = offsetof(struct userdefs, defrole); hdr = FHEADER_ROLE; } else { skip = -1; hdr = FHEADER; } /* get time */ timeval = time(NULL); /* write it to file */ if (fprintf(defptr, "%s%s\n", hdr, ctime(&timeval)) <= 0) { errmsg(M_UPDATE, "created"); return (EX_UPDATE); } for (i = 0; i < NDEF; i++) { int res = 0; if (tab[i].off == skip) continue; switch (tab[i].type) { case INT: res = fprintf(defptr, "%s%d\n", tab[i].name, FIELD(defs, &tab[i], int)); break; case STR: res = fprintf(defptr, "%s%s\n", tab[i].name, FIELD(defs, &tab[i], char *)); break; case PROJID: res = fprintf(defptr, "%s%d\n", tab[i].name, (int)FIELD(defs, &tab[i], projid_t)); break; } if (res <= 0) { errmsg(M_UPDATE, "created"); return (EX_UPDATE); } } (void) lockf(fileno(defptr), F_ULOCK, 0); (void) fclose(defptr); return (EX_SUCCESS); } /* Export command line keys to defaults for useradd -D */ void update_def(struct userdefs *ud) { int i; for (i = 0; i < NDEF; i++) { char *val; if (tab[i].uakey != NULL && (val = getsetdefval(tab[i].uakey, NULL)) != NULL) FIELD(ud, &tab[i], char *) = val; } } /* Import default keys for ordinary useradd */ void import_def(struct userdefs *ud) { int i; for (i = 0; i < NDEF; i++) { if (tab[i].uakey != NULL && tab[i].type == STR) { char *val = FIELD(ud, &tab[i], char *); if (val == getsetdefval(tab[i].uakey, val)) nkeys ++; } } }