From 333f7ecfa3e040191c66b2b92f6c117ca2cbac1d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 14:50:00 +0200 Subject: Adding upstream version 1:4.8.1. Signed-off-by: Daniel Baumann --- contrib/Makefile.am | 6 + contrib/Makefile.in | 482 ++++++++++++++++++++++++++++ contrib/README | 10 + contrib/adduser-old.c | 300 +++++++++++++++++ contrib/adduser.c | 502 +++++++++++++++++++++++++++++ contrib/adduser.sh | 90 ++++++ contrib/adduser2.sh | 743 +++++++++++++++++++++++++++++++++++++++++++ contrib/atudel | 85 +++++ contrib/groupmems.shar | 546 +++++++++++++++++++++++++++++++ contrib/pwdauth.c | 308 ++++++++++++++++++ contrib/shadow-anonftp.patch | 147 +++++++++ contrib/udbachk.tgz | Bin 0 -> 17571 bytes 12 files changed, 3219 insertions(+) create mode 100644 contrib/Makefile.am create mode 100644 contrib/Makefile.in create mode 100644 contrib/README create mode 100644 contrib/adduser-old.c create mode 100644 contrib/adduser.c create mode 100755 contrib/adduser.sh create mode 100755 contrib/adduser2.sh create mode 100755 contrib/atudel create mode 100644 contrib/groupmems.shar create mode 100644 contrib/pwdauth.c create mode 100644 contrib/shadow-anonftp.patch create mode 100644 contrib/udbachk.tgz (limited to 'contrib') diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 0000000..2c3160e --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1,6 @@ +# This is a dummy Makefile.am to get automake work flawlessly, +# and also cooperate to make a distribution for `make dist' + +EXTRA_DIST = README adduser.c adduser-old.c adduser.sh adduser2.sh \ + atudel groupmems.shar pwdauth.c shadow-anonftp.patch \ + udbachk.tgz diff --git a/contrib/Makefile.in b/contrib/Makefile.in new file mode 100644 index 0000000..bd88236 --- /dev/null +++ b/contrib/Makefile.in @@ -0,0 +1,482 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This is a dummy Makefile.am to get automake work flawlessly, +# and also cooperate to make a distribution for `make dist' +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = contrib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in README +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +ECONF_CPPFLAGS = @ECONF_CPPFLAGS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +GROUP_NAME_MAX_LENGTH = @GROUP_NAME_MAX_LENGTH@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBACL = @LIBACL@ +LIBATTR = @LIBATTR@ +LIBAUDIT = @LIBAUDIT@ +LIBCRACK = @LIBCRACK@ +LIBCRYPT = @LIBCRYPT@ +LIBECONF = @LIBECONF@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMD = @LIBMD@ +LIBOBJS = @LIBOBJS@ +LIBPAM = @LIBPAM@ +LIBS = @LIBS@ +LIBSELINUX = @LIBSELINUX@ +LIBSEMANAGE = @LIBSEMANAGE@ +LIBSKEY = @LIBSKEY@ +LIBTCB = @LIBTCB@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VENDORDIR = @VENDORDIR@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +XMLCATALOG = @XMLCATALOG@ +XML_CATALOG_FILE = @XML_CATALOG_FILE@ +XSLTPROC = @XSLTPROC@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +capcmd = @capcmd@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = README adduser.c adduser-old.c adduser.sh adduser2.sh \ + atudel groupmems.shar pwdauth.c shadow-anonftp.patch \ + udbachk.tgz + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign contrib/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..c4d1bc0 --- /dev/null +++ b/contrib/README @@ -0,0 +1,10 @@ +People keep sending various adduser programs and scripts... They are +all in this directory. I haven't tested them, use at your own risk. +Anyway, the best one I've seen so far is adduser-3.x from Debian. + +atudel is a perl script to remove at jobs owned by the specified user +(atrm in at-2.9 for Linux can't do that). + +udbachk.tgz is a passwd/group/shadow file integrity checker. + +--marekm diff --git a/contrib/adduser-old.c b/contrib/adduser-old.c new file mode 100644 index 0000000..1bf1f22 --- /dev/null +++ b/contrib/adduser-old.c @@ -0,0 +1,300 @@ +/**** +** 03/17/96 +** hacked a bit more, removed unused code, cleaned up for gcc -Wall. +** --marekm +** +** 02/26/96 +** modified to call shadow utils (useradd,chage,passwd) on shadowed +** systems - Cristian Gafton, gafton@sorosis.ro +** +** 6/27/95 +** shadow-adduser 1.4: +** +** now it copies the /etc/skel dir into the person's dir, +** makes the mail folders, changed some defaults and made a 'make +** install' just for the hell of it. +** +** Greg Gallagher +** CIN.Net +** +** 1/28/95 +** shadow-adduser 1.3: +** +** Basically a bug-fix on my additions in 1.2. Thanks to Terry Stewart +** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced. +** It was such a stupid bug that I would have never seen it myself. +** +** Brandon +***** +** 01/27/95 +** +** shadow-adduser 1.2: +** I took the C source from adduser-shadow (credits are below) and made +** it a little more worthwhile. Many small changes... Here's +** the ones I can remember: +** +** Removed support for non-shadowed systems (if you don't have shadow, +** use the original adduser, don't get this shadow version!) +** Added support for the correct /etc/shadow fields (Min days before +** password change, max days before password change, Warning days, +** and how many days from expiry date does the account go invalid) +** The previous version just left all of those fields blank. +** There is still one field left (expiry date for the account, period) +** which I have left blank because I do not use it and didn't want to +** spend any more time on this. I'm sure someone will put it in and +** tack another plethora of credits on here. :) +** Added in the password date field, which should always reflect the last +** date the password was changed, for expiry purposes. "passwd" always +** updates this field, so the adduser program should set it up right +** initially (or a user could keep thier initial password forever ;) +** The number is in days since Jan 1st, 1970. +** +** Have fun with it, and someone please make +** a real version(this is still just a hack) +** for us all to use (and Email it to me???) +** +** Brandon +** photon@usis.com +** +***** +** adduser 1.0: add a new user account (For systems not using shadow) +** With a nice little interface and a will to do all the work for you. +** +** Craig Hagan +** hagan@opine.cs.umass.edu +** +** Modified to really work, look clean, and find unused uid by Chris Cappuccio +** chris@slinky.cs.umass.edu +** +***** +** +** 01/19/95 +** +** FURTHER modifications to enable shadow passwd support (kludged, but +** no more so than the original) by Dan Crowson - dcrowson@mo.net +** +** Search on DAN for all changes... +** +***** +** +** cc -O -o adduser adduser.c +** Use gcc if you have it... (political reasons beyond my control) (chris) +** +** I've gotten this program to work with success under Linux (without +** shadow) and SunOS 4.1.3. I would assume it should work pretty well +** on any system that uses no shadow. (chris) +** +** If you have no crypt() then try +** cc -DNO_CRYPT -O -o adduser adduser.c xfdes.c +** I'm not sure how login operates with no crypt()... I guess +** the same way we're doing it here. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SHELL "/bin/bash" /* because BASH is your friend */ +#define DEFAULT_HOME "/home" +#define USERADD_PATH "/usr/sbin/useradd" +#define CHAGE_PATH "/usr/sbin/chage" +#define PASSWD_PATH "/usr/bin/passwd" +#define DEFAULT_GROUP 100 + +#define DEFAULT_MAX_PASS 60 +#define DEFAULT_WARN_PASS 10 +/* if you use this feature, you will get a lot of complaints from users + who rarely use their accounts :) (something like 3 months would be + more reasonable) --marekm */ +#define DEFAULT_USER_DIE /* 10 */ 0 + +void main() +{ + char foo[32]; + char uname[9],person[32],dir[32],shell[32]; + unsigned int group,min_pass,max_pass,warn_pass,user_die; + /* the group and uid of the new user */ + int bad=0,done=0,correct=0,gets_warning=0; + char cmd[255]; + struct group *grp; + + /* flags, in order: + * bad to see if the username is in /etc/passwd, or if strange stuff has + * been typed if the user might be put in group 0 + * done allows the program to exit when a user has been added + * correct loops until a password is found that isn't in /etc/passwd + * gets_warning allows the fflush to be skipped for the first gets + * so that output is still legible + */ + + /* The real program starts HERE! */ + + if(geteuid()!=0) + { + printf("It seems you don't have access to add a new user. Try\n"); + printf("logging in as root or su root to gain super-user access.\n"); + exit(1); + } + + /* Sanity checks + */ + + if (!(grp=getgrgid(DEFAULT_GROUP))){ + printf("Error: the default group %d does not exist on this system!\n", + DEFAULT_GROUP); + printf("adduser must be recompiled.\n"); + exit(1); + }; + + while(!correct) { /* loop until a "good" uname is chosen */ + while(!done) { + printf("\nLogin to add (^C to quit): "); + if(gets_warning) /* if the warning was already shown */ + fflush(stdout); /* fflush stdout, otherwise set the flag */ + else + gets_warning=1; + + gets(uname); + if(!strlen(uname)) { + printf("Empty input.\n"); + done=0; + continue; + }; + + /* what I saw here before made me think maybe I was running DOS */ + /* might this be a solution? (chris) */ + if (getpwnam(uname) != NULL) { + printf("That name is in use, choose another.\n"); + done=0; + } else + done=1; + }; /* done, we have a valid new user name */ + + /* all set, get the rest of the stuff */ + printf("\nEditing information for new user [%s]\n",uname); + + printf("\nFull Name [%s]: ",uname); + gets(person); + if (!strlen(person)) { + bzero(person,sizeof(person)); + strcpy(person,uname); + }; + + do { + bad=0; + printf("GID [%d]: ",DEFAULT_GROUP); + gets(foo); + if (!strlen(foo)) + group=DEFAULT_GROUP; + else + if (isdigit (*foo)) { + group = atoi(foo); + if (! (grp = getgrgid (group))) { + printf("unknown gid %s\n",foo); + group=DEFAULT_GROUP; + bad=1; + }; + } else + if ((grp = getgrnam (foo))) + group = grp->gr_gid; + else { + printf("unknown group %s\n",foo); + group=DEFAULT_GROUP; + bad=1; + } + if (group==0){ /* You're not allowed to make root group users! */ + printf("Creation of root group users not allowed (must be done by hand)\n"); + group=DEFAULT_GROUP; + bad=1; + }; + } while(bad); + + + fflush(stdin); + + printf("\nIf home dir ends with a / then [%s] will be appended to it\n",uname); + printf("Home Directory [%s/%s]: ",DEFAULT_HOME,uname); + fflush(stdout); + gets(dir); + if (!strlen(dir)) { /* hit return */ + sprintf(dir,"%s/%s",DEFAULT_HOME,uname); + fflush(stdin); + } else + if (dir[strlen(dir)-1]=='/') + sprintf(dir+strlen(dir),"%s",uname); + + printf("\nShell [%s]: ",DEFAULT_SHELL); + fflush(stdout); + gets(shell); + if (!strlen(shell)) + sprintf(shell,"%s",DEFAULT_SHELL); + + printf("\nMin. Password Change Days [0]: "); + gets(foo); + min_pass=atoi(foo); + + printf("Max. Password Change Days [%d]: ",DEFAULT_MAX_PASS); + gets(foo); + if (strlen(foo) > 1) + max_pass = atoi(foo); + else + max_pass = DEFAULT_MAX_PASS; + + printf("Password Warning Days [%d]: ",DEFAULT_WARN_PASS); + gets(foo); + warn_pass = atoi(foo); + if (warn_pass==0) + warn_pass = DEFAULT_WARN_PASS; + + printf("Days after Password Expiry for Account Locking [%d]: ",DEFAULT_USER_DIE); + gets(foo); + user_die = atoi(foo); + if (user_die == 0) + user_die = DEFAULT_USER_DIE; + + printf("\nInformation for new user [%s] [%s]:\n",uname,person); + printf("Home directory: [%s] Shell: [%s]\n",dir,shell); + printf("GID: [%d]\n",group); + printf("MinPass: [%d] MaxPass: [%d] WarnPass: [%d] UserExpire: [%d]\n", + min_pass,max_pass,warn_pass,user_die); + printf("\nIs this correct? [y/N]: "); + fflush(stdout); + gets(foo); + + done=bad=correct=(foo[0]=='y'||foo[0]=='Y'); + + if(bad!=1) + printf("\nUser [%s] not added\n",uname); + } + + bzero(cmd,sizeof(cmd)); + sprintf(cmd,"%s -g %d -d %s -s %s -c \"%s\" -m -k /etc/skel %s", + USERADD_PATH,group,dir,shell,person,uname); + printf("Calling useradd to add new user:\n%s\n",cmd); + if(system(cmd)){ + printf("User add failed!\n"); + exit(errno); + }; + bzero(cmd,sizeof(cmd)); + sprintf(cmd,"%s -m %d -M %d -W %d -I %d %s", CHAGE_PATH, + min_pass,max_pass,warn_pass,user_die,uname); + printf("%s\n",cmd); + if(system(cmd)){ + printf("There was an error setting password expire values\n"); + exit(errno); + }; + bzero(cmd,sizeof(cmd)); + sprintf(cmd,"%s %s",PASSWD_PATH,uname); + system(cmd); + printf("\nDone.\n"); +} + diff --git a/contrib/adduser.c b/contrib/adduser.c new file mode 100644 index 0000000..deebd4c --- /dev/null +++ b/contrib/adduser.c @@ -0,0 +1,502 @@ +/**** +** 04/21/96 +** hacked even more, replaced gets() with something slightly harder to buffer +** overflow. Added support for setting a default quota on new account, with +** edquota -p. Other cleanups for security, I let some users run adduser suid +** root to add new accounts. (overflow checks, clobber environment, valid +** shell checks, restrictions on gid + home dir settings). + +** Added max. username length. Used syslog() a bit for important events. +** Support to immediately expire account with passwd -e. + +** Called it version 2.0! Because I felt like it! + +** -- Chris, chris@ferret.lmh.ox.ac.uk + +** 03/17/96 +** hacked a bit more, removed unused code, cleaned up for gcc -Wall. +** --marekm +** +** 02/26/96 +** modified to call shadow utils (useradd,chage,passwd) on shadowed +** systems - Cristian Gafton, gafton@sorosis.ro +** +** 6/27/95 +** shadow-adduser 1.4: +** +** now it copies the /etc/skel dir into the person's dir, +** makes the mail folders, changed some defaults and made a 'make +** install' just for the hell of it. +** +** Greg Gallagher +** CIN.Net +** +** 1/28/95 +** shadow-adduser 1.3: +** +** Basically a bug-fix on my additions in 1.2. Thanks to Terry Stewart +** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced. +** It was such a stupid bug that I would have never seen it myself. +** +** Brandon +***** +** 01/27/95 +** +** shadow-adduser 1.2: +** I took the C source from adduser-shadow (credits are below) and made +** it a little more worthwhile. Many small changes... Here's +** the ones I can remember: +** +** Removed support for non-shadowed systems (if you don't have shadow, +** use the original adduser, don't get this shadow version!) +** Added support for the correct /etc/shadow fields (Min days before +** password change, max days before password change, Warning days, +** and how many days from expiry date does the account go invalid) +** The previous version just left all of those fields blank. +** There is still one field left (expiry date for the account, period) +** which I have left blank because I do not use it and didn't want to +** spend any more time on this. I'm sure someone will put it in and +** tack another plethora of credits on here. :) +** Added in the password date field, which should always reflect the last +** date the password was changed, for expiry purposes. "passwd" always +** updates this field, so the adduser program should set it up right +** initially (or a user could keep thier initial password forever ;) +** The number is in days since Jan 1st, 1970. +** +** Have fun with it, and someone please make +** a real version(this is still just a hack) +** for us all to use (and Email it to me???) +** +** Brandon +** photon@usis.com +** +***** +** adduser 1.0: add a new user account (For systems not using shadow) +** With a nice little interface and a will to do all the work for you. +** +** Craig Hagan +** hagan@opine.cs.umass.edu +** +** Modified to really work, look clean, and find unused uid by Chris Cappuccio +** chris@slinky.cs.umass.edu +** +***** +** +** 01/19/95 +** +** FURTHER modifications to enable shadow passwd support (kludged, but +** no more so than the original) by Dan Crowson - dcrowson@mo.net +** +** Search on DAN for all changes... +** +***** +** +** cc -O -o adduser adduser.c +** Use gcc if you have it... (political reasons beyond my control) (chris) +** +** I've gotten this program to work with success under Linux (without +** shadow) and SunOS 4.1.3. I would assume it should work pretty well +** on any system that uses no shadow. (chris) +** +** If you have no crypt() then try +** cc -DNO_CRYPT -O -o adduser adduser.c xfdes.c +** I'm not sure how login operates with no crypt()... I guess +** the same way we're doing it here. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IMMEDIATE_CHANGE /* Expire newly created password, must be changed + * immediately upon next login */ +#define HAVE_QUOTAS /* Obvious */ +#define EXPIRE_VALS_SET /* If defined, 'normal' users can't change + * password expiry values (if running suid root) */ + +#define HAVE_GETUSERSHELL /* FIXME: Isn't this defined in config.h too? */ +#define LOGGING /* If we want to log various things to syslog */ +#define MAX_USRNAME 8 /* Longer usernames seem to work on my system.... + * But they're probably a poor idea */ + + +#define DEFAULT_SHELL "/bin/bash" /* because BASH is your friend */ +#define DEFAULT_HOME "/home" +#define USERADD_PATH "/usr/sbin/useradd" +#define CHAGE_PATH "/usr/bin/chage" +#define PASSWD_PATH "/usr/bin/passwd" +#define EDQUOTA_PATH "/usr/sbin/edquota" +#define QUOTA_DEFAULT "defuser" +#define DEFAULT_GROUP 100 + +#define DEFAULT_MIN_PASS 0 +#define DEFAULT_MAX_PASS 100 +#define DEFAULT_WARN_PASS 14 +#define DEFAULT_USER_DIE 366 + +void safeget (char *, int); + +void +main (void) +{ + char foo[32]; + char usrname[32], person[32], dir[32], shell[32]; + unsigned int group, min_pass, max_pass, warn_pass, user_die; + /* the group and uid of the new user */ + int bad = 0, done = 0, correct = 0, olduid; + char cmd[255]; + struct group *grp; + + /* flags, in order: + * bad to see if the username is in /etc/passwd, or if strange stuff has + * been typed if the user might be put in group 0 + * done allows the program to exit when a user has been added + * correct loops until a username is found that isn't in /etc/passwd + */ + + /* The real program starts HERE! */ + + if (geteuid () != 0) + { + printf ("It seems you don't have access to add a new user. Try\n"); + printf ("logging in as root or su root to gain superuser access.\n"); + exit (1); + } + + /* Sanity checks + */ + +#ifdef LOGGING + openlog ("adduser", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); + syslog (LOG_INFO, "invoked by user %s\n", getpwuid (getuid ())->pw_name); +#endif + + if (!(grp = getgrgid (DEFAULT_GROUP))) + { + printf ("Error: the default group %d does not exist on this system!\n", + DEFAULT_GROUP); + printf ("adduser must be recompiled.\n"); +#ifdef LOGGING + syslog (LOG_ERR, "warning: failed. no such default group\n"); + closelog (); +#endif + exit (1); + }; + + while (!correct) + { /* loop until a "good" usrname is chosen */ + while (!done) + { + printf ("\nLogin to add (^C to quit): "); + fflush (stdout); + + safeget (usrname, sizeof (usrname)); + + if (!strlen (usrname)) + { + printf ("Empty input.\n"); + done = 0; + continue; + }; + + /* what I saw here before made me think maybe I was running DOS */ + /* might this be a solution? (chris) */ + if (strlen (usrname) > MAX_USRNAME) + { + printf ("That name is longer than the maximum of %d characters. Choose another.\n", MAX_USRNAME); + done = 0; + } + else if (getpwnam (usrname) != NULL) + { + printf ("That name is in use, choose another.\n"); + done = 0; + } + else if (strchr (usrname, ' ') != NULL) + { + printf ("No spaces in username!!\n"); + done = 0; + } + else + done = 1; + }; /* done, we have a valid new user name */ + + /* all set, get the rest of the stuff */ + printf ("\nEditing information for new user [%s]\n", usrname); + + printf ("\nFull Name [%s]: ", usrname); + fflush (stdout); + safeget (person, sizeof (person)); + if (!strlen (person)) + { + bzero (person, sizeof (person)); + strcpy (person, usrname); + }; + + if (getuid () == 0) + { + do + { + bad = 0; + printf ("GID [%d]: ", DEFAULT_GROUP); + fflush (stdout); + safeget (foo, sizeof (foo)); + if (!strlen (foo)) + group = DEFAULT_GROUP; + else if (isdigit (*foo)) + { + group = atoi (foo); + if (!(grp = getgrgid (group))) + { + printf ("unknown gid %s\n", foo); + group = DEFAULT_GROUP; + bad = 1; + }; + } + else if ((grp = getgrnam (foo))) + group = grp->gr_gid; + else + { + printf ("unknown group %s\n", foo); + group = DEFAULT_GROUP; + bad = 1; + } + if (group == 0) + { /* You're not allowed to make root group users! */ + printf ("Creation of root group users not allowed (must be done by hand)\n"); + group = DEFAULT_GROUP; + bad = 1; + }; + } + while (bad); + } + else + { + printf ("Group will be default of: %d\n", DEFAULT_GROUP); + group = DEFAULT_GROUP; + } + + if (getuid () == 0) + { + printf ("\nIf home dir ends with a / then '%s' will be appended to it\n", usrname); + printf ("Home Directory [%s/%s]: ", DEFAULT_HOME, usrname); + fflush (stdout); + safeget (dir, sizeof (dir)); + if (!strlen (dir)) + { /* hit return */ + sprintf (dir, "%s/%s", DEFAULT_HOME, usrname); + } + else if (dir[strlen (dir) - 1] == '/') + sprintf (dir+strlen(dir), "%s", usrname); + } + else + { + printf ("\nHome directory will be %s/%s\n", DEFAULT_HOME, usrname); + sprintf (dir, "%s/%s", DEFAULT_HOME, usrname); + } + + printf ("\nShell [%s]: ", DEFAULT_SHELL); + fflush (stdout); + safeget (shell, sizeof (shell)); + if (!strlen (shell)) + sprintf (shell, "%s", DEFAULT_SHELL); + else + { + char *sh; + int ok = 0; +#ifdef HAVE_GETUSERSHELL + setusershell (); + while ((sh = getusershell ()) != NULL) + if (!strcmp (shell, sh)) + ok = 1; + endusershell (); +#endif + if (!ok) + { + if (getuid () == 0) + printf ("Warning: root allowed non standard shell\n"); + else + { + printf ("Shell NOT in /etc/shells, DEFAULT used\n"); + sprintf (shell, "%s", DEFAULT_SHELL); + } + } + } + +#ifdef EXPIRE_VALS_SET + if (getuid () == 0) + { +#endif + printf ("\nMin. Password Change Days [%d]: ", DEFAULT_MIN_PASS); + fflush (stdout); + safeget (foo, sizeof (foo)); + if (strlen (foo) > 1) + min_pass = DEFAULT_MIN_PASS; + else + min_pass = atoi (foo); + + printf ("Max. Password Change Days [%d]: ", DEFAULT_MAX_PASS); + fflush (stdout); + safeget (foo, sizeof (foo)); + if (strlen (foo) > 1) + max_pass = atoi (foo); + else + max_pass = DEFAULT_MAX_PASS; + + printf ("Password Warning Days [%d]: ", DEFAULT_WARN_PASS); + fflush (stdout); + safeget (foo, sizeof (foo)); + warn_pass = atoi (foo); + if (warn_pass == 0) + + warn_pass = DEFAULT_WARN_PASS; + + printf ("Days after Password Expiry for Account Locking [%d]: ", DEFAULT_USER_DIE); + fflush (stdout); + safeget (foo, sizeof (foo)); + user_die = atoi (foo); + if (user_die == 0) + user_die = DEFAULT_USER_DIE; + +#ifdef EXPIRE_VALS_SET + } + else + { + printf ("\nSorry, account expiry values are set.\n"); + user_die = DEFAULT_USER_DIE; + warn_pass = DEFAULT_WARN_PASS; + max_pass = DEFAULT_MAX_PASS; + min_pass = DEFAULT_MIN_PASS; + } +#endif + + printf ("\nInformation for new user [%s] [%s]:\n", usrname, person); + printf ("Home directory: [%s] Shell: [%s]\n", dir, shell); + printf ("GID: [%d]\n", group); + printf ("MinPass: [%d] MaxPass: [%d] WarnPass: [%d] UserExpire: [%d]\n", + min_pass, max_pass, warn_pass, user_die); + printf ("\nIs this correct? [y/N]: "); + fflush (stdout); + safeget (foo, sizeof (foo)); + + done = bad = correct = (foo[0] == 'y' || foo[0] == 'Y'); + + if (bad != 1) + printf ("\nUser [%s] not added\n", usrname); + } + + /* Clobber the environment, I run this suid root sometimes to let + * non root privileged accounts add users --chris */ + + *environ = NULL; + + bzero (cmd, sizeof (cmd)); + sprintf (cmd, "%s -g %d -d %s -s %s -c \"%s\" -m -k /etc/skel %s", + USERADD_PATH, group, dir, shell, person, usrname); + printf ("Calling useradd to add new user:\n%s\n", cmd); + if (system (cmd)) + { + printf ("User add failed!\n"); +#ifdef LOGGING + syslog (LOG_ERR, "could not add new user\n"); + closelog (); +#endif + exit (errno); + }; + + olduid = getuid (); /* chage, passwd, edquota etc. require ruid = root + */ + setuid (0); + + bzero (cmd, sizeof (cmd)); + + /* Chage runs suid root. => we need ruid root to run it with + * anything other than chage -l + */ + + sprintf (cmd, "%s -m %d -M %d -W %d -I %d %s", CHAGE_PATH, + min_pass, max_pass, warn_pass, user_die, usrname); + printf ("%s\n", cmd); + if (system (cmd)) + { + printf ("There was an error setting password expire values\n"); +#ifdef LOGGING + syslog (LOG_ERR, "password expire values could not be set\n"); +#endif + }; + + /* I want to add a user completely with one easy command --chris */ + +#ifdef HAVE_QUOTAS + bzero (cmd, sizeof (cmd)); + sprintf (cmd, "%s -p %s -u %s", EDQUOTA_PATH, QUOTA_DEFAULT, usrname); + printf ("%s\n", cmd); + if (system (cmd)) + { + printf ("\nWarning: error setting quota\n"); +#ifdef LOGGING + syslog (LOG_ERR, "warning: account created but NO quotas set!\n"); +#endif /* LOGGING */ + } + else + printf ("\nDefault quota set.\n"); +#endif /* HAVE_QUOTAS */ + + bzero (cmd, sizeof (cmd)); + sprintf (cmd, "%s %s", PASSWD_PATH, usrname); + if (system (cmd)) + { + printf ("\nWarning: error setting password\n"); +#ifdef LOGGING + syslog (LOG_ERR, "warning: password set failed!\n"); +#endif + } +#ifdef IMMEDIATE_CHANGE + bzero (cmd, sizeof (cmd)); + sprintf (cmd, "%s -e %s", PASSWD_PATH, usrname); + if (system (cmd)) + { + printf ("\nWarning: error expiring password\n"); +#ifdef LOGGING + syslog (LOG_ERR, "warning: password expire failed!\n"); +#endif /* LOGGING */ + } +#endif /* IMMEDIATE_CHANGE */ + + setuid (olduid); + +#ifdef LOGGING + closelog (); +#endif + + printf ("\nDone.\n"); +} + +void +safeget (char *buf, int maxlen) +{ + int c, i = 0, bad = 0; + char *bstart = buf; + while ((c = getc (stdin)) != EOF && (c != '\n') && (++i < maxlen)) + { + bad = (!isalnum (c) && (c != '_') && (c != ' ')); + *(buf++) = (char) c; + } + *buf = '\0'; + + if (bad) + { + printf ("\nString contained banned character. Please stick to alphanumerics.\n"); + *bstart = '\0'; + } +} + diff --git a/contrib/adduser.sh b/contrib/adduser.sh new file mode 100755 index 0000000..0efb27a --- /dev/null +++ b/contrib/adduser.sh @@ -0,0 +1,90 @@ +#!/bin/sh +# adduser script for use with shadow passwords and useradd command. +# by Hrvoje Dogan , Dec 1995. + +echo -n "Login name for new user []:" +read LOGIN +if [ -z $LOGIN ] +then echo "Come on, man, you can't leave the login field empty...";exit +fi +echo +echo -n "User id for $LOGIN [ defaults to next available]:" +read ID +GUID="-u $ID" +if [ -z $ID ] +then GUID="" +fi + +echo +echo -n "Initial group for $LOGIN [users]:" +read GID +GGID="-g $GID" +if [ -z $GID ] +then GGID="" +fi + +echo +echo -n "Additional groups for $LOGIN []:" +read AGID +GAGID="-G $AGID" +if [ -z $AGID ] +then GAGID="" +fi + +echo +echo -n "$LOGIN's home directory [/home/$LOGIN]:" +read HME +GHME="-d $HME" +if [ -z $HME ] +then GHME="" +fi + +echo +echo -n "$LOGIN's shell [/bin/bash]:" +read SHL +GSHL="-s $SHL" +if [ -z $SHL ] +then GSHL="" +fi + +echo +echo -n "$LOGIN's account expiry date (MM/DD/YY) []:" +read EXP +GEXP="-e $EXP" +if [ -z $EXP ] +then GEXP="" +fi +echo +echo OK, I'm about to make a new account. Here's what you entered so far: +echo New login name: $LOGIN +if [ -z $GUID ] +then echo New UID: [Next available] +else echo New UID: $UID +fi +if [ -z $GGID ] +then echo Initial group: users +else echo Initial group: $GID +fi +if [ -z $GAGID ] +then echo Additional groups: [none] +else echo Additional groups: $AGID +fi +if [ -z $GHME ] +then echo Home directory: /home/$LOGIN +else echo Home directory: $HME +fi +if [ -z $GSHL ] +then echo Shell: /bin/bash +else echo Shell: $SHL +fi +if [ -z $GEXP ] +then echo Expiry date: [no expiration] +else echo Expiry date: $EXP +fi +echo "This is it... if you want to bail out, you'd better do it now." +read FOO +echo Making new account... +/usr/sbin/useradd $GHME -m $GEXP $GGID $GAGID $GSHL $GUID $LOGIN +/usr/bin/chfn $LOGIN +/usr/bin/passwd $LOGIN +echo "Done..." diff --git a/contrib/adduser2.sh b/contrib/adduser2.sh new file mode 100755 index 0000000..7656d02 --- /dev/null +++ b/contrib/adduser2.sh @@ -0,0 +1,743 @@ +#!/bin/bash +# +# adduser Interactive user adding program. +# +# Copyright (C) 1996 Petri Mattila, Prihateam Networks +# petri@prihateam.fi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# Changes: +# 220496 v0.01 Initial version +# 230496 v0.02 More checks, embolden summary +# 240496 Even more checks +# 250496 Help with ? +# 040596 v0.03 Cleanups +# 050596 v0.04 Bug fixes, expire date checks +# 070596 v0.05 Iso-latin-1 names +# + +## Defaults + +# default groups +def_group="users" +def_other_groups="" + +# default home directory +def_home_dir=/home/users + +# default shell +def_shell=/bin/tcsh + +# Default expiration date (mm/dd/yy) +def_expire="" + +# default dates +def_pwd_min=0 +def_pwd_max=90 +def_pwd_warn=14 +def_pwd_iact=14 + + +# possible UIDs +uid_low=1000 +uid_high=64000 + +# skel directory +skel=/etc/skel + +# default mode for home directory +def_mode=711 + +# Regex, that the login name must meet, only ANSI characters +login_regex='^[0-9a-zA-Z_-]*$' + +# Regex, that the user name must meet +# ANSI version +##name_regex='^[0-9a-zA-Z_-\ ]*$' +# ISO-LATIN-1 version +name_regex='^[0-9a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöùúûüýþÿ_-\ ]*$' + +# set PATH +export PATH="/bin:/sbin:/usr/bin:/usr/sbin" + +# Some special characters +case "$TERM" in + vt*|ansi*|con*|xterm*|linux*) + S='' # start embolden + E='' # end embolden + ;; + *) + S='' + E='' + ;; +esac + + +## Functions + +check_root() { + if test "$EUID" -ne 0 + then + echo "You must be root to run this program." + exit 1 + fi +} + +check_user() { + local usr pwd uid gid name home sh + + cat /etc/passwd | ( + while IFS=":" read usr pwd uid gid name home sh + do + if test "$1" = "${usr}" + then + return 1 + fi + done + return 0 + ) +} + +check_group() { + local read grp pwd gid members + + cat /etc/group | ( + while IFS=":" read grp pwd gid members + do + if test "$1" = "${grp}" + then + return 1 + fi + done + return 0 + ) +} + +check_other_groups() { + local grp check IFS + + check="$1" + IFS="," + + set ${check} + for grp + do + if check_group "${grp}" + then + echo "Group ${grp} does not exist." + return 1 + fi + done + return 0 +} + +check_uid() { + local usr pwd uid gid name home sh + + cat /etc/passwd | ( + while IFS=":" read usr pwd uid gid name home sh + do + if test "$1" = "${uid}" + then + return 1 + fi + done + return 0 + ) +} + +read_yn() { + local ans ynd + + ynd="$1" + + while : + do + read ans + case "${ans}" in + "") return ${ynd} ;; + [nN]) return 1 ;; + [yY]) return 0 ;; + *) echo -n "Y or N, please ? " ;; + esac + done +} + +read_login() { + echo + while : + do + echo -n "Login: ${def_login:+[${def_login}] }" + read login + + if test "${login}" = '?' + then + less /etc/passwd + echo + continue + fi + + if test -z "${login}" -a -n "${def_login}" + then + login="${def_login}" + echo "Using ${login}" + return + fi + + if test "${#login}" -gt 8 + then + echo "Login must be at most 8 characters long" + continue + fi + + if test "${#login}" -lt 2 + then + echo "Login must be at least 2 characters long" + continue + fi + + if ! expr "${login}" : "${login_regex}" &> /dev/null + then + echo "Please use letters, numbers and special characters _-,." + continue + fi + + if ! check_user "${login}" + then + echo "Username ${login} is already in use" + continue + fi + + def_login="${login}" + return + done +} + +read_name () { + echo + while : + do + echo -n "Real name: ${def_name:+[${def_name}] }" + read name + + if test "${name}" = '?' + then + less /etc/passwd + echo + continue + fi + + if test -z "${name}" -a -n "${def_name}" + then + name="${def_name}" + echo "Using ${name}" + fi + + if test "${#name}" -gt 32 + then + echo "Name should be at most 32 characters long" + continue + fi + + if ! expr "${name}" : "${name_regex}" &> /dev/null + then + echo "Please use letters, numbers, spaces and special characters ,._-" + continue + fi + + def_name="${name}" + return + done +} + +read_home() { + local x + + echo + while : + do + echo -n "Home Directory: [${def_home_dir}/${login}] " + read home + + if test -z "${home}" + then + home="${def_home_dir}/${login}" + echo "Using ${home}" + fi + + if ! expr "${home}" : '^[0-9a-zA-Z,._-\/]*$' &> /dev/null + then + echo "Please use letters, numbers, spaces and special characters ,._-/" + continue + fi + + x="$(basename ${home})" + if test "${x}" != "${login}" + then + echo "Warning: you are about to use different login name and home directory." + fi + + x="$(dirname ${home})" + if ! test -d "${x}" + then + echo "Directory ${x} does not exist." + echo "If you still want to use it, please make it manually." + continue + fi + + def_home_dir="${x}" + return + done +} + +read_shell () { + local x + + echo + while : + do + echo -n "Shell: [${def_shell}] " + read shell + + if test -z "${shell}" + then + shell="${def_shell}" + echo "Using ${shell}" + fi + + for x in $(cat /etc/shells) + do + if test "${x}" = "${shell}" + then + def_shell="${shell}" + return + fi + done + + echo "Possible shells are:" + cat /etc/shells + done +} + +read_group () { + echo + while : + do + echo -n "Group: [${def_group}] " + read group + + if test -z "${group}" + then + group="${def_group}" + echo "Using ${group}" + fi + + if test "${group}" = '?' + then + less /etc/group + echo + continue + fi + + if check_group "${group}" + then + echo "Group ${group} does not exist." + continue + fi + + def_group="${group}" + return + done +} + +read_other_groups () { + echo + while : + do + echo -n "Other groups: [${def_og:-none}] " + read other_groups + + if test "${other_groups}" = '?' + then + less /etc/group + echo + continue + fi + + if test -z "${other_groups}" + then + if test -n "${def_og}" + then + other_groups="${def_og}" + echo "Using ${other_groups}" + else + echo "No other groups" + return + fi + fi + + + if ! check_other_groups "${other_groups}" + then + continue + fi + + def_og="${other_groups}" + return + done +} + +read_uid () { + echo + while : + do + echo -n "uid: [first free] " + read uid + + if test -z "${uid}" + then + echo "Using first free UID." + return + fi + + if test "${uid}" = '?' + then + less /etc/passwd + echo + continue + fi + + if ! expr "${uid}" : '^[0-9]+$' &> /dev/null + then + echo "Please use numbers only." + continue + fi + if test "${uid}" -lt "${uid_low}" + then + echo "UID must be greater than ${uid_low}" + continue + fi + if test "${uid}" -gt "${uid_high}" + then + echo "UID must be smaller than ${uid_high}" + continue + fi + if ! check_uid "${uid}" + then + echo "UID ${uid} is already in use" + continue + fi + + return + done +} + +read_max_valid_days() { + echo + while : + do + echo -en "Maximum days between password changes: [${def_pwd_max}] " + read max_days + + if test -z "${max_days}" + then + max_days="${def_pwd_max}" + echo "Using ${max_days}" + return + fi + + if ! expr "${max_days}" : '^[0-9]+$' &> /dev/null + then + echo "Please use numbers only." + continue + fi + if test "${max_days}" -lt 7 + then + echo "Warning: you are using a value shorter than a week." + fi + + def_pwd_max="${max_days}" + return + done +} + +read_min_valid_days() { + echo + while : + do + echo -en "Minimum days between password changes: [${def_pwd_min}] " + read min_days + + if test -z "${min_days}" + then + min_days="${def_pwd_min}" + echo "Using ${min_days}" + return + fi + + if ! expr "${min_days}" : '^[0-9]+$' &> /dev/null + then + echo "Please use numbers only." + continue + fi + if test "${min_days}" -gt 7 + then + echo "Warning: you are using a value longer than a week." + fi + + def_pwd_min="${min_days}" + return + done +} + +read_warning_days() { + echo + while : + do + echo -en "Number of warning days before password expires: [${def_pwd_warn}] " + read warn_days + + if test -z "${warn_days}" + then + warn_days="${def_pwd_warn}" + echo "Using ${warn_days}" + fi + + if ! expr "${warn_days}" : '^[0-9]+$' &> /dev/null + then + echo "Please use numbers only." + continue + fi + if test "${warn_days}" -gt 14 + then + echo "Warning: you are using a value longer than two week." + fi + + def_pwd_warn="${warn_days}" + return + done +} + + +read_inactive_days() { + echo + while : + do + echo -en "Number of usable days after expiration: [${def_pwd_iact}] " + read iact_days + + if test -z "${iact_days}" + then + iact_days="${def_pwd_iact}" + echo "Using ${iact_days}" + return + fi + if ! expr "${iact_days}" : '^[0-9]+$' &> /dev/null + then + echo "Please use numbers only." + continue + fi + if test "${iact_days}" -gt 14 + then + echo "Warning: you are using a value that is more than two weeks." + fi + + def_pwd_iact="${iact_days}" + return + done +} + +read_expire_date() { + local ans + + echo + while : + do + echo -en "Expire date of this account (mm/dd/yy): [${def_expire:-never}] " + read ans + + if test -z "${ans}" + then + if test -z "${def_expire}" + then + ans="never" + else + ans="${def_expire}" + echo "Using ${def_expire}" + fi + fi + + if test "${ans}" = "never" + then + echo "Account will never expire." + def_expire="" + expire="" + return + fi + + if ! expr "${ans}" : '^[0-9][0-9]/[0-9][0-9]/[0-9][0-9]$' &> /dev/null + then + echo "Please use format mm/dd/yy" + continue + fi + + if ! expire_date="$(date -d ${ans} '+%A, %B %d %Y')" + then + continue + fi + + def_expire="${expire}" + return + done +} + +read_passwd_yn() { + echo -en "\nDo you want to set password [Y/n] ? " + if read_yn 0 + then + set_pwd="YES" + else + set_pwd="" + fi +} + + +print_values() { + +clear +cat << EOM + +Login: ${S}${login}${E} +Group: ${S}${group}${E} +Other groups: ${S}${other_groups:-[none]}${E} + +Real Name: ${S}${name}${E} + +uid: ${S}${uid:-[first free]}${E} +home: ${S}${home}${E} +shell: ${S}${shell}${E} + +Account expiration date: ${S}${expire_date:-never}${E} +Minimum days between password changes: ${S}${min_days}${E} +Maximum days between password changes: ${S}${max_days}${E} +Number of usable days after expiration: ${S}${iact_days}${E} +Number of warning days before expiration: ${S}${warn_days}${E} + +${S}${set_pwd:+Set password for this account.}${E} + +EOM +} + +set_user() { + if ! useradd \ + -c "${name}" \ + -d "${home}" \ + -g "${group}" \ + -s "${shell}" \ + ${expire:+-e ${expire}} \ + ${uid:+-u ${uid}} \ + ${other_groups:+-G ${other_groups}} \ + ${login} + then + echo "Error ($?) in useradd...exiting..." + exit 1 + fi +} + +set_aging() { + if ! passwd \ + -x ${max_days} \ + -n ${min_days} \ + -w ${warn_days} \ + -i ${iact_days} \ + ${login} + then + echo "Error ($?) in setting password aging...exiting..." + exit 1 + fi +} + +set_password() { + if test -n "${set_pwd}" + then + echo + passwd ${login} + echo + fi +} + +set_system() { + if test -d "${home}" + then + echo "Directory ${home} already exists." + echo "Skeleton files not copied." + return + fi + + echo -n "Copying skeleton files..." + ( + mkdir ${home} + cd ${skel} && cp -af . ${home} + chmod ${def_mode} ${home} + chown -R ${login}:${group} ${home} + ) + echo "done." + + ## Add your own stuff here: + echo -n "Setting up other files..." + ( + mailbox="/var/spool/mail/${login}" + touch ${mailbox} + chown "${login}:mail" ${mailbox} + chmod 600 ${mailbox} + ) + echo "done." +} + + +read_values() { + clear + echo -e "\nPlease answer the following questions about the new user to be added." + + while : + do + read_login + read_name + read_group + read_other_groups + read_home + read_shell + read_uid + read_expire_date + read_max_valid_days + read_min_valid_days + read_warning_days + read_inactive_days + read_passwd_yn + + print_values + + echo -n "Is this correct [N/y] ? " + read_yn 1 && return + done +} + + +main() { + check_root + read_values + set_user + set_aging + set_system + set_password +} + + +## Run it 8-) +main + +# End. diff --git a/contrib/atudel b/contrib/atudel new file mode 100755 index 0000000..0ca8783 --- /dev/null +++ b/contrib/atudel @@ -0,0 +1,85 @@ +#!/usr/bin/perl +# +# Copyright (c) 1996 Brian R. Gaeke +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Brian R. Gaeke. +# 4. The name of the author, Brian R. Gaeke, may not be used to endorse +# or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY BRIAN R. GAEKE ``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 BRIAN R. GAEKE 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. +# +# Additionally: +# +# This software is provided without support and without any obligation +# on the part of Brian R. Gaeke to assist in its use, correction, +# modification or enhancement. +# +####################################################################### +# +# this is atudel, version 2, by Brian R. Gaeke +# + +require "getopts.pl"; +&Getopts('v'); +$username = shift(@ARGV); +&usage unless $username; + +sub usage +{ + print STDERR "atudel - remove all at jobs owned by a user\n"; + print STDERR "usage: $0 [-v] username\n"; + exit(1); +} + +# odd. unless getpwnam($uname) doesn't seem to work for $uname eq "root" on +# my linux system. but this does. +die "user $username does not exist; stopping" + unless defined(getpwnam($username)); + +print "searching for at jobs owned by user $username ..." if $opt_v; + +chdir "/var/spool/atjobs" || + die "can't chdir to /var/spool/atjobs: $!\nstopping"; +opendir(DIR,".") || die "can't opendir(/var/spool/atjobs): $!\nstopping"; +@files = grep(!/^\./,grep(-f,readdir(DIR))); +closedir DIR; + +foreach $x (@files) +{ + $owner = (getpwuid((stat($x))[4]))[0]; + push(@nuke_bait,$x) if $owner eq $username; +} + +if (@nuke_bait) +{ + print "removed jobIDs: @{nuke_bait}.\n" if $opt_v; + unlink @nuke_bait; +} +elsif ($opt_v) +{ + print "\n"; +} + +exit 0; diff --git a/contrib/groupmems.shar b/contrib/groupmems.shar new file mode 100644 index 0000000..8472d93 --- /dev/null +++ b/contrib/groupmems.shar @@ -0,0 +1,546 @@ +#!/bin/sh +# This is a shell archive (produced by GNU sharutils 4.2.1). +# To extract the files from this archive, save it to some FILE, remove +# everything before the `!/bin/sh' line above, then type `sh FILE'. +# +# Made on 2000-05-25 14:41 CDT by . +# Source directory was `/home/gk4/src/groupmem'. +# +# Existing files will *not* be overwritten unless `-c' is specified. +# +# This shar contains: +# length mode name +# ------ ---------- ------------------------------------------ +# 1960 -rw-r--r-- Makefile +# 6348 -rw-r--r-- groupmems.c +# 3372 -rw------- groupmems.8 +# +save_IFS="${IFS}" +IFS="${IFS}:" +gettext_dir=FAILED +locale_dir=FAILED +first_param="$1" +for dir in $PATH +do + if test "$gettext_dir" = FAILED && test -f $dir/gettext \ + && ($dir/gettext --version >/dev/null 2>&1) + then + set `$dir/gettext --version 2>&1` + if test "$3" = GNU + then + gettext_dir=$dir + fi + fi + if test "$locale_dir" = FAILED && test -f $dir/shar \ + && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) + then + locale_dir=`$dir/shar --print-text-domain-dir` + fi +done +IFS="$save_IFS" +if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED +then + echo=echo +else + TEXTDOMAINDIR=$locale_dir + export TEXTDOMAINDIR + TEXTDOMAIN=sharutils + export TEXTDOMAIN + echo="$gettext_dir/gettext -s" +fi +if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then + shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"' +elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then + shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"' +elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then + shar_touch='touch -am $3$4$5$6$2 "$8"' +else + shar_touch=: + echo + $echo 'WARNING: not restoring timestamps. Consider getting and' + $echo "installing GNU \`touch', distributed in GNU File Utilities..." + echo +fi +rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch +# +if mkdir _sh10937; then + $echo 'x -' 'creating lock directory' +else + $echo 'failed to create lock directory' + exit 1 +fi +# ============= Makefile ============== +if test -f 'Makefile' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'Makefile' '(file already exists)' +else + $echo 'x -' extracting 'Makefile' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'Makefile' && +/* +# Copyright 2000, International Business Machines, Inc. +# All rights reserved. +# +# original author: George Kraft IV, gk4@us.ibm.com +# +# 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. Neither the name of International Business Machines, Inc., nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES, INC. AND +# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# INTERNATIONAL BUSINESS MACHINES, INC. OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +X +all: groupmems +X +groupmems: groupmems.c +X cc -g -o groupmems groupmems.c -L. -lshadow +X +install: groupmems +X -/usr/sbin/groupadd groups +X install -o root -g groups -m 4770 groupmems /usr/bin +X +install.man: groupmems.8 +X install -o root -g root -m 644 groupmems.8 /usr/man/man8 +X +SHAR_EOF + (set 20 00 05 25 14 40 28 'Makefile'; eval "$shar_touch") && + chmod 0644 'Makefile' || + $echo 'restore of' 'Makefile' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'Makefile:' 'MD5 check failed' +b46cf7ef8d59149093c011ced3f3103c Makefile +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Makefile'`" + test 1960 -eq "$shar_count" || + $echo 'Makefile:' 'original size' '1960,' 'current size' "$shar_count!" + fi +fi +# ============= groupmems.c ============== +if test -f 'groupmems.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'groupmems.c' '(file already exists)' +else + $echo 'x -' extracting 'groupmems.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'groupmems.c' && +/* +X * Copyright 2000, International Business Machines, Inc. +X * All rights reserved. +X * +X * original author: George Kraft IV, gk4@us.ibm.com +X * +X * Redistribution and use in source and binary forms, with or without +X * modification, are permitted provided that the following conditions +X * are met: +X * +X * 1. Redistributions of source code must retain the above copyright +X * notice, this list of conditions and the following disclaimer. +X * 2. Redistributions in binary form must reproduce the above copyright +X * notice, this list of conditions and the following disclaimer in the +X * documentation and/or other materials provided with the distribution. +X * 3. Neither the name of International Business Machines, Inc., nor the +X * names of its contributors may be used to endorse or promote products +X * derived from this software without specific prior written permission. +X * +X * THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES, INC. AND +X * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +X * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +X * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +X * INTERNATIONAL BUSINESS MACHINES, INC. OR CONTRIBUTORS BE LIABLE +X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +X * SUCH DAMAGE. +X */ +/* +** +** Utility "groupmem" adds and deletes members from a user's group. +** +** Setup (as "root"): +** +** groupadd -r groups +** chmod 2770 groupmems +** chown root.groups groupmems +** groupmems -g groups -a gk4 +** +** Usage (as "gk4"): +** +** groupmems -a olive +** groupmems -a jordan +** groupmems -a meghan +** groupmems -a morgan +** groupmems -a jake +** groupmems -l +** groupmems -d jake +** groupmems -l +*/ +X +#include +#include +#include +#include +#include +#include +#include "defines.h" +#include "groupio.h" +X +/* Exit Status Values */ +X +#define EXIT_SUCCESS 0 /* success */ +#define EXIT_USAGE 1 /* invalid command syntax */ +#define EXIT_GROUP_FILE 2 /* group file access problems */ +#define EXIT_NOT_ROOT 3 /* not superuser */ +#define EXIT_NOT_EROOT 4 /* not effective superuser */ +#define EXIT_NOT_PRIMARY 5 /* not primary owner of group */ +#define EXIT_NOT_MEMBER 6 /* member of group does not exist */ +#define EXIT_MEMBER_EXISTS 7 /* member of group already exists */ +X +#define TRUE 1 +#define FALSE 0 +X +/* Globals */ +X +extern int optind; +extern char *optarg; +static char *adduser = NULL; +static char *deluser = NULL; +static char *thisgroup = NULL; +static int purge = FALSE; +static int list = FALSE; +static int exclusive = 0; +X +static int isroot(void) { +X return getuid() ? FALSE : TRUE; +} +X +static int isgroup(void) { +X gid_t g = getgid(); +X struct group *grp = getgrgid(g); +X +X return TRUE; +} +X +static char *whoami(void) { +X struct group *grp = getgrgid(getgid()); +X struct passwd *usr = getpwuid(getuid()); +X +X if (0 == strcmp(usr->pw_name, grp->gr_name)) { +X return (char *)strdup(usr->pw_name); +X } else { +X return NULL; +X } +} +X +static void +addtogroup(char *user, char **members) { +X int i; +X char **pmembers; +X +X for (i = 0; NULL != members[i]; i++ ) { +X if (0 == strcmp(user, members[i])) { +X fprintf(stderr, "Member already exists\n"); +X exit(EXIT_MEMBER_EXISTS); +X } +X } +X +X if (0 == i) { +X pmembers = (char **)calloc(2, sizeof(char *)); +X } else { +X pmembers = (char **)realloc(members, sizeof(char *)*(i+1)); +X } +X +X *members = *pmembers; +X members[i] = user; +X members[i+1] = NULL; +} +X +static void +rmfromgroup(char *user, char **members) { +X int i; +X int found = FALSE; +X +X i = 0; +X while (!found && NULL != members[i]) { +X if (0 == strcmp(user, members[i])) { +X found = TRUE; +X } else { +X i++; +X } +X } +X +X while (found && NULL != members[i]) { +X members[i] = members[++i]; +X } +X +X if (!found) { +X fprintf(stderr, "Member to remove could not be found\n"); +X exit(EXIT_NOT_MEMBER); +X } +} +X +static void +nomembers(char **members) { +X int i; +X +X for (i = 0; NULL != members[i]; i++ ) { +X members[i] = NULL; +X } +} +X +static void +members(char **members) { +X int i; +X +X for (i = 0; NULL != members[i]; i++ ) { +X printf("%s ", members[i]); +X +X if (NULL == members[i+1]) { +X printf("\n"); +X } else { +X printf(" "); +X } +X } +} +X +static void usage(void) { +X fprintf(stderr, "usage: groupmems -a username | -d username | -D | -l [-g groupname]\n"); +X exit(EXIT_USAGE); +} +X +main(int argc, char **argv) { +X int arg, i; +X char *name; +X struct group *grp; +X +X while ((arg = getopt(argc, argv, "a:d:g:Dl")) != EOF) { +X switch (arg) { +X case 'a': +X adduser = strdup(optarg); +X ++exclusive; +X break; +X case 'd': +X deluser = strdup(optarg); +X ++exclusive; +X break; +X case 'g': +X thisgroup = strdup(optarg); +X break; +X case 'D': +X purge = TRUE; +X ++exclusive; +X break; +X case 'l': +X list = TRUE; +X ++exclusive; +X break; +X default: +X usage(); +X } +X } +X +X if (exclusive > 1 || optind < argc) { +X usage(); +X } +X +X if (!isroot() && NULL != thisgroup) { +X fprintf(stderr, "Only root can add members to different groups\n"); +X exit(EXIT_NOT_ROOT); +X } else if (isroot() && NULL != thisgroup) { +X name = thisgroup; +X } else if (!isgroup()) { +X fprintf(stderr, "Group access is required\n"); +X exit(EXIT_NOT_EROOT); +X } else if (NULL == (name = whoami())) { +X fprintf(stderr, "Not primary owner of current group\n"); +X exit(EXIT_NOT_PRIMARY); +X } +X +X if (!gr_lock()) { +X fprintf(stderr, "Unable to lock group file\n"); +X exit(EXIT_GROUP_FILE); +X } +X +X if (!gr_open(O_RDWR)) { +X fprintf(stderr, "Unable to open group file\n"); +X exit(EXIT_GROUP_FILE); +X } +X +X grp = (struct group *)gr_locate(name); +X +X if (NULL != adduser) { +X addtogroup(adduser, grp->gr_mem); +X gr_update(grp); +X } else if (NULL != deluser) { +X rmfromgroup(deluser, grp->gr_mem); +X gr_update(grp); +X } else if (purge) { +X nomembers(grp->gr_mem); +X gr_update(grp); +X } else if (list) { +X members(grp->gr_mem); +X } +X +X if (!gr_close()) { +X fprintf(stderr, "Cannot close group file\n"); +X exit(EXIT_GROUP_FILE); +X } +X +X gr_unlock(); +X +X exit(EXIT_SUCCESS); +} +X +/* EOF */ +SHAR_EOF + (set 20 00 05 25 14 36 38 'groupmems.c'; eval "$shar_touch") && + chmod 0644 'groupmems.c' || + $echo 'restore of' 'groupmems.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'groupmems.c:' 'MD5 check failed' +f0dd68f8d762d89d24d3ce1f4141f981 groupmems.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'groupmems.c'`" + test 6348 -eq "$shar_count" || + $echo 'groupmems.c:' 'original size' '6348,' 'current size' "$shar_count!" + fi +fi +# ============= groupmems.8 ============== +if test -f 'groupmems.8' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'groupmems.8' '(file already exists)' +else + $echo 'x -' extracting 'groupmems.8' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'groupmems.8' && +X.\" +X.\" Copyright 2000, International Business Machines, Inc. +X.\" All rights reserved. +X.\" +X.\" original author: George Kraft IV, gk4@us.ibm.com +X.\" +X.\" Redistribution and use in source and binary forms, with or without +X.\" modification, are permitted provided that the following conditions +X.\" are met: +X.\" +X.\" 1. Redistributions of source code must retain the above copyright +X.\" notice, this list of conditions and the following disclaimer. +X.\" 2. Redistributions in binary form must reproduce the above copyright +X.\" notice, this list of conditions and the following disclaimer in the +X.\" documentation and/or other materials provided with the distribution. +X.\" 3. Neither the name of International Business Machines, Inc., nor the +X.\" names of its contributors may be used to endorse or promote products +X.\" derived from this software without specific prior written permission. +X.\" +X.\" THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES, INC. AND +X.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +X.\" BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +X.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +X.\" INTERNATIONAL BUSINESS MACHINES, INC. OR CONTRIBUTORS BE LIABLE +X.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +X.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +X.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +X.\" SUCH DAMAGE. +X.\" +X.\" $Id$ +X.\" +X.TH GROUPMEMS 8 +X.SH NAME +groupmems \- Administer members of a user's primary group +X.SH SYNOPSIS +X.B groupmems +\fB-a\fI user_name \fR | +\fB-d\fI user_name \fR | +\fB-l\fR | +\fB-D\fR | +[\fB-g\fI group_name \fR] +X.SH DESCRIPTION +The \fBgroupmems\fR utility allows a user to administer their own +group membership list without the requirement of superuser privileges. +The \fBgroupmems\fR utility is for systems that configure its users to +be in their own name sake primary group (i.e., guest / guest). +X.P +Only the superuser, as administrator, can use \fBgroupmems\fR to alter +the memberships of other groups. +X.IP "\fB-a \fIuser_name\fR" +Add a new user to the group membership list. +X.IP "\fB-d \fIuser_name\fR" +Delete a user from the group membership list. +X.IP "\fB-l\fR" +List the group membership list. +X.IP "\fB-D\fR" +Delete all users from the group membership list. +X.IP "\fB-g \fIgroup_name\fR" +The superuser can specify which group membership list to modify. +X.SH SETUP +The \fBgroupmems\fR executable should be in mode \fB2770\fR as user \fBroot\fR +and in group \fBgroups\fR. The system administrator can add users to +group groups to allow or disallow them using the \fBgroupmems\fR utility +to manager their own group membership list. +X.P +X $ groupadd -r groups +X.br +X $ chmod 2770 groupmems +X.br +X $ chown root.groups groupmems +X.br +X $ groupmems -g groups -a gk4 +X.SH FILES +/etc/group +X.br +/etc/gshadow +X.SH SEE ALSO +X.BR chfn (1), +X.BR chsh (1), +X.BR useradd (8), +X.BR userdel (8), +X.BR usermod (8), +X.BR passwd (1), +X.BR groupadd (8), +X.BR groupdel (8) +X.SH AUTHOR +George Kraft IV (gk4@us.ibm.com) +X.\" EOF +SHAR_EOF + (set 20 00 05 25 14 38 23 'groupmems.8'; eval "$shar_touch") && + chmod 0600 'groupmems.8' || + $echo 'restore of' 'groupmems.8' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'groupmems.8:' 'MD5 check failed' +181e6cd3a3c9d3df320197fa2cde2b4a groupmems.8 +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'groupmems.8'`" + test 3372 -eq "$shar_count" || + $echo 'groupmems.8:' 'original size' '3372,' 'current size' "$shar_count!" + fi +fi +rm -fr _sh10937 +exit 0 diff --git a/contrib/pwdauth.c b/contrib/pwdauth.c new file mode 100644 index 0000000..ca15495 --- /dev/null +++ b/contrib/pwdauth.c @@ -0,0 +1,308 @@ +/* + * pwdauth.c - program to verify a given username/password pair. + * + * Run it with username in argv[1] (may be omitted - default is the + * current user), and send it the password over a pipe on stdin. + * Exit status: 0 - correct password, 1 - wrong password, >1 - other + * errors. For use with shadow passwords, this program should be + * installed setuid root. + * + * This can be used, for example, by xlock - you don't have to install + * this large and complex (== possibly insecure) program setuid root, + * just modify it to run this simple program to do the authentication. + * + * Recent versions (xlockmore-3.9) are cleaner, and drop privileges as + * soon as possible after getting the user's encrypted password. + * Using this program probably doesn't make it more secure, and has one + * disadvantage: since we don't get the encrypted user's password at + * startup (but at the time the user is authenticated), it is not clear + * how we should handle errors (like getpwnam() returning NULL). + * - fail the authentication? Problem: no way to unlock (other than kill + * the process from somewhere else) if the NIS server stops responding. + * - succeed and unlock? Problem: it's too easy to unlock by unplugging + * the box from the network and waiting until NIS times out... + * + * This program is Copyright (C) 1996 Marek Michalkiewicz + * . + * + * It may be used and distributed freely for any purposes. There is no + * warranty - use at your own risk. I am not liable for any damages etc. + * If you improve it, please send me your changes. + */ + +static char rcsid[] = "$Id$"; + +/* + * Define USE_SYSLOG to use syslog() to log successful and failed + * authentication. This should be safe even if your system has + * the infamous syslog buffer overrun security problem... + */ +#define USE_SYSLOG + +/* + * Define HAVE_GETSPNAM to get shadow passwords using getspnam(). + * Some systems don't have getspnam(), but getpwnam() returns + * encrypted passwords only if running as root. + * + * According to the xlock source (not tested, except Linux) - + * define: Linux, Solaris 2.x, SVR4, ... + * undef: HP-UX with Secured Passwords, FreeBSD, NetBSD, QNX. + * Known not supported (yet): Ultrix, OSF/1, SCO. + */ +#define HAVE_GETSPNAM + +/* + * Define HAVE_PW_ENCRYPT to use pw_encrypt() instead of crypt(). + * pw_encrypt() is like the standard crypt(), except that it may + * support better password hashing algorithms. + * + * Define if linking with libshadow.a from the shadow password + * suite (Linux, SunOS 4.x?). + */ +#undef HAVE_PW_ENCRYPT + +/* + * Define HAVE_AUTH_METHODS to support the shadow suite specific + * extension: the encrypted password field contains a list of + * administrator defined authentication methods, separated by + * semicolons. This program only supports the standard password + * authentication method (a string that doesn't start with '@'). + */ +#undef HAVE_AUTH_METHODS + +/* + * FAIL_DELAY - number of seconds to sleep before exiting if the + * password was wrong, to slow down password guessing attempts. + */ +#define FAIL_DELAY 2 + +/* No user-serviceable parts below :-). */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_SYSLOG +#include +#ifndef LOG_AUTHPRIV +#define LOG_AUTHPRIV LOG_AUTH +#endif +#endif + +#ifdef HAVE_GETSPNAM +#include +#endif + +#ifdef HAVE_PW_ENCRYPT +extern char *pw_encrypt(); +#define crypt pw_encrypt +#endif + +/* + * Read the password (one line) from fp. We don't turn off echo + * because we expect input from a pipe. + */ +static char * +get_line(fp) + FILE *fp; +{ + static char buf[128]; + char *cp; + int ch; + + cp = buf; + while ((ch = getc(fp)) != EOF && ch != '\0' && ch != '\n') { + if (cp >= buf + sizeof buf - 1) + break; + *cp++ = ch; + } + *cp = '\0'; + return buf; +} + +/* + * Get the password file entry for the current user. If the name + * returned by getlogin() is correct (matches the current real uid), + * return the entry for that user. Otherwise, return the entry (if + * any) matching the current real uid. Return NULL on failure. + */ +static struct passwd * +get_my_pwent() +{ + uid_t uid = getuid(); + char *name = getlogin(); + + if (name && *name) { + struct passwd *pw = getpwnam(name); + + if (pw && pw->pw_uid == uid) + return pw; + } + return getpwuid(uid); +} + +/* + * Verify the password. The system-dependent shadow support is here. + */ +static int +password_auth_ok(pw, pass) + const struct passwd *pw; + const char *pass; +{ + int result; + char *cp; +#ifdef HAVE_AUTH_METHODS + char *buf; +#endif +#ifdef HAVE_GETSPNAM + struct spwd *sp; +#endif + + if (pw) { +#ifdef HAVE_GETSPNAM + sp = getspnam(pw->pw_name); + if (sp) + cp = sp->sp_pwdp; + else +#endif + cp = pw->pw_passwd; + } else + cp = "xx"; + +#ifdef HAVE_AUTH_METHODS + buf = strdup(cp); /* will be modified by strtok() */ + if (!buf) { + fprintf(stderr, "Out of memory.\n"); + exit(13); + } + cp = strtok(buf, ";"); + while (cp && *cp == '@') + cp = strtok(NULL, ";"); + + /* fail if no password authentication for this user */ + if (!cp) + cp = "xx"; +#endif + + if (*pass || *cp) + result = (strcmp(crypt(pass, cp), cp) == 0); + else + result = 1; /* user with no password */ + +#ifdef HAVE_AUTH_METHODS + free(buf); +#endif + return result; +} + +/* + * Main program. + */ +int +main(argc, argv) + int argc; + char **argv; +{ + struct passwd *pw; + char *pass, *name; + char myname[32]; + +#ifdef USE_SYSLOG + openlog("pwdauth", LOG_PID | LOG_CONS, LOG_AUTHPRIV); +#endif + pw = get_my_pwent(); + if (!pw) { +#ifdef USE_SYSLOG + syslog(LOG_ERR, "can't get login name for uid %d.\n", + (int) getuid()); +#endif + fprintf(stderr, "Who are you?\n"); + exit(2); + } + strncpy(myname, pw->pw_name, sizeof myname - 1); + myname[sizeof myname - 1] = '\0'; + name = myname; + + if (argc > 1) { + name = argv[1]; + pw = getpwnam(name); + } + + pass = get_line(stdin); + if (password_auth_ok(pw, pass)) { +#ifdef USE_SYSLOG + syslog(pw->pw_uid ? LOG_INFO : LOG_NOTICE, + "user `%s' entered correct password for `%.32s'.\n", + myname, name); +#endif + exit(0); + } +#ifdef USE_SYSLOG + /* be careful not to overrun the syslog buffer */ + syslog((!pw || pw->pw_uid) ? LOG_NOTICE : LOG_WARNING, + "user `%s' entered incorrect password for `%.32s'.\n", + myname, name); +#endif +#ifdef FAIL_DELAY + sleep(FAIL_DELAY); +#endif + fprintf(stderr, "Wrong password.\n"); + exit(1); +} + +#if 0 +/* + * You can use code similar to the following to run this program. + * Return values: >=0 - program exit status (use the + * macros to get the exit code, it is shifted left by 8 bits), + * -1 - check errno. + */ +int +verify_password(const char *username, const char *password) +{ + int pipe_fd[2]; + int pid, wpid, status; + + if (pipe(pipe_fd)) + return -1; + + if ((pid = fork()) == 0) { + char *arg[3]; + char *env[1]; + + /* child */ + close(pipe_fd[1]); + if (pipe_fd[0] != 0) { + if (dup2(pipe_fd[0], 0) != 0) + _exit(127); + close(pipe_fd[0]); + } + arg[0] = "/usr/bin/pwdauth"; + arg[1] = username; + arg[2] = NULL; + env[0] = NULL; + execve(arg[0], arg, env); + _exit(127); + } else if (pid == -1) { + /* error */ + close(pipe_fd[0]); + close(pipe_fd[1]); + return -1; + } + /* parent */ + close(pipe_fd[0]); + write(pipe_fd[1], password, strlen(password)); + write(pipe_fd[1], "\n", 1); + close(pipe_fd[1]); + + while ((wpid = wait(&status)) != pid) { + if (wpid == -1) + return -1; + } + return status; +} +#endif diff --git a/contrib/shadow-anonftp.patch b/contrib/shadow-anonftp.patch new file mode 100644 index 0000000..e09647d --- /dev/null +++ b/contrib/shadow-anonftp.patch @@ -0,0 +1,147 @@ +Hello Marek, + +I have created a diffile against the 980403 release that adds +functionality to newusers for automatic handling of users with only +anonymous ftp login (using the guestgroup feature in ftpaccess, which +means that the users home directory looks like '/home/user/./'). It also +adds a commandline argument to specify an initial directory structure +for such users, with a tarball normally containing the bin,lib,etc +directories used in the chrooted environment. + +I am using it to automatically create chunks of users with only ftp +access for a webserver. + +I have tried to follow your coding standards and I believe it is bug +free but.. well, who knows. :) It's not much code however. + +I hope you find it useful. Do what you like with it, feel free to ask if +anything is unclear. + +Best rgds, + Calle Karlsson + ckn@kash.se + +diff -uNr shadow-980403.orig/src/newusers.c shadow-980403/src/newusers.c +--- shadow-980403.orig/src/newusers.c Fri Jan 30 00:22:43 1998 ++++ shadow-980403/src/newusers.c Fri Apr 17 16:55:33 1998 +@@ -76,11 +76,35 @@ + static void + usage(void) + { +- fprintf(stderr, "Usage: %s [ input ]\n", Prog); ++ fprintf (stderr, "Usage: %s [-p prototype tarfile] [ input ]\n", Prog); ++ fprintf (stderr, "The prototype tarfile is only used for users\n"); ++ fprintf (stderr, "marked as anonymous ftp users. It must be a full pathname.\n"); + exit(1); + } + + /* ++ * createuserdir - create a directory and chmod it ++ */ ++ ++static int ++createuserdir (char * dir, int uid, int gid, int line) ++{ ++ if (mkdir (dir, 0777 & ~getdef_num("UMASK", 077))) { ++ fprintf (stderr, "%s: line %d: mkdir %s failed\n", ++ Prog, line, dir); ++ return -1; ++ } ++ ++ if (chown (dir, uid, gid)) { ++ fprintf (stderr, "%s: line %d: chown %s failed\n", ++ Prog, line, dir); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* + * add_group - create a new group or add a user to an existing group + */ + +@@ -328,6 +352,8 @@ + main(int argc, char **argv) + { + char buf[BUFSIZ]; ++ char anonproto[BUFSIZ]; ++ int flag; + char *fields[8]; + int nfields; + char *cp; +@@ -340,12 +366,23 @@ + + Prog = Basename(argv[0]); + +- if (argc > 1 && argv[1][0] == '-') +- usage (); ++ * anonproto = '\0'; ++ ++ while ((flag = getopt (argc, argv, "p:h")) != EOF) { ++ switch (flag) { ++ case 'p': ++ STRFCPY(anonproto, optarg); ++ break; ++ case 'h': ++ default: ++ usage (); ++ break; ++ } ++ } + +- if (argc == 2) { +- if (! freopen (argv[1], "r", stdin)) { +- snprintf(buf, sizeof buf, "%s: %s", Prog, argv[1]); ++ if (optind < argc) { ++ if (! freopen (argv[optind], "r", stdin)) { ++ snprintf(buf, sizeof buf, "%s: %s", Prog, argv[optind]); + perror (buf); + exit (1); + } +@@ -499,15 +536,36 @@ + if (fields[6][0]) + newpw.pw_shell = fields[6]; + +- if (newpw.pw_dir[0] && access(newpw.pw_dir, F_OK)) { +- if (mkdir (newpw.pw_dir, +- 0777 & ~getdef_num("UMASK", 077))) +- fprintf (stderr, "%s: line %d: mkdir failed\n", +- Prog, line); +- else if (chown (newpw.pw_dir, +- newpw.pw_uid, newpw.pw_gid)) +- fprintf (stderr, "%s: line %d: chown failed\n", +- Prog, line); ++ if (newpw.pw_dir[0]) { ++ char * userdir = strdup (newpw.pw_dir); ++ char * anonpart; ++ int rc; ++ ++ if ((anonpart = strstr (userdir, "/./"))) { ++ * anonpart = '\0'; ++ anonpart += 2; ++ } ++ ++ if (access(userdir, F_OK)) ++ rc = createuserdir (userdir, newpw.pw_uid, newpw.pw_gid, line); ++ else ++ rc = 0; ++ ++ if (rc == 0 && anonpart) { ++ if (* anonproto) { ++ char cmdbuf [BUFSIZ]; ++ snprintf(cmdbuf, sizeof cmdbuf, ++ "cd %s; tar xf %s", ++ userdir, anonproto); ++ system (cmdbuf); ++ } ++ if (strlen (anonpart) > 1) { ++ strcat (userdir, anonpart); ++ if (access (userdir, F_OK)) ++ createuserdir (userdir, newpw.pw_uid, newpw.pw_gid, line); ++ } ++ } ++ free (userdir); + } + + /* diff --git a/contrib/udbachk.tgz b/contrib/udbachk.tgz new file mode 100644 index 0000000..605ad63 Binary files /dev/null and b/contrib/udbachk.tgz differ -- cgit v1.2.3