summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2013-07-17 01:32:29 +0000
committerXin LI <delphij@FreeBSD.org>2013-07-17 01:32:29 +0000
commitf233ff62a96a2d0c369be8dcd504c169cbd60ffa (patch)
treebf2472e6826b3095216f5fa242f1d5343c908527
parentde7ca2d0664571507e6541388f8eff0638e12c76 (diff)
parent78ed20543de7f07e92480d9d65202a25b4abcbcf (diff)
downloadpw-darwin-f233ff62a96a2d0c369be8dcd504c169cbd60ffa.tar.gz
pw-darwin-f233ff62a96a2d0c369be8dcd504c169cbd60ffa.zip
IFC @253398
-rw-r--r--libutil/gr_util.c193
-rw-r--r--libutil/libutil.h2
-rw-r--r--pw/pw.conf.5318
-rw-r--r--pw/pw_user.c8
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);