diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 |
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 |
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /userdb | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'userdb')
| -rw-r--r-- | userdb/Makefile.am | 73 | ||||
| -rw-r--r-- | userdb/configure.in | 170 | ||||
| -rw-r--r-- | userdb/html2man.pl.in | 174 | ||||
| -rw-r--r-- | userdb/makeuserdb.in | 171 | ||||
| -rw-r--r-- | userdb/makeuserdb.sgml | 324 | ||||
| -rw-r--r-- | userdb/pw2userdb.in | 70 | ||||
| -rw-r--r-- | userdb/userdb.c | 411 | ||||
| -rw-r--r-- | userdb/userdb.h | 68 | ||||
| -rw-r--r-- | userdb/userdb.pl.in | 263 | ||||
| -rw-r--r-- | userdb/userdb.sgml | 265 | ||||
| -rw-r--r-- | userdb/userdb2.c | 57 | ||||
| -rw-r--r-- | userdb/userdbmkpw.c | 119 | ||||
| -rw-r--r-- | userdb/userdbpw.c | 251 | ||||
| -rw-r--r-- | userdb/userdbpw.sgml | 129 |
14 files changed, 2545 insertions, 0 deletions
diff --git a/userdb/Makefile.am b/userdb/Makefile.am new file mode 100644 index 0000000..90a72ae --- /dev/null +++ b/userdb/Makefile.am @@ -0,0 +1,73 @@ +# +# Copyright 1998 - 2008 Double Precision, Inc. See COPYING for +# distribution information. + +noinst_LTLIBRARIES=libuserdb.la + +libuserdb_la_SOURCES=userdb.c userdb.h userdb2.c userdbmkpw.c + +BUILT_SOURCES= makeuserdb.html.in makeuserdb.8.in \ + userdb.html.in userdb.8.in \ + userdbpw.html.in userdbpw.8.in + +noinst_SCRIPTS=makeuserdb pw2userdb dummy +noinst_PROGRAMS=userdbpw +noinst_DATA=makeuserdb.html userdb.html userdbpw.html + +userdbpw_SOURCES=userdbpw.c +userdbpw_LDADD=libuserdb.la @HMACLIB@ @MD5LIB@ @SHA1LIB@ @CRYPTLIBS@ +userdbpw_LDFLAGS=-static + +man8=makeuserdb.8 userdb.8 userdbpw.8 +man_MANS=$(man8) + +CLEANFILES=$(man8) $(noinst_DATA) dummy + +makeuserdb.html: makeuserdb.html.in + ./config.status --file=$@ + +makeuserdb.8: makeuserdb.8.in + ./config.status --file=$@ + +userdb.html: userdb.html.in + ./config.status --file=$@ + +userdb.8: userdb.8.in + ./config.status --file=$@ + +userdbpw.html: userdbpw.html.in + ./config.status --file=$@ + +userdbpw.8: userdbpw.8.in + ./config.status --file=$@ + +if HAVE_SGML +makeuserdb.html.in: makeuserdb.sgml ../docbook/sgml2html + ../docbook/sgml2html makeuserdb.sgml makeuserdb.html.in + +makeuserdb.8.in: makeuserdb.sgml ../docbook/sgml2man + ../docbook/sgml2man makeuserdb.sgml makeuserdb.8.in + mv makeuserdb.8 makeuserdb.8.in + +userdb.html.in: userdb.sgml ../docbook/sgml2html + ../docbook/sgml2html userdb.sgml userdb.html.in + +userdb.8.in: userdb.sgml ../docbook/sgml2man + ../docbook/sgml2man userdb.sgml userdb.8.in + mv userdb.8 userdb.8.in + +userdbpw.html.in: userdbpw.sgml ../docbook/sgml2html + ../docbook/sgml2html userdbpw.sgml userdbpw.html.in + +userdbpw.8.in: userdbpw.sgml ../docbook/sgml2man + ../docbook/sgml2man userdbpw.sgml userdbpw.8.in + mv userdbpw.8 userdbpw.8.in + +endif + +EXTRA_DIST=$(BUILT_SOURCES) + +# Temporary autoconf kludge: + +dummy: $(man8) + touch dummy diff --git a/userdb/configure.in b/userdb/configure.in new file mode 100644 index 0000000..1a4585b --- /dev/null +++ b/userdb/configure.in @@ -0,0 +1,170 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl +dnl Copyright 1998 - 2007 Double Precision, Inc. See COPYING for +dnl distribution information. + +AC_INIT(libuserdb, 0.10, [courier-users@lists.sourceforge.net]) + +>confdefs.h # Kill PACKAGE_ macros. + +LPATH="$PATH:/usr/local/bin" + +AC_CONFIG_SRCDIR(userdb.c) +AC_CONFIG_AUX_DIR(../..) +AM_INIT_AUTOMAKE([foreign no-define]) +AM_CONFIG_HEADER(config.h) + +dnl Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_LIBTOOL +AC_PATH_PROGS(PERL, perl5 perl, perl, $LPATH) + +if test "$PERL" = "perl" +then + AC_MSG_ERROR(Perl not found.) +fi + +if test "$GCC" = "yes" +then + CFLAGS="$CFLAGS -Wall" +fi + +CFLAGS="$CFLAGS -I.. -I${srcdir}/.." + +dnl Checks for libraries. + +AC_ARG_WITH(userdb, [ ], userdb="$withval", userdb="/etc/userdb") +AC_SUBST(userdb) +USERDB="`echo $userdb | tr '[a-z]' '[A-Z]'`" +AC_SUBST(USERDB) + +AC_ARG_WITH(userdbmandir, [ ], mandir="$withval") + +AC_ARG_WITH(userdbtmpdir, [ ], tmpdir="$withval", tmpdir="") + +changequote({,}) + +if test "$tmpdir" = "" +then + tmpdir=`echo "$userdb" | sed 's/\/[^\/]*$//'` +fi + +changequote([,]) + +AC_SUBST(userdbtmpdir) +AC_SUBST(tmpdir) + +AC_ARG_WITH(makedatprog, [ ], makedat="$withval", makedat="$bindir/makedat") +AC_SUBST(makedat) + +if test -d ${srcdir}/../md5 +then + AC_DEFINE_UNQUOTED(HAVE_MD5,1,[ Whether libmd5.a is present ]) + MD5LIB=../md5/libmd5.la +else + MD5LIB="" +fi +AC_SUBST(MD5LIB) + +if test -d ${srcdir}/../sha1 +then + SHA1LIB=../sha1/libsha1.la +else + SHA1LIB="" +fi +AC_SUBST(SHA1LIB) + +if test -d ${srcdir}/../libhmac +then + AC_DEFINE_UNQUOTED(HAVE_HMAC,1, [ Whether libhmac.a is present ]) + HMACLIB=../libhmac/libhmac.la +else + HMACLIB="" +fi +AC_SUBST(HMACLIB) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(sys/stat.h sys/time.h unistd.h fcntl.h termios.h crypt.h) +AC_HEADER_TIME + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_PID_T +AC_TYPE_UID_T +AC_TYPE_SIGNAL +AC_SYS_LARGEFILE + +dnl Other checks + +AC_CHECK_LIB(crypt, crypt, CRYPTLIBS="-lcrypt") +saveLIBS="$LIBS" +LIBS="$CRYPTLIBS $LIBS" +AC_CHECK_FUNC(crypt, AC_DEFINE_UNQUOTED(HAVE_CRYPT,1, + [ Whether the crypt() function is available ])) +LIBS="$saveLIBS" +AC_CACHE_CHECK([for crypt() prototype],userdb_cv_NEED_CRYPT_PROTOTYPE, + + AC_TRY_COMPILE( [ + #if HAVE_CRYPT_H + #include <crypt.h> + #endif + #if HAVE_UNISTD_H + #include <unistd.h> + #endif + int crypt(int, int); + + ], [], userdb_cv_NEED_CRYPT_PROTOTYPE=1, + userdb_cv_NEED_CRYPT_PROTOTYPE=0 ) + + ) + +AC_DEFINE_UNQUOTED(NEED_CRYPT_PROTOTYPE, $userdb_cv_NEED_CRYPT_PROTOTYPE, + [ Whether crypt() must be explicitly prototyped ]) +AC_SUBST(CRYPTLIBS) + +AC_CHECK_FUNCS(isatty gettimeofday) + +AC_ARG_WITH(random, [ --with-random=/dev/urandom - location of the system random file generator +--without-random - there is no system random file generator ], + random="$withval", + random="y") + +case "$random" in +/*) + ;; +y*|1*) + AC_CACHE_CHECK([for random source],userdb_cv_RANDOM, + + if test -c /dev/urandom + then + userdb_cv_RANDOM=/dev/urandom + else + if test -c /dev/random + then + userdb_cv_RANDOM=/dev/random + else + userdb_cv_RANDOM="none" + fi + fi + ) + random="$userdb_cv_RANDOM" + ;; +*) + random="none" + ;; +esac + +if test "$random" != "none" +then + AC_DEFINE_UNQUOTED(RANDOM, "$random", + [ System random number generator ]) +fi + +AM_CONDITIONAL(HAVE_SGML, test -d ${srcdir}/../docbook) + +AC_OUTPUT(Makefile userdb.pl makeuserdb pw2userdb) diff --git a/userdb/html2man.pl.in b/userdb/html2man.pl.in new file mode 100644 index 0000000..0a8ca70 --- /dev/null +++ b/userdb/html2man.pl.in @@ -0,0 +1,174 @@ +#! @PERL@ +# +# Copyright 1998 - 1999 Double Precision, Inc. See COPYING for +# distribution information. + +############################################################################ +# +# Preprocess HTML file: put all directives on a separate line. Remove +# blank lines. +# +# +############################################################################ + +$pid=open(FD, "-|"); + +die "Can't fork.\n" unless defined $pid; + +if ($pid == 0) +{ + while (<>) + { + if ( $_ =~ s/^ *<[lL][iI]>// ) + { + $line=$_; + $line=<> if $line eq "\n"; + chop $line; + $line =~ s/ - /\n/; + ($line0,$line1)=split(/\n/,$line); + $line0 =~ s/"/\\"/g; + $line0 =~ s/\\/\\\\/g; + print ".TP\n.B \"$line0\n$line1\n"; + next; + } + while ( /<[^>]*\n$/ ) + { + chop; + $foo=$_; + last unless defined ($_=<>); + $_="$foo$_"; + } + print; + } + exit 0; +} + +$pid2=open(FD2, "-|"); +die "Can't fork.\n" unless defined $pid2; + +sub dosubst { + s/<[^>]*>//g; + s/ / /g; + s/</</g; + s/>/>/g; + s/&/\&/g; +} + +$INH1=0; +$INBODY=0; + +$inpre=0; + +if ($pid2 == 0) +{ + while (<FD>) + { + s/\\/\\\\/g; + s/<[iI]>/\\fI/g; + s/<\/[iI]>/\\fP/g; + s/<BR>/\n.br/g; + s/<br>/\n.br/g; + s/<[pP]>/\n.PP\n/g; + s/^\n\././; + + s/^ *// unless $inpre; + if (s/^<[hH]1>/.SH NAME\n/) + { + $INH1=1; + } + s/-/\\-/ if $INH1; + $INH1=0 if ( /<\/[hH]1>/ ); + + if (s/^<[hH]2>//) + { + $_=<FD> if $_ eq "\n"; + &dosubst; + $_ =~ s/^/.SH "/; + print $_; + next; + } + + if (s/^<[hH][3456789]>//) + { + $_=<FD> if $_ eq "\n"; + &dosubst; + $_ =~ s/^/.SS "/; + print $_; + next; + } + if (/^ *<(TITLE|title)>/) + { + while ( ! /<\/(title|TITLE)>/) + { + chop; + $_ = $_ . <FD>; + } + } + + + if (/^ *<(TITLE|title)>(.*)<\/(title|TITLE)>/) + { + ($cmd, $desc)=split(/ - /,$2); + $cmd =~ s/ *$//; + $desc =~ s/^ *//; + + open (DATE, 'date "+%B %e, %Y" | ') + || die "Can't run date.\n"; + $date=<DATE>; + close(DATE); + chomp $date; + $TITLE=".TH \"$cmd\" [SECTION] \"$date\" \"Double Precision, Inc.\" \"\"\n"; + next; + } + + if (/^<!-- *SECTION/) + { + chop; + s/.*SECTION *//; + s/ .*//; + $SECTION=$_; + next; + } + if (/^<!-- \$Id/) + { + s/.*\$Id/\$Id/; + s/ *-->.*//; + $RCS=".\\\" $_"; + print $RCS if $INBODY; + next; + } + if (/<\/(HEAD|head)>/) + { + $TITLE =~ s/\[SECTION\]/$SECTION/; + print $TITLE; + print $RCS; + print ".\\\" Copyright 1998-1999 Double Precision, Inc. See COPYING for\n"; + print ".\\\" distribution information.\n"; + $INBODY=1; + } + + s/^\./\\\&./ unless /^\.(SH|PP|br|TP|B|I) / || /^\.(SH|PP|br|TP|B|I|)\n/; + + $inpre=1 if s/^<(PRE|pre)>/.nf\n\n/; + $inpre=0 if s/<\/(PRE|pre)>/\n.fi\n.PP/; + + &dosubst; + print "$_"; + } + exit 0; +} + +$first=1; +$innf=0; +while (<FD2>) +{ + $first=0 if /^.TH/; + next if $first; + next if (! $innf) && /^\n$/; + $innf=1 if /^\.nf/; + $innf=0 if /^\.fi/; + + s/^ ? ? ?// if $innf; + print; +} +exit 0; diff --git a/userdb/makeuserdb.in b/userdb/makeuserdb.in new file mode 100644 index 0000000..4765309 --- /dev/null +++ b/userdb/makeuserdb.in @@ -0,0 +1,171 @@ +#! @PERL@ +# +# Create userdb database +# +# Usage: makeuserdb +# +# +# Copyright 1998 - 2006 Double Precision, Inc. See COPYING for +# distribution information. + +use Fcntl ':flock'; + +$prefix="@prefix@"; +$exec_prefix="@exec_prefix@"; +$bindir="@bindir@"; + +$ENV{'PATH'}="@bindir@:/usr/bin:/usr/local/bin:/bin"; + +$dbfile="@userdb@"; + +$makedat="@makedat@"; + +$name=shift @ARGV; +if ($name eq "-f") { + $dbfile=shift @ARGV; + $dbfile=~s/\/$//; +} + +$datfile=$dbfile.".dat"; +# XXX the lock file here is etc/userdb.lock but the userdb command uses etc/.lock.userdb +$lockfile=$dbfile.".lock"; +$shadowfile=$dbfile."shadow.dat"; +$tmpdatfile=$dbfile.".tmp"; +$tmpshadowfile=$dbfile."shadow.tmp"; + +$mode=(stat($dbfile))[2]; +die "$dbfile: not found.\n" unless defined $mode; + +die "$dbfile: MAY NOT HAVE GROUP OR WORLD PERMISSIONS!!\n" + if ( $mode & 077); + +eval { + die "SYMLINK\n" if -l $dbfile; +}; + +die "ERROR: Wrong makeuserdb command.\n ($dbfile is a symbolic link)\n" + if $@ eq "SYMLINK\n"; + +eval { + die "SYMLINK\n" if -l $datfile; +}; + +die "ERROR: Wrong makeuserdb command.\n ($datfile is a symbolic link)\n" + if $@ eq "SYMLINK\n"; + +eval { + die "SYMLINK\n" if -l $shadowfile; +}; + +die "ERROR: Wrong makeuserdb command.\n ($shadowfile is a symbolic link)\n" + if $@ eq "SYMLINK\n"; + +umask (022); +open(LOCK, ">$lockfile") or die "Can't open $lockfile: $!"; +flock(LOCK,LOCK_EX) || die "Can't lock $lockfile: $!"; + +open (DBPIPE, "| ${makedat} - $tmpdatfile $datfile") || die "$!\n"; +umask (066); +open (SHADOWPIPE, "| ${makedat} - $tmpshadowfile $shadowfile") + || die "$!\n"; + +eval { + + if ( -d $dbfile ) + { + my (@dirs); + my (@files); + + push @dirs, $dbfile; + while ( $#dirs >= 0 ) + { + $dir=shift @dirs; + opendir(DIR, $dir) || die "$!\n"; + while ( defined($filename=readdir(DIR))) + { + next if $filename =~ /^\./; + if ( -d "$dir/$filename" ) + { + push @dirs, "$dir/$filename"; + } + else + { + push @files, "$dir/$filename"; + } + } + closedir(DIR); + } + + while (defined ($filename=shift @files)) + { + &do_file( $filename ); + } + } + else + { + &do_file( $dbfile ); + } + + print DBPIPE ".\n" || die "$!\n"; + print SHADOWPIPE ".\n" || die "$!\n"; +} ; + +$err=$@; +if ($err) +{ + print "$err"; + exit (1); +} + +close(DBPIPE) || die "$!\n"; +exit (1) if $?; +close(SHADOWPIPE) || die "$!\n"; +exit (1) if $?; + +exit (0); + +sub do_file { +my ($filename)=@_; +my ($addr, $fields); +my (@nonshadow, @shadow); + +my $location=substr($filename, length("@userdb@")); + + $location =~ s/^\///; + $location =~ s/\/$//; + $location .= "/" if $location ne ""; + + open (F, $filename) || die "$filename: $!\n"; + while (<F>) + { + if ( /^[\n#]/ || ! /^([^\t]*)\t(.*)/ ) + { + print DBPIPE; + print SHADOWPIPE; + next; + } + ($addr,$fields)=($1,$2); + undef @nonshadow; + undef @shadow; + + foreach ( split (/\|/, $fields ) ) + { + if ( /^[^=]*pw=/ ) + { + push @shadow, $_; + } + else + { + push @nonshadow, $_; + } + } + + push @nonshadow, "_=$location"; + ( print DBPIPE "$addr\t" . join("|", @nonshadow) . "\n" + || die "$!\n" ) if $#nonshadow >= 0; + ( print SHADOWPIPE "$addr\t" . join("|", @shadow) . "\n" + || die "$!\n" ) if $#shadow >= 0; + } + print DBPIPE "\n"; + print SHADOWPIPE "\n"; +} diff --git a/userdb/makeuserdb.sgml b/userdb/makeuserdb.sgml new file mode 100644 index 0000000..f10270a --- /dev/null +++ b/userdb/makeuserdb.sgml @@ -0,0 +1,324 @@ +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> + + <!-- Copyright 1998 - 2007 Double Precision, Inc. See COPYING for --> + <!-- distribution information. --> + +<refentry id="makeuserdb"> + + <refmeta> + <refentrytitle>makeuserdb</refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo>Double Precision, Inc.</refmiscinfo> + </refmeta> + + <refnamediv> + <refname>makeuserdb</refname> + <refpurpose>create @userdb@</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>makeuserdb</command> + <arg>-f <replaceable>filename</replaceable></arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>pw2userdb</command> + </cmdsynopsis> + + <cmdsynopsis> + <command>vchkpw2userdb</command> + <arg>--vpopmailhome=<replaceable>dir</replaceable></arg> + <arg>--todir=<replaceable>dir</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>DESCRIPTION</title> + + <para> +<command>makeuserdb</command> creates <filename>@userdb@.dat</filename> from +the contents of <filename>@userdb@</filename>. +<filename>@userdb@</filename>'s contents are described later in this document. +<application>Maildrop</application>, +<application>Courier</application>, and other applications use +<filename>@userdb@.dat</filename> as a +substitute/complement for your system password file. +The usual purpose for +<filename>@userdb@.dat</filename> is to specify "virtual" accounts - accounts +that do +not have an associated system login. +Usually (but not necessarily) all virtual accounts share the same +system userid. +<filename>@userdb@.dat</filename> may also replace +your system password file. Because the system password file is a text file, +when there's a large number of accounts it will be significantly faster to +search +<filename>@userdb.dat@</filename>, which is a binary database, +instead of a flat text file that the system password file usually is.</para> + + <para> +The <command>makeuserdb</command> command can be safely executed during +normal system activity.</para> + + <para> +The <option>-f</option> option creates +<filename><replaceable>filename</replaceable>.dat</filename> from +<filename><replaceable>filename</replaceable></filename>, instead of the +default <filename>@userdb@.dat</filename> from +<filename>@userdb@</filename>.</para> + + <refsect2> + <title>Format of <filename>@userdb@</filename></title> + <para> +<filename>@userdb@</filename> is a plain text file that can be created using +any text editor. Blank lines are ignored. Lines that start with the # +character are comments, and are also ignored. +Other lines define properties of a single +"account", one line per account. +<filename>@userdb@</filename> may be a directory instead of a plain file. +In that case all files in <filename>@userdb@</filename> are essentially +concatenated, and are treated as a single file. +Each line takes the following format:</para> + + <blockquote> + <informalexample> + <literallayout><replaceable>name</replaceable><token><TAB></token><replaceable>field</replaceable>=<replaceable>value</replaceable>|<replaceable>field</replaceable>=<replaceable>value</replaceable>...</literallayout> + </informalexample> + </blockquote> + +<para><replaceable>name</replaceable> is the account name. +<replaceable>name</replaceable> MUST contain only lowercase characters +If <application>Courier</application> is +configured to treat lowercase and uppercase account names as +identical, <replaceable>name</replaceable> is followed by exactly one tab +character, then a list of field/value pairs separated by vertical slashes. +<replaceable>field</replaceable> is the name of the field, +<replaceable>value</replaceable> is the field value. +Fields and values themself cannot contain slashes or control characters. +Fields may be +specified in any order. Here are all the currently defined fields. Note that +not every field is used by every application that reads +<filename>@userdb@.dat</filename>.</para> + + <blockquote> + <para> +<parameter>uid</parameter> - <replaceable>value</replaceable> is a (possibly) +unique numerical user ID for this account.</para> + + <para> +<parameter>gid</parameter> - <replaceable>value</replaceable> is a (possibly) +unique numerical group ID for this account.</para> + + <para> +<parameter>home</parameter> - <replaceable>value</replaceable> is the account's home +directory.</para> + + <para> +<parameter>shell</parameter> - <replaceable>value</replaceable> is the account's default +login shell.</para> + + + <para> +<parameter>systempw</parameter> - <replaceable>value</replaceable> is the account's +password. See +<ulink url="userdbpw.html"><citerefentry><refentrytitle>userdbpw</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink> +for details on how to set up this field.</para> + + <para> +<parameter>pop3pw, esmtppw, imappw...</parameter> - <replaceable>value</replaceable> +specifies a separate password used only for authenticating access using a +specific service, such as POP3, IMAP, or anything else. If not defined, +<parameter>systempw</parameter> is always used. This allows access to an account to be +restricted only to certain services, such as POP3, even if other services +are also enabled on the server.</para> + + <para> +<parameter>mail</parameter> - <replaceable>value</replaceable> specifies the location of +the account's Maildir mailbox. This is an optional field that is normally +used when <command>userdb</command> is used to provide aliases for other +mail accounts. For example, one particular multi-domain E-mail +service configuration +that's used by both <application>Qmail</application> and +<application>Courier</application> servers is to deliver mail for a +mailbox in a virtual domain, such as "user@example.com", to a local mailbox +called "example-user". Instead of requiring the E-mail account +holder to log in as +"example-user" to download mail from this account, a <command>userdb</command> +entry for "user@example.com" is set up with <parameter>mail</parameter> set to the +location of example-user's Maildir mailbox, thus hiding the internal +mail configuration from the E-mail account holder's view.</para> + + <para> +<parameter>quota</parameter> - <replaceable>value</replaceable> specifies the +maildir quota for the account's Maildir. +This has nothing to do with actual filesystem quotas. +<application>Courier</application> has a +software-based Maildir quota enforcement +mechanism which requires additional setup and configuration. +See +<ulink url="maildirquota.html"><citerefentry><refentrytitle>maildirquota</refentrytitle><manvolnum>7</manvolnum></citerefentry></ulink> +for additional information.</para> + </blockquote> + </refsect2> + <refsect2> + <title><filename>@userdb@shadow.dat</filename></title> + + <para> +All fields whose name ends with 'pw' will NOT copied to +<filename>@userdb@.dat</filename>. These fields will be copied to +<filename>@userdb@shadow.dat</filename>. +<command>makeuserdb</command> creates <filename>@userdb@shadow.dat</filename> +without any group and world permissions. +Note that <command>makeuserdb</command> reports an error +if <command>@userdb@</command> has any group +or world permissions.</para> + </refsect2> + + <refsect2> + + <title>CONVERTING <filename>/etc/passwd</filename> +and vpopmail to <filename>@userdb@</filename> format</title> + + <para> +<command>pw2userdb</command> reads the <filename>/etc/passwd</filename> and +<filename>/etc/shadow</filename> files and converts all entries to the +<filename>@userdb@</filename> format, +printing the result on standard output. +The output of <command>pw2userdb</command> +can be saved as <command>@userdb@</command> (or as some file in this +subdirectory). +Linear searches of <filename>/etc/passwd</filename> can +be very slow when you have +tens of thousands of accounts. +Programs like <command>maildrop</command> always look in +<filename>@userdb@</filename> first. +By saving the system password file in +<filename>@userdb@</filename> it is possible to significantly reduce the +amount of +time it takes to look up this information.</para> + + <para> +After saving the output of <command>pw2userdb</command>, you must still run +<command>makeuserdb</command> to create +<filename>@userdb@.dat</filename>.</para> + + <para> +<command>vchkpw2userdb</command> converts a vpopmail-style +directory hierarchy to the <filename>@userdb@</filename> format. +This is an external virtual domain management package that's often used +with <application>Qmail</application> servers.</para> + + <para> +Generally, an account named 'vpopmail' is reserved for this purpose. +In +that account the file <filename>users/vpasswd</filename> has the same +layout as +<filename>/etc/passwd</filename>, and performs a similar function, except +that all userid in <filename>users/vpasswd</filename> have the same userid. +Additionally, the +<filename>domains</filename> subdirectory stores virtual accounts for +multiple domains. For example, +<filename>domains/example.com/vpasswd</filename> +has the passwd file for the domain <parameter>example.com</parameter>. +Some systems also have a soft link, <parameter>domains/default</parameter>, +that points to a domain that's considered a "default" domain.</para> + + <para> +The <command>vchkpw2userdb</command> reads all this information, and tries to +convert it into the <filename>@userdb@</filename> format. The +<parameter>--vpopmailhost</parameter> option specifies the top level +directory, if it is +not the home directory of the vpopmail account.</para> + + <para> +The <command>vchkpw2userdb</command> script prints the results on standard +output. If specified, the <parameter>--todir</parameter> option +tries to convert all +<filename>vpasswd</filename> files one at a time, saving each one +individually in <replaceable>dir</replaceable>. For example:</para> + +<blockquote> + <informalexample> + <literallayout> +mkdir @userdb@ +vchkpw2userdb --todir=@userdb@/vpopmail +makeuserdb +</literallayout> + </informalexample> + </blockquote> + + <para> +It is still necessary to run <command>makeuserdb</command>, of course, to +create the binary database file <filename>@userdb@.dat</filename></para> + + <para> +NOTE: You are still required to create the <command>@userdb@</command> entry +which maps +system userids back to accounts, +"<replaceable>uid</replaceable>=<token><TAB></token><replaceable>name</replaceable>", +if that's applicable. <command>vchkpw2userdb</command> will not do it for +you.</para> + + <para> +NOTE: <command>makeuserdb</command> may complain about duplicate entries, if +your "default" entries in <filename>users/vpasswd</filename> or +<filename>domains/default/vpasswd</filename> are the same as anything in any +other <filename>@userdb@</filename> file. It is also likely that you'll end +up with duplicate, but distinct, entries for every account in the default +domain. For +example, if your default domain is example.com, you'll end up with duplicate +entries - you'll have entries for both <parameter>user</parameter> and +<parameter>user@example.com</parameter>.</para> + + <para>If you intend to maintain the master set of accounts using +vchkpw/vpopmail, +in order to avoid cleaning this up every time, you might want to consider +doing the following: run <command>vchkpw2userdb</command> once, using the +<parameter>--todir</parameter> option. +Then, go into the resulting directory, and +replace one of the redundant files with a soft link to +<filename>/dev/null</filename>. +This allows you to run +<command>vchkpw2userdb</command> without having to go in and +cleaning up again, afterwards.</para> + </refsect2> + </refsect1> + + <refsect1> + <title>FILES</title> + + <literallayout> +<filename>@userdb@</filename> +<filename>@userdb@.dat</filename> +<filename>@userdb@shadow.dat</filename> +<filename>@tmpdir@/userdb.tmp</filename> - temporary file +<filename>@tmpdir@/userdbshadow.tmp</filename> - temporary file +</literallayout> + + </refsect1> + <refsect1> + <title>BUGS</title> + + + <para><command>makeuserdb</command> is a Perl script, and uses Perl's portable +locking. +Perl's documentation notes that certain combinations of locking options may +not work with some networks.</para> + </refsect1> + + <refsect1> + <title>SEE ALSO</title> + + <para> +<ulink url="userdb.html"><citerefentry><refentrytitle>userdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink>, +<ulink url="maildrop.html"><citerefentry><refentrytitle>maildrop</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink>, +<ulink url="courier.html"><citerefentry><refentrytitle>courier</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink>, +<ulink url="maildirquota.html"><citerefentry><refentrytitle>maildirquota</refentrytitle><manvolnum>7</manvolnum></citerefentry></ulink>. +</para> + + </refsect1> + +</refentry> + diff --git a/userdb/pw2userdb.in b/userdb/pw2userdb.in new file mode 100644 index 0000000..b036d9d --- /dev/null +++ b/userdb/pw2userdb.in @@ -0,0 +1,70 @@ +#! @PERL@ +# +# Convert /etc/passwd and /etc/shadow to userdb format. +# +# +# Copyright 1998 - 1999 Double Precision, Inc. See COPYING for +# distribution information. + +use Getopt::Long; + +# +# Some undocumented options here (for vchkpw2userdb) +# + +die "Invalid options.\n" unless + GetOptions("passwd=s" => \$passwd, "shadow=s" => \$shadow, + "noshadow" => \$noshadow, "nouid" => \$nouid, + "domain=s" => \$domain, "vpopuid" => \$vpopuid ); + +($dummy, $dummy, $fixed_uid, $fixed_gid)=getpwnam("vpopmail") + if $vpopuid; + +$passwd="/etc/passwd" unless $passwd =~ /./; +$shadow="/etc/shadow" unless $shadow =~ /./; + +$domain="" unless $domain =~ /./; +$domain="\@$domain" if $domain =~ /./; + +open(PASSWD, $passwd) || die "$!\n"; + +while (<PASSWD>) +{ + chop if /\n$/; + next if /^#/; + ($acct,$passwd,$uid,$gid,$name,$home,$shell)=split( /:/ ); + + ($uid,$gid)=($fixed_uid,$fixed_gid) if $vpopuid; + + $PASSWORD{$acct}=$passwd if $passwd ne "x"; + $UID{$acct}=$uid; + $GID{$acct}=$gid; + $HOME{$acct}=$home; + $SHELL{$acct}=$shell; + + $name =~ s/\|/./g; # Just in case + $GECOS{$acct}=$name; +} +close (PASSWD); + +if ( -f $shadow && ! $noshadow) +{ + open (SHADOW, $shadow) || die "$!\n"; + while (<SHADOW>) + { + next if /^#/; + ($acct,$passwd,$dummy)=split(/:/); + $PASSWORD{$acct}=$passwd; + } + close (SHADOW); +} + +while ( defined ($key=each %UID)) +{ + print "$key$domain\tuid=$UID{$key}|gid=$GID{$key}|home=$HOME{$key}" . + ( $SHELL{$key} =~ /./ ? "|shell=$SHELL{$key}":"") . + ( $PASSWORD{$key} =~ /./ ? "|systempw=$PASSWORD{$key}":"") . + ( $GECOS{$key} =~ /./ ? "|gecos=$GECOS{$key}":"") . + "\n"; + print "$UID{$key}=\t$key\n" unless $nouid; +} diff --git a/userdb/userdb.c b/userdb/userdb.c new file mode 100644 index 0000000..e5a6066 --- /dev/null +++ b/userdb/userdb.c @@ -0,0 +1,411 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include "dbobj.h" +#include "userdb.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <time.h> +#include <sys/types.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + + +static struct dbobj d; +static time_t dt; +static ino_t di; + +static int initialized=0; +int userdb_debug_level=0; + +/* Open userdb.dat, if already opened, see if it changed, if so reopen */ + +void userdb_init(const char *n) +{ +struct stat stat_buf; + + if (initialized) + { + if (stat(n, &stat_buf) || + stat_buf.st_mtime != dt || + stat_buf.st_ino != di) + { + dbobj_close(&d); + initialized=0; + dt=stat_buf.st_mtime; + di=stat_buf.st_ino; + } + } + else if (stat(n, &stat_buf)) + { + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdb: unable to stat %s: %s\n", + n, strerror(errno)); + return; + } + else + { + dt=stat_buf.st_mtime; + di=stat_buf.st_ino; + } + + if (!initialized) + { + if (dbobj_open(&d, n, "R")) + { + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdb: failed to open %s\n", + n); + return; + } + if (userdb_debug_level) + fprintf(stderr, "DEBUG: userdb: opened %s\n", n); + initialized=1; + } +} + +void userdb_close() +{ + if (initialized) + { + dbobj_close(&d); + initialized=0; + } + userdb_debug_level=0; +} + +void userdb_set_debug(int lvl) +{ + userdb_debug_level = lvl; +} + +/* Fetch a record from userdb.dat */ + +char *userdb(const char *u) +{ +char *p,*q; +size_t l; + + if (!initialized) + { + errno=ENOENT; + return (0); + } + + q=dbobj_fetch(&d, u, strlen(u), &l, ""); + if (!q) + { + if (userdb_debug_level) + fprintf(stderr, "DEBUG: userdb: entry not found\n"); + errno=ENOENT; + return(0); + } + + p=malloc(l+1); + if (!p) + { + free(q); + return (0); + } + + if (l) memcpy(p, q, l); + free(q); + p[l]=0; + return (p); +} + +/* Return a pointer to a specific field in this record */ + +const char *userdb_get(const char *u, const char *n, int *l) +{ +int nl=strlen(n); + + while (u && *u) + { + if (memcmp(u, n, nl) == 0 && + (u[nl] == 0 || u[nl] == '=' || u[nl] == '|')) + { + u += nl; + *l=0; + if (*u == '=') + { + ++u; + while ( u[*l] && u[*l] != '|') + ++ *l; + } + return (u); + } + u=strchr(u, '|'); + if (u) ++u; + } + return (0); +} + +/* Extract field as an unsigned int */ + +unsigned userdb_getu(const char *u, const char *n, unsigned defnum) +{ + int l; + const char *p; + + if ((p=userdb_get(u, n, &l)) != 0) + { + defnum=0; + while (l && *p >= '0' && *p <= '9') + { + defnum = defnum * 10 + (*p++ - '0'); + --l; + } + } + return (defnum); +} + +/* Extract a field into a dynamically allocated buffer */ + +char *userdb_gets(const char *u, const char *n) +{ + int l; + const char *p; + char *q; + + if ((p=userdb_get(u, n, &l)) != 0) + { + q=malloc(l+1); + if (!q) + return (0); + + if (l) memcpy(q, p, l); + q[l]=0; + return (q); + } + errno=ENOENT; + return (0); +} + +/* Create a userdbs structure based upon a uid (reverse lookup) */ + +struct userdbs *userdb_createsuid(uid_t u) +{ +char buf[80]; +char *p=buf+sizeof(buf)-1, *q; +struct userdbs *s; + + /* Lookup uid= record */ + + *p=0; + *--p='='; + do + { + *--p= "0123456789"[u % 10]; + u=u/10; + } while (u); + p=userdb(p); + if (!p) return (0); + + /* Have account name, now look it up. */ + + q=userdb(p); + if (!q) + { + free(p); + return (0); + } + s=userdb_creates(q); + if (s) + s->udb_name=p; + else + free(p); + free(q); + return (s); +} + +static struct userdbs *userdb_enum(char *key, size_t keylen, + char *val, size_t vallen) +{ + if (key) + { + char *valz=malloc(vallen+1); + + if (valz) + { + struct userdbs *udbs; + + memcpy(valz, val, vallen); + valz[vallen]=0; + + udbs=userdb_creates(valz); + + if (udbs) + { + if ((udbs->udb_name=malloc(keylen+1)) != NULL) + { + memcpy(udbs->udb_name, key, keylen); + udbs->udb_name[keylen]=0; + free(valz); + return udbs; + } + userdb_frees(udbs); + } + free(valz); + } + } + return NULL; +} + + +struct userdbs *userdb_enum_first() +{ + char *val; + size_t vallen; + size_t keylen; + char *key=dbobj_firstkey(&d, &keylen, &val, &vallen); + + if (key) + { + struct userdbs *udbs=userdb_enum(key, keylen, val, vallen); + + free(val); + + if (udbs) + return udbs; + + /* Could be a reverse UID entry */ + + return userdb_enum_next(); + } + return NULL; +} + +struct userdbs *userdb_enum_next() +{ + char *val; + size_t vallen; + size_t keylen; + char *key; + + while ((key=dbobj_nextkey(&d, &keylen, &val, &vallen)) != NULL) + { + struct userdbs *udbs=userdb_enum(key, keylen, val, vallen); + + free(val); + + if (udbs) + return udbs; + } + return NULL; +} + +/* Extracted a userdb.dat record, convert it to a userdbs structure */ + +struct userdbs *userdb_creates(const char *u) +{ +struct userdbs *udbs=(struct userdbs *)malloc(sizeof(struct userdbs)); +char *s; + + if (!udbs) return (0); + memset((char *)udbs, 0, sizeof(*udbs)); + + if ((udbs->udb_dir=userdb_gets(u, "home")) == 0) + { + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdb: required value 'home' is missing\n"); + userdb_frees(udbs); + return (0); + } + + if ((s=userdb_gets(u, "uid")) != 0) + { + udbs->udb_uid=atol(s); + free(s); + if ((s=userdb_gets(u, "gid")) != 0) + { + udbs->udb_gid=atol(s); + free(s); + + if ((s=userdb_gets(u, "shell")) != 0) + udbs->udb_shell=s; + else if (errno != ENOENT) + { + userdb_frees(udbs); + return (0); + } + + if ((s=userdb_gets(u, "mail")) != 0) + udbs->udb_mailbox=s; + else if (errno != ENOENT) + { + userdb_frees(udbs); + return (0); + } + if ((s=userdb_gets(u, "quota")) != 0) + udbs->udb_quota=s; + else if (errno != ENOENT) + { + userdb_frees(udbs); + return (0); + } + if ((s=userdb_gets(u, "gecos")) != 0) + udbs->udb_gecos=s; + else if (errno != ENOENT) + { + userdb_frees(udbs); + return (0); + } + if ((s=userdb_gets(u, "options")) != 0) + udbs->udb_options=s; + else if (errno != ENOENT) + { + userdb_frees(udbs); + return (0); + } + udbs->udb_source=userdb_gets(u, "_"); + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdb: home=%s, uid=%ld, gid=%ld, shell=%s, " + "mail=%s, quota=%s, gecos=%s, options=%s\n", + udbs->udb_dir ? udbs->udb_dir : "<unset>", + (long)udbs->udb_uid, (long)udbs->udb_gid, + udbs->udb_shell ? udbs->udb_shell : "<unset>", + udbs->udb_mailbox ? udbs->udb_mailbox : "<unset>", + udbs->udb_quota ? udbs->udb_quota : "<unset>", + udbs->udb_gecos ? udbs->udb_gecos : "<unset>", + udbs->udb_options ? udbs->udb_options : "<unset>"); + return (udbs); + } + else + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdb: required value 'gid' is missing\n"); + } + else + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdb: required value 'uid' is missing\n"); + userdb_frees(udbs); + return (0); +} + +void userdb_frees(struct userdbs *u) +{ + if (u->udb_options) free(u->udb_options); + if (u->udb_name) free(u->udb_name); + if (u->udb_gecos) free(u->udb_gecos); + if (u->udb_dir) free(u->udb_dir); + if (u->udb_shell) free(u->udb_shell); + if (u->udb_mailbox) free(u->udb_mailbox); + if (u->udb_quota) free(u->udb_quota); + if (u->udb_source) free(u->udb_source); + free(u); +} + diff --git a/userdb/userdb.h b/userdb/userdb.h new file mode 100644 index 0000000..3b2690a --- /dev/null +++ b/userdb/userdb.h @@ -0,0 +1,68 @@ +#ifndef userdb_h +#define userdb_h + +/* +** Copyright 1998 - 2001 Double Precision, Inc. +** See COPYING for distribution information. +*/ + + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Functions to access local/config/userdb.dat +*/ + +void userdb_set_debug(int); +void userdb_init(const char *); +void userdb_close(); +char *userdb(const char *); /* Fetch the record */ +char *userdbshadow(const char *, + const char *); /* Fetch the userdbshadow record */ + + /* Extract field from the record */ +const char *userdb_get(const char *, /* The record */ + const char *, /* Field name */ + int *); /* Content length returned */ + + /* Extract numerical field from record */ + +unsigned userdb_getu(const char *, /* The record */ + const char *, /* Field name */ + unsigned); /* Returned if field not found */ + + /* Extract string into malloced buffer */ +char *userdb_gets(const char *, /* The record */ + const char *); /* The field */ + +struct userdbs { + char *udb_name; /* Account name, ONLY set by userdb_createsuid */ + char *udb_gecos; /* GECOS */ + char *udb_dir; /* Home directory */ + char *udb_shell; /* Shell */ + char *udb_mailbox; /* Default mailbox */ + char *udb_quota; /* Maildir quota */ + char *udb_options; /* Options, see INSTALL */ + uid_t udb_uid; + gid_t udb_gid; + + char *udb_source; /* Non-blank - source file in userdb dir */ + } ; + +struct userdbs *userdb_creates(const char *); +struct userdbs *userdb_createsuid(uid_t); +struct userdbs *userdb_enum_first(); +struct userdbs *userdb_enum_next(); + +void userdb_frees(struct userdbs *); +char *userdb_mkmd5pw(const char *); + +#ifdef __cplusplus +} ; +#endif + +#endif diff --git a/userdb/userdb.pl.in b/userdb/userdb.pl.in new file mode 100644 index 0000000..db16bcc --- /dev/null +++ b/userdb/userdb.pl.in @@ -0,0 +1,263 @@ +#! @PERL@ +# +# Copyright 1998 - 1999 Double Precision, Inc. See COPYING for +# distribution information. + +use Fcntl ':flock'; + +$prefix="@prefix@"; +$exec_prefix="@exec_prefix@"; +$userdb="@userdb@"; + +eval { + die "SYMLINK\n" if -l $userdb; +}; + +die "ERROR: Wrong userdb command.\n ($userdb is a symbolic link)\n" + if $@ eq "SYMLINK\n"; + +sub usage { + print "Usage: $0 [path/.../ | -f file ]name set field=value field=value...\n"; + print " $0 [path/.../ | -f file ]name unset field field...\n"; + print " $0 [path/.../ | -f file ]name del\n"; + print " $0 -show [path/... | -f file ] [name]\n"; + exit 1; +} + +$name=shift @ARGV; +$doshow=0; + +if ($name eq "-show") +{ + $doshow=1; + $name=shift @ARGV; +} + +if ($name eq "-f") +{ + $userdb=shift @ARGV; + $name=shift @ARGV; +} +elsif ( $name =~ /^(.*)\/([^\/]*)$/ ) +{ + $userdb="$userdb/$1"; + $name=$2; +} + + +if ($doshow) +{ + &usage unless $userdb =~ /./; +} +else +{ + $verb=shift @ARGV; + + &usage unless $verb =~ /./ && $name =~ /./ && $userdb =~ /./; +} + +while (defined ($link= &safe_readlink($userdb))) +{ + $userdb .= "/"; + $userdb = "" if $link =~ /^\//; + $userdb .= $link; +} + +$tmpuserdb= $userdb =~ /^(.*)\/([^\/]*)$/ ? "$1/.tmp.$2":".tmp.$userdb"; +$lockuserdb= $userdb =~ /^(.*)\/([^\/]*)$/ ? "$1/.lock.$2":".lock.$userdb"; + +if ( $doshow && ! defined $name) +{ +} +else +{ + die "Invalid name: $name\n" + unless $name =~ /^[\@a-zA-Z0-9\.\-\_\:\+]+$/; +} + +grep( (/[\|\n]/ && die "Invalid field or value.\n"), @ARGV); + +umask(066); + +open(LOCK, ">$lockuserdb") or die "Can't open $lockuserdb: $!"; +flock(LOCK,LOCK_EX) || die "Can't lock $lockuserdb: $!"; + +if ( $doshow ) +{ + if (open (OLDFILE, $userdb)) + { + stat(OLDFILE); + die "$userdb: not a file.\n" unless -f _; + + while ( defined($_=<OLDFILE>) ) + { + chop if /\n$/; + next if /^#/; + next unless /^([^\t]+)(\t(.*))?$/; + ($addr,$vals)=($1,$3); + if (defined $name) + { + if ($name eq $addr) + { + $vals =~ s/\|/\n/g; + print "$vals\n"; + last; + } + } + else + { + print "$addr\n"; + } + } + } + close (OLDFILE); +} +elsif ( $verb eq "set" ) +{ + $isatty=1; + + eval { + $isatty=0 unless -t STDIN; + } ; + + &doadd; + $mode= (stat $userdb)[2]; + chmod ($mode & 0777,$tmpuserdb ) if defined $mode; + rename $tmpuserdb,$userdb; +} +elsif ( $verb eq "unset" ) +{ + if ($#ARGV >= 0 && &dodel) + { + $mode= (stat $userdb)[2]; + chmod ($mode & 0777 ,$tmpuserdb) if defined $mode; + rename ($tmpuserdb,$userdb) + } +} +elsif ( $verb eq "del" ) +{ + &usage unless $#ARGV < 0; + if (&dodel) + { + $mode= (stat $userdb)[2]; + chmod ($mode & 0777 ,$tmpuserdb) if defined $mode; + rename ($tmpuserdb,$userdb) + } +} +else +{ + &usage; +} +exit 0; + +sub doadd { +my (%FIELDS); +my ($key, $in); + + foreach $key (@ARGV) + { + next if $key =~ /=/; + print "$name.$key: " if $isatty; + exit 1 unless defined ($in=<STDIN>); + chop $in if $in =~ /\n$/; + die "Invalid value.\n" if $in =~ /[\|\n]/; + $key = "$key=$in"; + } + + open (NEWFILE, ">$tmpuserdb") || die "$!\n"; + if (open (OLDFILE, $userdb)) + { + stat(OLDFILE); + die "$userdb: not a file.\n" unless -f _; + while ( defined($_=<OLDFILE>) ) + { + chop if /\n$/; + if ( /^([^\t]+)(\t(.*))?$/ && ($1 eq $name)) + { + grep( (/^([^=]*)(=.*)?$/, + $FIELDS{$1}="$2"), split(/\|/, $3)); + while ( defined ($key=shift @ARGV)) + { + $key =~ /^([^=]*)(=.*)?$/; + $FIELDS{$1}="$2"; + } + $name="$name\t"; + grep ( $name="$name$_$FIELDS{$_}|", + keys %FIELDS); + chop $name; + print NEWFILE "$name\n" || die "$!\n"; + while (<OLDFILE>) + { + print NEWFILE || die "$!\n"; + } + close (OLDFILE); + close (NEWFILE) || die "$!\n"; + return; + } + print NEWFILE "$_\n" || die "$!\n"; + } + close (OLDFILE); + } + + $name="$name\t"; + grep ( $name="$name$_|", @ARGV ); + chop $name; + print NEWFILE "$name\n" || die "$!\n"; + close (NEWFILE) || die "$!\n"; +} + +sub dodel { +my (%FIELDS); + + open (NEWFILE, ">$tmpuserdb") || die "$!\n"; + if (open (OLDFILE, $userdb)) + { + stat(OLDFILE); + die "$userdb: not a file.\n" unless -f _; + while ( defined($_=<OLDFILE>) ) + { + chop if /\n$/; + if ( /^([^\t]+)(\t(.*))?$/ && ($1 eq $name)) + { + if ($#ARGV >= 0) + { + grep( (/^([^=]*)(=.*)?$/, + $FIELDS{$1}=$2), + split(/\|/, $3)); + grep( delete $FIELDS{$_}, @ARGV); + + $name="$name\t"; + grep ( $name="$name$_$FIELDS{$_}|", + keys %FIELDS); + chop $name; + $name="$name\n"; + print NEWFILE "$name" || die "$!\n"; + } + while (<OLDFILE>) + { + print NEWFILE || die "$!\n"; + } + close (OLDFILE); + close (NEWFILE) || die "$!\n"; + return (1); + } + print NEWFILE "$_\n" || die "$!\n"; + } + close (OLDFILE); + } + unlink "$tmpuserdb"; + return (0); +} + +sub safe_readlink { +my ($l)=@_; +my ($err,$link); + + eval { + + $link=readlink($l); + } ; + + $link=undef if $@; + return $link; +} diff --git a/userdb/userdb.sgml b/userdb/userdb.sgml new file mode 100644 index 0000000..6bb6a13 --- /dev/null +++ b/userdb/userdb.sgml @@ -0,0 +1,265 @@ +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> + + <!-- Copyright 1998 - 2007 Double Precision, Inc. See COPYING for --> + <!-- distribution information. --> + +<refentry id="userdb"> + + <refmeta> + <refentrytitle>userdb</refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo>Double Precision, Inc.</refmiscinfo> + </refmeta> + + <refnamediv> + <refname>userdb</refname> + <refpurpose>manipulate @userdb@</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>userdb</command> + <arg choice='req'><replaceable>addr</replaceable></arg> + <arg choice='plain'>set</arg> + <arg choice='req' rep='repeat'><replaceable>field</replaceable>=<replaceable>value</replaceable></arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='req'><replaceable>addr</replaceable></arg> + <arg choice='plain'>unset</arg> + <arg choice='req' rep='repeat'><replaceable>field</replaceable></arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='req'><replaceable>addr</replaceable></arg> + <arg choice='plain'>del</arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='req'><replaceable>path/addr</replaceable></arg> + <group> + <arg choice='plain'>set</arg> + <arg choice='plain'>unset</arg> + <arg choice='plain'>del</arg> + </group> + <arg choice='plain'>...</arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='plain'>-f</arg> + <arg choice='req'><replaceable>file</replaceable></arg> + <arg choice='req'><replaceable>adr</replaceable></arg> + <group> + <arg choice='plain'>set</arg> + <arg choice='plain'>unset</arg> + <arg choice='plain'>del</arg> + </group> + <arg choice='plain'>...</arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='plain'>-show</arg> + <arg choice='req'><replaceable>path</replaceable></arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='plain'>-show</arg> + <arg choice='req'><replaceable>path</replaceable></arg> + <arg choice='req'><replaceable>addr</replaceable></arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='plain'>-show</arg> + <arg choice='plain'>-f</arg> + <arg choice='req'><replaceable>file</replaceable></arg> + </cmdsynopsis> + + <cmdsynopsis> + <command>userdb</command> + <arg choice='plain'>-show</arg> + <arg choice='plain'>-f</arg> + <arg choice='req'><replaceable>file</replaceable></arg> + <arg choice='req'><replaceable>addr</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>DESCRIPTION</title> + + <para> +<command>userdb</command> is a convenient script to individually manipulate +entries in <filename>@userdb@</filename>. See +<ulink url="makeuserdb.html"><citerefentry><refentrytitle>makeuserdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink> +for a description of its contents. <filename>@userdb@</filename> can always +be edited using any text editor, but <command>userdb</command> is a +convenient way to modify this file from another script.</para> + + <para> +<filename>@userdb@</filename> can also be a subdirectory, instead of a file. +Specify <option><replaceable>foo/bar/addr</replaceable></option> to manipulate +<option><replaceable>addr</replaceable></option> in the file +<filename>@userdb@<replaceable>/foo/bar</replaceable></filename>. You can +also use the +<option>-f</option> flag: <option>-f +<replaceable>@userdb@/foo/bar</replaceable></option> is equivalent. Use +whatever form makes the most sense to you.</para> + + <para> +<filename>@userdb@</filename> must not have any group or world +permissions. That's +because its contents may include system passwords (depending upon the +application which uses this virtual user account database).</para> + + <para> +Each line in <filename>@userdb@</filename> takes following form:</para> + +<blockquote> +<computeroutput> +<replaceable>addr</replaceable><token><TAB></token><replaceable>field</replaceable>=<replaceable>value</replaceable>|<replaceable>field</replaceable>=<replaceable>value</replaceable>... +</computeroutput> + </blockquote> + + <para> +<replaceable>addr</replaceable> specifies a unique virtual address. It +is followed by a single +tab character, then a list of +<replaceable>field</replaceable>=<replaceable>value</replaceable> pairs, +separated by +vertical slash characters. See +<ulink url="makeuserdb.html"><citerefentry><refentrytitle>makeuserdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink> +for field definitions.</para> + + <para> +A text editor can be used to add blank lines or comments in +<filename>@userdb@</filename>. Any blank lines or comments are ignored by the +<command>userdb</command> script.</para> + + <para> +The names of the actual fields, and their contents, are defined entirely by +applications that use the <filename>@userdb@</filename> database, the +<command>userdb</command> command just adds or removes arbitrary fields.</para> + + + <para> +For example:</para> +<blockquote> + <informalexample> + <literallayout><command>userdb default/info set mail=/home/mail/info</command></literallayout> + </informalexample> + </blockquote> + + <para> +This command accesses the address "info" in +<filename>@userdb@/default</filename>.</para> + + <para> +If the second argument to <command>userdb</command> is +"<parameter>set</parameter>", the +remaining arguments are taken as +<parameter><replaceable>field</replaceable>=<replaceable>value</replaceable></parameter> pairs, which are +added to the record for <replaceable>addr</replaceable>. If there is no +record for <replaceable>addr</replaceable>, a +new record will be appended to the file. If +<replaceable>addr</replaceable> exists, any existing +values of any specified fields are removed. If +<parameter>=<replaceable>value</replaceable></parameter> is missing, +<command>userdb</command> stops and prompts for it. This is useful if +you're setting +a password field, where you do not want to specify the password on the command +line, which can be seen by the +<citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry> +command. If <command>userdb</command> is being +executed by a script, the value can be provided on standard input.</para> + + <para>Use "<parameter>unset</parameter>" to delete fields from an existing +record. Use +"<parameter>del</parameter>" to delete all fields in the existing record, +plus the record itself.</para> + + + <refsect2><title>DISPLAYING <filename>@userdb@</filename></title> + + <para> +If the first argument to userdb +is <parameter>-show</parameter>, <command>userdb</command> +displays the contents of <filename>@userdb@</filename>. If +<filename>@userdb@</filename> is a +subdirectory, +<parameter><replaceable>path</replaceable></parameter> must refer to a +specific file in <filename>@userdb@</filename>. The +<parameter>-f</parameter> option can be used instead of +<parameter><replaceable>path</replaceable></parameter> in order to specify an +arbitrary file.</para> + + <para> +If +<parameter><replaceable>addr</replaceable></parameter> is not specified, +<command>userdb</command> produces a list, on standard +output, containing all addresses found in the file, on per line. If +<parameter><replaceable>addr</replaceable></parameter> is specified, +<command>userdb</command> produces a list, on standard output, of +all the fields in <filename>@userdb@</filename> for this +<parameter><replaceable>addr</replaceable></parameter>.</para> + + </refsect2> + + <refsect2> + <title>REBUILDING <filename>@userdb@.dat</filename></title> + + <para> +The actual virtual account/address database is +<filename>@userdb@.dat</filename>. +This is a binary database file. <command>@userdb@</command> is the plain text +version. After running <command>userdb</command>, execute the +<ulink url="makeuserdb.html"><citerefentry><refentrytitle>makeuserdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink> command to rebuild +<filename>@userdb@.dat</filename> for the changes to take effect.</para> + </refsect2> + + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para> +<parameter><replaceable>addr</replaceable></parameter> must be unique. +If <filename>@userdb@</filename> is a subdirectory, +it's possible to create the same +<parameter><replaceable>addr</replaceable></parameter> +in different files in the subdirectory. +This is an error that is not currently detected by <command>userdb</command>, +however the subsequent +<ulink url="makeuserdb.html"><citerefentry><refentrytitle>makeuserdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink> command +will fail with an error message.</para> + </refsect1> + + <refsect1> + <title>FILES</title> + + <para> +<filename> @userdb@</filename> - plain text file, or directory of plain text files</para> + <para> +<filename> .lock.filename</filename> - lock file for <filename>filename</filename></para> + <para> +<filename> .tmp.filename</filename> - temporary file used to create new contents of <filename>filename</filename></para> + </refsect1> + + <refsect1> + <title>SEE ALSO</title> + + <para> +<ulink url="makeuserdb.html"><citerefentry><refentrytitle>makeuserdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink>, + +<ulink url="userdbpw.html"><citerefentry><refentrytitle>userdbpw</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink></para> + + </refsect1> + +</refentry> + diff --git a/userdb/userdb2.c b/userdb/userdb2.c new file mode 100644 index 0000000..fd904c1 --- /dev/null +++ b/userdb/userdb2.c @@ -0,0 +1,57 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include "dbobj.h" +#include "userdb.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + + +extern int userdb_debug_level; + +char *userdbshadow(const char *sh, const char *u) +{ +struct dbobj d; +char *p,*q; +size_t l; + + dbobj_init(&d); + + if (dbobj_open(&d, sh, "R")) + { + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdbshadow: unable to open %s\n", sh); + return (0); + } + + q=dbobj_fetch(&d, u, strlen(u), &l, ""); + dbobj_close(&d); + if (!q) + { + if (userdb_debug_level) + fprintf(stderr, + "DEBUG: userdbshadow: entry not found\n"); + errno=ENOENT; + return(0); + } + + p=malloc(l+1); + if (!p) + { + free(q); + return (0); + } + + if (l) memcpy(p, q, l); + free(q); + p[l]=0; + return (p); +} diff --git a/userdb/userdbmkpw.c b/userdb/userdbmkpw.c new file mode 100644 index 0000000..3786a83 --- /dev/null +++ b/userdb/userdbmkpw.c @@ -0,0 +1,119 @@ +/* +** Copyright 2001 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include <sys/types.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif +#if HAVE_MD5 +#include "md5/md5.h" +#endif + +#include <string.h> +#include <stdio.h> +#include <signal.h> +#include <stdlib.h> +#if HAVE_TERMIOS_H +#include <termios.h> +#endif +#if HAVE_CRYPT_H +#include <crypt.h> +#endif + +#if HAVE_CRYPT +#if NEED_CRYPT_PROTOTYPE +extern char *crypt(const char *, const char *); +#endif +#endif + +char userdb_hex64[]="./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#ifdef RANDOM +void userdb_get_random(char *buf, unsigned n) +{ +int f=open(RANDOM, O_RDONLY); +int l; + + if (f < 0) + { + perror(RANDOM); + exit(1); + } + while (n) + { + l=read(f, buf, n); + if (l < 0) + { + perror("read"); + exit(1); + } + n -= l; + buf += l; + } + close(f); +} +#endif + +#if HAVE_MD5 +char *userdb_mkmd5pw(const char *buf) +{ + int i; + char salt[9]; + + salt[8]=0; +#ifdef RANDOM + userdb_get_random(salt, 8); + for (i=0; i<8; i++) + salt[i] = userdb_hex64[salt[i] & 63 ]; + +#else + { + + struct { +#if HAVE_GETTIMEOFDAY + struct timeval tv; +#else + time_t tv; +#endif + pid_t p; + } s; + + MD5_DIGEST d; +#if HAVE_GETTIMEOFDAY + struct timezone tz; + + gettimeofday(&s.tv, &tz); +#else + time(&s.tv); +#endif + s.p=getpid(); + + md5_digest(&s, sizeof(s), d); + for (i=0; i<8; i++) + salt[i]=userdb_hex64[ ((unsigned char *)d)[i] ]; + } +#endif + return (md5_crypt(buf, salt)); +} +#endif diff --git a/userdb/userdbpw.c b/userdb/userdbpw.c new file mode 100644 index 0000000..23620df --- /dev/null +++ b/userdb/userdbpw.c @@ -0,0 +1,251 @@ +/* +** Copyright 1998 - 2006 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include <sys/types.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif +#if HAVE_MD5 +#include "md5/md5.h" +#endif +#if HAVE_HMAC +#include "libhmac/hmac.h" +#endif + +#include <string.h> +#include <stdio.h> +#include <signal.h> +#include <stdlib.h> +#if HAVE_TERMIOS_H +#include <termios.h> +#endif +#if HAVE_CRYPT_H +#include <crypt.h> +#endif + +#if HAVE_CRYPT +#if NEED_CRYPT_PROTOTYPE +extern char *crypt(const char *, const char *); +#endif +#endif + +extern char userdb_hex64[]; + +#ifdef RANDOM +extern void userdb_get_random(char *buf, unsigned n); +#endif + +#if HAVE_MD5 + +char *userdb_mkmd5pw(const char *); + +#endif + +/* +** Where possible, we turn off echo when entering the password. +** We set up a signal handler to catch signals and restore the echo +** prior to exiting. +*/ + +#if HAVE_TERMIOS_H +static struct termios tios; +static int have_tios; + +static RETSIGTYPE sighandler(int signum) +{ + if (write(1, "\n", 1) < 0) + ; /* ignore gcc warning */ + tcsetattr(0, TCSANOW, &tios); + _exit(0); +#if RETSIGTYPE != void + return (0); +#endif +} +#endif + +static void read_pw(char *buf) +{ +int n, c; + + n=0; + while ((c=getchar()) != EOF && c != '\n') + if (n < BUFSIZ-1) + buf[n++]=c; + if (c == EOF && n == 0) exit(1); + buf[n]=0; +} + +int main(int argc, char **argv) +{ +int n=1; +int md5=0; +char buf[BUFSIZ]; +char salt[9]; +#if HAVE_HMAC +struct hmac_hashinfo *hmac=0; +#endif + + while (n < argc) + { + if (strcmp(argv[n], "-md5") == 0) + { + md5=1; + ++n; + continue; + } +#if HAVE_HMAC + if (strncmp(argv[n], "-hmac-", 6) == 0) + { + int i; + + for (i=0; hmac_list[i] && + strcmp(hmac_list[i]->hh_name, argv[n]+6); i++) + ; + if (hmac_list[i]) + { + hmac=hmac_list[i]; + ++n; + continue; + } + } +#endif + fprintf(stderr, "%s: invalid argument.\n", argv[0]); + exit(1); + } + + /* Read the password */ +#if HAVE_TERMIOS_H + + have_tios=0; + if (tcgetattr(0, &tios) == 0) + { + struct termios tios2; + char buf2[BUFSIZ]; + + have_tios=1; + signal(SIGINT, sighandler); + signal(SIGHUP, sighandler); + tios2=tios; + tios2.c_lflag &= ~ECHO; + tcsetattr(0, TCSANOW, &tios2); + + for (;;) + { + if (write(2, "Password: ", 10) < 0) + ; /* ignore gcc warning */ + read_pw(buf); + if (write(2, "\nReenter password: ", 19) < 0) + ; /* ignore gcc warning */ + read_pw(buf2); + if (strcmp(buf, buf2) == 0) break; + if (write(2, "\nPasswords don't match.\n\n", 25) < 0) + ; /* ignore gcc warning */ + } + + } + else +#endif + read_pw(buf); + +#if HAVE_TERMIOS_H + if (have_tios) + { + if (write(2, "\n", 1) < 0) + ; /* ignore gcc warning */ + + tcsetattr(0, TCSANOW, &tios); + signal(SIGINT, SIG_DFL); + signal(SIGHUP, SIG_DFL); + } +#endif + + /* Set the password */ + +#if HAVE_HMAC + if (hmac) + { + unsigned char *p=malloc(hmac->hh_L*2); + unsigned i; + + if (!p) + { + perror("malloc"); + exit(1); + } + + hmac_hashkey(hmac, buf, strlen(buf), p, p+hmac->hh_L); + for (i=0; i<hmac->hh_L*2; i++) + printf("%02x", (int)p[i]); + printf("\n"); + exit(0); + } +#endif + +#if HAVE_CRYPT + +#else + md5=1; +#endif + +#if HAVE_MD5 + if (md5) + { + + printf("%s\n", userdb_mkmd5pw(buf)); + exit(0); + } +#endif +#ifdef RANDOM + userdb_get_random(salt, 2); + salt[0]=userdb_hex64[salt[0] & 63]; + salt[1]=userdb_hex64[salt[0] & 63]; +#else + { + time_t t; + int i; + + time(&t); + t ^= getpid(); + salt[0]=0; + salt[1]=0; + for (i=0; i<6; i++) + { + salt[0] <<= 1; + salt[1] <<= 1; + salt[0] |= (t & 1); + t >>= 1; + salt[1] |= (t & 1); + t >>= 1; + } + salt[0]=userdb_hex64[(unsigned)salt[0]]; + salt[1]=userdb_hex64[(unsigned)salt[1]]; + } +#endif + +#if HAVE_CRYPT + printf("%s\n", crypt(buf, salt)); + fflush(stdout); +#endif + return (0); +} diff --git a/userdb/userdbpw.sgml b/userdb/userdbpw.sgml new file mode 100644 index 0000000..246c9cc --- /dev/null +++ b/userdb/userdbpw.sgml @@ -0,0 +1,129 @@ +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> + + <!-- Copyright 1998 - 2007 Double Precision, Inc. See COPYING for --> + <!-- distribution information. --> + +<refentry id="userdbpw"> + + <refmeta> + <refentrytitle>userdbpw</refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo>Double Precision, Inc.</refmiscinfo> + </refmeta> + + <refnamediv> + <refname>userdbpw</refname> + <refpurpose>create an encrypted password</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>userdbpw</command> + <group> + <arg choice='opt'>-md5</arg> + <arg choice='opt'>-hmac-md5</arg> + <arg choice='opt'>-hmac-sha1</arg> + </group> + <arg choice='plain'>|</arg> + <command>userdb</command> + <arg choice='req'><replaceable>name</replaceable></arg> + <arg choice='plain'>set</arg> + <arg choice='req'><replaceable>field</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>DESCRIPTION</title> + + <para><command>userdbpw</command> enables secure entry of encrypted +passwords into <filename>@userdb@</filename>.</para> + + <para><command>userdbpw</command> reads a single line of text on +standard input, encrypts it, and prints the encrypted result to standard +output.</para> + + <para>If standard input is attached to a terminal device, +<command>userdbpw</command> explicitly issues a "Password: " prompt on +standard error, and turns off echo while the password is entered.</para> + + <para>The <option>-md5</option> option is available on systems that use +MD5-hashed passwords (such as systems that use the current version of the +PAM library for authenticating, with MD5 passwords enabled). +This option creates an MD5 password hash, instead of using the +traditional <function>crypt()</function> function.</para> + + <para><option>-hmac-md5</option> and <option>-hmac-sha1</option> options +are available only if the userdb library is installed by an application +that uses a challenge/response authentication mechanism. +<option>-hmac-md5</option> creates an intermediate HMAC context using the +MD5 hash function. <option>-hmac-sha1</option> uses the SHA1 hash function +instead. Whether either HMAC function is actually available depends on the +actual application that installs the <option>userdb</option> library.</para> + + <para>Note that even though the result of HMAC hashing looks like an encrypted +password, it's really not. HMAC-based challenge/response authentication +mechanisms require the cleartext password to be available as cleartext. +Computing an intermediate HMAC context does scramble the cleartext password, +however if its compromised, it WILL be possible for an attacker to succesfully +authenticate. Therefore, applications that use challenge/response +authentication will store intermediate HMAC contexts in the "pw" fields in the +userdb database, which will be compiled into the +<filename>userdbshadow.dat</filename> +database, which has group and world permissions turned off. The +userdb library also requires that the cleartext userdb source for the +<filename>userdb.dat</filename> and +<filename>userdbshadow.dat</filename> databases is also stored with the +group and world permissions turned off.</para> + + <para><command>userdbpw</command> is usually used together in a pipe with +<command>userdb</command>, which reads from standard input. For example:</para> + + <blockquote> + <informalexample> + <programlisting><command>userdbpw -md5 | userdb users/john set systempw</command></programlisting> + </informalexample> + </blockquote> + + <para>or:</para> + +<blockquote> + <informalexample> + <programlisting><command>userdbpw -hmac-md5 | userdb users/john set hmac-md5pw</command></programlisting> + </informalexample> + </blockquote> + + <para>These commands set the <option>systempw</option> field in the record for +the user <option>john</option> in <filename>@userdb@/users</filename> file, and the +<option>hmac-md5pw</option> field. Don't forget to run +<command>makeuserdb</command> for the change to take effect.</para> + + <para>The following command does the same thing:</para> + + <blockquote> + <informalexample> + <programlisting><command>userdb users/john set systempw=<option>SECRETPASSWORD</option></command></programlisting> + </informalexample> + </blockquote> + + <para>However, this command passes the secret password as an argument to the +<command>userdb</command> command, which can be viewed by anyone who happens +to run +<citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry> +at the same time. Using <command>userdbpw</command> allows the secret password +to be specified in a way that cannot be easily viewed by +<citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> + </refsect1> + + <refsect1> + <title>SEE ALSO</title> + + <para> +<ulink url="userdb.html"><citerefentry><refentrytitle>userdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink>, + +<ulink url="makeuserdb.html"><citerefentry><refentrytitle>makeuserdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></ulink></para> + + </refsect1> + +</refentry> + |
