Index: cvs2svn/tags/v1_1/share/man/man4/tun.4 =================================================================== --- cvs2svn/tags/v1_1/share/man/man4/tun.4 (nonexistent) +++ cvs2svn/tags/v1_1/share/man/man4/tun.4 (revision 29197) @@ -0,0 +1,216 @@ +.\" $NetBSD: tun.4,v 1.1 1996/06/25 22:17:37 pk Exp $ +.\" Based on PR#2411 +.\" +.Dd March 10, 1996 +.Dt TUN 4 +.Os NetBSD 1.1 +.Sh NAME +.Nm tun +.Nd tunnel software network interface +.Sh SYNOPSIS +.Cd pseudo-device tun Op Ar count +.Sh DESCRIPTION +The +.Nm tun +interface is a software loopback mechanism that can be loosely +described as the network interface analog of the +.Xr pty 4 , +that is, +.Nm tun +does for network interfaces what the +.Nm pty +driver does for terminals. +.Pp +The +.Nm tun +driver, like the +.Nm pty +driver, provides two interfaces: an interface like the usual facility +it is simulating +.Po +a network interface in the case of +.Nm tun , +or a terminal for +.Nm pty Pc , +and a character-special device +.Dq control +interface. +.Pp +The network interfaces are named +.Sy tun Ns Ar 0 , +.Sy tun Ns Ar 1 , +etc, as many in all as the +.Ar count +figure given on the +.Sy pseudo-device +line. Each one supports the usual network-interface +.Xr ioctl 2 Ns s , +such as +.Dv SIOCSIFADDR +and +.Dv SIOCSIFNETMASK , +and thus can be used with +.Xr ifconfig 8 +like any other interface. At boot time, they are +.Dv POINTOPOINT +interfaces, but this can be changed; see the description of the control +device, below. When the system chooses to transmit a packet on the +network interface, the packet can be read from the control device +.Po +it appears as +.Dq input +there +.Pc ; +writing a packet to the control device generates an input +packet on the network interface, as if the +.Pq non-existent +hardware had just received it. +.Pp +The tunnel device, normally +.Pa /dev/tun Ns Sy N , +is exclusive-open +.Po +it cannot be opened if it is already open +.Pc +and is restricted to the super-user. A +.Fn read +call will return an error +.Pq Er EHOSTDOWN +if the interface is not +.Dq ready +.Po +which means that the control device is open and the interface's +address has been set +.Pc . +Once the interface is ready, +.Fn read +will return a packet if one is available; if not, it will either block +until one is or return +.Er EWOULDBLOCK , +depending on whether non-blocking I/O has been enabled. If the packet +is longer than is allowed for in the buffer passed to +.Fn read , +the extra data will be silently dropped. +.Pp +Packets can be optionally prepended with the destination address as presented +to the network interface output routine +.Pq Sq Li tunoutput . +The destination address is in +.Sq Li struct sockaddr +format. The actual length of the prepended address is in the member +.Sq Li sa_len . +The packet data follows immediately. +A +.Xr write 2 +call passes a packet in to be +.Dq received +on the pseudo-interface. Each +.Fn write +call supplies exactly one packet; the packet length is taken from the +amount of data provided to +.Fn write . +Writes will not block; if the packet cannot be accepted for a +transient reason +.Pq e.g., no buffer space available , +it is silently dropped; if the reason is not transient +.Pq e.g., packet too large , +an error is returned. +If +.Dq link-layer mode +is on +.Pq see Dv TUNSLMODE No below , +the actual packet data must be preceded by a +.Sq Li struct sockaddr . +The driver currently only inspects the +.Sq Li sa_family +field. +The following +.Xr ioctl 2 +calls are supported +.Pq defined in Aq Pa net/if_tun.h Ns : +.Bl -tag -width TUNSIFMODE +.It Dv TUNSDEBUG +The argument should be a pointer to an +.Va int ; +this sets the internal debugging variable to that value. What, if +anything, this variable controls is not documented here; see the source +code. +.It Dv TUNGDEBUG +The argument should be a pointer to an +.Va int ; +this stores the internal debugging variable's value into it. +.It Dv TUNSIFMODE +The argument should be a pointer to an +.Va int ; +its value must be +.Dv IFF_POINTOPOINT +or +.Dv IFF_BROADCAST . +The type of the corresponding +.Em tun Ns Sy n +interface is set to the supplied type. If the value is anything else, +an +.Er EINVAL +error occurs. The interface must be down at the time; if it is up, an +.Er EBUSY +error occurs. +.It Dv TUNSLMODE +The argument should be a pointer to an +.Va int ; +a non-zero value turns on +.Dq link-layer +mode, causing packets read from the tunnel device to be prepended with +network destination address. +.It Dv FIONBIO +Turn non-blocking I/O for reads off or on, according as the argument +.Va int Ns 's +value is or isn't zero +.Pq Writes are always nonblocking . +.It Dv FIOASYNC +Turn asynchronous I/O for reads +.Po +i.e., generation of +.Dv SIGIO +when data is available to be read +.Pc off or on, according as the argument +.Va int Ns 's +value is or isn't zero. +.It Dv FIONREAD +If any packets are queued to be read, store the size of the first one +into the argument +.Va int ; +otherwise, store zero. +.It Dv TIOCSPGRP +Set the process group to receive +.Dv SIGIO +signals, when asynchronous I/O is enabled, to the argument +.Va int +value. +.It Dv TIOCGPGRP +Retrieve the process group value for +.Dv SIGIO +signals into the argument +.Va int +value. +.El +.Pp +The control device also supports +.Xr select 2 +for read; selecting for write is pointless, and always succeeds, since +writes are always non-blocking. +.Pp +On the last close of the data device, by default, the interface is +brought down +.Po as if with +.Dq ifconfig tun Ns Sy n No down +.Pc . +All queued packets are thrown away. +.Po If the interface is up when the data device is not open +output packets are always +thrown away rather than letting them pile up +.Pc . +.Sh SEE ALSO +.Xr intro 4 , +.Xr inet 4 +.Sh BUGS +Currently is IP-only. Property changes on: cvs2svn/tags/v1_1/share/man/man4/tun.4 ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/Makefile =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/Makefile (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/Makefile (revision 29197) @@ -0,0 +1,18 @@ +# $Id$ + +PROG= pw +SRCS= pw.c pw_conf.c pw_user.c pw_group.c pw_log.c \ + grupd.c pwupd.c fileupd.c edgroup.c psdate.c \ + bitmap.c cpdir.c rm_r.c + +MAN5= pw.conf.5 +MAN8= pw.8 + +CFLAGS+= -Wall $(CDB) +LDADD= -lcrypt +DPADD= ${LIBCRYPT} + +BINOWN= root +BINMODE=0555 + +.include Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/cpdir.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/cpdir.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/cpdir.c (revision 29197) @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwupd.h" + +void +copymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid) +{ + int rc = 0; + char src[MAXPATHLEN]; + char dst[MAXPATHLEN]; + + if (mkdir(dir, mode) != 0 && errno != EEXIST) { + sprintf(src, "mkdir(%s)", dir); + perror(src); + } else { + int infd, outfd; + struct stat st; + + static char counter = 0; + static char *copybuf = NULL; + + ++counter; + chown(dir, uid, gid); + if (skel == NULL || *skel == '\0') + rc = 1; + else { + DIR *d = opendir(skel); + + if (d != NULL) { + struct dirent *e; + + while ((e = readdir(d)) != NULL) { + char *p = e->d_name; + + sprintf(src, "%s/%s", skel, p); + if (stat(src, &st) == 0) { + if (strncmp(p, "dot.", 4) == 0) /* Conversion */ + p += 3; + sprintf(dst, "%s/%s", dir, p); + if (S_ISDIR(st.st_mode)) { /* Recurse for this */ + if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) + copymkdir(dst, src, (st.st_mode & 0777), uid, gid); + /* + * Note: don't propogate 'special' attributes + */ + } else if (S_ISREG(st.st_mode) && (outfd = open(dst, O_RDWR | O_CREAT | O_EXCL, st.st_mode)) != -1) { + if ((infd = open(src, O_RDONLY)) == -1) { + close(outfd); + remove(dst); + } else { + int b; + + /* + * Allocate our copy buffer if we need to + */ + if (copybuf == NULL) + copybuf = malloc(4096); + while ((b = read(infd, copybuf, 4096)) > 0) + write(outfd, copybuf, b); + close(infd); + close(outfd); + chown(dst, uid, gid); + } + } + } + } + closedir(d); + } + } + if (--counter == 0 && copybuf != NULL) { + free(copybuf); + copybuf = NULL; + } + } +} + Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/cpdir.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw.8 =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw.8 (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw.8 (revision 29197) @@ -0,0 +1,800 @@ +.\" Copyright (c) 1996 +.\" David L. Nugent. +.\" Password Maintenance +.\" +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by David L. Nugent. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. +.\" +.\" $Id$ +.\" +.Dd December 9, 1996 +.Dt PW 8 +.Os +.Sh NAME +.Nm pw +.Nd create, remove, modify & display system users and groups +.Sh SYNOPSIS +.Nm pw +.Ar useradd +.Op name|uid +.Op Fl C Ar config +.Op Fl q +.Op Fl n Ar name +.Op Fl u Ar uid +.Op Fl c Ar comment +.Op Fl d Ar dir +.Op Fl e Ar date +.Op Fl p Ar date +.Op Fl g Ar group +.Op Fl G Ar grouplist +.Op Fl m +.Op Fl k Ar dir +.Op Fl s Ar shell +.Op Fl o +.Op Fl L Ar class +.Op Fl h Ar fd +.Op Fl N +.Op Fl P +.Nm pw +.Ar useradd +.Op name|uid +.Op Fl D +.Op Fl C Ar config +.Op Fl q +.Op Fl b Ar dir +.Op Fl e Ar days +.Op Fl p Ar days +.Op Fl g Ar group +.Op Fl G Ar grouplist +.Op Fl k Ar dir +.Op Fl u Ar min,max +.Op Fl i Ar min,max +.Op Fl w Ar method +.Op Fl s Ar shell +.Nm pw +.Ar userdel +.Op name|uid +.Op Fl n Ar name +.Op Fl u Ar uid +.Op Fl r +.Nm pw +.Ar usermod +.Op name|uid +.Op Fl C Ar config +.Op Fl q +.Op Fl n Ar name +.Op Fl u Ar uid +.Op Fl c Ar comment +.Op Fl d Ar dir +.Op Fl e Ar date +.Op Fl p Ar date +.Op Fl g Ar group +.Op Fl G Ar grouplist +.Op Fl l Ar name +.Op Fl m +.Op Fl k Ar dir +.Op Fl w Ar method +.Op Fl s Ar shell +.Op Fl L Ar class +.Op Fl h Ar fd +.Op Fl N +.Op Fl P +.Nm pw +.Ar usershow +.Op name|uid +.Op Fl n Ar name +.Op Fl u Ar uid +.Op Fl F +.Op Fl P +.Op Fl a +.Nm pw +.Ar usernext +.Op Fl C Ar config +.Op Fl q +.Nm pw +.Ar groupadd +.Op group|gid +.Op Fl C Ar config +.Op Fl q +.Op Fl n Ar group +.Op Fl g Ar gid +.Op Fl M Ar members +.Op Fl o +.Op Fl h Ar fd +.Op Fl N +.Op Fl P +.Nm pw +.Ar groupdel +.Op Fl n Ar name +.Op Fl g Ar gid +.Nm pw +.Ar groupmod +.Op Fl C Ar config +.Op Fl q +.Op Fl F +.Op Fl n Ar name +.Op Fl g Ar gid +.Op Fl l Ar name +.Op Fl M Ar members +.Op Fl m Ar newmembers +.Op Fl h Ar fd +.Op Fl N +.Op Fl P +.Nm pw +.Ar groupshow +.Op Fl n Ar name +.Op Fl g Ar gid +.Op Fl F +.Op Fl P +.Op Fl a +.Nm pw +.Ar groupnext +.Op Fl C Ar config +.Op Fl q +.Sh DESCRIPTION +.Nm pw +is a command-line based editor for the system +.Em user +and +.Em group +files, allowing the superuser and easy to use and standardised way of adding, +modifying and removing users and groups. +Note that +.Nm pw +only operates on the local user and group files; NIS users and groups must be +maintained on the NIS server. +.Nm pw +handles updating the passwd, master.passwd, group and the secure and insecure +password database files, and must be run as root. +.Pp +The first one or two keywords provided on +.Xr pw 8 's +command line provide the context for the remainder of the arguments. +One of the keywords +.Ar user +and +.Ar group +may be combined or provided separately with +.Ar add , +.Ar del , +.Ar mod , +.Ar show , +or +.Ar next , +and may be specified in either order (ie. showuser, usershow, show user and user show +are all considered to be the same thing). +This flexiblity is useful for interactive scripts which call +.Nm pw +for the actual user and group database manipulation. +Following these keywords, you may optionally specify the user or group name or numeric +id as an alternative to using the +.Fl n Ar name , +.Fl u Ar uid , +.Fl g Ar gid +options. +.Pp +The following flags are common to all modes of operation: +.Pp +.Bl -tag -width "-G grouplist" +.It Fl C Ar config +By default, +.Nm pw +reads the file +.Pa /etc/pw.conf +to obtain policy information on how new user accounts and groups are to be created, +and the +.Fl C +option specifies a different configuration file. +Most of the contents in the configuration file may be overridden via command line +options, but it may be more useful to set up standard information for addition of +new accounts in the configuration file. +.It Fl q +Use of this option causes +.Nm pw +to suppress error messages, which may be useful in interactive environments where it +is preferable to interpret status codes returned by +.Nm pw +rather than messing up a carefully formatted display. +.It Fl N +This option is available in add and modify operations, and causes +.Nm pw +to skip updating the user/group databases and instead print the result +of the operation without actually performing it. +You may use the +.Fl P +option to switch between standard passwd and readable formats. +.El +.Pp +.Sh USER OPTIONS +The following options apply to the +.Ar useradd , +and +.Ar usermod , +commands: +.Pp +.Bl -tag -width "-G grouplist" +.It Fl n Ar name +Specifies the user/account name. +.It Fl u Ar uid +Specifies the user/account numeric id. +.Pp +Usually, you need only to provide one or the other of these options, as the account +name will imply the uid, and vice verca. +Also, you may provide either the account or userid immediately after the +.Ar useradd , +.Ar userdel , +.Ar usermod +or +.Ar usershow +keyword on the command line without the need to use +.Ql Fl n +or +.Ql Fl u . +There are times, however, were you need to provide both. +For example, when changing the uid of an existing user with +.Ar usermod , +or overriding the default uid when creating a new account. +If you wish +.Nm pw +to automatically allocate the uid to a new user on +.Ar useradd , +then you should +.Em not +use the +.Ql Fl u +option. +.El +.Pp +Options available with both +.Ar useradd +and +.Ar usermod +are: +.Bl -tag -width "-G grouplist" +.It Fl c Ar comment +This field sets the contents of the passwd GECOS field, which normally contains up +to four comma-separated fields containing the user's full name, office or location, +work and home phone numbers. +These sub-fields are used by convention only, however, and are optional. +If this field is to contain spaces, you need to quote the comment itself with double +quotes +.Ql \&" . +Avoid using commas in this field as these are used as sub-field separators, and the +colon +.Ql \&: +character also cannot be used as this is the field separator in the passwd file. +.It Fl d Ar dir +This option sets the account's home directory. +Normally, you will only use this if the home directory is to be different from the +default (which is determined from pw.conf, which specifies the base home directory +- normally /home - with the account name as a subdirectory). +.It Fl e Ar date +Sets the account's expiration date. +Format of the date is either a UNIX time in decimal, or a date in +.Ql \& dd-mmm-yy[yy] +format, where dd is the day, mmm is the month, either in numeric or alphabetic format +('Jan', 'Feb' etc) and year is either a two or four digit year. +This option also accepts a relative date in the form +.Ql \&+n[mhdwoy] +where +.Ql \&n +is a decimal, octal (leading 0) or hexadecimal (leading 0x) digit followed by the +number of Minutes, Hours, Days, Weeks, mOnths or Years from the current date at +which the expiry date is to be set. +.It Fl p Ar date +Sets the account's password expiration date. +This field is identical to the account expiration date option, except that it +applies to forced password changes. +The same formats are accepted as with the account expiratino option. +.It Fl g Ar group +Sets the account's primary group to the given group. +.Ar group +may be either the group name or its corresponding group id number. +.It Fl G Ar grouplist +Sets the additional groups to which an account belongs. +.Ar grouplist +is a comma-separated list or group names or group ids. +When adding a user, the user's name is added to the group lists in +.Pa /etc/group , +and when editing a user, the user's name is also added to the group lists, and +removed from any groups not specified in +.Ar grouplist . +Note: a user should not be added to their primary group in +.Pa /etc/group . +Also, group membership changes do not take effect immediately for current logins, +only logins subsequent to the change. +.It Fl L Ar class +This option sets the login class for the user being created. +See +.Xr login.conf 5 +for more information on user classes. +.It Fl m +This option instructs +.Nm pw +to attempt to create the user's home directory. +While primarily useful when adding a new account with +.Ar useradd , +this may also be of use when moving an existing user's home directory elsewhere on +the filesystem. +The new home directory is populated with the contents of the +.Ar skeleton +directory, which typically contains a set of shell configuration files that the +user may personalise to taste. +When +.Ql Fl m +is used on an account with +.Ar usermod , +any existing configuration files in the user's home directory are +.Em not +overwritten with the prototype files. +.Pp +When a user's home directory is created, it will be default be as a subdirectory of the +.Ar basehome +directory specified with the +.Ql Fl b Ar dir +option (see below), and will be named the same as the account. +This may be overridden with the +.Ql Fl d Ar dir +option on the command line, if desired. +.It Fl k Ar dir +Sets the +.Ar skeleton +subdirectory, from which the basic startup and configuration files are copied when +the user's home directory is created. +This option only has meaning when used with +.Ql Fl D +(see below) or +.Ql Fl m . +.It Fl s Ar shell +Sets or changes the user's login shell to +.Ar shell . +If the path to the shell program is omitted, +.Nm pw +searches the +.Ar shellpath +specified in +.Pa /etc/pw.conf +and fills it in as appropriate. +Note that unless you have a specific reason to do so, you should avoid +specifying the path - this will allow +.Nm pw +to validate that the program exists and is executable. +Specifying a full path (or supplying a blank "" shell) avoids this check +and allows for such entries as +.Ql \& /nonexistent +that should be set for accounts not intended for interactive login. +.It Fl L Ar class +Sets the +.Em class +field in the user's passwd record. +This field is not currently used, but will be in the future used to specify a +.Em termcap +entry like tag (see +.Xr passwd 5 +for details). +.It Fl h Ar fd +This option provides a special interface by which interactive scripts can +set an account password using +.Nm pw . +Because the command line and environment are fundamental insecure mechanisms +by which programs can accept information, +.Nm pw +will only allow setting of account and group passwords via a file descriptor +(usually a pipe between an interactive script and the program). +.Ar sh , +.Ar bash , +.Ar ksh +and +.Ar perl +all posses mechanisms by which this can be done. +Alternatively, +.Nm pw +will prompt for the user's password if +.Ql Fl h Ar 0 +is given, nominating +.Em stdin +as the file descriptor on which to read the password. +Note that this password will be read once and once only and is intended +for use by a script or similar rather than interactive use. +If you wish to have new password confirmation along the lines of +.Xr passwd 1 , +this must be implemented as part of the interactive script that calls +.Nm pw . +.Pp +If a value of +.Ql \&- +is given as the argument +.Ar fd , +then the password will be set to +.Ql \&* , +rendering the account inaccessible via passworded login. +.El +.Pp +It is possible to use +.Ar useradd +to create a new account that duplicates an existing user id. +While this is normally considered an error and will be rejected, the +.Ql Fl o +option overrides the check for duplicates and allows the duplication of +the user id. +This may be useful if you allow the same user to login under +different contexts (different group allocations, different home +directory, different shell) while providing basically the same +permissions for access to the user's files in each account. +.Pp +The +.Ar useradd +command also has the ability to set new user and group defaults by using the +.Ql Fl D +option. +Instead of adding a new user, +.Nm pw +writes a new set of defaults to its configuration file, +.Pa /etc/pw.conf . +When using the +.Ql Fl D +option, you must not use either +.Ql Fl n Ar name +or +.Ql Fl u Ar uid +or an error will result. +Use of +.Ql Fl D +changes the meaning of several command line switches in the +.Ar useradd +command. +These are: +.Bl -tag -width "-G grouplist" +.It Fl D +Set default values in +.Pa /etc/pw.conf +configuration file, or a different named configuration file if the +.Ql Fl C Ar config +option is used. +.It Fl b Ar dir +Sets the root directory in which user home directories are created. +The default value for this is +.Ql \&/home , +but it may be set elsewhere as desired. +.It Fl e Ar days +Sets the default account expiration period in days. +Unlike use without +.Ql Fl D , +the argument must be numeric, which specifies the number of days after creation when +the account is to expire. +A value of 0 suppresses automatic calculation of the expiry date. +.It Fl p Ar days +Sets the default password expiration period in days. +.It Fl g Ar group +Sets the default group for new users. +If a blank group is specified using +.Ql Fl g Ar \&"" , +then new users will be allocated their own private primary group (a new group created +with the same name as their login name). +If a group is supplied, either its name or uid may be given as an argument. +.It Fl G Ar grouplist +Sets the default groups in which new users are made members. +This is a separate set of groups from the primary group, and you should avoid +nominating the same group as both the primary and in extra groups. +In other words, these extra groups determine membership in groups +.Em other than +the primary group. +.Ar grouplist +is a comma-separated list of group names or ids, or a mixture of both, and are always +stored in +.Pa /etc/pw.conf +by their symbolic names. +.It Fl L Ar class +This option sets the default login class for new users. +.It Fl k Ar dir +Sets the default +.Em skeleton +directory, from which prototype shell and other initialisation files are copied when +.Nm pw +creates a user's home directory. +.It Fl u Ar min,max , Fl i Ar min,max +These options set the minimum and maximum user and group ids allocated for new accounts +and groups created by +.Nm pw . +The default values for each is 1000 minimum and 32000 maximum. +.Ar min +and +.Ar max +are both numbers, where max must be greater than min, and both must be between 0 +and 32767. +In general, user and group ids less than 100 are reserved for use by the system, +and numbers greater than 32000 may also be reserved for special purposes (used by +some system daemons). +.It Fl w Ar method +The +.Ql Fl w +option sets the default method used to set passwords for newly created user accounts. +.Ar method +is one of: +.Pp +.Bl -tag -width random -offset indent -compact +.It no +disables login on newly created accounts +.It yes +forces the password to be the account name +.It none +forces a blank password +.It random +Generates a random password +.El +.Pp +The +.Ql \&random +or +.Ql \&no +methods are the most secure; in the former case, +.Nm pw +generates a password and prints it to stdout, which is suitable where you issue +users with passwords to access their accounts rather than having the user nominate +their own (possibly poorly chosen) password. +The +.Ql \&no +method requires that the superuser use +.Xr passwd 1 +to render the account accessible with a password. +.El +.Pp +The +.Ar userdel +command has only three valid options. The +.Ql Fl n Ar name +and +.Ql Fl u Ar uid +options have already been covered above. +The additional option is: +.Bl -tag -width "-G grouplist" +.It Fl r +This tells +.Nm pw +to remove the user's home directory and all of its contents. +.Nm pw +errs on the side of caution when removing files from the system. +Firstly, it will not do so if the uid of the account being removed is also used by +another account on the system, and the 'home' directory in the password file is +a valid path that commences with the character +.Ql \&/ . +Secondly, it will only remove files and directories that are actually owned by +the user, or symbolic links owned by anyone under the user's home directory. +Finally, after deleting all contents owned by the user only empty directories +will be removed. +If any additional cleanup work is required, this is left to the adminstrator. +.El +.Pp +Mail spool files and crontabs are always removed when an account is deleted as these +are unconditionally attached to the user name. +Jobs queued for processing by +.Ar at +are also removed if the user's uid is unique (not also used by another account on the +system). +.Pp +The +.Ar usershow +command allows viewing of an account in one of two formats. +By default, the format is identical to the format used in +.Pa /etc/master.passwd +with the password field replaced with a +.Ql \&* . +If the +.Ql Fl P +option is used, then +.Nm pw +outputs the account details in a more human readable form. +The +.Ql Fl a +option lists all users currently on file. +.Pp +The command +.Ar usernext +returns the next available user and group ids separated by a colon. +This is normally of interest only to interactive scripts or front-ends +that use +.Nm pw . +.Pp +.Sh GROUP OPTIONS +The +.Ql Fl C Ar config +and +.Ql Fl q +options (explained at the start of the previous section) are available +with the group manipulation commands. +Other common options to all group-related commands are: +.Bl -tag -width "-m newmembers" +.It Fl n Ar name +Specifies the group name. +.It Fl g Ar gid +Specifies the group numeric id. +.Pp +As with the account name and id fields, you will usually only need +to supply one of these, as the group name implies the uid and vice +versa. +You will only need to use both when setting a specific group id +against a new group or when changing the uid of an existing group. +.It Fl M Ar memberlist +This option provides an alternative way to add existing users to a +new group (in groupadd) or replace an existing membership list (in +groupmod). +.Ar memberlist +is a comma separated list of valid and existing user names or uids. +.It Fl m Ar newmembers +Similar to +.Op M , +this option allows the +.Em addition +of existing users to a group without first replacing the existing list of +members. +Login names or user ids may be used, and duplicated users are automatically +and silently eliminated. +.El +.Pp +.Ar groupadd +also has a +.Ql Fl o +option that allows allocation of an existing group id to new group. +The default action is to reject an attempt to add a group, and this option overrides +the check for duplicate group ids. +There is rarely any need to duplicate a group id. +.Pp +The +.Ar groupmod +command adds one additonal option: +.Pp +.Bl -tag -width "-m newmembers" +.It Fl l Ar name +This option allows changing of an existing group name to +.Ql \&name . +The new name must not already exist, and any attempt to duplicate an existing group +name will be rejected. +.El +.Pp +Options for +.Ar groupshow +are the same as for +.Ar usershow , +with the +.Ql Fl g Ar gid +replacing +.Ql Fl u Ar uid +to specify the group id. +.Pp +The command +.Ar groupnext +returns the next available group id on standard output. +.Sh DIAGNOSTICS +.Nm pw +returns EXIT_SUCCESS on successful operation, otherwise one of the +following exit codes defined by +.Xr sysexits 3 +as follows: +.Bl -tag -width xxxx +.It EX_USAGE +.Bl -bullet -compact +.It +Command line syntax errors (invalid keyword, unknown option) +.El +.It EX_NOPERM +.Bl -bullet -compact +.It +Attempting to run one of the update modes as non-root. +.El +.It EX_OSERR +.Bl -bullet -compact +.It +Memory allocation error. +.It +Read error from password file descriptor. +.El +.It EX_DATAERR +.Bl -bullet -compact +.It +Bad or invalid data provided or missing on the command line or +via the password flie descriptor. +.It +Attempted to remove, rename root account or change its uid. +.El +.It EX_OSFILE +.Bl -bullet -compact +.It +Skeleton directory is invalid or does not exist. +.It +Base home directory is invalid or does not exist. +.It +Invalid or non-existant shell specified. +.El +.It EX_NOUSER +.Bl -bullet -compact +.It +User, user id, group or group id specified does not exist. +.It +User or group recorded added or modified unexpectedly disappeared. +.El +.It EX_SOFTWARE +.Bl -bullet -compact +.It +No more group or user ids available within specified range. +.El +.It EX_IOERR +.Bl -bullet -compact +.It +Unable to rewrite configuration file. +.It +Error updating group or user database files. +.It +Update error for passwd or group database files. +.El +.It EX_CONFIG +.Bl -bullet -compact +.It +No base home directory configured. +.El +.El +.Pp +.Sh NOTES +For a summary of options available with each command, you can use +.Dl pw [command] help +For example, +.Dl pw useradd help +lists all available options for the useradd operation. +.Sh FILES +.Bl -tag -width /etc/master.passwd.new -compact +.It Pa /etc/master.passwd +The user database +.It Pa /etc/passwd +A Version 7 format password file +.It Pa /etc/login.conf +The user capabilities database +.It Pa /etc/group +The group database +.It Pa /etc/master.passwd.new +Temporary copy of the master password file +.It Pa /etc/passwd.new +Temporary copy of the Version 7 password file +.It Pa /etc/group.new +Temporary copy of the group file +.It Pa /etc/pw.conf +Pw default options file +.El +.Sh SEE ALSO +.Xr pw.conf 5 , +.Xr passwd 1 , +.Xr chpass 1 , +.Xr passwd 5 , +.Xr group 5 , +.Xr pwd_mkdb 8 , +.Xr login.conf 5 , +.Xr vipw 5 +.Sh HISTORY +.Nm pw +was written to mimick many of the options used in the SYSV +.Em shadow +support suite, but is modified for passwd and group fields specific to +the BSD 4.4 operating system, and combines all of the major elements +into a single command. + Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw.8 ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw.c (revision 29197) @@ -0,0 +1,339 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include "pw.h" + +static char *progname = "pw"; + +const char *Modes[] = {"add", "del", "mod", "show", "next", NULL}; +const char *Which[] = {"user", "group", NULL}; +static const char *Combo1[] = { + "useradd", "userdel", "usermod", "usershow", "usernext", + "groupadd", "groupdel", "groupmod", "groupshow", "groupnext", + NULL}; +static const char *Combo2[] = { + "adduser", "deluser", "moduser", "showuser", "nextuser", + "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup", +NULL}; + +static struct cargs arglist; + +static int getindex(const char *words[], const char *word); +static void cmdhelp(int mode, int which); + + +int +main(int argc, char *argv[]) +{ + int ch; + int mode = -1; + int which = -1; + struct userconf *cnf; + + static const char *opts[W_NUM][M_NUM] = + { + { /* user */ + "C:qn:u:c:d:e:p:g:G:mk:s:oL:i:w:h:Db:NP", + "C:qn:u:r", + "C:qn:u:c:d:e:p:g:G:mk:s:w:L:h:FNP", + "C:qn:u:FPa", + "C:q" + }, + { /* grp */ + "C:qn:g:h:M:pNP", + "C:qn:g:", + "C:qn:g:l:h:FM:m:NP", + "C:qn:g:FPa", + "C:q" + } + }; + + static int (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) = + { /* Request handlers */ + pw_user, + pw_group + }; + + umask(0); /* We wish to handle this manually */ + progname = strrchr(argv[0], '/'); + if (progname != NULL) + ++progname; + else + progname = argv[0]; + + LIST_INIT(&arglist); + + /* + * Break off the first couple of words to determine what exactly + * we're being asked to do + */ + while (argc > 1 && *argv[1] != '-') { + int tmp; + + if ((tmp = getindex(Modes, argv[1])) != -1) + mode = tmp; + else if ((tmp = getindex(Which, argv[1])) != -1) + which = tmp; + else if ((tmp = getindex(Combo1, argv[1])) != -1 || (tmp = getindex(Combo2, argv[1])) != -1) { + which = tmp / M_NUM; + mode = tmp % M_NUM; + } else if (strcmp(argv[1], "help") == 0) + cmdhelp(mode, which); + else if (which != -1 && mode != -1 && arglist.lh_first == NULL) + addarg(&arglist, 'n', argv[1]); + else + cmderr(EX_USAGE, "Unknown keyword `%s'\n", argv[1]); + ++argv; + --argc; + } + + /* + * Bail out unless the user is specific! + */ + if (mode == -1 || which == -1) + cmdhelp(mode, which); + + /* + * We know which mode we're in and what we're about to do, so now + * let's dispatch the remaining command line args in a genric way. + */ + argv[0] = progname; /* Preserve this */ + optarg = NULL; + + while ((ch = getopt(argc, argv, opts[which][mode])) != -1) { + if (ch == '?') + cmderr(EX_USAGE, NULL); + else + addarg(&arglist, ch, optarg); + optarg = NULL; + } + + /* + * Must be root to attempt an update + */ + if (getuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL) + cmderr(EX_NOPERM, "you must be root to run this program\n"); + + /* + * We should immediately look for the -q 'quiet' switch so that we + * don't bother with extraneous errors + */ + if (getarg(&arglist, 'q') != NULL) + freopen("/dev/null", "w", stderr); + + /* + * Now, let's do the common initialisation + */ + cnf = read_userconfig(getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL); + return funcs[which] (cnf, mode, &arglist); +} + +static int +getindex(const char *words[], const char *word) +{ + int i = 0; + + while (words[i]) { + if (strcmp(words[i], word) == 0) + return i; + i++; + } + return -1; +} + + +/* + * This is probably an overkill for a cmdline help system, but it reflects + * the complexity of the command line. + */ + +static void +banner(void) +{ + fprintf(stderr, "%s: ", progname); +} + +void +cmderr(int ec, char const * fmt,...) +{ + if (fmt != NULL) { + va_list argp; + + banner(); + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); + } + exit(ec); +} + +static void +cmdhelp(int mode, int which) +{ + banner(); + if (which == -1) + fprintf(stderr, "usage: %s [user|group] [add|del|mod|show|next] [ help | switches/values ]\n", progname); + else if (mode == -1) + fprintf(stderr, "usage: %s %s [add|del|mod|show|next] [ help | switches/values ]\n", progname, Which[which]); + else { + + /* + * We need to give mode specific help + */ + static const char *help[W_NUM][M_NUM] = + { + { + "usage: %s useradd [name] [switches]\n" + "\t-C config configuration file\n" + "\t-q quiet operation\n" + " Adding users:\n" + "\t-n name login name\n" + "\t-u uid user id\n" + "\t-c comment user name/comment\n" + "\t-d directory home directory\n" + "\t-e date account expiry date\n" + "\t-p date password expiry date\n" + "\t-g grp initial group\n" + "\t-G grp1,grp2 additional groups\n" + "\t-m [ -k dir ] create and set up home\n" + "\t-s shell name of login shell\n" + "\t-o duplicate uid ok\n" + "\t-L class user class\n" + "\t-h fd read password on fd\n" + "\t-N no update\n" + " Setting defaults:\n" + "\t-D set user defaults\n" + "\t-b dir default home root dir\n" + "\t-e period default expiry period\n" + "\t-p period default password change period\n" + "\t-g group default group\n" + "\t-G grp1,grp2 additional groups\n" + "\t-L class default user class\n" + "\t-k dir default home skeleton\n" + "\t-u min,max set min,max uids\n" + "\t-i min,max set min,max gids\n" + "\t-w method set default password method\n" + "\t-s shell default shell\n", + "usage: %s userdel [uid|name] [switches]\n" + "\t-n name login name\n" + "\t-u uid user id\n" + "\t-r remove home & contents\n", + "usage: %s usermod [uid|name] [switches]\n" + "\t-C config configuration file\n" + "\t-q quiet operation\n" + "\t-F force add if no user\n" + "\t-n name login name\n" + "\t-u uid user id\n" + "\t-c comment user name/comment\n" + "\t-d directory home directory\n" + "\t-e date account expiry date\n" + "\t-p date password expiry date\n" + "\t-g grp initial group\n" + "\t-G grp1,grp2 additional groups\n" + "\t-l name new login name\n" + "\t-L class user class\n" + "\t-m [ -k dir ] create and set up home\n" + "\t-s shell name of login shell\n" + "\t-w method set new password using method\n" + "\t-h fd read password on fd\n" + "\t-N no update\n", + "usage: %s usershow [uid|name] [switches]\n" + "\t-n name login name\n" + "\t-u uid user id\n" + "\t-F force print\n" + "\t-P prettier format\n" + "\t-a print all users\n", + "usage: %s usernext [switches]\n" + "\t-C config configuration file\n" + }, + { + "usage: %s groupadd [group|gid] [switches]\n" + "\t-C config configuration file\n" + "\t-q quiet operation\n" + "\t-n group group name\n" + "\t-g gid group id\n" + "\t-M usr1,usr2 add users as group members\n" + "\t-o duplicate gid ok\n" + "\t-N no update\n", + "usage: %s groupdel [group|gid] [switches]\n" + "\t-n name group name\n" + "\t-g gid group id\n", + "usage: %s groupmod [group|gid] [switches]\n" + "\t-C config configuration file\n" + "\t-q quiet operation\n" + "\t-F force add if not exists\n" + "\t-n name group name\n" + "\t-g gid group id\n" + "\t-M usr1,usr2 replaces users as group members\n" + "\t-m usr1,usr2 add users as group members\n" + "\t-l name new group name\n" + "\t-N no update\n", + "usage: %s groupshow [group|gid] [switches]\n" + "\t-n name group name\n" + "\t-g gid group id\n" + "\t-F force print\n" + "\t-P prettier format\n" + "\t-a print all accounting groups\n", + "usage: %s groupnext [switches]\n" + "\t-C config configuration file\n" + } + }; + + fprintf(stderr, help[which][mode], progname); + } + exit(EXIT_FAILURE); +} + +struct carg * +getarg(struct cargs * _args, int ch) +{ + struct carg *c = _args->lh_first; + + while (c != NULL && c->ch != ch) + c = c->list.le_next; + return c; +} + +struct carg * +addarg(struct cargs * _args, int ch, char *argstr) +{ + struct carg *ca = malloc(sizeof(struct carg)); + + if (ca == NULL) + cmderr(EX_OSERR, "Abort - out of memory\n"); + ca->ch = ch; + ca->val = argstr; + LIST_INSERT_HEAD(_args, ca, list); + return ca; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw.conf.5 =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw.conf.5 (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw.conf.5 (revision 29197) @@ -0,0 +1,300 @@ +.\" Copyright (c) 1996 +.\" David L. Nugent. +.\" Password Maintenance +.\" +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by David L. Nugent. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. +.\" +.\" $Id$ +.\" +.Dd December 9, 1996 +.Dt PW.CONF 5 +.Os +.Sh NAME +.Nm pw.conf +.Nd format of the pw.conf configuration file +.Sh DESCRIPTION +The file +.Aq Pa /etc/pw.conf +contains configuration data for the +.Xr pw 8 +program. +The +.Xr pw 8 +program 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 +.Ql \&useradd +command and the +.Ql \&-D +option, or by editing it directly with a text editor. +.Pp +Each line in +.Aq 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 recognised by +.Xr pw 8 +are: +.Bl -tag -width password_days -offset indent -compact +.It defaultpasswd +affects passwords generated for new users +.It reuseuids +reuse gaps in uid sequences +.It reusegids +reuse gaps in gid sequences +.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 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 +disables login on newly created accounts +.It yes +forces the password to be the account name +.It none +forces a blank password +.It random +Generates 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. +.Xr pw 8 +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 +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. +.Xr pw 8 's +.Ql \&-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 +.Ar shellpath +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 +.Ar extragroups +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 +.Ql \&-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 determines 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 +.Ql \&-u +and +.Ql \&-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. +.Pp +.Sh LIMITS +The maximum line length of +.Pa /etc/acct/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 pw 8 , +.Xr login.conf 5 , +.Xr passwd 1 , +.Xr passwd 5 , +.Xr group 5 + + Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw.conf.5 ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw.h =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw.h (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw.h (revision 29197) @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psdate.h" + +enum _mode +{ + M_ADD, + M_DELETE, + M_UPDATE, + M_PRINT, + M_NEXT, + M_NUM +}; + +enum _which +{ + W_USER, + W_GROUP, + W_NUM +}; + +struct carg +{ + int ch; + char *val; + LIST_ENTRY(carg) list; +}; + +extern LIST_HEAD(cargs, carg) arglist; + +struct userconf +{ + int default_password; /* Default password for new users? */ + int reuse_uids; /* Reuse uids? */ + int reuse_gids; /* Reuse gids? */ + char *dotdir; /* Where to obtain skeleton files */ + char *newmail; /* Mail to send to new accounts */ + char *logfile; /* Where to log changes */ + char *home; /* Where to create home directory */ + char *shelldir; /* Where shells are located */ + char **shells; /* List of shells */ + char *shell_default; /* Default shell */ + char *default_group; /* Default group number */ + char **groups; /* Default (additional) groups */ + char *default_class; /* Default user class */ + uid_t min_uid, max_uid; /* Allowed range of uids */ + gid_t min_gid, max_gid; /* Allowed range of gids */ + int expire_days; /* Days to expiry */ + int password_days; /* Days to password expiry */ +}; + +#define _PATH_PW_CONF "/etc/pw.conf" +#define _UC_MAXLINE 1024 +#define _UC_MAXSHELLS 32 +#define _UC_MAXGROUPS 200 + +struct userconf *read_userconfig(char const * file); +int write_userconfig(char const * file); +struct carg *addarg(struct cargs * _args, int ch, char *argstr); +struct carg *getarg(struct cargs * _args, int ch); +void cmderr(int ec, char const * fmt,...); + +int pw_user(struct userconf * cnf, int mode, struct cargs * _args); +int pw_group(struct userconf * cnf, int mode, struct cargs * _args); + +int addpwent(struct passwd * pwd); +int delpwent(struct passwd * pwd); +int chgpwent(char const * login, struct passwd * pwd); +int fmtpwent(char *buf, struct passwd * pwd); + +int addgrent(struct group * grp); +int delgrent(struct group * grp); +int chggrent(char const * login, struct group * grp); +int fmtgrent(char *buf, struct group * grp); + +int boolean_val(char const * str, int dflt); +char const *boolean_str(int val); +char *newstr(char const * p); + +void pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...); +char *pw_pwcrypt(char *password); + +extern const char *Modes[]; +extern const char *Which[]; Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw_group.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw_group.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw_group.c (revision 29197) @@ -0,0 +1,320 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include + +#include "pw.h" +#include "bitmap.h" + + +static int print_group(struct group * grp, int pretty); +static gid_t gr_gidpolicy(struct userconf * cnf, struct cargs * args); + +int +pw_group(struct userconf * cnf, int mode, struct cargs * args) +{ + struct carg *a_name = getarg(args, 'n'); + struct carg *a_gid = getarg(args, 'g'); + struct carg *arg; + struct group *grp = NULL; + char *members[_UC_MAXGROUPS]; + + static struct group fakegroup = + { + "nogroup", + "*", + -1, + NULL + }; + + /* + * With M_NEXT, we only need to return the + * next gid to stdout + */ + if (mode == M_NEXT) + { + gid_t next = gr_gidpolicy(cnf, args); + if (getarg(args, 'q')) + return next; + printf("%ld\n", (long)next); + return EXIT_SUCCESS; + } + + if (mode == M_PRINT && getarg(args, 'a')) { + int pretty = getarg(args, 'P') != NULL; + + setgrent(); + while ((grp = getgrent()) != NULL) + print_group(grp, pretty); + endgrent(); + return EXIT_SUCCESS; + } + if (a_gid == NULL) { + if (a_name == NULL) + cmderr(EX_DATAERR, "group name or id required\n"); + + if (mode != M_ADD && grp == NULL && isdigit(*a_name->val)) { + (a_gid = a_name)->ch = 'g'; + a_name = NULL; + } + } + grp = (a_name != NULL) ? getgrnam(a_name->val) : getgrgid((gid_t) atoi(a_gid->val)); + + if (mode == M_UPDATE || mode == M_DELETE || mode == M_PRINT) { + if (a_name == NULL && grp == NULL) /* Try harder */ + grp = getgrgid(atoi(a_gid->val)); + + if (grp == NULL) { + if (mode == M_PRINT && getarg(args, 'F')) { + fakegroup.gr_name = a_name ? a_name->val : "nogroup"; + fakegroup.gr_gid = a_gid ? (gid_t) atol(a_gid->val) : -1; + return print_group(&fakegroup, getarg(args, 'P') != NULL); + } + cmderr(EX_DATAERR, "unknown group `%s'\n", a_name ? a_name->val : a_gid->val); + } + if (a_name == NULL) /* Needed later */ + a_name = addarg(args, 'n', grp->gr_name); + + /* + * Handle deletions now + */ + if (mode == M_DELETE) { + gid_t gid = grp->gr_gid; + + if (delgrent(grp) == -1) + cmderr(EX_IOERR, "Error updating group file: %s\n", strerror(errno)); + pw_log(cnf, mode, W_GROUP, "%s(%ld) removed", a_name->val, (long) gid); + return EXIT_SUCCESS; + } else if (mode == M_PRINT) + return print_group(grp, getarg(args, 'P') != NULL); + + if (a_gid) + grp->gr_gid = (gid_t) atoi(a_gid->val); + + if ((arg = getarg(args, 'l')) != NULL) + grp->gr_name = arg->val; + } else { + if (a_name == NULL) /* Required */ + cmderr(EX_DATAERR, "group name required\n"); + else if (grp != NULL) /* Exists */ + cmderr(EX_DATAERR, "group name `%s' already exists\n", a_name->val); + + memset(members, 0, sizeof members); + grp = &fakegroup; + grp->gr_name = a_name->val; + grp->gr_passwd = "*"; + grp->gr_gid = gr_gidpolicy(cnf, args); + grp->gr_mem = members; + } + + /* + * This allows us to set a group password Group passwords is an + * antique idea, rarely used and insecure (no secure database) Should + * be discouraged, but it is apparently still supported by some + * software. + */ + + if ((arg = getarg(args, 'h')) != NULL) { + if (strcmp(arg->val, "-") == 0) + grp->gr_passwd = "*"; /* No access */ + else { + int fd = atoi(arg->val); + int b; + int istty = isatty(fd); + struct termios t; + char *p, line[256]; + + if (istty) { + if (tcgetattr(fd, &t) == -1) + istty = 0; + else { + struct termios n = t; + + /* Disable echo */ + n.c_lflag &= ~(ECHO); + tcsetattr(fd, TCSANOW, &n); + printf("%sassword for group %s:", (mode == M_UPDATE) ? "New p" : "P", grp->gr_name); + fflush(stdout); + } + } + b = read(fd, line, sizeof(line) - 1); + if (istty) { /* Restore state */ + tcsetattr(fd, TCSANOW, &t); + fputc('\n', stdout); + fflush(stdout); + } + if (b < 0) { + perror("-h file descriptor"); + return EX_OSERR; + } + line[b] = '\0'; + if ((p = strpbrk(line, " \t\r\n")) != NULL) + *p = '\0'; + if (!*line) + cmderr(EX_DATAERR, "empty password read on file descriptor %d\n", fd); + grp->gr_passwd = pw_pwcrypt(line); + } + } + + if (((arg = getarg(args, 'M')) != NULL || (arg = getarg(args, 'm')) != NULL) && arg->val) { + int i = 0; + char *p; + struct passwd *pwd; + + if (arg->ch == 'm') { + while (i < _UC_MAXGROUPS && grp->gr_mem[i] != NULL) { + members[i] = grp->gr_mem[i]; + i++; + } + } + for (p = strtok(arg->val, ", \t"); i < _UC_MAXGROUPS && p != NULL; p = strtok(NULL, ", \t")) { + int j; + if ((pwd = getpwnam(p)) == NULL) { + if (!isdigit(*p) || (pwd = getpwuid((uid_t) atoi(p))) == NULL) + cmderr(EX_NOUSER, "user `%s' does not exist\n", p); + } + /* + * Check for duplicates + */ + for (j = 0; j < i && strcmp(members[j], pwd->pw_name)!=0; j++) + ; + if (j == i) + members[i++] = newstr(pwd->pw_name); + } + while (i < _UC_MAXGROUPS) + members[i++] = NULL; + grp->gr_mem = members; + } + + if (getarg(args, 'N') != NULL) + return print_group(grp, getarg(args, 'P') != NULL); + + if ((mode == M_ADD && !addgrent(grp)) || (mode == M_UPDATE && !chggrent(a_name->val, grp))) { + perror("group update"); + return EX_IOERR; + } + /* grp may have been invalidated */ + if ((grp = getgrnam(a_name->val)) == NULL) + cmderr(EX_SOFTWARE, "group disappeared during update\n"); + + pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid); + + return EXIT_SUCCESS; +} + + +static gid_t +gr_gidpolicy(struct userconf * cnf, struct cargs * args) +{ + struct group *grp; + gid_t gid = (gid_t) - 1; + struct carg *a_gid = getarg(args, 'g'); + + /* + * Check the given gid, if any + */ + if (a_gid != NULL) { + gid = (gid_t) atol(a_gid->val); + + if ((grp = getgrgid(gid)) != NULL && getarg(args, 'o') == NULL) + cmderr(EX_DATAERR, "gid `%ld' has already been allocated\n", (long) grp->gr_gid); + } else { + struct bitmap bm; + + /* + * We need to allocate the next available gid under one of + * two policies a) Grab the first unused gid b) Grab the + * highest possible unused gid + */ + if (cnf->min_gid >= cnf->max_gid) { /* Sanity claus^H^H^H^Hheck */ + cnf->min_gid = 1000; + cnf->max_gid = 32000; + } + bm = bm_alloc(cnf->max_gid - cnf->min_gid + 1); + + /* + * Now, let's fill the bitmap from the password file + */ + setgrent(); + while ((grp = getgrent()) != NULL) + if (grp->gr_gid >= (int) cnf->min_gid && grp->gr_gid <= (int) cnf->max_gid) + bm_setbit(&bm, grp->gr_gid - cnf->min_gid); + endgrent(); + + /* + * Then apply the policy, with fallback to reuse if necessary + */ + if (cnf->reuse_gids) + gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); + else { + gid = (gid_t) (bm_lastset(&bm) + 1); + if (!bm_isset(&bm, gid)) + gid += cnf->min_gid; + else + gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid); + } + + /* + * Another sanity check + */ + if (gid < cnf->min_gid || gid > cnf->max_gid) + cmderr(EX_SOFTWARE, "unable to allocate a new gid - range fully used\n"); + bm_dealloc(&bm); + } + return gid; +} + + +static int +print_group(struct group * grp, int pretty) +{ + if (!pretty) { + char buf[_UC_MAXLINE]; + + fmtgrent(buf, grp); + fputs(buf, stdout); + } else { + int i; + + printf("Group Name : %-10s #%lu\n" + " Members : ", + grp->gr_name, (long) grp->gr_gid); + for (i = 0; i < _UC_MAXGROUPS && grp->gr_mem[i]; i++) + printf("%s%s", i ? "," : "", grp->gr_mem[i]); + fputs("\n\n", stdout); + } + return EXIT_SUCCESS; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw_group.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw_user.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw_user.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw_user.c (revision 29197) @@ -0,0 +1,902 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pw.h" +#include "bitmap.h" +#include "pwupd.h" + +static int print_user(struct passwd * pwd, int pretty); +static uid_t pw_uidpolicy(struct userconf * cnf, struct cargs * args); +static uid_t pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer); +static time_t pw_pwdpolicy(struct userconf * cnf, struct cargs * args); +static time_t pw_exppolicy(struct userconf * cnf, struct cargs * args); +static char *pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user); +static char *pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell); +static char *pw_password(struct userconf * cnf, struct cargs * args, char const * user); +static char *pw_checkname(char *name, int gecos); +static char *shell_path(char const * path, char *shells[], char *sh); +static void rmat(uid_t uid); + +/*- + * -C config configuration file + * -q quiet operation + * -n name login name + * -u uid user id + * -c comment user name/comment + * -d directory home directory + * -e date account expiry date + * -p date password expiry date + * -g grp primary group + * -G grp1,grp2 additional groups + * -m [ -k dir ] create and set up home + * -s shell name of login shell + * -o duplicate uid ok + * -L class user class + * -l name new login name + * -h fd password filehandle + * -F force print or add + * Setting defaults: + * -D set user defaults + * -b dir default home root dir + * -e period default expiry period + * -p period default password change period + * -g group default group + * -G grp1,grp2.. default additional groups + * -L class default login class + * -k dir default home skeleton + * -s shell default shell + * -w method default password method + */ + +int +pw_user(struct userconf * cnf, int mode, struct cargs * args) +{ + char *p = NULL; + struct carg *a_name; + struct carg *a_uid; + struct carg *arg; + struct passwd *pwd = NULL; + struct group *grp; + struct stat st; + char line[MAXPWLINE]; + + static struct passwd fakeuser = + { + NULL, + "*", + -1, + -1, + 0, + "", + "User &", + "/bin/sh", + 0, + 0 + }; + + /* + * With M_NEXT, we only need to return the + * next uid to stdout + */ + if (mode == M_NEXT) + { + uid_t next = pw_uidpolicy(cnf, args); + if (getarg(args, 'q')) + return next; + printf("%ld:", (long)next); + pw_group(cnf, mode, args); + return EXIT_SUCCESS; + } + + /* + * We can do all of the common legwork here + */ + + if ((arg = getarg(args, 'b')) != NULL) { + cnf->home = arg->val; + if (stat(cnf->home, &st) == -1 || !S_ISDIR(st.st_mode)) + cmderr(EX_OSFILE, "root home `%s' is not a directory or does not exist\n", cnf->home); + } + if ((arg = getarg(args, 'e')) != NULL) + cnf->expire_days = atoi(arg->val); + + if ((arg = getarg(args, 'p')) != NULL && arg->val) + cnf->password_days = atoi(arg->val); + + if ((arg = getarg(args, 'g')) != NULL) { + p = arg->val; + if ((grp = getgrnam(p)) == NULL) { + if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL) + cmderr(EX_NOUSER, "group `%s' does not exist\n", p); + } + cnf->default_group = newstr(grp->gr_name); + } + if ((arg = getarg(args, 'L')) != NULL) + cnf->default_class = pw_checkname(arg->val, 0); + + if ((arg = getarg(args, 'G')) != NULL && arg->val) { + int i = 0; + + for (p = strtok(arg->val, ", \t"); i < _UC_MAXGROUPS && p != NULL; p = strtok(NULL, ", \t")) { + if ((grp = getgrnam(p)) == NULL) { + if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL) + cmderr(EX_NOUSER, "group `%s' does not exist\n", p); + } + cnf->groups[i++] = newstr(grp->gr_name); + } + while (i < _UC_MAXGROUPS) + cnf->groups[i++] = NULL; + } + if ((arg = getarg(args, 'k')) != NULL) { + if (stat(cnf->dotdir = arg->val, &st) == -1 || S_ISDIR(st.st_mode)) + cmderr(EX_OSFILE, "skeleton `%s' is not a directory or does not exist\n", cnf->dotdir); + } + if ((arg = getarg(args, 's')) != NULL) + cnf->shell_default = arg->val; + + if (mode == M_ADD && getarg(args, 'D')) { + if (getarg(args, 'n') != NULL) + cmderr(EX_DATAERR, "can't combine `-D' with `-n name'\n"); + if ((arg = getarg(args, 'u')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) { + if ((cnf->min_uid = (uid_t) atoi(p)) == 0) + cnf->min_uid = 1000; + if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_uid = (uid_t) atoi(p)) < cnf->min_uid) + cnf->max_uid = 32000; + } + if ((arg = getarg(args, 'i')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) { + if ((cnf->min_gid = (gid_t) atoi(p)) == 0) + cnf->min_gid = 1000; + if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_gid = (gid_t) atoi(p)) < cnf->min_gid) + cnf->max_gid = 32000; + } + if ((arg = getarg(args, 'w')) != NULL) + cnf->default_password = boolean_val(arg->val, cnf->default_password); + + arg = getarg(args, 'C'); + if (write_userconfig(arg ? arg->val : NULL)) + return EXIT_SUCCESS; + perror("config update"); + return EX_IOERR; + } + if (mode == M_PRINT && getarg(args, 'a')) { + int pretty = getarg(args, 'P') != NULL; + + setpwent(); + while ((pwd = getpwent()) != NULL) + print_user(pwd, pretty); + endpwent(); + return EXIT_SUCCESS; + } + if ((a_name = getarg(args, 'n')) != NULL) + pwd = getpwnam(pw_checkname(a_name->val, 0)); + a_uid = getarg(args, 'u'); + + if (a_uid == NULL) { + if (a_name == NULL) + cmderr(EX_DATAERR, "user name or id required\n"); + + /* + * Determine whether 'n' switch is name or uid - we don't + * really don't really care which we have, but we need to + * know. + */ + if (mode != M_ADD && pwd == NULL && isdigit(*a_name->val) && atoi(a_name->val) > 0) { /* Assume uid */ + (a_uid = a_name)->ch = 'u'; + a_name = NULL; + } + } + /* + * Update, delete & print require that the user exists + */ + if (mode == M_UPDATE || mode == M_DELETE || mode == M_PRINT) { + if (a_name == NULL && pwd == NULL) /* Try harder */ + pwd = getpwuid(atoi(a_uid->val)); + + if (pwd == NULL) { + if (mode == M_PRINT && getarg(args, 'F')) { + fakeuser.pw_name = a_name ? a_name->val : "nouser"; + fakeuser.pw_uid = a_uid ? (uid_t) atol(a_uid->val) : -1; + return print_user(&fakeuser, getarg(args, 'P') != NULL); + } + if (a_name == NULL) + cmderr(EX_NOUSER, "no such uid `%s'\n", a_uid->val); + cmderr(EX_NOUSER, "no such user `%s'\n", a_name->val); + } + if (a_name == NULL) /* May be needed later */ + a_name = addarg(args, 'n', newstr(pwd->pw_name)); + + /* + * Handle deletions now + */ + if (mode == M_DELETE) { + char file[MAXPATHLEN]; + char home[MAXPATHLEN]; + uid_t uid = pwd->pw_uid; + + if (strcmp(pwd->pw_name, "root") == 0) + cmderr(EX_DATAERR, "cannot remove user 'root'\n"); + + /* + * Remove crontabs + */ + sprintf(file, "/var/cron/tabs/%s", pwd->pw_name); + if (access(file, F_OK) == 0) { + sprintf(file, "crontab -u %s -r", pwd->pw_name); + system(file); + } + /* + * Save these for later, since contents of pwd may be + * invalidated by deletion + */ + sprintf(file, "%s/%s", _PATH_MAILDIR, pwd->pw_name); + strncpy(home, pwd->pw_dir, sizeof home); + home[sizeof home - 1] = '\0'; + + if (!delpwent(pwd)) + cmderr(EX_IOERR, "Error updating passwd file: %s\n", strerror(errno)); + editgroups(a_name->val, NULL); + + pw_log(cnf, mode, W_USER, "%s(%ld) account removed", a_name->val, (long) uid); + + /* + * Remove mail file + */ + remove(file); + + /* + * Remove at jobs + */ + if (getpwuid(uid) == NULL) + rmat(uid); + + /* + * Remove home directory and contents + */ + if (getarg(args, 'r') != NULL && *home == '/' && getpwuid(uid) == NULL) { + if (stat(home, &st) != -1) { + rm_r(home, uid); + pw_log(cnf, mode, W_USER, "%s(%ld) home '%s' %sremoved", + a_name->val, (long) uid, home, + stat(home, &st) == -1 ? "" : "not completely "); + } + } + return EXIT_SUCCESS; + } else if (mode == M_PRINT) + return print_user(pwd, getarg(args, 'P') != NULL); + + /* + * The rest is edit code + */ + if ((arg = getarg(args, 'l')) != NULL) { + if (strcmp(pwd->pw_name, "root") == 0) + cmderr(EX_DATAERR, "can't rename `root' account\n"); + pwd->pw_name = pw_checkname(arg->val, 0); + } + if ((arg = getarg(args, 'u')) != NULL && isdigit(*arg->val)) { + pwd->pw_uid = (uid_t) atol(arg->val); + if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0) + cmderr(EX_DATAERR, "can't change uid of `root' account\n"); + if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) + fprintf(stderr, "WARNING: account `%s' will have a uid of 0 (superuser access!)\n", pwd->pw_name); + } + if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) /* Already checked this */ + pwd->pw_gid = (gid_t) getgrnam(cnf->default_group)->gr_gid; + + if ((arg = getarg(args, 'p')) != NULL) { + if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) + pwd->pw_change = 0; + else { + time_t now = time(NULL); + time_t expire = parse_date(now, arg->val); + + if (now == expire) + cmderr(EX_DATAERR, "Invalid password change date `%s'\n", arg->val); + pwd->pw_change = expire; + } + } + if ((arg = getarg(args, 'e')) != NULL) { + if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) + pwd->pw_expire = 0; + else { + time_t now = time(NULL); + time_t expire = parse_date(now, arg->val); + + if (now == expire) + cmderr(EX_DATAERR, "Invalid account expiry date `%s'\n", arg->val); + pwd->pw_expire = expire; + } + } + if ((arg = getarg(args, 's')) != NULL) + pwd->pw_shell = shell_path(cnf->shelldir, cnf->shells, arg->val); + + if (getarg(args, 'L')) + pwd->pw_class = cnf->default_class; + + if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL) + pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); + + } else { + if (a_name == NULL) /* Required */ + cmderr(EX_DATAERR, "login name required\n"); + else if ((pwd = getpwnam(a_name->val)) != NULL) /* Exists */ + cmderr(EX_DATAERR, "login name `%s' already exists\n", a_name->val); + + /* + * Now, set up defaults for a new user + */ + pwd = &fakeuser; + pwd->pw_name = a_name->val; + pwd->pw_class = cnf->default_class ? cnf->default_class : ""; + pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); + pwd->pw_uid = pw_uidpolicy(cnf, args); + pwd->pw_gid = pw_gidpolicy(cnf, args, pwd->pw_name, (gid_t) pwd->pw_uid); + pwd->pw_change = pw_pwdpolicy(cnf, args); + pwd->pw_expire = pw_exppolicy(cnf, args); + pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name); + pwd->pw_shell = pw_shellpolicy(cnf, args, NULL); + + if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) + fprintf(stderr, "WARNING: new account `%s' has a uid of 0 (superuser access!)\n", pwd->pw_name); + } + + /* + * Shared add/edit code + */ + if ((arg = getarg(args, 'c')) != NULL) + pwd->pw_gecos = pw_checkname(arg->val, 1); + + if ((arg = getarg(args, 'h')) != NULL) { + if (strcmp(arg->val, "-") == 0) + pwd->pw_passwd = "*"; /* No access */ + else { + int fd = atoi(arg->val); + int b; + int istty = isatty(fd); + struct termios t; + + if (istty) { + if (tcgetattr(fd, &t) == -1) + istty = 0; + else { + struct termios n = t; + + /* Disable echo */ + n.c_lflag &= ~(ECHO); + tcsetattr(fd, TCSANOW, &n); + printf("%sassword for user %s:", (mode == M_UPDATE) ? "New p" : "P", pwd->pw_name); + fflush(stdout); + } + } + b = read(fd, line, sizeof(line) - 1); + if (istty) { /* Restore state */ + tcsetattr(fd, TCSANOW, &t); + fputc('\n', stdout); + fflush(stdout); + } + if (b < 0) { + perror("-h file descriptor"); + return EX_IOERR; + } + line[b] = '\0'; + if ((p = strpbrk(line, " \t\r\n")) != NULL) + *p = '\0'; + if (!*line) + cmderr(EX_DATAERR, "empty password read on file descriptor %d\n", fd); + pwd->pw_passwd = pw_pwcrypt(line); + } + } + + /* + * Special case: -N only displays & exits + */ + if (getarg(args, 'N') != NULL) + return print_user(pwd, getarg(args, 'P') != NULL); + + if ((mode == M_ADD && !addpwent(pwd)) || + (mode == M_UPDATE && !chgpwent(a_name->val, pwd))) { + perror("password update"); + return EX_IOERR; + } + /* + * Ok, user is created or changed - now edit group file + */ + + if (mode == M_ADD || getarg(args, 'G') != NULL) + editgroups(pwd->pw_name, cnf->groups); + + /* pwd may have been invalidated */ + if ((pwd = getpwnam(a_name->val)) == NULL) + cmderr(EX_NOUSER, "user '%s' disappeared during update\n", a_name->val); + + grp = getgrgid(pwd->pw_gid); + pw_log(cnf, mode, W_USER, "%s(%ld):%s(%d):%s:%s:%s", + pwd->pw_name, (long) pwd->pw_uid, + grp ? grp->gr_name : "unknown", (long) (grp ? grp->gr_gid : -1), + pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); + + /* + * If adding, let's touch and chown the user's mail file. This is not + * strictly necessary under BSD with a 0755 maildir but it also + * doesn't hurt anything to create the empty mailfile + */ + if (mode == M_ADD) { + FILE *fp; + + sprintf(line, "%s/%s", _PATH_MAILDIR, pwd->pw_name); + close(open(line, O_RDWR | O_CREAT, 0600)); /* Preserve contents & + * mtime */ + chown(line, pwd->pw_uid, pwd->pw_gid); + + /* + * Send mail to the new user as well, if we are asked to + */ + if (cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) { + FILE *pfp = popen(_PATH_SENDMAIL " -t", "w"); + + if (pfp == NULL) + perror("sendmail"); + else { + fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name); + while (fgets(line, sizeof(line), fp) != NULL) { + /* Do substitutions? */ + fputs(line, pfp); + } + pclose(pfp); + pw_log(cnf, mode, W_USER, "%s(%ld) new user mail sent", + pwd->pw_name, (long) pwd->pw_uid); + } + fclose(fp); + } + } + /* + * Finally, let's create and populate the user's home directory. Note + * that this also `works' for editing users if -m is used, but + * existing files will *not* be overwritten. + */ + if (getarg(args, 'm') != NULL && pwd->pw_dir && *pwd->pw_dir == '/' && pwd->pw_dir[1]) { + copymkdir(pwd->pw_dir, cnf->dotdir, 0755, pwd->pw_uid, pwd->pw_gid); + pw_log(cnf, mode, W_USER, "%s(%ld) home %s made", + pwd->pw_name, (long) pwd->pw_uid, pwd->pw_dir); + } + return EXIT_SUCCESS; +} + + +static uid_t +pw_uidpolicy(struct userconf * cnf, struct cargs * args) +{ + struct passwd *pwd; + uid_t uid = (uid_t) - 1; + struct carg *a_uid = getarg(args, 'u'); + + /* + * Check the given uid, if any + */ + if (a_uid != NULL) { + uid = (uid_t) atol(a_uid->val); + + if ((pwd = getpwuid(uid)) != NULL && getarg(args, 'o') == NULL) + cmderr(EX_DATAERR, "uid `%ld' has already been allocated\n", (long) pwd->pw_uid); + } else { + struct bitmap bm; + + /* + * We need to allocate the next available uid under one of + * two policies a) Grab the first unused uid b) Grab the + * highest possible unused uid + */ + if (cnf->min_uid >= cnf->max_uid) { /* Sanity + * claus^H^H^H^Hheck */ + cnf->min_uid = 1000; + cnf->max_uid = 32000; + } + bm = bm_alloc(cnf->max_uid - cnf->min_uid + 1); + + /* + * Now, let's fill the bitmap from the password file + */ + setpwent(); + while ((pwd = getpwent()) != NULL) + if (pwd->pw_uid >= (int) cnf->min_uid && pwd->pw_uid <= (int) cnf->max_uid) + bm_setbit(&bm, pwd->pw_uid - cnf->min_uid); + endpwent(); + + /* + * Then apply the policy, with fallback to reuse if necessary + */ + if (cnf->reuse_uids || (uid = (uid_t) (bm_lastset(&bm) + cnf->min_uid + 1)) > cnf->max_uid) + uid = (uid_t) (bm_firstunset(&bm) + cnf->min_uid); + + /* + * Another sanity check + */ + if (uid < cnf->min_uid || uid > cnf->max_uid) + cmderr(EX_SOFTWARE, "unable to allocate a new uid - range fully used\n"); + bm_dealloc(&bm); + } + return uid; +} + + +static uid_t +pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer) +{ + struct group *grp; + gid_t gid = (uid_t) - 1; + struct carg *a_gid = getarg(args, 'g'); + + /* + * If no arg given, see if default can help out + */ + if (a_gid == NULL && cnf->default_group && *cnf->default_group) + a_gid = addarg(args, 'g', cnf->default_group); + + /* + * Check the given gid, if any + */ + setgrent(); + if (a_gid != NULL) { + if ((grp = getgrnam(a_gid->val)) == NULL) { + gid = (gid_t) atol(a_gid->val); + if ((gid == 0 && !isdigit(*a_gid->val)) || (grp = getgrgid(gid)) == NULL) + cmderr(EX_NOUSER, "group `%s' is not defined\n", a_gid->val); + } + gid = grp->gr_gid; + } else if ((grp = getgrnam(nam)) != NULL && grp->gr_mem[0] == NULL) { + gid = grp->gr_gid; /* Already created? Use it anyway... */ + } else { + struct cargs grpargs; + char tmp[32]; + + LIST_INIT(&grpargs); + addarg(&grpargs, 'n', nam); + + /* + * We need to auto-create a group with the user's name. We + * can send all the appropriate output to our sister routine + * bit first see if we can create a group with gid==uid so we + * can keep the user and group ids in sync. We purposely do + * NOT check the gid range if we can force the sync. If the + * user's name dups an existing group, then the group add + * function will happily handle that case for us and exit. + */ + if (getgrgid(prefer) == NULL) { + sprintf(tmp, "%lu", (unsigned long) prefer); + addarg(&grpargs, 'g', tmp); + } + if (getarg(args, 'N')) + { + addarg(&grpargs, 'N', NULL); + addarg(&grpargs, 'q', NULL); + gid = pw_group(cnf, M_NEXT, &grpargs); + } + else + { + pw_group(cnf, M_ADD, &grpargs); + if ((grp = getgrnam(nam)) != NULL) + gid = grp->gr_gid; + } + a_gid = grpargs.lh_first; + while (a_gid != NULL) { + struct carg *t = a_gid->list.le_next; + LIST_REMOVE(a_gid, list); + a_gid = t; + } + } + endgrent(); + return gid; +} + + +static time_t +pw_pwdpolicy(struct userconf * cnf, struct cargs * args) +{ + time_t result = 0; + time_t now = time(NULL); + struct carg *arg = getarg(args, 'e'); + + if (arg != NULL) { + if ((result = parse_date(now, arg->val)) == now) + cmderr(EX_DATAERR, "invalid date/time `%s'\n", arg->val); + } else if (cnf->password_days > 0) + result = now + ((long) cnf->password_days * 86400L); + return result; +} + + +static time_t +pw_exppolicy(struct userconf * cnf, struct cargs * args) +{ + time_t result = 0; + time_t now = time(NULL); + struct carg *arg = getarg(args, 'e'); + + if (arg != NULL) { + if ((result = parse_date(now, arg->val)) == now) + cmderr(EX_DATAERR, "invalid date/time `%s'\n", arg->val); + } else if (cnf->expire_days > 0) + result = now + ((long) cnf->expire_days * 86400L); + return result; +} + + +static char * +pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user) +{ + struct carg *arg = getarg(args, 'd'); + + if (arg) + return arg->val; + else { + static char home[128]; + + if (cnf->home == NULL || *cnf->home == '\0') + cmderr(EX_CONFIG, "no base home directory set\n"); + sprintf(home, "%s/%s", cnf->home, user); + return home; + } +} + +static char * +shell_path(char const * path, char *shells[], char *sh) +{ + if (sh != NULL && (*sh == '/' || *sh == '\0')) + return sh; /* specified full path or forced none */ + else { + char *p; + char paths[_UC_MAXLINE]; + + /* + * We need to search paths + */ + strncpy(paths, path, sizeof paths); + paths[sizeof paths - 1] = '\0'; + for (p = strtok(paths, ": \t\r\n"); p != NULL; p = strtok(NULL, ": \t\r\n")) { + int i; + static char shellpath[256]; + + if (sh != NULL) { + sprintf(shellpath, "%s/%s", p, sh); + if (access(shellpath, X_OK) == 0) + return shellpath; + } else + for (i = 0; i < _UC_MAXSHELLS && shells[i] != NULL; i++) { + sprintf(shellpath, "%s/%s", p, shells[i]); + if (access(shellpath, X_OK) == 0) + return shellpath; + } + } + if (sh == NULL) + cmderr(EX_OSFILE, "can't find shell `%s' in shell paths\n", sh); + cmderr(EX_CONFIG, "no default shell available or defined\n"); + return NULL; + } +} + + +static char * +pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell) +{ + char *sh = newshell; + struct carg *arg = getarg(args, 's'); + + if (newshell == NULL && arg != NULL) + sh = arg->val; + return shell_path(cnf->shelldir, cnf->shells, sh ? sh : cnf->shell_default); +} + +static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ."; + +char * +pw_pwcrypt(char *password) +{ + int i; + char salt[12]; + + static char buf[256]; + + /* + * Calculate a salt value + */ + srandom((unsigned) (time(NULL) | getpid())); + for (i = 0; i < 8; i++) + salt[i] = chars[random() % 63]; + salt[i] = '\0'; + + return strcpy(buf, crypt(password, salt)); +} + + +static char * +pw_password(struct userconf * cnf, struct cargs * args, char const * user) +{ + int i, l; + char pwbuf[32]; + + switch (cnf->default_password) { + case -1: /* Random password */ + srandom((unsigned) (time(NULL) | getpid())); + l = (random() % 8 + 8); /* 8 - 16 chars */ + for (i = 0; i < l; i++) + pwbuf[i] = chars[random() % sizeof(chars)]; + pwbuf[i] = '\0'; + + /* + * We give this information back to the user + */ + if (getarg(args, 'h') == NULL && getarg(args, 'N') == NULL) { + if (isatty(0)) + printf("Password is: "); + printf("%s\n", pwbuf); + fflush(stdout); + } + break; + + case -2: /* No password at all! */ + return ""; + + case 0: /* No login - default */ + default: + return "*"; + + case 1: /* user's name */ + strncpy(pwbuf, user, sizeof pwbuf); + pwbuf[sizeof pwbuf - 1] = '\0'; + break; + } + return pw_pwcrypt(pwbuf); +} + + +static int +print_user(struct passwd * pwd, int pretty) +{ + if (!pretty) { + char buf[_UC_MAXLINE]; + + fmtpwent(buf, pwd); + fputs(buf, stdout); + } else { + int j; + char *p; + struct group *grp = getgrgid(pwd->pw_gid); + char uname[60] = "User &", office[60] = "[None]", + wphone[60] = "[None]", hphone[60] = "[None]"; + + if ((p = strtok(pwd->pw_gecos, ",")) != NULL) { + strncpy(uname, p, sizeof uname); + uname[sizeof uname - 1] = '\0'; + if ((p = strtok(NULL, ",")) != NULL) { + strncpy(office, p, sizeof office); + office[sizeof office - 1] = '\0'; + if ((p = strtok(NULL, ",")) != NULL) { + strncpy(wphone, p, sizeof wphone); + wphone[sizeof wphone - 1] = '\0'; + if ((p = strtok(NULL, "")) != NULL) { + strncpy(hphone, p, sizeof hphone); + hphone[sizeof hphone - 1] = '\0'; + } + } + } + } + /* + * Handle '&' in gecos field + */ + if ((p = strchr(uname, '&')) != NULL) { + int l = strlen(pwd->pw_name); + int m = strlen(p); + + memmove(p + l, p + 1, m); + memmove(p, pwd->pw_name, l); + *p = (char) toupper(*p); + } + printf("Login Name : %-10s #%-22ld Group : %-10s #%ld\n" + " Full Name : %s\n" + " Home : %-32.32s Class : %s\n" + " Shell : %-32.32s Office : %s\n" + "Work Phone : %-32.32s Home Phone : %s\n", + + pwd->pw_name, (long) pwd->pw_uid, + grp ? grp->gr_name : "(invalid)", (long) pwd->pw_gid, + uname, pwd->pw_dir, pwd->pw_class, + pwd->pw_shell, office, wphone, hphone); + setgrent(); + j = 0; + while ((grp=getgrent()) != NULL) + { + int i = 0; + while (i < _UC_MAXGROUPS && grp->gr_mem[i] != NULL) + { + if (strcmp(grp->gr_mem[i], pwd->pw_name)==0) + { + printf(j++ == 0 ? " Groups : %s" : ",%s", grp->gr_name); + break; + } + ++i; + } + } + endgrent(); + printf("%s\n", j ? "\n" : ""); + } + return EXIT_SUCCESS; +} + +static char * +pw_checkname(char *name, int gecos) +{ + int l = 0; + char const *notch = gecos ? ":" : " :+-&#%$^()!@~*?<>=|\\/\""; + + while (name[l]) { + if (strchr(notch, name[l]) != NULL || name[l] < ' ') + cmderr(EX_DATAERR, "invalid character `%c' in field\n", name[l]); + ++l; + } + if (!gecos && l > 8) + cmderr(EX_DATAERR, "name too long `%s'\n", name); + return name; +} + + +static void +rmat(uid_t uid) +{ + DIR *d = opendir("/var/at/jobs"); + + if (d != NULL) { + struct dirent *e; + + while ((e = readdir(d)) != NULL) { + struct stat st; + + if (strncmp(e->d_name, ".lock", 5) != 0 && + stat(e->d_name, &st) == 0 && + !S_ISDIR(st.st_mode) && + st.st_uid == uid) { + char tmp[MAXPATHLEN]; + + sprintf(tmp, "/usr/bin/atrm %s", e->d_name); + system(tmp); + } + } + closedir(d); + } +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw_user.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.c (revision 29197) @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwupd.h" + +#define HAVE_PWDB_C 1 + +static int +pwdb(char *arg,...) +{ + int i = 0; + pid_t pid; + va_list ap; + char *args[8]; + + args[i++] = _PATH_PWD_MKDB; + va_start(ap, arg); + while (i < 6 && arg != NULL) { + args[i++] = arg; + arg = va_arg(ap, char *); + } + args[i++] = _PATH_MASTERPASSWD; + args[i] = NULL; + + if ((pid = fork()) == -1) /* Error (errno set) */ + i = -1; + else if (pid == 0) { /* Child */ + execv(args[0], args); + _exit(1); + } else { /* Parent */ + waitpid(pid, &i, 0); + if ((i = WEXITSTATUS(i)) != 0) + errno = EIO; /* set SOMETHING */ + } + return i; +} + +int +fmtpwentry(char *buf, struct passwd * pwd, int type) +{ + int l; + char *pw; + + pw = (pwd->pw_passwd == NULL || !*pwd->pw_passwd) ? "" : (type == PWF_MASTER) ? pwd->pw_passwd : "*"; + + if (type == PWF_PASSWD) + l = sprintf(buf, "%s:*:%ld:%ld:%s:%s:%s\n", + pwd->pw_name, (long) pwd->pw_uid, (long) pwd->pw_gid, + pwd->pw_gecos ? pwd->pw_gecos : "User &", + pwd->pw_dir, pwd->pw_shell); + else + l = sprintf(buf, "%s:%s:%ld:%ld:%s:%lu:%lu:%s:%s:%s\n", + pwd->pw_name, pw, (long) pwd->pw_uid, (long) pwd->pw_gid, + pwd->pw_class ? pwd->pw_class : "", + (unsigned long) pwd->pw_change, + (unsigned long) pwd->pw_expire, + pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); + return l; +} + + +int +fmtpwent(char *buf, struct passwd * pwd) +{ + return fmtpwentry(buf, pwd, PWF_STANDARD); +} + +static int +pw_update(struct passwd * pwd, char const * user, int mode) +{ + int rc = 0; + + endpwent(); + + /* + * First, let's check the see if the database is alright + * Note: -c is only available in FreeBSD 2.2 and above + */ +#ifdef HAVE_PWDB_C + if (pwdb("-c", NULL) == 0) { /* Check only */ +#else + { /* No -c */ +#endif + char pfx[32]; + char pwbuf[MAXPWLINE]; + int l = sprintf(pfx, "%s:", user); + + /* + * Update the passwd file first + */ + if (pwd == NULL) + *pwbuf = '\0'; + else + fmtpwentry(pwbuf, pwd, PWF_PASSWD); + if ((rc = fileupdate(_PATH_PASSWD, 0644, pwbuf, pfx, l, mode)) != 0) { + + /* + * Then the master.passwd file + */ + if (pwd != NULL) + fmtpwentry(pwbuf, pwd, PWF_MASTER); + if ((rc = fileupdate(_PATH_MASTERPASSWD, 0644, pwbuf, pfx, l, mode)) != 0) + rc = pwdb(NULL) == 0; + } + } + return rc; +} + +int +addpwent(struct passwd * pwd) +{ + return pw_update(pwd, pwd->pw_name, UPD_CREATE); +} + +int +chgpwent(char const * login, struct passwd * pwd) +{ + return pw_update(pwd, login, UPD_REPLACE); +} + +int +delpwent(struct passwd * pwd) +{ + return pw_update(NULL, pwd->pw_name, UPD_DELETE); +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/README =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/README (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/README (revision 29197) @@ -0,0 +1,22 @@ + +pw is a command-line driven passwd/group editor utility that provides +an easy and safe means of modifying of any/all fields in the system +password files, and has an add, modify and delete mode for user and +group records. Command line options have been fashioned to be similar +to those used by the Sun/shadow commands: useradd, usermod, userdel, +groupadd, groupmod, groupdel, but combines all operations within the +single command `pw'. + +User add mode also provides a means of easily setting system useradd +defaults (see pw.conf.5), so that adding a user is as easy as issuing +the command "pw useradd ". Creation of a unique primary +group for each user and automatic memberhip in secondary groups +is fully supported. + +This program may be FreBSD specific, but should be trivial to port to +other bsd4.4 variants. + +Author and maintainer: David L. Nugent, + +$Id$ + Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/README ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.c (revision 29197) @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include + +#include "bitmap.h" + +struct bitmap +bm_alloc(int size) +{ + struct bitmap bm; + int szmap = (size / 8) + !!(size % 8); + + bm.size = size; + bm.map = malloc(szmap); + if (bm.map) + memset(bm.map, 0, szmap); + return bm; +} + +void +bm_dealloc(struct bitmap * bm) +{ + if (bm->map) + free(bm->map); +} + +static void +bm_getmask(int *pos, unsigned char *bmask) +{ + *bmask = (unsigned char) (1 << (*pos % 8)); + *pos /= 8; +} + +void +bm_setbit(struct bitmap * bm, int pos) +{ + unsigned char bmask; + + bm_getmask(&pos, &bmask); + bm->map[pos] |= bmask; +} + +void +bm_clrbit(struct bitmap * bm, int pos) +{ + unsigned char bmask; + + bm_getmask(&pos, &bmask); + bm->map[pos] &= ~bmask; +} + +int +bm_isset(struct bitmap * bm, int pos) +{ + unsigned char bmask; + + bm_getmask(&pos, &bmask); + return !!(bm->map[pos] & bmask); +} + +int +bm_firstunset(struct bitmap * bm) +{ + int szmap = (bm->size / 8) + !!(bm->size % 8); + int at = 0; + int pos = 0; + + while (pos < szmap) { + unsigned char bmv = bm->map[pos++]; + unsigned char bmask = 1; + + while (bmask & 0xff) { + if ((bmv & bmask) == 0) + return at; + bmask <<= 1; + ++at; + } + } + return at; +} + +int +bm_lastset(struct bitmap * bm) +{ + int szmap = (bm->size / 8) + !!(bm->size % 8); + int at = 0; + int pos = 0; + int ofs = 0; + + while (pos < szmap) { + unsigned char bmv = bm->map[pos++]; + unsigned char bmask = 1; + + while (bmask & 0xff) { + if ((bmv & bmask) != 0) + ofs = at; + bmask <<= 1; + ++at; + } + } + return ofs; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.h =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.h (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.h (revision 29197) @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#ifndef _BITMAP_H_ +#define _BITMAP_H_ + +#include + +struct bitmap +{ + int size; + unsigned char *map; +}; + +__BEGIN_DECLS +struct bitmap bm_alloc __P((int size)); +void bm_dealloc __P((struct bitmap * bm)); +void bm_setbit __P((struct bitmap * bm, int pos)); +void bm_clrbit __P((struct bitmap * bm, int pos)); +int bm_isset __P((struct bitmap * bm, int pos)); +int bm_firstunset __P((struct bitmap * bm)); +int bm_lastset __P((struct bitmap * bm)); +__END_DECLS + +#endif /* !_BITMAP_H */ Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/bitmap.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/edgroup.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/edgroup.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/edgroup.c (revision 29197) @@ -0,0 +1,206 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwupd.h" + +static int +isingroup(char const * name, char **mem) +{ + int i; + + for (i = 0; i < MAXGROUPS && mem[i] != NULL; i++) + if (strcmp(name, mem[i]) == 0) + return i; + return -1; +} + +static char groupfile[] = _PATH_GROUP; +static char grouptmp[] = _PATH_GROUP ".new"; + +int +editgroups(char *name, char **groups) +{ + int rc = 0; + int infd; + + if ((infd = open(groupfile, O_RDWR | O_CREAT | O_EXLOCK, 0644)) != -1) { + FILE *infp; + + if ((infp = fdopen(infd, "r+")) == NULL) + close(infd); + else { + int outfd; + + if ((outfd = open(grouptmp, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, 0644)) != -1) { + FILE *outfp; + + if ((outfp = fdopen(outfd, "w+")) == NULL) + close(outfd); + else { + char line[MAXPWLINE]; + char outl[MAXPWLINE]; + + while (fgets(line, sizeof(line), infp) != NULL) { + char *p = strchr(line, '\n'); + + if (p == NULL) { /* Line too long */ + int ch; + + fputs(line, outfp); + while ((ch = fgetc(infp)) != EOF) { + fputc(ch, outfp); + if (ch == '\n') + break; + } + continue; + } + if (*line == '#') + strcpy(outl, line); + else if (*line == '\n') + *outl = '\0'; + else { + int i, + mno = 0; + char *cp = line; + char const *sep = ":\n"; + struct group grp; + char *mems[MAXGROUPS]; + + memset(&grp, 0, sizeof grp); + grp.gr_mem = mems; + for (i = 0; (p = strsep(&cp, sep)) != NULL; i++) { + switch (i) { + case 0: /* Group name */ + grp.gr_name = p; + break; + case 1: /* Group password */ + grp.gr_passwd = p; + break; + case 2: /* Group id */ + grp.gr_gid = atoi(p); + break; + case 3: /* Member list */ + cp = p; + sep = ",\n"; + break; + default: /* Individual members */ + if (mno < MAXGROUPS && *p) + mems[mno++] = p; + break; + } + } + if (i < 2) /* Bail out - + * insufficient fields */ + continue; + + for (i = mno; i < MAXGROUPS; i++) + mems[i] = NULL; + + /* + * Delete from group, or add to group? + */ + if (groups == NULL || isingroup(grp.gr_name, groups) == -1) { /* Delete */ + int idx; + + while ((idx = isingroup(name, mems)) != -1) { + for (i = idx; i < (MAXGROUPS - 1); i++) + mems[i] = mems[i + 1]; + mems[i] = NULL; + --mno; + } + + /* + * Special case - deleting user and group may be user's own + */ + if (groups == NULL && mems[0] == NULL && strcmp(name, grp.gr_name) == 0) { /* First, make _sure_ we + * don't have other + * members */ + struct passwd *pwd; + + setpwent(); + while ((pwd = getpwent()) != NULL && pwd->pw_gid != grp.gr_gid); + endpwent(); + if (pwd == NULL) /* No members at all */ + continue; /* Drop the group */ + } + } else if (isingroup(name, mems) == -1) + mems[mno++] = name; + fmtgrentry(outl, &grp, PWF_GROUP); + } + fputs(outl, outfp); + } + if (fflush(outfp) != EOF) { + rc = 1; + + /* + * Copy data back into the original file and truncate + */ + rewind(infp); + rewind(outfp); + while (fgets(line, sizeof(line), outfp) != NULL) + fputs(line, infp); + + /* + * This is a gross hack, but we may have corrupted the + * original file. Unfortunately, it will lose preservation + * of the inode. + */ + if (fflush(infp) == EOF || ferror(infp)) + rc = rename(grouptmp, groupfile) == 0; + else + ftruncate(infd, ftell(infp)); + } + fclose(outfp); + } + remove(grouptmp); + } + fclose(infp); + } + } + return rc; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/edgroup.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/fileupd.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/fileupd.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/fileupd.c (revision 29197) @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwupd.h" + +int +fileupdate(char const * filename, mode_t fmode, char const * newline, char const * prefix, int pfxlen, int updmode) +{ + int rc = 0; + + if (pfxlen <= 1) + errno = EINVAL; + else { + int infd = open(filename, O_RDWR | O_CREAT | O_EXLOCK, fmode); + + if (infd != -1) { + FILE *infp = fdopen(infd, "r+"); + + if (infp == NULL) + close(infd); + else { + int outfd; + char file[MAXPATHLEN]; + + strcpy(file, filename); + strcat(file, ".new"); + outfd = open(file, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, fmode); + if (outfd != -1) { + FILE *outfp = fdopen(outfd, "w+"); + + if (outfp == NULL) + close(outfd); + else { + int updated = UPD_CREATE; + char line[2048]; + + while (fgets(line, sizeof(line), infp) != NULL) { + char *p = strchr(line, '\n'); + + if (p == NULL) { /* Line too long */ + int ch; + + fputs(line, outfp); + while ((ch = fgetc(infp)) != EOF) { + fputc(ch, outfp); + if (ch == '\n') + break; + } + continue; + } + if (*line != '#' && *line != '\n') { + if (!updated && strncmp(line, prefix, pfxlen) == 0) { + updated = updmode == UPD_REPLACE ? UPD_REPLACE : UPD_DELETE; + + /* + * Only actually write changes if updating + */ + if (updmode == UPD_REPLACE) + strcpy(line, newline); + else if (updmode == UPD_DELETE) + continue; + } + } + fputs(line, outfp); + } + + /* + * Now, we need to decide what to do: If we are in + * update mode, and no record was updated, then error If + * we are in insert mode, and record already exists, + * then error + */ + if (updmode != updated) + errno = (updmode == UPD_CREATE) ? EEXIST : ENOENT; + else { + + /* + * If adding a new record, append it to the end + */ + if (updmode == UPD_CREATE) + fputs(newline, outfp); + + /* + * Flush the file and check for the result + */ + rc = fflush(outfp) != EOF; + if (rc) { + + /* + * Copy data back into the + * original file and truncate + */ + rewind(infp); + rewind(outfp); + while (fgets(line, sizeof(line), outfp) != NULL) + fputs(line, infp); + + /* + * This is a gross hack, but we may have + * corrupted the original file + * Unfortunately, it will lose the inode. + */ + if (fflush(infp) == EOF || ferror(infp)) + rc = rename(file, filename) == 0; + else + ftruncate(infd, ftell(infp)); + } + } + fclose(outfp); + } + remove(file); + } + fclose(infp); + } + } + } + return rc; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/fileupd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/grupd.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/grupd.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/grupd.c (revision 29197) @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwupd.h" + +int +fmtgrentry(char *buf, struct group * grp, int type) +{ + int i, l; + + if (type == PWF_STANDARD) + l = sprintf(buf, "%s:*:%ld:", grp->gr_name, (long) grp->gr_gid); + else + l = sprintf(buf, "%s:%s:%ld:", grp->gr_name, grp->gr_passwd, (long) grp->gr_gid); + + /* + * Now, list members + */ + for (i = 0; i < 200 && grp->gr_mem[i]; i++) + l += sprintf(buf + l, "%s%s", i ? "," : "", grp->gr_mem[i]); + buf[l++] = '\n'; + buf[l] = '\0'; + return l; +} + + +int +fmtgrent(char *buf, struct group * grp) +{ + return fmtgrentry(buf, grp, PWF_STANDARD); +} + + +static int +gr_update(struct group * grp, char const * group, int mode) +{ + int l; + char pfx[32]; + char grbuf[MAXPWLINE]; + + endgrent(); + l = sprintf(pfx, "%s:", group); + + /* + * Update the group file + */ + if (grp == NULL) + *grbuf = '\0'; + else + fmtgrentry(grbuf, grp, PWF_PASSWD); + return fileupdate(_PATH_GROUP, 0644, grbuf, pfx, l, mode); +} + + +int +addgrent(struct group * grp) +{ + return gr_update(grp, grp->gr_name, UPD_CREATE); +} + +int +chggrent(char const * login, struct group * grp) +{ + return gr_update(grp, login, UPD_REPLACE); +} + +int +delgrent(struct group * grp) +{ + return gr_update(NULL, grp->gr_name, UPD_DELETE); +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/grupd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/psdate.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/psdate.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/psdate.c (revision 29197) @@ -0,0 +1,303 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include + +#include "psdate.h" + + +static int +a2i(char const ** str) +{ + int i = 0; + char const *s = *str; + + if (isdigit(*s)) { + i = atoi(s); + while (isdigit(*s)) + ++s; + *str = s; + } + return i; +} + +static int +numerics(char const * str) +{ + int rc = isdigit(*str); + + if (rc) + while (isdigit(*str) || *str == 'x') + ++str; + return rc && !*str; +} + +static int +aindex(char const * arr[], char const ** str, int len) +{ + int l, i; + char mystr[32]; + + mystr[len] = '\0'; + l = strlen(strncpy(mystr, *str, len)); + for (i = 0; i < l; i++) + mystr[i] = (char) tolower(mystr[i]); + for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); + if (arr[i] == NULL) + i = -1; + else { /* Skip past it */ + while (**str && isalpha(**str)) + ++(*str); + /* And any following whitespace */ + while (**str && (**str == ',' || isspace(**str))) + ++(*str); + } /* Return index */ + return i; +} + +static int +weekday(char const ** str) +{ + static char const *days[] = + {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; + + return aindex(days, str, 3); +} + +static int +month(char const ** str) +{ + static char const *months[] = + {"jan", "feb", "mar", "apr", "may", "jun", "jul", + "aug", "sep", "oct", "nov", "dec", NULL}; + + return aindex(months, str, 3); +} + +static void +parse_time(char const * str, int *hour, int *min, int *sec) +{ + *hour = a2i(&str); + if ((str = strchr(str, ':')) == NULL) + *min = *sec = 0; + else { + ++str; + *min = a2i(&str); + *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str); + } +} + + +static void +parse_datesub(char const * str, int *day, int *mon, int *year) +{ + int i; + + static char const nchrs[] = "0123456789 \t,/-."; + + if ((i = month(&str)) != -1) { + *mon = i; + if ((i = a2i(&str)) != 0) + *day = i; + } else if ((i = a2i(&str)) != 0) { + *day = i; + while (*str && strchr(nchrs + 10, *str) != NULL) + ++str; + if ((i = month(&str)) != -1) + *mon = i; + else if ((i = a2i(&str)) != 0) + *mon = i - 1; + } else + return; + + while (*str && strchr(nchrs + 10, *str) != NULL) + ++str; + if (isdigit(*str)) { + *year = atoi(str); + if (*year > 1900) + *year -= 1900; + else if (*year < 32) + *year += 100; + } +} + + +/*- + * Parse time must be flexible, it handles the following formats: + * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now + * 0xnnnnnnnn UNIX timestamp in hexadecimal + * 0nnnnnnnnn UNIX timestamp in octal + * 0 Given time + * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years + * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years + * dd[ ./-]mmm[ ./-]yy Date } + * hh:mm:ss Time } May be combined + */ + +time_t +parse_date(time_t dt, char const * str) +{ + char *p; + int i; + long val; + struct tm *T; + + if (dt == 0) + dt = time(NULL); + + while (*str && isspace(*str)) + ++str; + + if (numerics(str)) { + val = strtol(str, &p, 0); + dt = val ? val : dt; + } else if (*str == '+' || *str == '-') { + val = strtol(str, &p, 0); + switch (*p) { + case 'h': + case 'H': /* hours */ + dt += (val * 3600L); + break; + case '\0': + case 'm': + case 'M': /* minutes */ + dt += (val * 60L); + break; + case 's': + case 'S': /* seconds */ + dt += val; + break; + case 'd': + case 'D': /* days */ + dt += (val * 86400L); + break; + case 'w': + case 'W': /* weeks */ + dt += (val * 604800L); + break; + case 'o': + case 'O': /* months */ + T = localtime(&dt); + T->tm_mon += (int) val; + i = T->tm_mday; + goto fixday; + case 'y': + case 'Y': /* years */ + T = localtime(&dt); + T->tm_year += (int) val; + i = T->tm_mday; + fixday: + dt = mktime(T); + T = localtime(&dt); + if (T->tm_mday != i) { + T->tm_mday = 1; + dt = mktime(T); + dt -= (time_t) 86400L; + } + default: /* unknown */ + break; /* leave untouched */ + } + } else { + char *q, tmp[64]; + + /* + * Skip past any weekday prefix + */ + weekday(&str); + str = strncpy(tmp, str, sizeof tmp - 1); + tmp[sizeof tmp - 1] = '\0'; + T = localtime(&dt); + + /* + * See if we can break off any timezone + */ + while ((q = strrchr(tmp, ' ')) != NULL) { + if (strchr("(+-", q[1]) != NULL) + *q = '\0'; + else { + int j = 1; + + while (q[j] && isupper(q[j])) + ++j; + if (q[j] == '\0') + *q = '\0'; + else + break; + } + } + + /* + * See if there is a time hh:mm[:ss] + */ + if ((p = strchr(tmp, ':')) == NULL) { + + /* + * No time string involved + */ + T->tm_hour = T->tm_min = T->tm_sec = 0; + parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year); + } else { + char datestr[64], timestr[64]; + + /* + * Let's chip off the time string + */ + if ((q = strpbrk(p, " \t")) != NULL) { /* Time first? */ + int l = q - str; + + strncpy(timestr, str, l); + timestr[l] = '\0'; + strncpy(datestr, q + 1, sizeof datestr); + datestr[sizeof datestr - 1] = '\0'; + parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); + parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); + } else if ((q = strrchr(tmp, ' ')) != NULL) { /* Time last */ + int l = q - tmp; + + strncpy(timestr, q + 1, sizeof timestr); + timestr[sizeof timestr - 1] = '\0'; + strncpy(datestr, tmp, l); + datestr[l] = '\0'; + } else /* Bail out */ + return dt; + parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); + parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); + } + dt = mktime(T); + } + return dt; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/psdate.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/psdate.h =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/psdate.h (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/psdate.h (revision 29197) @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#ifndef _PSDATE_H_ +#define _PSDATE_H_ + +#include +#include + +__BEGIN_DECLS +time_t parse_date __P((time_t dt, char const * str)); +void print_date __P((char *buf, time_t t, int dotime)); +__END_DECLS + +#endif /* !_PSDATE_H_ */ Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/psdate.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw_conf.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw_conf.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw_conf.c (revision 29197) @@ -0,0 +1,458 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include + +#include "pw.h" + +#define debugging 0 + +enum { + _UC_NONE, + _UC_DEFAULTPWD, + _UC_REUSEUID, + _UC_REUSEGID, + _UC_DOTDIR, + _UC_NEWMAIL, + _UC_LOGFILE, + _UC_HOMEROOT, + _UC_SHELLPATH, + _UC_SHELLS, + _UC_DEFAULTSHELL, + _UC_DEFAULTGROUP, + _UC_EXTRAGROUPS, + _UC_DEFAULTCLASS, + _UC_MINUID, + _UC_MAXUID, + _UC_MINGID, + _UC_MAXGID, + _UC_EXPIRE, + _UC_PASSWORD, + _UC_FIELDS +}; + +static char bourne_shell[] = "sh"; + +static char *system_shells[_UC_MAXSHELLS] = +{ + bourne_shell, + "csh" +}; + +static char *default_groups[_UC_MAXGROUPS] = +{ + NULL +}; + +static char const *booltrue[] = +{ + "yes", "true", "1", "on", NULL +}; +static char const *boolfalse[] = +{ + "no", "false", "0", "off", NULL +}; + +static struct userconf config = +{ + 0, /* Default password for new users? (nologin) */ + 0, /* Reuse uids? */ + 0, /* Reuse gids? */ + "/usr/share/skel", /* Where to obtain skeleton files */ + NULL, /* Mail to send to new accounts */ + "/var/log/userlog", /* Where to log changes */ + "/home", /* Where to create home directory */ + "/bin", /* Where shells are located */ + system_shells, /* List of shells (first is default) */ + bourne_shell, /* Default shell */ + NULL, /* Default group name */ + default_groups, /* Default (additional) groups */ + NULL, /* Default login class */ + 1000, 32000, /* Allowed range of uids */ + 1000, 32000, /* Allowed range of gids */ + 0, /* Days until account expires */ + 0 /* Days until password expires */ +}; + +static char const *comments[_UC_FIELDS] = +{ + "#\n# pw.conf - user/group configuration defaults\n#\n", + "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", + "\n# Reuse gaps in uid sequence? (yes or no)\n", + "\n# Reuse gaps in gid sequence? (yes or no)\n", + "\n# Obtain default dotfiles from this directory\n", + "\n# Mail this file to new user (/etc/newuser.msg or no)\n", + "\n# Log add/change/remove information in this file\n", + "\n# Root directory in which $HOME directory is created\n", + "\n# Colon separated list of directories containing valid shells\n", + "\n# Space separated list of available shells (without paths)\n", + "\n# Default shell (without path)\n", + "\n# Default group (leave blank for new group per user)\n", + "\n# Extra groups for new users\n", + "\n# Default login class for new users\n", + "\n# Range of valid default user ids\n", + NULL, + "\n# Range of valid default group ids\n", + NULL, + "\n# Days after which account expires (0=disabled)\n", + "\n# Days after which password expires (0=disabled)\n" +}; + +static char const *kwds[] = +{ + "", + "defaultpasswd", + "reuseuids", + "reusegids", + "skeleton", + "newmail", + "logfile", + "home", + "shellpath", + "shells", + "defaultshell", + "defaultgroup", + "extragroups", + "defaultclass", + "minuid", + "maxuid", + "mingid", + "maxgid", + "expire_days", + "password_days", + NULL +}; + +static char * +unquote(char const * str) +{ + if (str && (*str == '"' || *str == '\'')) { + char *p = strchr(str + 1, *str); + + if (p != NULL) + *p = '\0'; + return (char *) (*++str ? str : NULL); + } + return (char *) str; +} + +int +boolean_val(char const * str, int dflt) +{ + if ((str = unquote(str)) != NULL) { + int i; + + for (i = 0; booltrue[i]; i++) + if (strcmp(str, booltrue[i]) == 0) + return 1; + for (i = 0; boolfalse[i]; i++) + if (strcmp(str, boolfalse[i]) == 0) + return 0; + + /* + * Special cases for defaultpassword + */ + if (strcmp(str, "random") == 0) + return -1; + if (strcmp(str, "none") == 0) + return -2; + } + return dflt; +} + +char const * +boolean_str(int val) +{ + if (val == -1) + return "random"; + else if (val == -2) + return "none"; + else + return val ? booltrue[0] : boolfalse[0]; +} + +char * +newstr(char const * p) +{ + char *q = NULL; + + if ((p = unquote(p)) != NULL) { + int l = strlen(p) + 1; + + if ((q = malloc(l)) != NULL) + memcpy(q, p, l); + } + return q; +} + + +struct userconf * +read_userconfig(char const * file) +{ + FILE *fp; + + if (file == NULL) + file = _PATH_PW_CONF; + if ((fp = fopen(file, "r")) != NULL) { + char buf[_UC_MAXLINE]; + + while (fgets(buf, sizeof buf, fp) != NULL) { + char *p = strchr(buf, '\n'); + + if (p == NULL) { /* Line too long */ + int ch; + + while ((ch = fgetc(fp)) != '\n' && ch != EOF); + } else { + *p = '\0'; + if (*buf && *buf != '\n' && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { + static char const toks[] = " \t\r\n,="; + char *q = strtok(NULL, toks); + int i = 0; + + while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) + ++i; +#if debugging + if (i == _UC_FIELDS) + printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); + else + printf("Got kwd[%s]=%s\n", p, q); +#endif + switch (i) { + case _UC_DEFAULTPWD: + config.default_password = boolean_val(q, 1); + break; + case _UC_REUSEUID: + config.reuse_uids = boolean_val(q, 0); + break; + case _UC_REUSEGID: + config.reuse_gids = boolean_val(q, 0); + break; + case _UC_DOTDIR: + config.dotdir = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_NEWMAIL: + config.newmail = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_LOGFILE: + config.logfile = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_HOMEROOT: + config.home = (q == NULL || !boolean_val(q, 1)) + ? "/home" : newstr(q); + break; + case _UC_SHELLPATH: + config.shelldir = (q == NULL || !boolean_val(q, 1)) + ? "/bin" : newstr(q); + break; + case _UC_SHELLS: + for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) + system_shells[i] = newstr(q); + if (i > 0) + while (i < _UC_MAXSHELLS) + system_shells[i++] = NULL; + break; + case _UC_DEFAULTSHELL: + config.shell_default = (q == NULL || !boolean_val(q, 1)) + ? (char *) bourne_shell : newstr(q); + break; + case _UC_DEFAULTGROUP: + config.default_group = (q == NULL || !boolean_val(q, 1) || getgrnam(q) == NULL) + ? NULL : newstr(q); + break; + case _UC_EXTRAGROUPS: + for (i = 0; i < _UC_MAXGROUPS && q != NULL; i++, q = strtok(NULL, toks)) + default_groups[i] = newstr(q); + if (i > 0) + while (i < _UC_MAXGROUPS) + default_groups[i++] = NULL; + break; + case _UC_DEFAULTCLASS: + config.default_class = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_MINUID: + if ((q = unquote(q)) != NULL && isdigit(*q)) + config.min_uid = (uid_t) atol(q); + break; + case _UC_MAXUID: + if ((q = unquote(q)) != NULL && isdigit(*q)) + config.max_uid = (uid_t) atol(q); + break; + case _UC_MINGID: + if ((q = unquote(q)) != NULL && isdigit(*q)) + config.min_gid = (gid_t) atol(q); + break; + case _UC_MAXGID: + if ((q = unquote(q)) != NULL && isdigit(*q)) + config.max_gid = (gid_t) atol(q); + break; + case _UC_EXPIRE: + if ((q = unquote(q)) != NULL && isdigit(*q)) + config.expire_days = atoi(q); + break; + case _UC_PASSWORD: + if ((q = unquote(q)) != NULL && isdigit(*q)) + config.password_days = atoi(q); + break; + case _UC_FIELDS: + case _UC_NONE: + break; + } + } + } + } + fclose(fp); + } + return &config; +} + + +int +write_userconfig(char const * file) +{ + int fd; + + if (file == NULL) + file = _PATH_PW_CONF; + + if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { + FILE *fp; + + if ((fp = fdopen(fd, "w")) == NULL) + close(fd); + else { + int i, j, k; + char buf[_UC_MAXLINE]; + + for (i = _UC_NONE; i < _UC_FIELDS; i++) { + int quote = 1; + char const *val = buf; + + *buf = '\0'; + switch (i) { + case _UC_DEFAULTPWD: + val = boolean_str(config.default_password); + break; + case _UC_REUSEUID: + val = boolean_str(config.reuse_uids); + break; + case _UC_REUSEGID: + val = boolean_str(config.reuse_gids); + break; + case _UC_DOTDIR: + val = config.dotdir ? config.dotdir : boolean_str(0); + break; + case _UC_NEWMAIL: + val = config.newmail ? config.newmail : boolean_str(0); + break; + case _UC_LOGFILE: + val = config.logfile ? config.logfile : boolean_str(0); + break; + case _UC_HOMEROOT: + val = config.home; + break; + case _UC_SHELLPATH: + val = config.shelldir; + break; + case _UC_SHELLS: + for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) + k += sprintf(buf + k, "%s\"%s\"", k ? "," : "", system_shells[j]); + quote = 0; + break; + case _UC_DEFAULTSHELL: + val = config.shell_default ? config.shell_default : bourne_shell; + break; + case _UC_DEFAULTGROUP: + val = config.default_group ? config.default_group : ""; + break; + case _UC_EXTRAGROUPS: + for (j = k = 0; j < _UC_MAXGROUPS && default_groups[j] != NULL; j++) + k += sprintf(buf + k, "%s\"%s\"", k ? "," : "", default_groups[j]); + quote = 0; + break; + case _UC_DEFAULTCLASS: + val = config.default_class ? config.default_class : ""; + break; + case _UC_MINUID: + sprintf(buf, "%lu", (unsigned long) config.min_uid); + quote = 0; + break; + case _UC_MAXUID: + sprintf(buf, "%lu", (unsigned long) config.max_uid); + quote = 0; + break; + case _UC_MINGID: + sprintf(buf, "%lu", (unsigned long) config.min_gid); + quote = 0; + break; + case _UC_MAXGID: + sprintf(buf, "%lu", (unsigned long) config.max_gid); + quote = 0; + break; + case _UC_EXPIRE: + sprintf(buf, "%d", config.expire_days); + quote = 0; + break; + case _UC_PASSWORD: + sprintf(buf, "%d", config.password_days); + quote = 0; + break; + case _UC_NONE: + break; + } + + if (comments[i]) + fputs(comments[i], fp); + + if (*kwds[i]) { + if (quote) + fprintf(fp, "%s = \"%s\"\n", kwds[i], val); + else + fprintf(fp, "%s = %s\n", kwds[i], val); +#if debugging + printf("WROTE: %s = %s\n", kwds[i], val); +#endif + } + } + return fclose(fp) != EOF; + } + } + return 0; +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw_conf.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pw_log.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pw_log.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pw_log.c (revision 29197) @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include + +#include "pw.h" + +static FILE *logfile = NULL; + +void +pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...) +{ + if (cnf->logfile && *cnf->logfile) { + if (logfile == NULL) { /* With umask==0 we need to control file access modes on create */ + int fd = open(cnf->logfile, O_WRONLY | O_CREAT | O_APPEND, 0600); + + if (fd != -1) + logfile = fdopen(fd, "a"); + } + if (logfile != NULL) { + va_list argp; + int l; + time_t now = time(NULL); + struct tm *t = localtime(&now); + char nfmt[256]; + char *name; + + if ((name = getenv("LOGNAME")) == NULL && (name = getenv("USER")) == NULL) + name = "unknown"; + strftime(nfmt, sizeof nfmt, "%d-%b-%Y %R ", t); + l = strlen(nfmt); + sprintf(nfmt + strlen(nfmt), "[%s:%s%s] %s\n", name, Which[which], Modes[mode], fmt); + va_start(argp, fmt); + vfprintf(logfile, nfmt, argp); + va_end(argp); + fflush(logfile); + } + } +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pw_log.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.h =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.h (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.h (revision 29197) @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#ifndef _PWUPD_H_ +#define _PWUPD_H_ + +#include +#include +#include + +#include + +enum updtype +{ + UPD_DELETE = -1, + UPD_CREATE = 0, + UPD_REPLACE = 1 +}; + +__BEGIN_DECLS +int fileupdate __P((char const * fname, mode_t fm, char const * nline, char const * pfx, int pfxlen, int updmode)); +__END_DECLS + +enum pwdfmttype +{ + PWF_STANDARD, /* MASTER format but with '*' as password */ + PWF_PASSWD, /* V7 format */ + PWF_GROUP = PWF_PASSWD, + PWF_MASTER /* MASTER format with password */ +}; + +__BEGIN_DECLS +int addpwent __P((struct passwd * pwd)); +int delpwent __P((struct passwd * pwd)); +int chgpwent __P((char const * login, struct passwd * pwd)); +int fmtpwent __P((char *buf, struct passwd * pwd)); +int fmtpwentry __P((char *buf, struct passwd * pwd, int type)); +int addgrent __P((struct group * grp)); +int delgrent __P((struct group * grp)); +int chggrent __P((char const * name, struct group * grp)); +int fmtgrent __P((char *buf, struct group * grp)); +int fmtgrentry __P((char *buf, struct group * grp, int type)); +int editgroups __P((char *name, char **groups)); +__END_DECLS + +#define MAXGROUPS 200 +#define MAXPWLINE 1024 + +__BEGIN_DECLS +void copymkdir __P((char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid)); +void rm_r __P((char const * dir, uid_t uid)); +__END_DECLS + +#endif /* !_PWUPD_H */ Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/pwupd.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/usr.sbin/pw/rm_r.c =================================================================== --- cvs2svn/tags/v1_1/usr.sbin/pw/rm_r.c (nonexistent) +++ cvs2svn/tags/v1_1/usr.sbin/pw/rm_r.c (revision 29197) @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1996 by 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 as + * the first lines of this file unmodified. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David L. Nugent. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``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 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pwupd.h" + +void +rm_r(char const * dir, uid_t uid) +{ + DIR *d = opendir(dir); + + if (d != NULL) { + struct dirent *e; + struct stat st; + char file[MAXPATHLEN]; + + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) { + sprintf(file, "%s/%s", dir, e->d_name); + if (lstat(file, &st) == 0) { /* Need symlinks, not + * linked file */ + if (S_ISDIR(st.st_mode)) /* Directory - recurse */ + rm_r(file, uid); + else { + if (S_ISLNK(st.st_mode) || st.st_uid == uid) + remove(file); + } + } + } + } + closedir(d); + if (lstat(dir, &st) == 0) { + if (S_ISLNK(st.st_mode)) + remove(dir); + else if (st.st_uid == uid) + rmdir(dir); + } + } +} Property changes on: cvs2svn/tags/v1_1/usr.sbin/pw/rm_r.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/Makefile =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/Makefile (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/Makefile (revision 29197) @@ -0,0 +1,5 @@ +# $Id: Makefile,v 1.1 1997/08/12 18:23:24 pst Exp $ + +SUBDIR= daily weekly monthly + +.include Property changes on: cvs2svn/tags/v1_1/etc/periodic/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/Makefile.inc =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/Makefile.inc (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/Makefile.inc (revision 29197) @@ -0,0 +1,12 @@ +# $Id: Makefile.inc,v 1.1 1997/08/12 18:23:25 pst Exp $ + +BINDIR= /etc/periodic/${.CURDIR:T} +BINOWN= root +BINGRP= wheel + +all depend etc lint: + +install: + cd ${.CURDIR}; \ + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 755 ${BIN} \ + ${DESTDIR}/${BINDIR} Property changes on: cvs2svn/tags/v1_1/etc/periodic/Makefile.inc ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/100.clean-disks =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/100.clean-disks (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/100.clean-disks (revision 29197) @@ -0,0 +1,15 @@ +#!/bin/sh +# +# $Id: 100.clean-disks,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +# This is a security hole, never use 'find' on a public directory +# with -exec rm -f as root. This can be exploited to delete any file +# on the system. +# + +exit 0 # do not run by default + +find / \( ! -fstype local -o -fstype rdonly \) -a -prune -o \ + \( -name '[#,]*' -o -name '.#*' -o -name a.out -o -name '*.core' \ + -o -name '*.CKP' -o -name '.emacs_[0-9]*' \) \ + -a -atime +3 -exec rm -f -- {} \; Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/100.clean-disks ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/110.clean-tmps =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/110.clean-tmps (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/110.clean-tmps (revision 29197) @@ -0,0 +1,32 @@ +#!/bin/sh +# +# $Id: 110.clean-tmps,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +# This is a security hole, never use 'find' on a public directory +# with -exec rm -f as root. This can be exploited to delete any file +# on the system. +# +# Use at your own risk, but for a long-living system, this might come +# more useful than the boot-time cleaning of /tmp. If /var/tmp and +# /tmp are symlinked together, only one of the below will actually +# run. +# + +exit 0 # do not run by default + +if [ -d /tmp ]; then + cd /tmp && { + find . -type f -atime +3 -ctime +3 ! -name '.X*-lock' \ + -exec rm -f -- {} \; + find -d . ! -name . -type d -mtime +1 -exec rmdir -- {} \; \ + >/dev/null 2>&1 + } +fi + +if [ -d /var/tmp ]; then + cd /var/tmp && { + find . ! -name . -atime +7 -ctime +3 -exec rm -f -- {} \; + find -d . ! -name . -type d -mtime +1 -exec rmdir -- {} \; \ + >/dev/null 2>&1 + } +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/110.clean-tmps ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/120.clean-preserve =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/120.clean-preserve (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/120.clean-preserve (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $Id: 120.clean-preserve,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# + +if [ -d /var/preserve ]; then + echo "" + echo "Removing stale files from /var/preserve:" + cd /var/preserve && find . ! -name . -mtime +7 -exec rm -f -- {} \; +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/120.clean-preserve ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/130.clean-msgs =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/130.clean-msgs (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/130.clean-msgs (revision 29197) @@ -0,0 +1,11 @@ +#!/bin/sh +# +# $Id: 130.clean-msgs,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +# remove system messages older than 21 days +# +if [ -d /var/msgs ] ; then + echo + echo "Cleaning out old system announcements:" + msgs -c +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/130.clean-msgs ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/140.clean-rwho =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/140.clean-rwho (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/140.clean-rwho (revision 29197) @@ -0,0 +1,11 @@ +#!/bin/sh +# +# $Id: 140.clean-rwho,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# + +if [ -d /var/rwho ] ; then + echo "" + echo "Removing stale files from /var/rwho" + cd /var/rwho && find . ! -name . -mtime +7 -exec rm -f -- {} \; +fi + Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/140.clean-rwho ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/200.backup-passwd =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/200.backup-passwd (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/200.backup-passwd (revision 29197) @@ -0,0 +1,35 @@ +#!/bin/sh +# +# $Id: 200.backup-passwd,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +bak=/var/backups + +if [ -f /etc/master.passwd -o -f /etc/group ] ; then + echo "" + echo "Backup passwd and group files:" + + if [ ! -f $bak/master.passwd.bak ] ; then + echo "no $bak/master.passwd.bak" + cp -p /etc/master.passwd $bak/master.passwd.bak + fi + + if cmp -s $bak/master.passwd.bak /etc/master.passwd; then :; else + echo "$host passwd diffs:" + diff $bak/master.passwd.bak /etc/master.passwd |\ + sed 's/^\([<>] [^:]*\):[^:]*:/\1:(password):/' + mv $bak/master.passwd.bak $bak/master.passwd.bak2 + cp -p /etc/master.passwd $bak/master.passwd.bak + fi + + if [ ! -f $bak/group.bak ] ; then + echo "no $bak/group.bak" + cp -p /etc/group $bak/group.bak + fi + + if cmp -s $bak/group.bak /etc/group; then :; else + echo "$host group diffs:" + diff $bak/group.bak /etc/group + mv $bak/group.bak $bak/group.bak2 + cp -p /etc/group $bak/group.bak + fi +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/200.backup-passwd ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/210.backup-aliases =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/210.backup-aliases (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/210.backup-aliases (revision 29197) @@ -0,0 +1,22 @@ +#!/bin/sh +# +# $Id: 210.backup-aliases,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# +bak=/var/backups + +if [ -f /etc/aliases ] ; then + echo "" + echo "Backing up mail aliases:" + + if [ ! -f $bak/aliases.bak ] ; then + echo "no $bak/aliases.bak" + cp -p /etc/aliases $bak/aliases.bak + fi + + if cmp -s $bak/aliases.bak /etc/aliases; then :; else + echo "$host aliases diffs:" + diff $bak/aliases.bak /etc/aliases + mv $bak/aliases.bak $bak/aliases.bak2 + cp -p /etc/aliases $bak/aliases.bak + fi +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/210.backup-aliases ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/220.backup-distfile =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/220.backup-distfile (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/220.backup-distfile (revision 29197) @@ -0,0 +1,15 @@ +#!/bin/sh +# +# $Id: 220.backup-distfile,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +bak=/var/backups + +if [ -f /etc/Distfile ]; then + echo "" + echo "Backing up /etc/Distfile" + + if cmp -s $bak/Distfile.bak /etc/Distfile; then :; else + mv $bak/Distfile.bak $bak/Distfile.bak2 + cp /etc/Distfile $bak/Distfile.bak + fi +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/220.backup-distfile ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/300.calendar =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/300.calendar (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/300.calendar (revision 29197) @@ -0,0 +1,17 @@ +#!/bin/sh +# +# $Id: 300.calendar,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +# `calendar -a' needs to die. Why? Because it's a bad idea, particular +# with networked home directories, but also in general. If you want the +# output of `calendar' mailed to you, set up a cron job to do it, +# or run it from your ~/.profile or ~/.login. +# + +exit 0 # do not run by default + +if [ -f /usr/bin/calendar ] ; then + echo "" + echo "Running calendar:" + calendar -a +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/300.calendar ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/310.accounting =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/310.accounting (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/310.accounting (revision 29197) @@ -0,0 +1,15 @@ +#!/bin/sh +# +# $Id: 310.accounting,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -f /var/account/acct ] ; then + echo "" + echo "Rotating accounting logs and gathering statistics:" + cd /var/account + if [ -f acct.2 ] ; then mv -f acct.2 acct.3 ; fi + if [ -f acct.1 ] ; then mv -f acct.1 acct.2 ; fi + if [ -f acct.0 ] ; then mv -f acct.0 acct.1 ; fi + cp -pf acct acct.0 + sa -s > /dev/null +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/310.accounting ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/320.rdist =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/320.rdist (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/320.rdist (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $Id: 320.rdist,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -f /etc/Distfile ]; then + echo "" + echo "Running rdist with /etc/Distfile:" + rdist -f /etc/Distfile +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/320.rdist ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/330.news =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/330.news (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/330.news (revision 29197) @@ -0,0 +1,11 @@ +#!/bin/sh +# +# $Id: 330.news,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +# Expire news articles +# (This is present only for backwards compatibility, usually the news +# system handles this on its own). + +if [ -f /etc/news.expire ]; then + /etc/news.expire +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/330.news ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/340.uucp =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/340.uucp (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/340.uucp (revision 29197) @@ -0,0 +1,13 @@ +#!/bin/sh +# +# $Id: 340.uucp,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +# Local cleanup of UUCP files. This is for backwards compatibility, +# /etc/uuclean.daily doesn't exist by default. +# +if [ -d /var/spool/uucp -a -f /etc/uuclean.daily ]; then + echo "" + echo "Cleaning up UUCP:" + echo /etc/uuclean.daily | su daemon +fi + Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/340.uucp ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/400.status-disks =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/400.status-disks (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/400.status-disks (revision 29197) @@ -0,0 +1,14 @@ +#!/bin/sh +# +# $Id: 400.status-disks,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# + +echo "" +echo "Disk status:" + +df -k -t nonfs + +# display which filesystems need backing up + +echo "" +dump W Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/400.status-disks ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/410.status-uucp =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/410.status-uucp (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/410.status-uucp (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $Id: 410.status-uucp,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# + +if [ -d /var/spool/uucp -a -x /usr/bin/uustat ]; then + echo "" + echo "uucp status:" + uustat -a +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/410.status-uucp ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/420.status-network =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/420.status-network (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/420.status-network (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $Id: 420.status-network,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -x /usr/bin/netstat ] ; then + echo "" + echo "Network interface status:" + netstat -i +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/420.status-network ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/430.status-rwho =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/430.status-rwho (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/430.status-rwho (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $Id: 430.status-rwho,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# + +if [ -d /var/rwho -a -x /usr/bin/rwho ] ; then + echo "" + echo "Local network system status:" + ruptime +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/430.status-rwho ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/440.status-mailq =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/440.status-mailq (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/440.status-mailq (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh +# +# $Id: 440.status-mailq,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# +if [ -x /usr/sbin/mailq -a -d /var/spool/mqueue ] ; then + echo "" + echo "Mail in local queue:" + + mailq +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/440.status-mailq ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/450.status-security =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/450.status-security (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/450.status-security (revision 29197) @@ -0,0 +1,11 @@ +#!/bin/sh +# +# $Id: 450.status-security,v 1.1.1.1 1997/08/12 17:51:15 pst Exp $ +# + +if [ -f /etc/security -a -x /usr/sbin/sendmail ] ; then + echo "" + echo "Security check (output mailed separately)" + + sh /etc/security 2>&1 | sendmail root +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/450.status-security ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/999.local =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/999.local (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/999.local (revision 29197) @@ -0,0 +1,13 @@ +#!/bin/sh +# +# $Id: 999.local,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# +# Run the old /etc/daily.local script. This is really for backwards +# compatibility more than anything else. +# +if [ -f /etc/daily.local ]; then + echo "" + echo "Running daily.local:" + + sh /etc/daily.local +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/999.local ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/daily/Makefile =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/daily/Makefile (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/daily/Makefile (revision 29197) @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.1 1997/08/12 18:23:26 pst Exp $ + +BIN= 100.clean-disks \ + 110.clean-tmps \ + 120.clean-preserve \ + 130.clean-msgs \ + 140.clean-rwho \ + 200.backup-passwd \ + 210.backup-aliases \ + 220.backup-distfile \ + 300.calendar \ + 310.accounting \ + 320.rdist \ + 330.news \ + 340.uucp \ + 400.status-disks \ + 410.status-uucp \ + 420.status-network \ + 430.status-rwho \ + 440.status-mailq \ + 450.status-security \ + 999.local + +.include Property changes on: cvs2svn/tags/v1_1/etc/periodic/daily/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/monthly/200.accounting =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/monthly/200.accounting (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/monthly/200.accounting (revision 29197) @@ -0,0 +1,11 @@ +#!/bin/sh - +# +# $Id: 200.accounting,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -x /usr/sbin/ac ] ; then + echo "" + echo "Doing login accounting:" + + ac -p | sort -nr +1 +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/monthly/200.accounting ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/monthly/999.local =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/monthly/999.local (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/monthly/999.local (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh - +# +# $Id: 999.local,v 1.1 1997/08/12 18:23:27 pst Exp $ +# +if [ -f /etc/monthly.local ]; then + echo "" + echo "Running monthly.local:" + + sh /etc/monthly.local +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/monthly/999.local ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/monthly/Makefile =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/monthly/Makefile (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/monthly/Makefile (revision 29197) @@ -0,0 +1,6 @@ +# $Id: Makefile,v 1.1 1997/08/12 18:23:28 pst Exp $ + +BIN= 200.accounting \ + 999.local + +.include Property changes on: cvs2svn/tags/v1_1/etc/periodic/monthly/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/100.clean-src =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/100.clean-src (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/100.clean-src (revision 29197) @@ -0,0 +1,42 @@ +#!/bin/sh - +# +# $Id: 100.clean-src,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# +# Clean up /usr/src +# +# This really hasn't been used in generations, it's just here for +# backwards compatibility -- we don't even use SCCS anymore +# + +exit 0 # do not run by default + +# see if /usr/src exists and is local before doing anything + +if [ -d /usr/src -a \ + X"`find -f /usr/src ! -fstype local -prune -or -type d -print -prune`" != X ]; +then + + echo "" + echo "Removing old .o files from /usr/src:" + + find /usr/src -name '*.o' -atime +21 -print -a -exec rm -f {} \; + + echo "looking for checked out files in /usr/src:" + TDIR=/tmp/_checkout$$ + + mkdir $TDIR + + for file in `find -f /usr/src ! -fstype local -prune -or \ + -name 'p.*' -print | egrep 'SCCS/p\.'`; do + owner=`awk '{ print $3 }' $file` + echo "$owner $file" + echo $file >> $TDIR/$owner + done | sed -e 's,SCCS/p.,,' + + for file in $TDIR/*; do + sed -e 's,SCCS/p.,,' $file | \ + Mail -s 'checked out files' `basename $file` + done + + rm -rf $TDIR +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/100.clean-src ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/120.clean-kvmdb =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/120.clean-kvmdb (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/120.clean-kvmdb (revision 29197) @@ -0,0 +1,15 @@ +#!/bin/sh - +# +# $Id: 120.clean-kvmdb,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -d /var/db -a -x /usr/sbin/sysctl ] ; then + echo "" + echo "Cleaning up kernel database files:" + + kernel=`sysctl -n kern.bootfile` + kernel=kvm_`basename ${kernel}`.db + + find /var/db -name "kvm_*.db" -a ! -name ${kernel} -a \ + -atime +7 -exec rm -f -- {} \; +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/120.clean-kvmdb ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/300.uucp =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/300.uucp (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/300.uucp (revision 29197) @@ -0,0 +1,12 @@ +#!/bin/sh - +# +# $Id: 300.uucp,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# +# This is really here for backwards compatibility, clean.weekly is not +# created by default anymore. + +if [ -d /var/spool/uucp -a -f /usr/libexec/uucp/clean.weekly ]; then + echo "" + echo "Cleaning up UUCP:" + echo /usr/libexec/uucp/clean.weekly | su daemon +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/300.uucp ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/310.locate =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/310.locate (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/310.locate (revision 29197) @@ -0,0 +1,18 @@ +#!/bin/sh - +# +# $Id: 310.locate,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# +locdb=/var/db/locate.database + +if [ -x /usr/libexec/locate.updatedb -a -f $locdb ] ; then + + echo "" + echo "Rebuilding locate database:" + + touch ${locdb}; chown nobody ${locdb}; chmod 644 ${locdb} + + echo /usr/libexec/locate.updatedb | nice -5 su -fm nobody 2>&1 |\ + fgrep -v 'Permission denied' + + chmod 444 ${locdb} +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/310.locate ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/320.whatis =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/320.whatis (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/320.whatis (revision 29197) @@ -0,0 +1,18 @@ +#!/bin/sh - +# +# $Id: 320.whatis,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -x /usr/libexec/makewhatis.local -a -d /usr/share/man ] ; then + + echo "" + echo "Rebuilding whatis database:" + + if [ -d /usr/X11R6/man ] ; then + MANPATH=${MANPATH:-/usr/share/man:/usr/X11R6/man:/usr/local/man} + else + MANPATH=${MANPATH:-/usr/share/man:/usr/local/man} + fi + + /usr/libexec/makewhatis.local "${MANPATH}" +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/320.whatis ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/330.catman =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/330.catman (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/330.catman (revision 29197) @@ -0,0 +1,12 @@ +#!/bin/sh - +# +# $Id: 330.catman,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +exit 0 # do not run by default + +if [ -x /usr/libexec/catman.local -a -d /usr/share/man/cat1 ] ; then + echo "" + echo "Reformatting manual pages:" + echo /usr/libexec/catman.local "${MANPATH}" | su -fm man +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/330.catman ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/999.local =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/999.local (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/999.local (revision 29197) @@ -0,0 +1,10 @@ +#!/bin/sh - +# +# $Id: 999.local,v 1.1.1.1 1997/08/12 17:51:16 pst Exp $ +# + +if [ -f /etc/weekly.local ]; then + echo "" + echo "Running weekly.local:" + sh /etc/weekly.local +fi Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/999.local ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: cvs2svn/tags/v1_1/etc/periodic/weekly/Makefile =================================================================== --- cvs2svn/tags/v1_1/etc/periodic/weekly/Makefile (nonexistent) +++ cvs2svn/tags/v1_1/etc/periodic/weekly/Makefile (revision 29197) @@ -0,0 +1,11 @@ +# $Id: Makefile,v 1.2 1997/08/12 23:11:24 adam Exp $ + +BIN= 100.clean-src \ + 120.clean-kvmdb \ + 300.uucp \ + 310.locate \ + 320.whatis \ + 330.catman \ + 999.local + +.include Property changes on: cvs2svn/tags/v1_1/etc/periodic/weekly/Makefile ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property