diff options
| author | Xin LI <delphij@FreeBSD.org> | 2013-07-17 01:32:29 +0000 |
|---|---|---|
| committer | Xin LI <delphij@FreeBSD.org> | 2013-07-17 01:32:29 +0000 |
| commit | f233ff62a96a2d0c369be8dcd504c169cbd60ffa (patch) | |
| tree | bf2472e6826b3095216f5fa242f1d5343c908527 | |
| parent | de7ca2d0664571507e6541388f8eff0638e12c76 (diff) | |
| parent | 78ed20543de7f07e92480d9d65202a25b4abcbcf (diff) | |
| download | pw-darwin-f233ff62a96a2d0c369be8dcd504c169cbd60ffa.tar.gz pw-darwin-f233ff62a96a2d0c369be8dcd504c169cbd60ffa.zip | |
IFC @253398
| -rw-r--r-- | libutil/gr_util.c | 193 | ||||
| -rw-r--r-- | libutil/libutil.h | 2 | ||||
| -rw-r--r-- | pw/pw.conf.5 | 318 | ||||
| -rw-r--r-- | pw/pw_user.c | 8 |
4 files changed, 440 insertions, 81 deletions
diff --git a/libutil/gr_util.c b/libutil/gr_util.c index 3f7e199..6f74507 100644 --- a/libutil/gr_util.c +++ b/libutil/gr_util.c @@ -49,6 +49,8 @@ static char group_dir[PATH_MAX]; static char group_file[PATH_MAX]; static char tempname[PATH_MAX]; static int initialized; +static size_t grmemlen(const struct group *, const char *, int *); +static struct group *grcopy(const struct group *gr, char *mem, const char *, int ndx); /* * Initialize statics @@ -359,26 +361,30 @@ gr_equal(const struct group *gr1, const struct group *gr2) if (gr1->gr_gid != gr2->gr_gid) return (false); - /* Check all members in both groups. */ - if (gr1->gr_mem == NULL || gr2->gr_mem == NULL) { - if (gr1->gr_mem != gr2->gr_mem) - return (false); - } else { - for (gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL; gr1_ndx++) { - for (gr2_ndx = 0;; gr2_ndx++) { - if (gr2->gr_mem[gr2_ndx] == NULL) - return (false); - if (strcmp(gr1->gr_mem[gr1_ndx], - gr2->gr_mem[gr2_ndx]) == 0) { - break; - } - } + /* Check all members in both groups. + * getgrnam can return gr_mem with a pointer to NULL. + * gr_dup and gr_add strip out this superfluous NULL, setting + * gr_mem to NULL for no members. + */ + if (gr1->gr_mem != NULL && gr2->gr_mem != NULL) { + int i; + + for (i = 0; gr1->gr_mem[i] != NULL; i++) { + if (strcmp(gr1->gr_mem[i], gr2->gr_mem[i]) != 0) + return (false); } - - /* Check that group2 does not have more members than group1. */ - if (gr2->gr_mem[gr1_ndx] != NULL) - return (false); } + /* Count number of members in both structs */ + gr2_ndx = 0; + if (gr2->gr_mem != NULL) + for(; gr2->gr_mem[gr2_ndx] != NULL; gr2_ndx++) + /* empty */; + gr1_ndx = 0; + if (gr1->gr_mem != NULL) + for(; gr1->gr_mem[gr1_ndx] != NULL; gr1_ndx++) + /* empty */; + if (gr1_ndx != gr2_ndx) + return (false); return (true); } @@ -429,90 +435,129 @@ gr_make(const struct group *gr) struct group * gr_dup(const struct group *gr) { - struct group *newgr; - char *dst; + return (gr_add(gr, NULL)); +} +/* + * Add a new member name to a struct group. + */ +struct group * +gr_add(const struct group *gr, const char *newmember) +{ + char *mem; size_t len; - int ndx; int num_mem; - /* Calculate size of the group. */ - len = sizeof(*newgr); - if (gr->gr_name != NULL) - len += strlen(gr->gr_name) + 1; - if (gr->gr_passwd != NULL) - len += strlen(gr->gr_passwd) + 1; - if (gr->gr_mem != NULL) { - for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) - len += strlen(gr->gr_mem[num_mem]) + 1; - len += (num_mem + 1) * sizeof(*gr->gr_mem); - } else - num_mem = -1; + num_mem = 0; + len = grmemlen(gr, newmember, &num_mem); /* Create new group and copy old group into it. */ - if ((newgr = malloc(len)) == NULL) + if ((mem = malloc(len)) == NULL) return (NULL); - /* point new gr_mem to end of struct + 1 */ - if (gr->gr_mem != NULL) - newgr->gr_mem = (char **)(newgr + 1); - else + return (grcopy(gr, mem, newmember, num_mem)); +} + +/* It is safer to walk the pointers given at gr_mem since there is no + * guarantee the gr_mem + strings are contiguous in the given struct group + * but compactify the new group into the following form. + * + * The new struct is laid out like this in memory. The example given is + * for a group with two members only. + * + * { + * (char *name) + * (char *passwd) + * (int gid) + * (gr_mem * newgrp + sizeof(struct group) + sizeof(**)) points to gr_mem area + * gr_mem area + * (member1 *) + * (member2 *) + * (NULL) + * (name string) + * (passwd string) + * (member1 string) + * (member2 string) + * } + */ +/* + * Copy the contents of a group plus given name to a preallocated group struct + */ +static struct group * +grcopy(const struct group *gr, char *dst, const char *name, int ndx) +{ + int i; + struct group *newgr; + + newgr = (struct group *)(void *)dst; /* avoid alignment warning */ + dst += sizeof(*newgr); + if (ndx != 0) { + newgr->gr_mem = (char **)(void *)(dst); /* avoid alignment warning */ + dst += (ndx + 1) * sizeof(*newgr->gr_mem); + } else newgr->gr_mem = NULL; - /* point dst after the end of all the gr_mem pointers in newgr */ - dst = (char *)&newgr->gr_mem[num_mem + 1]; if (gr->gr_name != NULL) { newgr->gr_name = dst; dst = stpcpy(dst, gr->gr_name) + 1; - } else { + } else newgr->gr_name = NULL; - } if (gr->gr_passwd != NULL) { newgr->gr_passwd = dst; dst = stpcpy(dst, gr->gr_passwd) + 1; - } else { + } else newgr->gr_passwd = NULL; - } newgr->gr_gid = gr->gr_gid; + i = 0; + /* Original group struct might have a NULL gr_mem */ if (gr->gr_mem != NULL) { - for (ndx = 0; ndx < num_mem; ndx++) { - newgr->gr_mem[ndx] = dst; - dst = stpcpy(dst, gr->gr_mem[ndx]) + 1; + for (; gr->gr_mem[i] != NULL; i++) { + newgr->gr_mem[i] = dst; + dst = stpcpy(dst, gr->gr_mem[i]) + 1; } - newgr->gr_mem[ndx] = NULL; } + /* If name is not NULL, newgr->gr_mem is known to be not NULL */ + if (name != NULL) { + newgr->gr_mem[i++] = dst; + dst = stpcpy(dst, name) + 1; + } + /* if newgr->gr_mem is not NULL add NULL marker */ + if (newgr->gr_mem != NULL) + newgr->gr_mem[i] = NULL; + return (newgr); } /* - * Add a new member name to a struct group. + * Calculate length of a struct group + given name */ -struct group * -gr_add(struct group *gr, char *newmember) +static size_t +grmemlen(const struct group *gr, const char *name, int *num_mem) { - size_t mlen; - int num_mem=0; - char **members; - struct group *newgr; - - if (newmember == NULL) - return(gr_dup(gr)); + size_t len; + int i; + if (gr == NULL) + return (0); + /* Calculate size of the group. */ + len = sizeof(*gr); + if (gr->gr_name != NULL) + len += strlen(gr->gr_name) + 1; + if (gr->gr_passwd != NULL) + len += strlen(gr->gr_passwd) + 1; + i = 0; if (gr->gr_mem != NULL) { - for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) { - if (strcmp(gr->gr_mem[num_mem], newmember) == 0) { - errno = EEXIST; - return (NULL); - } + for (; gr->gr_mem[i] != NULL; i++) { + len += strlen(gr->gr_mem[i]) + 1; + len += sizeof(*gr->gr_mem); } } - /* Allocate enough for current pointers + 1 more and NULL marker */ - mlen = (num_mem + 2) * sizeof(*gr->gr_mem); - if ((members = malloc(mlen)) == NULL) - return (NULL); - memcpy(members, gr->gr_mem, num_mem * sizeof(*gr->gr_mem)); - members[num_mem++] = newmember; - members[num_mem] = NULL; - gr->gr_mem = members; - newgr = gr_dup(gr); - free(members); - return (newgr); + if (name != NULL) { + i++; + len += strlen(name) + 1; + len += sizeof(*gr->gr_mem); + } + /* Allow for NULL pointer */ + if (i != 0) + len += sizeof(*gr->gr_mem); + *num_mem = i; + return(len); } /* diff --git a/libutil/libutil.h b/libutil/libutil.h index b1b2405..b8b9836 100644 --- a/libutil/libutil.h +++ b/libutil/libutil.h @@ -167,7 +167,7 @@ int gr_copy(int __ffd, int _tfd, const struct group *_gr, struct group * gr_dup(const struct group *_gr); struct group * - gr_add(struct group *_gr, char *_newmember); + gr_add(const struct group *_gr, const char *_newmember); int gr_equal(const struct group *_gr1, const struct group *_gr2); void gr_fini(void); int gr_init(const char *_dir, const char *_master); diff --git a/pw/pw.conf.5 b/pw/pw.conf.5 new file mode 100644 index 0000000..61c40e8 --- /dev/null +++ b/pw/pw.conf.5 @@ -0,0 +1,318 @@ +.\" Copyright (C) 1996 +.\" David L. Nugent. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd March 30, 2007 +.Dt PW.CONF 5 +.Os +.Sh NAME +.Nm pw.conf +.Nd format of the pw.conf configuration file +.Sh DESCRIPTION +The file +.Pa /etc/pw.conf +contains configuration data for the +.Xr pw 8 +utility. +The +.Xr pw 8 +utility is used for maintenance of the system password and group +files, allowing users and groups to be added, deleted and changed. +This file may be modified via the +.Xr pw 8 +command using the +.Ar useradd +command and the +.Fl D +option, or by editing it directly with a text editor. +.Pp +Each line in +.Pa /etc/pw.conf +is treated either a comment or as configuration data; +blank lines and lines commencing with a +.Ql \&# +character are considered comments, and any remaining lines are +examined for a leading keyword, followed by corresponding data. +.Pp +Keywords recognized by +.Xr pw 8 +are: +.Bl -tag -width password_days -offset indent -compact +.It defaultpasswd +affect passwords generated for new users +.It reuseuids +reuse gaps in uid sequences +.It reusegids +reuse gaps in gid sequences +.It nispasswd +path to the +.Tn NIS +passwd database +.It skeleton +where to obtain default home contents +.It newmail +mail to send to new users +.It logfile +log user/group modifications to this file +.It home +root directory for home directories +.It homemode +permissions for home directory +.It shellpath +paths in which to locate shell programs +.It shells +list of valid shells (without path) +.It defaultshell +default shell (without path) +.It defaultgroup +default group +.It extragroups +add new users to this groups +.It defaultclass +place new users in this login class +.It minuid +.It maxuid +range of valid default user ids +.It mingid +.It maxgid +range of valid default group ids +.It expire_days +days after which account expires +.It password_days +days after which password expires +.El +.Pp +Valid values for +.Ar defaultpasswd +are: +.Bl -tag -width password_days -offset indent -compact +.It no +disable login on newly created accounts +.It yes +force the password to be the account name +.It none +force a blank password +.It random +generate a random password +.El +.Pp +The second and third options are insecure and should be avoided if +possible on a publicly accessible system. +The first option requires that the superuser run +.Xr passwd 1 +to set a password before the account may be used. +This may also be useful for creating administrative accounts. +The final option causes +.Xr pw 8 +to respond by printing a randomly generated password on stdout. +This is the preferred and most secure option. +The +.Xr pw 8 +utility also provides a method of setting a specific password for the new +user via a filehandle (command lines are not secure). +.Pp +Both +.Ar reuseuids +and +.Ar reusegids +determine the method by which new user and group id numbers are +generated. +A +.Ql \&yes +in this field will cause +.Xr pw 8 +to search for the first unused user or group id within the allowed +range, whereas a +.Ql \&no +will ensure that no other existing user or group id within the range +is numerically lower than the new one generated, and therefore avoids +reusing gaps in the user or group id sequence that are caused by +previous user or group deletions. +Note that if the default group is not specified using the +.Ar defaultgroup +keyword, +.Xr pw 8 +will create a new group for the user and attempt to keep the new +user's uid and gid the same. +If the new user's uid is currently in use as a group id, then the next +available group id is chosen instead. +.Pp +On +.Tn NIS +servers which maintain a separate passwd database to +.Pa /etc/master.passwd , +this option allows the additional file to be concurrently updated +as user records are added, modified or removed. +If blank or set to 'no', no additional database is updated. +An absolute pathname must be used. +.Pp +The +.Ar skeleton +keyword nominates a directory from which the contents of a user's +new home directory is constructed. +This is +.Pa /usr/share/skel +by default. +The +.Xr pw 8 Ns 's +.Fl m +option causes the user's home directory to be created and populated +using the files contained in the +.Ar skeleton +directory. +.Pp +To send an initial email to new users, the +.Ar newmail +keyword may be used to specify a path name to a file containing +the message body of the message to be sent. +To avoid sending mail when accounts are created, leave this entry +blank or specify +.Ql \&no . +.Pp +The +.Ar logfile +option allows logging of password file modifications into the +nominated log file. +To avoid creating or adding to such a logfile, then leave this +field blank or specify +.Ql \&no . +.Pp +The +.Ar home +keyword is mandatory. +This specifies the location of the directory in which all new user +home directories are created. +.Pp +The +.Ar homemode +keyword is optional. +It specifies the creation mask of the user's home directory and is modified by +.Xr umask 2 . +.Pp +The +.Ar shellpath +keyword specifies a list of directories - separated by colons +.Ql \&: +- which contain the programs used by the login shells. +.Pp +The +.Ar shells +keyword specifies a list of programs available for use as login +shells. +This list is a comma-separated list of shell names which should +not contain a path. +These shells must exist in one of the directories nominated by +.Ar shellpath . +.Pp +The +.Ar defaultshell +keyword nominates which shell program to use for new users when +none is specified on the +.Xr pw 8 +command line. +.Pp +The +.Ar defaultgroup +keyword defines the primary group (the group id number in the +password file) used for new accounts. +If left blank, or the word +.Ql \&no +is used, then each new user will have a corresponding group of +their own created automatically. +This is the recommended procedure for new users as it best secures each +user's files against interference by other users of the system +irrespective of the +.Em umask +normally used by the user. +.Pp +The +.Ar extragroups +keyword provides an automatic means of placing new users into groups within +the +.Pa /etc/groups +file. +This is useful where all users share some resources, and is preferable +to placing users into the same primary group. +The effect of this keyword can be overridden using the +.Fl G +option on the +.Xr pw 8 +command line. +.Pp +The +.Ar defaultclass +field determines the login class (See +.Xr login.conf 5 ) +that new users will be allocated unless overwritten by +.Xr pw 8 . +.Pp +The +.Ar minuid , +.Ar maxuid , +.Ar mingid , +.Ar maxgid +keywords determine the allowed ranges of automatically allocated user +and group id numbers. +The default values for both user and group ids are 1000 and 32000 as +minimum and maximum respectively. +The user and group id's actually used when creating an account with +.Xr pw 8 +may be overridden using the +.Fl u +and +.Fl g +command line options. +.Pp +The +.Ar expire_days +and +.Ar password_days +are used to automatically calculate the number of days from the date +on which an account is created when the account will expire or the +user will be forced to change the account's password. +A value of +.Ql \&0 +in either field will disable the corresponding (account or password) +expiration date. +.Sh LIMITS +The maximum line length of +.Pa /etc/pw.conf +is 1024 characters. +Longer lines will be skipped and treated +as comments. +.Sh FILES +.Bl -tag -width /etc/master.passwd -compact +.It Pa /etc/pw.conf +.It Pa /etc/passwd +.It Pa /etc/master.passwd +.It Pa /etc/group +.El +.Sh SEE ALSO +.Xr passwd 1 , +.Xr umask 2 , +.Xr group 5 , +.Xr login.conf 5 , +.Xr passwd 5 , +.Xr pw 8 diff --git a/pw/pw_user.c b/pw/pw_user.c index 5f4d7a9..def238c 100644 --- a/pw/pw_user.c +++ b/pw/pw_user.c @@ -200,7 +200,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) strlcpy(dbuf, cnf->home, sizeof(dbuf)); p = dbuf; if (stat(dbuf, &st) == -1) { - while ((p = strchr(++p, '/')) != NULL) { + while ((p = strchr(p + 1, '/')) != NULL) { *p = '\0'; if (stat(dbuf, &st) == -1) { if (mkdir(dbuf, _DEF_DIRMODE) == -1) @@ -513,8 +513,6 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) time_t now = time(NULL); time_t expire = parse_date(now, arg->val); - if (now == expire) - errx(EX_DATAERR, "invalid password change date `%s'", arg->val); if (pwd->pw_change != expire) { pwd->pw_change = expire; edited = 1; @@ -533,8 +531,6 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) time_t now = time(NULL); time_t expire = parse_date(now, arg->val); - if (now == expire) - errx(EX_DATAERR, "invalid account expiry date `%s'", arg->val); if (pwd->pw_expire != expire) { pwd->pw_expire = expire; edited = 1; @@ -577,7 +573,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) lc = login_getpwclass(pwd); if (lc == NULL || - login_setcryptfmt(lc, "md5", NULL) == NULL) + login_setcryptfmt(lc, "sha512", NULL) == NULL) warn("setting crypt(3) format"); login_close(lc); pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); |
