[svn-upgrade] Integrating new upstream version, shadow (19990709)
This commit is contained in:
90
src/Makefile.am
Normal file
90
src/Makefile.am
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
AUTOMAKE_OPTIONS = 1.0 foreign
|
||||
|
||||
# Watch out; note the difference between prefix & exec_prefix.
|
||||
# Normally configure sets exec_prefix to root when prefix is /usr.
|
||||
|
||||
bindir = ${exec_prefix}/bin
|
||||
sbindir = ${exec_prefix}/sbin
|
||||
ubindir = ${prefix}/bin
|
||||
usbindir = ${prefix}/sbin
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
noinst_HEADERS = patchlevel.h
|
||||
|
||||
DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
|
||||
|
||||
# XXX why are login and su in /bin anyway (other than for
|
||||
# historical reasons)?
|
||||
#
|
||||
# if the system is screwed so badly that it can't mount /usr,
|
||||
# you can (hopefully) boot single user, and then you're root
|
||||
# so you don't need these programs for recovery.
|
||||
#
|
||||
# also /lib/libshadow.so.x.xx (if any) could be moved to /usr/lib
|
||||
# and installation would be much simpler (just two directories,
|
||||
# $prefix/bin and $prefix/sbin, no install-data hacks...)
|
||||
|
||||
bin_PROGRAMS = login \
|
||||
su
|
||||
ubin_PROGRAMS = faillog lastlog \
|
||||
chage chfn chsh expiry gpasswd newgrp passwd
|
||||
usbin_PROGRAMS = chpasswd dpasswd groupadd groupdel groupmod \
|
||||
logoutd mkpasswd newusers \
|
||||
useradd userdel usermod grpck pwck vipw \
|
||||
grpconv grpunconv pwconv pwunconv
|
||||
|
||||
EXTRA_DIST = shadowconfig.sh
|
||||
|
||||
# id and groups are from gnu, sulogin from sysvinit,
|
||||
# also suid programs are installed by hand.
|
||||
# XXX installation by hand breaks libtool shared lib support
|
||||
# (the wrapper scripts get installed instead of binaries),
|
||||
# so we now chmod the programs by hand after normal installation.
|
||||
|
||||
suidbins = su
|
||||
suidubins = chage chfn chsh expiry gpasswd newgrp passwd
|
||||
|
||||
install-exec-hook:
|
||||
for i in $(suidbins); do \
|
||||
chmod 4755 $(bindir)/$$i; \
|
||||
done
|
||||
|
||||
install-data-hook:
|
||||
for i in $(suidubins); do \
|
||||
chmod 4755 $(ubindir)/$$i; \
|
||||
done
|
||||
rm -f $(ubindir)/sg
|
||||
ln -s newgrp $(ubindir)/sg
|
||||
|
||||
noinst_PROGRAMS = groups id sulogin
|
||||
|
||||
#install-exec-local:
|
||||
# $(mkinstalldirs) $(bindir)
|
||||
# for i in $(suidbins); do \
|
||||
# $(INSTALL) -m 4755 $$i $(bindir); \
|
||||
# done
|
||||
# $(mkinstalldirs) $(ubindir)
|
||||
# for i in $(suidubins); do \
|
||||
# $(INSTALL) -m 4755 $$i $(ubindir); \
|
||||
# done
|
||||
# rm -f $(bindir)/sg
|
||||
# ln -s $(ubindir)/newgrp $(bindir)/sg
|
||||
#
|
||||
#noinst_PROGRAMS = id groups \
|
||||
# su \
|
||||
# chage chfn chsh expiry gpasswd newgrp passwd \
|
||||
# sulogin
|
||||
|
||||
shlibs = ../lib/libshadow.la
|
||||
# With glibc2, almost all programs need libcrypt for some reason,
|
||||
# even those that don't actually use crypt().
|
||||
LDADD = ${shlibs} ../libmisc/libmisc.a ../lib/libshadow.a @INTLLIBS@ @LIBCRYPT@ @LIBTCFS@ @LIBSKEY@
|
||||
INCLUDES = -I${top_srcdir}/lib -I$(top_srcdir)/libmisc
|
||||
|
||||
chfn_LDADD = ${LDADD} @LIBPAM@
|
||||
chsh_LDADD = ${LDADD} @LIBPAM@
|
||||
login_LDADD = ${LDADD} @LIBPAM@
|
||||
passwd_LDADD = ${LDADD} @LIBCRACK@ @LIBPAM@
|
||||
su_LDADD = ${LDADD} @LIBPAM@
|
||||
|
873
src/Makefile.in
Normal file
873
src/Makefile.in
Normal file
@ -0,0 +1,873 @@
|
||||
# Makefile.in generated automatically by automake 1.3 from Makefile.am
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998 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.
|
||||
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libexecdir = @libexecdir@
|
||||
datadir = @datadir@
|
||||
sysconfdir = @sysconfdir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
localstatedir = @localstatedir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
mandir = @mandir@
|
||||
includedir = @includedir@
|
||||
oldincludedir = /usr/include
|
||||
|
||||
DISTDIR =
|
||||
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
|
||||
top_builddir = ..
|
||||
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
transform = @program_transform_name@
|
||||
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
host_alias = @host_alias@
|
||||
host_triplet = @host@
|
||||
CATALOGS = @CATALOGS@
|
||||
CATOBJEXT = @CATOBJEXT@
|
||||
CC = @CC@
|
||||
CPP = @CPP@
|
||||
DATADIRNAME = @DATADIRNAME@
|
||||
GENCAT = @GENCAT@
|
||||
GMOFILES = @GMOFILES@
|
||||
GMSGFMT = @GMSGFMT@
|
||||
GT_NO = @GT_NO@
|
||||
GT_YES = @GT_YES@
|
||||
INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
|
||||
INSTOBJEXT = @INSTOBJEXT@
|
||||
INTLDEPS = @INTLDEPS@
|
||||
INTLLIBS = @INTLLIBS@
|
||||
INTLOBJS = @INTLOBJS@
|
||||
LD = @LD@
|
||||
LIBCRACK = @LIBCRACK@
|
||||
LIBCRYPT = @LIBCRYPT@
|
||||
LIBPAM = @LIBPAM@
|
||||
LIBSKEY = @LIBSKEY@
|
||||
LIBTCFS = @LIBTCFS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKINSTALLDIRS = @MKINSTALLDIRS@
|
||||
MSGFMT = @MSGFMT@
|
||||
NM = @NM@
|
||||
PACKAGE = @PACKAGE@
|
||||
POFILES = @POFILES@
|
||||
POSUB = @POSUB@
|
||||
RANLIB = @RANLIB@
|
||||
U = @U@
|
||||
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
|
||||
USE_NLS = @USE_NLS@
|
||||
VERSION = @VERSION@
|
||||
YACC = @YACC@
|
||||
l = @l@
|
||||
|
||||
AUTOMAKE_OPTIONS = 1.0 foreign
|
||||
|
||||
# Watch out; note the difference between prefix & exec_prefix.
|
||||
# Normally configure sets exec_prefix to root when prefix is /usr.
|
||||
|
||||
bindir = ${exec_prefix}/bin
|
||||
sbindir = ${exec_prefix}/sbin
|
||||
ubindir = ${prefix}/bin
|
||||
usbindir = ${prefix}/sbin
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
noinst_HEADERS = patchlevel.h
|
||||
|
||||
DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
|
||||
|
||||
# XXX why are login and su in /bin anyway (other than for
|
||||
# historical reasons)?
|
||||
#
|
||||
# if the system is screwed so badly that it can't mount /usr,
|
||||
# you can (hopefully) boot single user, and then you're root
|
||||
# so you don't need these programs for recovery.
|
||||
#
|
||||
# also /lib/libshadow.so.x.xx (if any) could be moved to /usr/lib
|
||||
# and installation would be much simpler (just two directories,
|
||||
# $prefix/bin and $prefix/sbin, no install-data hacks...)
|
||||
|
||||
bin_PROGRAMS = login \
|
||||
su
|
||||
ubin_PROGRAMS = faillog lastlog \
|
||||
chage chfn chsh expiry gpasswd newgrp passwd
|
||||
usbin_PROGRAMS = chpasswd dpasswd groupadd groupdel groupmod \
|
||||
logoutd mkpasswd newusers \
|
||||
useradd userdel usermod grpck pwck vipw \
|
||||
grpconv grpunconv pwconv pwunconv
|
||||
|
||||
EXTRA_DIST = shadowconfig.sh
|
||||
|
||||
# id and groups are from gnu, sulogin from sysvinit,
|
||||
# also suid programs are installed by hand.
|
||||
# XXX installation by hand breaks libtool shared lib support
|
||||
# (the wrapper scripts get installed instead of binaries),
|
||||
# so we now chmod the programs by hand after normal installation.
|
||||
|
||||
suidbins = su
|
||||
suidubins = chage chfn chsh expiry gpasswd newgrp passwd
|
||||
|
||||
noinst_PROGRAMS = groups id sulogin
|
||||
|
||||
#install-exec-local:
|
||||
# $(mkinstalldirs) $(bindir)
|
||||
# for i in $(suidbins); do \
|
||||
# $(INSTALL) -m 4755 $$i $(bindir); \
|
||||
# done
|
||||
# $(mkinstalldirs) $(ubindir)
|
||||
# for i in $(suidubins); do \
|
||||
# $(INSTALL) -m 4755 $$i $(ubindir); \
|
||||
# done
|
||||
# rm -f $(bindir)/sg
|
||||
# ln -s $(ubindir)/newgrp $(bindir)/sg
|
||||
#
|
||||
#noinst_PROGRAMS = id groups \
|
||||
# su \
|
||||
# chage chfn chsh expiry gpasswd newgrp passwd \
|
||||
# sulogin
|
||||
|
||||
shlibs = ../lib/libshadow.la
|
||||
# With glibc2, almost all programs need libcrypt for some reason,
|
||||
# even those that don't actually use crypt().
|
||||
LDADD = ${shlibs} ../libmisc/libmisc.a ../lib/libshadow.a @INTLLIBS@ @LIBCRYPT@ @LIBTCFS@ @LIBSKEY@
|
||||
INCLUDES = -I${top_srcdir}/lib -I$(top_srcdir)/libmisc
|
||||
|
||||
chfn_LDADD = ${LDADD} @LIBPAM@
|
||||
chsh_LDADD = ${LDADD} @LIBPAM@
|
||||
login_LDADD = ${LDADD} @LIBPAM@
|
||||
passwd_LDADD = ${LDADD} @LIBCRACK@ @LIBPAM@
|
||||
su_LDADD = ${LDADD} @LIBPAM@
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = ../config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(ubin_PROGRAMS) \
|
||||
$(usbin_PROGRAMS)
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
login_SOURCES = login.c
|
||||
login_OBJECTS = login.o
|
||||
login_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
login_LDFLAGS =
|
||||
su_SOURCES = su.c
|
||||
su_OBJECTS = su.o
|
||||
su_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
su_LDFLAGS =
|
||||
groups_SOURCES = groups.c
|
||||
groups_OBJECTS = groups.o
|
||||
groups_LDADD = $(LDADD)
|
||||
groups_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
groups_LDFLAGS =
|
||||
id_SOURCES = id.c
|
||||
id_OBJECTS = id.o
|
||||
id_LDADD = $(LDADD)
|
||||
id_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
id_LDFLAGS =
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_OBJECTS = sulogin.o
|
||||
sulogin_LDADD = $(LDADD)
|
||||
sulogin_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
sulogin_LDFLAGS =
|
||||
faillog_SOURCES = faillog.c
|
||||
faillog_OBJECTS = faillog.o
|
||||
faillog_LDADD = $(LDADD)
|
||||
faillog_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
faillog_LDFLAGS =
|
||||
lastlog_SOURCES = lastlog.c
|
||||
lastlog_OBJECTS = lastlog.o
|
||||
lastlog_LDADD = $(LDADD)
|
||||
lastlog_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
lastlog_LDFLAGS =
|
||||
chage_SOURCES = chage.c
|
||||
chage_OBJECTS = chage.o
|
||||
chage_LDADD = $(LDADD)
|
||||
chage_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
chage_LDFLAGS =
|
||||
chfn_SOURCES = chfn.c
|
||||
chfn_OBJECTS = chfn.o
|
||||
chfn_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
chfn_LDFLAGS =
|
||||
chsh_SOURCES = chsh.c
|
||||
chsh_OBJECTS = chsh.o
|
||||
chsh_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
chsh_LDFLAGS =
|
||||
expiry_SOURCES = expiry.c
|
||||
expiry_OBJECTS = expiry.o
|
||||
expiry_LDADD = $(LDADD)
|
||||
expiry_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
expiry_LDFLAGS =
|
||||
gpasswd_SOURCES = gpasswd.c
|
||||
gpasswd_OBJECTS = gpasswd.o
|
||||
gpasswd_LDADD = $(LDADD)
|
||||
gpasswd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
gpasswd_LDFLAGS =
|
||||
newgrp_SOURCES = newgrp.c
|
||||
newgrp_OBJECTS = newgrp.o
|
||||
newgrp_LDADD = $(LDADD)
|
||||
newgrp_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
newgrp_LDFLAGS =
|
||||
passwd_SOURCES = passwd.c
|
||||
passwd_OBJECTS = passwd.o
|
||||
passwd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
passwd_LDFLAGS =
|
||||
chpasswd_SOURCES = chpasswd.c
|
||||
chpasswd_OBJECTS = chpasswd.o
|
||||
chpasswd_LDADD = $(LDADD)
|
||||
chpasswd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
chpasswd_LDFLAGS =
|
||||
dpasswd_SOURCES = dpasswd.c
|
||||
dpasswd_OBJECTS = dpasswd.o
|
||||
dpasswd_LDADD = $(LDADD)
|
||||
dpasswd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
dpasswd_LDFLAGS =
|
||||
groupadd_SOURCES = groupadd.c
|
||||
groupadd_OBJECTS = groupadd.o
|
||||
groupadd_LDADD = $(LDADD)
|
||||
groupadd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
groupadd_LDFLAGS =
|
||||
groupdel_SOURCES = groupdel.c
|
||||
groupdel_OBJECTS = groupdel.o
|
||||
groupdel_LDADD = $(LDADD)
|
||||
groupdel_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
groupdel_LDFLAGS =
|
||||
groupmod_SOURCES = groupmod.c
|
||||
groupmod_OBJECTS = groupmod.o
|
||||
groupmod_LDADD = $(LDADD)
|
||||
groupmod_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
groupmod_LDFLAGS =
|
||||
logoutd_SOURCES = logoutd.c
|
||||
logoutd_OBJECTS = logoutd.o
|
||||
logoutd_LDADD = $(LDADD)
|
||||
logoutd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
logoutd_LDFLAGS =
|
||||
mkpasswd_SOURCES = mkpasswd.c
|
||||
mkpasswd_OBJECTS = mkpasswd.o
|
||||
mkpasswd_LDADD = $(LDADD)
|
||||
mkpasswd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
mkpasswd_LDFLAGS =
|
||||
newusers_SOURCES = newusers.c
|
||||
newusers_OBJECTS = newusers.o
|
||||
newusers_LDADD = $(LDADD)
|
||||
newusers_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
newusers_LDFLAGS =
|
||||
useradd_SOURCES = useradd.c
|
||||
useradd_OBJECTS = useradd.o
|
||||
useradd_LDADD = $(LDADD)
|
||||
useradd_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
useradd_LDFLAGS =
|
||||
userdel_SOURCES = userdel.c
|
||||
userdel_OBJECTS = userdel.o
|
||||
userdel_LDADD = $(LDADD)
|
||||
userdel_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
userdel_LDFLAGS =
|
||||
usermod_SOURCES = usermod.c
|
||||
usermod_OBJECTS = usermod.o
|
||||
usermod_LDADD = $(LDADD)
|
||||
usermod_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
usermod_LDFLAGS =
|
||||
grpck_SOURCES = grpck.c
|
||||
grpck_OBJECTS = grpck.o
|
||||
grpck_LDADD = $(LDADD)
|
||||
grpck_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
grpck_LDFLAGS =
|
||||
pwck_SOURCES = pwck.c
|
||||
pwck_OBJECTS = pwck.o
|
||||
pwck_LDADD = $(LDADD)
|
||||
pwck_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
pwck_LDFLAGS =
|
||||
vipw_SOURCES = vipw.c
|
||||
vipw_OBJECTS = vipw.o
|
||||
vipw_LDADD = $(LDADD)
|
||||
vipw_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
vipw_LDFLAGS =
|
||||
grpconv_SOURCES = grpconv.c
|
||||
grpconv_OBJECTS = grpconv.o
|
||||
grpconv_LDADD = $(LDADD)
|
||||
grpconv_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
grpconv_LDFLAGS =
|
||||
grpunconv_SOURCES = grpunconv.c
|
||||
grpunconv_OBJECTS = grpunconv.o
|
||||
grpunconv_LDADD = $(LDADD)
|
||||
grpunconv_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
grpunconv_LDFLAGS =
|
||||
pwconv_SOURCES = pwconv.c
|
||||
pwconv_OBJECTS = pwconv.o
|
||||
pwconv_LDADD = $(LDADD)
|
||||
pwconv_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
pwconv_LDFLAGS =
|
||||
pwunconv_SOURCES = pwunconv.c
|
||||
pwunconv_OBJECTS = pwunconv.o
|
||||
pwunconv_LDADD = $(LDADD)
|
||||
pwunconv_DEPENDENCIES = ../lib/libshadow.la ../libmisc/libmisc.a \
|
||||
../lib/libshadow.a
|
||||
pwunconv_LDFLAGS =
|
||||
CFLAGS = @CFLAGS@
|
||||
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
|
||||
LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
HEADERS = $(noinst_HEADERS)
|
||||
|
||||
DIST_COMMON = Makefile.am Makefile.in
|
||||
|
||||
|
||||
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
|
||||
|
||||
TAR = tar
|
||||
GZIP = --best
|
||||
SOURCES = login.c su.c groups.c id.c sulogin.c faillog.c lastlog.c chage.c chfn.c chsh.c expiry.c gpasswd.c newgrp.c passwd.c chpasswd.c dpasswd.c groupadd.c groupdel.c groupmod.c logoutd.c mkpasswd.c newusers.c useradd.c userdel.c usermod.c grpck.c pwck.c vipw.c grpconv.c grpunconv.c pwconv.c pwunconv.c
|
||||
OBJECTS = login.o su.o groups.o id.o sulogin.o faillog.o lastlog.o chage.o chfn.o chsh.o expiry.o gpasswd.o newgrp.o passwd.o chpasswd.o dpasswd.o groupadd.o groupdel.o groupmod.o logoutd.o mkpasswd.o newusers.o useradd.o userdel.o usermod.o grpck.o pwck.o vipw.o grpconv.o grpunconv.o pwconv.o pwunconv.o
|
||||
|
||||
all: Makefile $(PROGRAMS) $(HEADERS)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .S .c .lo .o .s
|
||||
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
|
||||
cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps src/Makefile
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
|
||||
|
||||
mostlyclean-binPROGRAMS:
|
||||
|
||||
clean-binPROGRAMS:
|
||||
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
|
||||
|
||||
distclean-binPROGRAMS:
|
||||
|
||||
maintainer-clean-binPROGRAMS:
|
||||
|
||||
install-binPROGRAMS: $(bin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
$(mkinstalldirs) $(DESTDIR)$(bindir)
|
||||
@list='$(bin_PROGRAMS)'; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
|
||||
$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-binPROGRAMS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
list='$(bin_PROGRAMS)'; for p in $$list; do \
|
||||
rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
|
||||
done
|
||||
|
||||
mostlyclean-noinstPROGRAMS:
|
||||
|
||||
clean-noinstPROGRAMS:
|
||||
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
|
||||
|
||||
distclean-noinstPROGRAMS:
|
||||
|
||||
maintainer-clean-noinstPROGRAMS:
|
||||
|
||||
mostlyclean-ubinPROGRAMS:
|
||||
|
||||
clean-ubinPROGRAMS:
|
||||
-test -z "$(ubin_PROGRAMS)" || rm -f $(ubin_PROGRAMS)
|
||||
|
||||
distclean-ubinPROGRAMS:
|
||||
|
||||
maintainer-clean-ubinPROGRAMS:
|
||||
|
||||
install-ubinPROGRAMS: $(ubin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
$(mkinstalldirs) $(DESTDIR)$(ubindir)
|
||||
@list='$(ubin_PROGRAMS)'; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(ubindir)/`echo $$p|sed '$(transform)'`"; \
|
||||
$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(ubindir)/`echo $$p|sed '$(transform)'`; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-ubinPROGRAMS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
list='$(ubin_PROGRAMS)'; for p in $$list; do \
|
||||
rm -f $(DESTDIR)$(ubindir)/`echo $$p|sed '$(transform)'`; \
|
||||
done
|
||||
|
||||
mostlyclean-usbinPROGRAMS:
|
||||
|
||||
clean-usbinPROGRAMS:
|
||||
-test -z "$(usbin_PROGRAMS)" || rm -f $(usbin_PROGRAMS)
|
||||
|
||||
distclean-usbinPROGRAMS:
|
||||
|
||||
maintainer-clean-usbinPROGRAMS:
|
||||
|
||||
install-usbinPROGRAMS: $(usbin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
$(mkinstalldirs) $(DESTDIR)$(usbindir)
|
||||
@list='$(usbin_PROGRAMS)'; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(usbindir)/`echo $$p|sed '$(transform)'`"; \
|
||||
$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(usbindir)/`echo $$p|sed '$(transform)'`; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-usbinPROGRAMS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
list='$(usbin_PROGRAMS)'; for p in $$list; do \
|
||||
rm -f $(DESTDIR)$(usbindir)/`echo $$p|sed '$(transform)'`; \
|
||||
done
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.s.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.S.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.o core *.core
|
||||
|
||||
clean-compile:
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
maintainer-clean-compile:
|
||||
|
||||
.c.lo:
|
||||
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
|
||||
|
||||
.s.lo:
|
||||
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
|
||||
|
||||
.S.lo:
|
||||
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
|
||||
maintainer-clean-libtool:
|
||||
|
||||
login: $(login_OBJECTS) $(login_DEPENDENCIES)
|
||||
@rm -f login
|
||||
$(LINK) $(login_LDFLAGS) $(login_OBJECTS) $(login_LDADD) $(LIBS)
|
||||
|
||||
su: $(su_OBJECTS) $(su_DEPENDENCIES)
|
||||
@rm -f su
|
||||
$(LINK) $(su_LDFLAGS) $(su_OBJECTS) $(su_LDADD) $(LIBS)
|
||||
|
||||
groups: $(groups_OBJECTS) $(groups_DEPENDENCIES)
|
||||
@rm -f groups
|
||||
$(LINK) $(groups_LDFLAGS) $(groups_OBJECTS) $(groups_LDADD) $(LIBS)
|
||||
|
||||
id: $(id_OBJECTS) $(id_DEPENDENCIES)
|
||||
@rm -f id
|
||||
$(LINK) $(id_LDFLAGS) $(id_OBJECTS) $(id_LDADD) $(LIBS)
|
||||
|
||||
sulogin: $(sulogin_OBJECTS) $(sulogin_DEPENDENCIES)
|
||||
@rm -f sulogin
|
||||
$(LINK) $(sulogin_LDFLAGS) $(sulogin_OBJECTS) $(sulogin_LDADD) $(LIBS)
|
||||
|
||||
faillog: $(faillog_OBJECTS) $(faillog_DEPENDENCIES)
|
||||
@rm -f faillog
|
||||
$(LINK) $(faillog_LDFLAGS) $(faillog_OBJECTS) $(faillog_LDADD) $(LIBS)
|
||||
|
||||
lastlog: $(lastlog_OBJECTS) $(lastlog_DEPENDENCIES)
|
||||
@rm -f lastlog
|
||||
$(LINK) $(lastlog_LDFLAGS) $(lastlog_OBJECTS) $(lastlog_LDADD) $(LIBS)
|
||||
|
||||
chage: $(chage_OBJECTS) $(chage_DEPENDENCIES)
|
||||
@rm -f chage
|
||||
$(LINK) $(chage_LDFLAGS) $(chage_OBJECTS) $(chage_LDADD) $(LIBS)
|
||||
|
||||
chfn: $(chfn_OBJECTS) $(chfn_DEPENDENCIES)
|
||||
@rm -f chfn
|
||||
$(LINK) $(chfn_LDFLAGS) $(chfn_OBJECTS) $(chfn_LDADD) $(LIBS)
|
||||
|
||||
chsh: $(chsh_OBJECTS) $(chsh_DEPENDENCIES)
|
||||
@rm -f chsh
|
||||
$(LINK) $(chsh_LDFLAGS) $(chsh_OBJECTS) $(chsh_LDADD) $(LIBS)
|
||||
|
||||
expiry: $(expiry_OBJECTS) $(expiry_DEPENDENCIES)
|
||||
@rm -f expiry
|
||||
$(LINK) $(expiry_LDFLAGS) $(expiry_OBJECTS) $(expiry_LDADD) $(LIBS)
|
||||
|
||||
gpasswd: $(gpasswd_OBJECTS) $(gpasswd_DEPENDENCIES)
|
||||
@rm -f gpasswd
|
||||
$(LINK) $(gpasswd_LDFLAGS) $(gpasswd_OBJECTS) $(gpasswd_LDADD) $(LIBS)
|
||||
|
||||
newgrp: $(newgrp_OBJECTS) $(newgrp_DEPENDENCIES)
|
||||
@rm -f newgrp
|
||||
$(LINK) $(newgrp_LDFLAGS) $(newgrp_OBJECTS) $(newgrp_LDADD) $(LIBS)
|
||||
|
||||
passwd: $(passwd_OBJECTS) $(passwd_DEPENDENCIES)
|
||||
@rm -f passwd
|
||||
$(LINK) $(passwd_LDFLAGS) $(passwd_OBJECTS) $(passwd_LDADD) $(LIBS)
|
||||
|
||||
chpasswd: $(chpasswd_OBJECTS) $(chpasswd_DEPENDENCIES)
|
||||
@rm -f chpasswd
|
||||
$(LINK) $(chpasswd_LDFLAGS) $(chpasswd_OBJECTS) $(chpasswd_LDADD) $(LIBS)
|
||||
|
||||
dpasswd: $(dpasswd_OBJECTS) $(dpasswd_DEPENDENCIES)
|
||||
@rm -f dpasswd
|
||||
$(LINK) $(dpasswd_LDFLAGS) $(dpasswd_OBJECTS) $(dpasswd_LDADD) $(LIBS)
|
||||
|
||||
groupadd: $(groupadd_OBJECTS) $(groupadd_DEPENDENCIES)
|
||||
@rm -f groupadd
|
||||
$(LINK) $(groupadd_LDFLAGS) $(groupadd_OBJECTS) $(groupadd_LDADD) $(LIBS)
|
||||
|
||||
groupdel: $(groupdel_OBJECTS) $(groupdel_DEPENDENCIES)
|
||||
@rm -f groupdel
|
||||
$(LINK) $(groupdel_LDFLAGS) $(groupdel_OBJECTS) $(groupdel_LDADD) $(LIBS)
|
||||
|
||||
groupmod: $(groupmod_OBJECTS) $(groupmod_DEPENDENCIES)
|
||||
@rm -f groupmod
|
||||
$(LINK) $(groupmod_LDFLAGS) $(groupmod_OBJECTS) $(groupmod_LDADD) $(LIBS)
|
||||
|
||||
logoutd: $(logoutd_OBJECTS) $(logoutd_DEPENDENCIES)
|
||||
@rm -f logoutd
|
||||
$(LINK) $(logoutd_LDFLAGS) $(logoutd_OBJECTS) $(logoutd_LDADD) $(LIBS)
|
||||
|
||||
mkpasswd: $(mkpasswd_OBJECTS) $(mkpasswd_DEPENDENCIES)
|
||||
@rm -f mkpasswd
|
||||
$(LINK) $(mkpasswd_LDFLAGS) $(mkpasswd_OBJECTS) $(mkpasswd_LDADD) $(LIBS)
|
||||
|
||||
newusers: $(newusers_OBJECTS) $(newusers_DEPENDENCIES)
|
||||
@rm -f newusers
|
||||
$(LINK) $(newusers_LDFLAGS) $(newusers_OBJECTS) $(newusers_LDADD) $(LIBS)
|
||||
|
||||
useradd: $(useradd_OBJECTS) $(useradd_DEPENDENCIES)
|
||||
@rm -f useradd
|
||||
$(LINK) $(useradd_LDFLAGS) $(useradd_OBJECTS) $(useradd_LDADD) $(LIBS)
|
||||
|
||||
userdel: $(userdel_OBJECTS) $(userdel_DEPENDENCIES)
|
||||
@rm -f userdel
|
||||
$(LINK) $(userdel_LDFLAGS) $(userdel_OBJECTS) $(userdel_LDADD) $(LIBS)
|
||||
|
||||
usermod: $(usermod_OBJECTS) $(usermod_DEPENDENCIES)
|
||||
@rm -f usermod
|
||||
$(LINK) $(usermod_LDFLAGS) $(usermod_OBJECTS) $(usermod_LDADD) $(LIBS)
|
||||
|
||||
grpck: $(grpck_OBJECTS) $(grpck_DEPENDENCIES)
|
||||
@rm -f grpck
|
||||
$(LINK) $(grpck_LDFLAGS) $(grpck_OBJECTS) $(grpck_LDADD) $(LIBS)
|
||||
|
||||
pwck: $(pwck_OBJECTS) $(pwck_DEPENDENCIES)
|
||||
@rm -f pwck
|
||||
$(LINK) $(pwck_LDFLAGS) $(pwck_OBJECTS) $(pwck_LDADD) $(LIBS)
|
||||
|
||||
vipw: $(vipw_OBJECTS) $(vipw_DEPENDENCIES)
|
||||
@rm -f vipw
|
||||
$(LINK) $(vipw_LDFLAGS) $(vipw_OBJECTS) $(vipw_LDADD) $(LIBS)
|
||||
|
||||
grpconv: $(grpconv_OBJECTS) $(grpconv_DEPENDENCIES)
|
||||
@rm -f grpconv
|
||||
$(LINK) $(grpconv_LDFLAGS) $(grpconv_OBJECTS) $(grpconv_LDADD) $(LIBS)
|
||||
|
||||
grpunconv: $(grpunconv_OBJECTS) $(grpunconv_DEPENDENCIES)
|
||||
@rm -f grpunconv
|
||||
$(LINK) $(grpunconv_LDFLAGS) $(grpunconv_OBJECTS) $(grpunconv_LDADD) $(LIBS)
|
||||
|
||||
pwconv: $(pwconv_OBJECTS) $(pwconv_DEPENDENCIES)
|
||||
@rm -f pwconv
|
||||
$(LINK) $(pwconv_LDFLAGS) $(pwconv_OBJECTS) $(pwconv_LDADD) $(LIBS)
|
||||
|
||||
pwunconv: $(pwunconv_OBJECTS) $(pwunconv_DEPENDENCIES)
|
||||
@rm -f pwunconv
|
||||
$(LINK) $(pwunconv_LDFLAGS) $(pwunconv_OBJECTS) $(pwunconv_LDADD) $(LIBS)
|
||||
|
||||
tags: TAGS
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP)
|
||||
here=`pwd` && cd $(srcdir) \
|
||||
&& mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS)'; \
|
||||
unique=`for i in $$list; do echo $$i; done | \
|
||||
awk ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|
||||
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
|
||||
|
||||
mostlyclean-tags:
|
||||
|
||||
clean-tags:
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID
|
||||
|
||||
maintainer-clean-tags:
|
||||
|
||||
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
|
||||
|
||||
subdir = src
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
d=$(srcdir); \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|| cp -p $$d/$$file $(distdir)/$$file; \
|
||||
done
|
||||
chage.o: chage.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
|
||||
../lib/shadowio.h
|
||||
chfn.o: chfn.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
|
||||
../lib/getdef.h ../lib/pwauth.h
|
||||
chpasswd.o: chpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
|
||||
../lib/shadowio.h
|
||||
chsh.o: chsh.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
|
||||
../lib/getdef.h ../lib/pwauth.h
|
||||
dpasswd.o: dpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/dialup.h
|
||||
expiry.o: expiry.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h
|
||||
faillog.o: faillog.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/faillog.h
|
||||
gpasswd.o: gpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/groupio.h \
|
||||
../lib/sgroupio.h
|
||||
groupadd.o: groupadd.c ../config.h ../lib/rcsid.h ../lib/defines.h \
|
||||
../lib/gshadow_.h ../lib/prototypes.h ../libmisc/chkname.h \
|
||||
../lib/getdef.h ../lib/groupio.h ../lib/sgroupio.h
|
||||
groupdel.o: groupdel.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/groupio.h \
|
||||
../lib/sgroupio.h
|
||||
groupmod.o: groupmod.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
|
||||
../lib/groupio.h ../lib/sgroupio.h
|
||||
groups.o: groups.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h
|
||||
grpck.o: grpck.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
|
||||
../lib/commonio.h ../lib/groupio.h ../lib/sgroupio.h
|
||||
grpconv.o: grpconv.c ../config.h ../lib/prototypes.h ../lib/defines.h \
|
||||
../lib/gshadow_.h ../lib/groupio.h ../lib/sgroupio.h \
|
||||
../lib/rcsid.h
|
||||
grpunconv.o: grpunconv.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/groupio.h \
|
||||
../lib/sgroupio.h
|
||||
id.o: id.c ../config.h ../lib/rcsid.h ../lib/defines.h ../lib/gshadow_.h
|
||||
lastlog.o: lastlog.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h
|
||||
login.o: login.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/faillog.h \
|
||||
../libmisc/failure.h ../lib/pwauth.h ../lib/getdef.h \
|
||||
../lib/dialchk.h
|
||||
logoutd.o: logoutd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h
|
||||
mkpasswd.o: mkpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h
|
||||
newgrp.o: newgrp.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
|
||||
newusers.o: newusers.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h \
|
||||
../lib/pwio.h ../lib/groupio.h ../lib/shadowio.h
|
||||
passwd.o: passwd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwauth.h \
|
||||
../lib/shadowio.h ../lib/pwio.h ../lib/getdef.h
|
||||
pwck.o: pwck.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
|
||||
../lib/commonio.h ../lib/pwio.h ../lib/shadowio.h
|
||||
pwconv.o: pwconv.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
|
||||
../lib/shadowio.h ../lib/getdef.h
|
||||
pwunconv.o: pwunconv.c ../config.h ../lib/rcsid.h ../lib/defines.h \
|
||||
../lib/gshadow_.h ../lib/prototypes.h ../lib/pwio.h \
|
||||
../lib/shadowio.h
|
||||
sulogin.o: sulogin.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h \
|
||||
../lib/pwauth.h
|
||||
su.o: su.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/pwauth.h \
|
||||
../lib/getdef.h
|
||||
useradd.o: useradd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
|
||||
../lib/pwauth.h ../lib/faillog.h ../lib/groupio.h \
|
||||
../lib/sgroupio.h ../lib/pwio.h ../lib/shadowio.h \
|
||||
../lib/getdef.h
|
||||
userdel.o: userdel.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h \
|
||||
../lib/pwauth.h ../lib/groupio.h ../lib/pwio.h \
|
||||
../lib/shadowio.h ../lib/sgroupio.h
|
||||
usermod.o: usermod.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
|
||||
../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
|
||||
../lib/faillog.h ../lib/pwauth.h ../lib/getdef.h \
|
||||
../lib/groupio.h ../lib/sgroupio.h ../lib/pwio.h \
|
||||
../lib/shadowio.h
|
||||
vipw.o: vipw.c ../config.h ../lib/rcsid.h ../lib/defines.h \
|
||||
../lib/gshadow_.h ../lib/prototypes.h ../lib/pwio.h \
|
||||
../lib/shadowio.h ../lib/groupio.h ../lib/sgroupio.h
|
||||
|
||||
info:
|
||||
dvi:
|
||||
check: all
|
||||
$(MAKE)
|
||||
installcheck:
|
||||
install-exec: install-binPROGRAMS
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) install-exec-hook
|
||||
|
||||
install-data: install-ubinPROGRAMS install-usbinPROGRAMS
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) install-data-hook
|
||||
|
||||
install: install-exec install-data all
|
||||
@:
|
||||
|
||||
uninstall: uninstall-binPROGRAMS uninstall-ubinPROGRAMS uninstall-usbinPROGRAMS
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
|
||||
installdirs:
|
||||
$(mkinstalldirs) $(DATADIR)$(bindir) $(DATADIR)$(ubindir) \
|
||||
$(DATADIR)$(usbindir)
|
||||
|
||||
|
||||
mostlyclean-generic:
|
||||
-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
|
||||
|
||||
clean-generic:
|
||||
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
|
||||
|
||||
distclean-generic:
|
||||
-rm -f Makefile $(DISTCLEANFILES)
|
||||
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
|
||||
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
|
||||
mostlyclean: mostlyclean-binPROGRAMS mostlyclean-noinstPROGRAMS \
|
||||
mostlyclean-ubinPROGRAMS mostlyclean-usbinPROGRAMS \
|
||||
mostlyclean-compile mostlyclean-libtool \
|
||||
mostlyclean-tags mostlyclean-generic
|
||||
|
||||
clean: clean-binPROGRAMS clean-noinstPROGRAMS clean-ubinPROGRAMS \
|
||||
clean-usbinPROGRAMS clean-compile clean-libtool \
|
||||
clean-tags clean-generic mostlyclean
|
||||
|
||||
distclean: distclean-binPROGRAMS distclean-noinstPROGRAMS \
|
||||
distclean-ubinPROGRAMS distclean-usbinPROGRAMS \
|
||||
distclean-compile distclean-libtool distclean-tags \
|
||||
distclean-generic clean
|
||||
-rm -f config.status
|
||||
-rm -f libtool
|
||||
|
||||
maintainer-clean: maintainer-clean-binPROGRAMS \
|
||||
maintainer-clean-noinstPROGRAMS \
|
||||
maintainer-clean-ubinPROGRAMS \
|
||||
maintainer-clean-usbinPROGRAMS maintainer-clean-compile \
|
||||
maintainer-clean-libtool maintainer-clean-tags \
|
||||
maintainer-clean-generic distclean
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
|
||||
.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
|
||||
maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
|
||||
mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \
|
||||
clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \
|
||||
mostlyclean-ubinPROGRAMS distclean-ubinPROGRAMS clean-ubinPROGRAMS \
|
||||
maintainer-clean-ubinPROGRAMS uninstall-ubinPROGRAMS \
|
||||
install-ubinPROGRAMS mostlyclean-usbinPROGRAMS distclean-usbinPROGRAMS \
|
||||
clean-usbinPROGRAMS maintainer-clean-usbinPROGRAMS \
|
||||
uninstall-usbinPROGRAMS install-usbinPROGRAMS mostlyclean-compile \
|
||||
distclean-compile clean-compile maintainer-clean-compile \
|
||||
mostlyclean-libtool distclean-libtool clean-libtool \
|
||||
maintainer-clean-libtool tags mostlyclean-tags distclean-tags \
|
||||
clean-tags maintainer-clean-tags distdir info dvi installcheck \
|
||||
install-exec install-data install uninstall all installdirs \
|
||||
mostlyclean-generic distclean-generic clean-generic \
|
||||
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
|
||||
|
||||
|
||||
install-exec-hook:
|
||||
for i in $(suidbins); do \
|
||||
chmod 4755 $(bindir)/$$i; \
|
||||
done
|
||||
|
||||
install-data-hook:
|
||||
for i in $(suidubins); do \
|
||||
chmod 4755 $(ubindir)/$$i; \
|
||||
done
|
||||
rm -f $(ubindir)/sg
|
||||
ln -s newgrp $(ubindir)/sg
|
||||
|
||||
# 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:
|
821
src/chage.c
Normal file
821
src/chage.c
Normal file
@ -0,0 +1,821 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: chage.c,v 1.15 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
/*
|
||||
* chage depends on some form of aging being present. It makes no sense
|
||||
* to have a program that has no input.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#ifndef AGING
|
||||
#define AGING
|
||||
#endif /* AGING */
|
||||
#else /* !SHADOWPWD */
|
||||
#if !defined(ATT_AGE) && defined(AGING)
|
||||
#undef AGING
|
||||
#endif /* !ATT_AGE && AGING */
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
static char *Prog;
|
||||
|
||||
#ifdef AGING /*{*/
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
static long mindays;
|
||||
static long maxdays;
|
||||
static long lastday;
|
||||
#ifdef SHADOWPWD
|
||||
static long warndays;
|
||||
static long inactdays;
|
||||
static long expdays;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* External identifiers
|
||||
*/
|
||||
|
||||
extern long a64l();
|
||||
extern char *l64a();
|
||||
|
||||
#include "pwio.h"
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#include "shadowio.h"
|
||||
#endif
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
#ifdef NDBM
|
||||
extern int pw_dbm_mode;
|
||||
#ifdef SHADOWPWD
|
||||
extern int sp_dbm_mode;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* #defines for messages. This facilitates foreign language conversion
|
||||
* since all messages are defined right here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* xgettext doesn't like #defines, so now we only leave untranslated
|
||||
* messages here. -MM
|
||||
*/
|
||||
|
||||
#define AGE_CHANGED "changed password expiry for %s\n"
|
||||
#define LOCK_FAIL "failed locking %s\n"
|
||||
#define OPEN_FAIL "failed opening %s\n"
|
||||
#define WRITE_FAIL "failed updating %s\n"
|
||||
#define CLOSE_FAIL "failed rewriting %s\n"
|
||||
|
||||
#define EPOCH "1969-12-31"
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#define DBMERROR2 "error updating DBM shadow entry.\n"
|
||||
#else
|
||||
#define DBMERROR2 "error updating DBM passwd entry.\n"
|
||||
#endif
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static void date_to_str P_((char *, size_t, time_t));
|
||||
static int new_fields P_((void));
|
||||
static void print_date P_((time_t));
|
||||
static void list_fields P_((void));
|
||||
int main P_((int, char **));
|
||||
static void cleanup P_((int));
|
||||
|
||||
/*
|
||||
* usage - print command line syntax and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#ifdef SHADOWPWD
|
||||
fprintf(stderr, _("Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"), Prog);
|
||||
#else
|
||||
fprintf(stderr, _("Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n"), Prog);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
date_to_str(char *buf, size_t maxsize, time_t date)
|
||||
{
|
||||
struct tm *tp;
|
||||
|
||||
tp = gmtime(&date);
|
||||
#ifdef HAVE_STRFTIME
|
||||
strftime(buf, maxsize, "%Y-%m-%d", tp);
|
||||
#else
|
||||
snprintf(buf, maxsize, "%04d-%02d-%02d",
|
||||
tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday);
|
||||
#endif /* HAVE_STRFTIME */
|
||||
}
|
||||
|
||||
/*
|
||||
* new_fields - change the user's password aging information interactively.
|
||||
*
|
||||
* prompt the user for all of the password age values. set the fields
|
||||
* from the user's response, or leave alone if nothing was entered. the
|
||||
* value (-1) is used to indicate the field should be removed if possible.
|
||||
* any other negative value is an error. very large positive values will
|
||||
* be handled elsewhere.
|
||||
*/
|
||||
|
||||
static int
|
||||
new_fields(void)
|
||||
{
|
||||
char buf[200];
|
||||
char *cp;
|
||||
|
||||
printf(_("Enter the new value, or press return for the default\n\n"));
|
||||
|
||||
snprintf(buf, sizeof buf, "%ld", mindays);
|
||||
change_field(buf, sizeof buf, _("Minimum Password Age"));
|
||||
if (((mindays = strtol (buf, &cp, 10)) == 0 && *cp) || mindays < -1)
|
||||
return 0;
|
||||
|
||||
snprintf(buf, sizeof buf, "%ld", maxdays);
|
||||
change_field(buf, sizeof buf, _("Maximum Password Age"));
|
||||
if (((maxdays = strtol (buf, &cp, 10)) == 0 && *cp) || maxdays < -1)
|
||||
return 0;
|
||||
|
||||
date_to_str(buf, sizeof buf, lastday * SCALE);
|
||||
|
||||
change_field(buf, sizeof buf, _("Last Password Change (YYYY-MM-DD)"));
|
||||
|
||||
if (strcmp (buf, EPOCH) == 0)
|
||||
lastday = -1;
|
||||
else if ((lastday = strtoday (buf)) == -1)
|
||||
return 0;
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
snprintf(buf, sizeof buf, "%ld", warndays);
|
||||
change_field (buf, sizeof buf, _("Password Expiration Warning"));
|
||||
if (((warndays = strtol (buf, &cp, 10)) == 0 && *cp) || warndays < -1)
|
||||
return 0;
|
||||
|
||||
snprintf(buf, sizeof buf, "%ld", inactdays);
|
||||
change_field(buf, sizeof buf, _("Password Inactive"));
|
||||
if (((inactdays = strtol (buf, &cp, 10)) == 0 && *cp) || inactdays < -1)
|
||||
return 0;
|
||||
|
||||
date_to_str(buf, sizeof buf, expdays * SCALE);
|
||||
|
||||
change_field(buf, sizeof buf, _("Account Expiration Date (YYYY-MM-DD)"));
|
||||
|
||||
if (strcmp (buf, EPOCH) == 0)
|
||||
expdays = -1;
|
||||
else if ((expdays = strtoday (buf)) == -1)
|
||||
return 0;
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
print_date(time_t date)
|
||||
{
|
||||
#ifdef HAVE_STRFTIME
|
||||
struct tm *tp;
|
||||
char buf[80];
|
||||
|
||||
tp = gmtime(&date);
|
||||
strftime(buf, sizeof buf, "%b %d, %Y", tp);
|
||||
puts(buf);
|
||||
#else
|
||||
struct tm *tp;
|
||||
char *cp;
|
||||
|
||||
tp = gmtime(&date);
|
||||
cp = asctime(tp);
|
||||
printf("%6.6s, %4.4s\n", cp + 4, cp + 20);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* list_fields - display the current values of the expiration fields
|
||||
*
|
||||
* display the password age information from the password fields. date
|
||||
* values will be displayed as a calendar date, or the word "Never" if
|
||||
* the date is 1/1/70, which is day number 0.
|
||||
*/
|
||||
|
||||
static void
|
||||
list_fields(void)
|
||||
{
|
||||
long changed = 0;
|
||||
long expires;
|
||||
|
||||
/*
|
||||
* Start with the easy numbers - the number of days before the
|
||||
* password can be changed, the number of days after which the
|
||||
* password must be chaged, the number of days before the
|
||||
* password expires that the user is told, and the number of
|
||||
* days after the password expires that the account becomes
|
||||
* unusable.
|
||||
*/
|
||||
|
||||
printf(_("Minimum:\t%ld\n"), mindays);
|
||||
printf(_("Maximum:\t%ld\n"), maxdays);
|
||||
#ifdef SHADOWPWD
|
||||
printf(_("Warning:\t%ld\n"), warndays);
|
||||
printf(_("Inactive:\t%ld\n"), inactdays);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The "last change" date is either "Never" or the date the
|
||||
* password was last modified. The date is the number of
|
||||
* days since 1/1/1970.
|
||||
*/
|
||||
|
||||
printf(_("Last Change:\t\t"));
|
||||
if (lastday <= 0) {
|
||||
printf(_("Never\n"));
|
||||
} else {
|
||||
changed = lastday * SCALE;
|
||||
print_date(changed);
|
||||
}
|
||||
|
||||
/*
|
||||
* The password expiration date is determined from the last
|
||||
* change date plus the number of days the password is valid
|
||||
* for.
|
||||
*/
|
||||
|
||||
printf(_("Password Expires:\t"));
|
||||
if (lastday <= 0 || maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
|
||||
printf (_("Never\n"));
|
||||
} else {
|
||||
expires = changed + maxdays * SCALE;
|
||||
print_date(expires);
|
||||
}
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
/*
|
||||
* The account becomes inactive if the password is expired
|
||||
* for more than "inactdays". The expiration date is calculated
|
||||
* and the number of inactive days is added. The resulting date
|
||||
* is when the active will be disabled.
|
||||
*/
|
||||
|
||||
printf ("Password Inactive:\t");
|
||||
if (lastday <= 0 || inactdays <= 0 ||
|
||||
maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
|
||||
printf ("Never\n");
|
||||
} else {
|
||||
expires = changed + (maxdays + inactdays) * SCALE;
|
||||
print_date(expires);
|
||||
}
|
||||
|
||||
/*
|
||||
* The account will expire on the given date regardless of the
|
||||
* password expiring or not.
|
||||
*/
|
||||
|
||||
printf ("Account Expires:\t");
|
||||
if (expdays <= 0) {
|
||||
printf ("Never\n");
|
||||
} else {
|
||||
expires = expdays * SCALE;
|
||||
print_date(expires);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* chage - change a user's password aging information
|
||||
*
|
||||
* This command controls the password aging information.
|
||||
*
|
||||
* The valid options are
|
||||
*
|
||||
* -m minimum number of days before password change (*)
|
||||
* -M maximim number of days before password change (*)
|
||||
* -d last password change date (*)
|
||||
* -l password aging information
|
||||
* -W expiration warning days (*)
|
||||
* -I password inactive after expiration (*)
|
||||
* -E account expiration date (*)
|
||||
*
|
||||
* (*) requires root permission to execute.
|
||||
*
|
||||
* All of the time fields are entered in the internal format
|
||||
* which is either seconds or days.
|
||||
*
|
||||
* The options -W, -I and -E all depend on the SHADOWPWD
|
||||
* macro being defined.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int flag;
|
||||
int lflg = 0;
|
||||
int mflg = 0;
|
||||
int Mflg = 0;
|
||||
int dflg = 0;
|
||||
#ifdef SHADOWPWD
|
||||
int Wflg = 0;
|
||||
int Iflg = 0;
|
||||
int Eflg = 0;
|
||||
const struct spwd *sp;
|
||||
struct spwd spwd;
|
||||
#else
|
||||
char new_age[5];
|
||||
#endif
|
||||
uid_t ruid = getuid ();
|
||||
const struct passwd *pw;
|
||||
struct passwd pwent;
|
||||
char name[BUFSIZ];
|
||||
|
||||
sanitize_env();
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* Get the program name so that error messages can use it.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
openlog("chage", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
#ifdef NDBM
|
||||
#ifdef SHADOWPWD
|
||||
sp_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
pw_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse the flags. The difference between password file
|
||||
* formats includes the number of fields, and whether the
|
||||
* dates are entered as days or weeks. Shadow password
|
||||
* file info =must= be entered in days, while regular
|
||||
* password file info =must= be entered in weeks.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#define FLAGS "lm:M:W:I:E:d:"
|
||||
#else
|
||||
#define FLAGS "lm:M:d:"
|
||||
#endif
|
||||
while ((flag = getopt(argc, argv, FLAGS)) != EOF) {
|
||||
#undef FLAGS
|
||||
switch (flag) {
|
||||
case 'l':
|
||||
lflg++;
|
||||
break;
|
||||
case 'm':
|
||||
mflg++;
|
||||
mindays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'M':
|
||||
Mflg++;
|
||||
maxdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'd':
|
||||
dflg++;
|
||||
if (strchr (optarg, '/'))
|
||||
lastday = strtoday (optarg);
|
||||
else
|
||||
lastday = strtol (optarg, 0, 10);
|
||||
break;
|
||||
#ifdef SHADOWPWD
|
||||
case 'W':
|
||||
Wflg++;
|
||||
warndays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'I':
|
||||
Iflg++;
|
||||
inactdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'E':
|
||||
Eflg++;
|
||||
if (strchr (optarg, '/'))
|
||||
expdays = strtoday (optarg);
|
||||
else
|
||||
expdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make certain the flags do not conflict and that there is
|
||||
* a user name on the command line.
|
||||
*/
|
||||
|
||||
if (argc != optind + 1)
|
||||
usage ();
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg))
|
||||
#else
|
||||
if (lflg && (mflg || Mflg || dflg))
|
||||
#endif
|
||||
{
|
||||
fprintf (stderr, _("%s: do not include \"l\" with other flags\n"), Prog);
|
||||
closelog();
|
||||
usage ();
|
||||
}
|
||||
|
||||
/*
|
||||
* An unprivileged user can ask for their own aging information,
|
||||
* but only root can change it, or list another user's aging
|
||||
* information.
|
||||
*/
|
||||
|
||||
if (ruid != 0 && ! lflg) {
|
||||
fprintf (stderr, _("%s: permission denied\n"), Prog);
|
||||
closelog();
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock and open the password file. This loads all of the
|
||||
* password file entries into memory. Then we get a pointer
|
||||
* to the password file entry for the requested user.
|
||||
*/
|
||||
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock password file\n"), Prog);
|
||||
SYSLOG((LOG_ERR, LOCK_FAIL, PASSWD_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (!pw_open((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open password file\n"), Prog);
|
||||
cleanup(1);
|
||||
SYSLOG((LOG_ERR, OPEN_FAIL, PASSWD_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (!(pw = pw_locate(argv[optind]))) {
|
||||
fprintf(stderr, _("%s: unknown user: %s\n"), Prog, argv[optind]);
|
||||
cleanup(1);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pwent = *pw;
|
||||
STRFCPY(name, pwent.pw_name);
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
/*
|
||||
* For shadow password files we have to lock the file and
|
||||
* read in the entries as was done for the password file.
|
||||
* The user entries does not have to exist in this case;
|
||||
* a new entry will be created for this user if one does
|
||||
* not exist already.
|
||||
*/
|
||||
|
||||
if (!spw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock shadow password file\n"), Prog);
|
||||
cleanup(1);
|
||||
SYSLOG((LOG_ERR, LOCK_FAIL, SHADOW_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (!spw_open((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow password file\n"), Prog);
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, OPEN_FAIL, SHADOW_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sp = spw_locate(argv[optind]);
|
||||
|
||||
/*
|
||||
* Set the fields that aren't being set from the command line
|
||||
* from the password file.
|
||||
*/
|
||||
|
||||
if (sp) {
|
||||
spwd = *sp;
|
||||
|
||||
if (! Mflg)
|
||||
maxdays = spwd.sp_max;
|
||||
if (! mflg)
|
||||
mindays = spwd.sp_min;
|
||||
if (! dflg)
|
||||
lastday = spwd.sp_lstchg;
|
||||
if (! Wflg)
|
||||
warndays = spwd.sp_warn;
|
||||
if (! Iflg)
|
||||
inactdays = spwd.sp_inact;
|
||||
if (! Eflg)
|
||||
expdays = spwd.sp_expire;
|
||||
}
|
||||
#ifdef ATT_AGE
|
||||
else
|
||||
#endif /* ATT_AGE */
|
||||
#endif /* SHADOWPWD */
|
||||
#ifdef ATT_AGE
|
||||
{
|
||||
if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
|
||||
if (! Mflg)
|
||||
maxdays = c64i (pwent.pw_age[0]) * (WEEK/SCALE);
|
||||
if (! mflg)
|
||||
mindays = c64i (pwent.pw_age[1]) * (WEEK/SCALE);
|
||||
if (! dflg && strlen (pwent.pw_age) == 4)
|
||||
lastday = a64l (pwent.pw_age+2) * (WEEK/SCALE);
|
||||
} else {
|
||||
mindays = 0;
|
||||
maxdays = 10000L * (DAY/SCALE);
|
||||
lastday = -1;
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
warndays = inactdays = expdays = -1;
|
||||
#endif /* SHADOWPWD */
|
||||
}
|
||||
#endif /* ATT_AGE */
|
||||
|
||||
/*
|
||||
* Print out the expiration fields if the user has
|
||||
* requested the list option.
|
||||
*/
|
||||
|
||||
if (lflg) {
|
||||
if (ruid != 0 && ruid != pwent.pw_uid) {
|
||||
fprintf(stderr, _("%s: permission denied\n"), Prog);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
list_fields();
|
||||
cleanup(2);
|
||||
closelog();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If none of the fields were changed from the command line,
|
||||
* let the user interactively change them.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (! mflg && ! Mflg && ! dflg && ! Wflg && ! Iflg && ! Eflg)
|
||||
#else
|
||||
if (! mflg && ! Mflg && ! dflg)
|
||||
#endif
|
||||
{
|
||||
printf(_("Changing the aging information for %s\n"), name);
|
||||
if (!new_fields()) {
|
||||
fprintf(stderr, _("%s: error changing fields\n"), Prog);
|
||||
cleanup(2);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
/*
|
||||
* There was no shadow entry. The new entry will have the
|
||||
* encrypted password transferred from the normal password
|
||||
* file along with the aging information.
|
||||
*/
|
||||
|
||||
if (sp == 0) {
|
||||
sp = &spwd;
|
||||
memzero(&spwd, sizeof spwd);
|
||||
|
||||
spwd.sp_namp = xstrdup (pwent.pw_name);
|
||||
spwd.sp_pwdp = xstrdup (pwent.pw_passwd);
|
||||
spwd.sp_flag = -1;
|
||||
|
||||
pwent.pw_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
|
||||
#ifdef ATT_AGE
|
||||
pwent.pw_age = "";
|
||||
#endif
|
||||
if (!pw_update(&pwent)) {
|
||||
fprintf(stderr, _("%s: can't update password file\n"), Prog);
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, WRITE_FAIL, PASSWD_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
#ifdef NDBM
|
||||
(void) pw_dbm_update (&pwent);
|
||||
endpwent ();
|
||||
#endif
|
||||
}
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
|
||||
/*
|
||||
* Copy the fields back to the shadow file entry and
|
||||
* write the modified entry back to the shadow file.
|
||||
* Closing the shadow and password files will commit
|
||||
* any changes that have been made.
|
||||
*/
|
||||
|
||||
spwd.sp_max = maxdays;
|
||||
spwd.sp_min = mindays;
|
||||
spwd.sp_lstchg = lastday;
|
||||
spwd.sp_warn = warndays;
|
||||
spwd.sp_inact = inactdays;
|
||||
spwd.sp_expire = expdays;
|
||||
|
||||
if (!spw_update(&spwd)) {
|
||||
fprintf(stderr, _("%s: can't update shadow password file\n"), Prog);
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, WRITE_FAIL, SHADOW_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
#else /* !SHADOWPWD */
|
||||
|
||||
/*
|
||||
* fill in the new_age string with the new values
|
||||
*/
|
||||
|
||||
if (maxdays > (63 * 7) && mindays == 0) {
|
||||
new_age[0] = '\0';
|
||||
} else {
|
||||
if (maxdays > (63 * 7))
|
||||
maxdays = 63 * 7;
|
||||
|
||||
if (mindays > (63 * 7))
|
||||
mindays = 63 * 7;
|
||||
|
||||
new_age[0] = i64c (maxdays / 7);
|
||||
new_age[1] = i64c ((mindays + 6) / 7);
|
||||
|
||||
if (lastday == 0)
|
||||
new_age[2] = '\0';
|
||||
else
|
||||
strcpy (new_age + 2, l64a (lastday / 7));
|
||||
|
||||
}
|
||||
pwent.pw_age = new_age;
|
||||
|
||||
if (!pw_update(&pwent)) {
|
||||
fprintf(stderr, _("%s: can't update password file\n"), Prog);
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, WRITE_FAIL, PASSWD_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
#ifdef NDBM
|
||||
#ifdef SHADOWPWD
|
||||
|
||||
/*
|
||||
* See if the shadow DBM file exists and try to update it.
|
||||
*/
|
||||
|
||||
if (sp_dbm_present() && !sp_dbm_update(&spwd)) {
|
||||
fprintf(stderr, _("Error updating the DBM password entry.\n"));
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, DBMERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
endspent();
|
||||
|
||||
#else /* !SHADOWPWD */
|
||||
|
||||
/*
|
||||
* See if the password DBM file exists and try to update it.
|
||||
*/
|
||||
|
||||
if (pw_dbm_present() && !pw_dbm_update(&pwent)) {
|
||||
fprintf(stderr, _("Error updating the DBM password entry.\n"));
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, DBMERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
endpwent ();
|
||||
#endif /* SHADOWPWD */
|
||||
#endif /* NDBM */
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
/*
|
||||
* Now close the shadow password file, which will cause all
|
||||
* of the entries to be re-written.
|
||||
*/
|
||||
|
||||
if (!spw_close()) {
|
||||
fprintf(stderr, _("%s: can't rewrite shadow password file\n"), Prog);
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, CLOSE_FAIL, SHADOW_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
/*
|
||||
* Close the password file. If any entries were modified, the
|
||||
* file will be re-written.
|
||||
*/
|
||||
|
||||
if (!pw_close()) {
|
||||
fprintf(stderr, _("%s: can't rewrite password file\n"), Prog);
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_ERR, CLOSE_FAIL, PASSWD_FILE));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
cleanup(2);
|
||||
SYSLOG((LOG_INFO, AGE_CHANGED, name));
|
||||
closelog();
|
||||
exit(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup - unlock any locked password files
|
||||
*/
|
||||
|
||||
static void
|
||||
cleanup(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case 2:
|
||||
#ifdef SHADOWPWD
|
||||
spw_unlock ();
|
||||
#endif
|
||||
case 1:
|
||||
pw_unlock ();
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#else /*} !AGING {*/
|
||||
|
||||
/*
|
||||
* chage - but there is no age info!
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *Prog;
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
fprintf (stderr, _("%s: no aging information present\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#endif /*} AGING */
|
||||
|
602
src/chfn.c
Normal file
602
src/chfn.c
Normal file
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: chfn.c,v 1.15 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include "pwio.h"
|
||||
#include "getdef.h"
|
||||
#include "pwauth.h"
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include "pam_defs.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global variables.
|
||||
*/
|
||||
|
||||
static char *Prog;
|
||||
static char fullnm[BUFSIZ];
|
||||
static char roomno[BUFSIZ];
|
||||
static char workph[BUFSIZ];
|
||||
static char homeph[BUFSIZ];
|
||||
static char slop[BUFSIZ];
|
||||
static int amroot;
|
||||
|
||||
/*
|
||||
* External identifiers
|
||||
*/
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
#ifdef NDBM
|
||||
extern int pw_dbm_mode;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* #defines for messages. This facilitates foreign language conversion
|
||||
* since all messages are defined right here.
|
||||
*/
|
||||
|
||||
#define WRONGPWD2 "incorrect password for `%s'"
|
||||
#define PWDBUSY2 "can't lock /etc/passwd\n"
|
||||
#define OPNERROR2 "can't open /etc/passwd\n"
|
||||
#define UPDERROR2 "error updating passwd entry\n"
|
||||
#define DBMERROR2 "error updating DBM passwd entry.\n"
|
||||
#define NOTROOT2 "can't setuid(0).\n"
|
||||
#define CLSERROR2 "can't rewrite /etc/passwd.\n"
|
||||
#define UNLKERROR2 "can't unlock /etc/passwd.\n"
|
||||
#define CHGGECOS "changed user `%s' information.\n"
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static int may_change_field P_((int));
|
||||
static void new_fields P_((void));
|
||||
static char *copy_field P_((char *, char *, char *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - print command line syntax and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
if (amroot)
|
||||
fprintf(stderr,
|
||||
_("Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\t[ -h home_ph ] [ -o other ] [ user ]\n"),
|
||||
Prog);
|
||||
else
|
||||
fprintf(stderr,
|
||||
_("Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"),
|
||||
Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
may_change_field(int field)
|
||||
{
|
||||
const char *cp;
|
||||
|
||||
/*
|
||||
* CHFN_RESTRICT can now specify exactly which fields may be
|
||||
* changed by regular users, by using any combination of the
|
||||
* following letters:
|
||||
* f - full name
|
||||
* r - room number
|
||||
* w - work phone
|
||||
* h - home phone
|
||||
*
|
||||
* This makes it possible to disallow changing the room number
|
||||
* information, for example - this feature was suggested by
|
||||
* Maciej 'Tycoon' Majchrowski.
|
||||
*
|
||||
* For backward compatibility, "yes" is equivalent to "rwh",
|
||||
* "no" is equivalent to "frwh". Only root can change anything
|
||||
* if the string is empty or not defined at all.
|
||||
*/
|
||||
if (amroot)
|
||||
return 1;
|
||||
cp = getdef_str("CHFN_RESTRICT");
|
||||
if (!cp)
|
||||
cp = "";
|
||||
else if (strcmp(cp, "yes") == 0)
|
||||
cp = "rwh";
|
||||
else if (strcmp(cp, "no") == 0)
|
||||
cp = "frwh";
|
||||
if (strchr(cp, field))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* new_fields - change the user's GECOS information interactively
|
||||
*
|
||||
* prompt the user for each of the four fields and fill in the fields
|
||||
* from the user's response, or leave alone if nothing was entered.
|
||||
*/
|
||||
|
||||
static void
|
||||
new_fields(void)
|
||||
{
|
||||
printf(_("Enter the new value, or press return for the default\n"));
|
||||
|
||||
if (may_change_field('f'))
|
||||
change_field(fullnm, sizeof fullnm, _("Full Name"));
|
||||
else
|
||||
printf(_("\tFull Name: %s\n"), fullnm);
|
||||
|
||||
if (may_change_field('r'))
|
||||
change_field(roomno, sizeof roomno, _("Room Number"));
|
||||
else
|
||||
printf(_("\tRoom Number: %s\n"), roomno);
|
||||
|
||||
if (may_change_field('w'))
|
||||
change_field(workph, sizeof workph, _("Work Phone"));
|
||||
else
|
||||
printf(_("\tWork Phone: %s\n"), workph);
|
||||
|
||||
if (may_change_field('h'))
|
||||
change_field(homeph, sizeof homeph, _("Home Phone"));
|
||||
else
|
||||
printf(_("\tHome Phone: %s\n"), homeph);
|
||||
|
||||
if (amroot)
|
||||
change_field(slop, sizeof slop, _("Other"));
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_field - get the next field from the gecos field
|
||||
*
|
||||
* copy_field copies the next field from the gecos field, returning a
|
||||
* pointer to the field which follows, or NULL if there are no more
|
||||
* fields.
|
||||
*
|
||||
* in - the current GECOS field
|
||||
* out - where to copy the field to
|
||||
* extra - fields with '=' get copied here
|
||||
*/
|
||||
|
||||
static char *
|
||||
copy_field(char *in, char *out, char *extra)
|
||||
{
|
||||
char *cp = NULL;
|
||||
|
||||
while (in) {
|
||||
if ((cp = strchr (in, ',')))
|
||||
*cp++ = '\0';
|
||||
|
||||
if (! strchr (in, '='))
|
||||
break;
|
||||
|
||||
if (extra) {
|
||||
if (extra[0])
|
||||
strcat (extra, ",");
|
||||
|
||||
strcat (extra, in);
|
||||
}
|
||||
in = cp;
|
||||
}
|
||||
if (in && out)
|
||||
strcpy (out, in);
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* chfn - change a user's password file information
|
||||
*
|
||||
* This command controls the GECOS field information in the
|
||||
* password file entry.
|
||||
*
|
||||
* The valid options are
|
||||
*
|
||||
* -f full name
|
||||
* -r room number
|
||||
* -w work phone number
|
||||
* -h home phone number
|
||||
* -o other information (*)
|
||||
*
|
||||
* (*) requires root permission to execute.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *cp; /* temporary character pointer */
|
||||
const struct passwd *pw; /* password file entry */
|
||||
struct passwd pwent; /* modified password file entry */
|
||||
char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */
|
||||
char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */
|
||||
int flag; /* flag currently being processed */
|
||||
int fflg = 0; /* -f - set full name */
|
||||
int rflg = 0; /* -r - set room number */
|
||||
int wflg = 0; /* -w - set work phone number */
|
||||
int hflg = 0; /* -h - set home phone number */
|
||||
int oflg = 0; /* -o - set other information */
|
||||
char *user;
|
||||
|
||||
sanitize_env();
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* This command behaves different for root and non-root
|
||||
* users.
|
||||
*/
|
||||
|
||||
amroot = (getuid () == 0);
|
||||
#ifdef NDBM
|
||||
pw_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the program name. The program name is used as a
|
||||
* prefix to most error messages. It is also used as input
|
||||
* to the openlog() function for error logging.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
openlog("chfn", LOG_PID, LOG_AUTH);
|
||||
|
||||
/*
|
||||
* The remaining arguments will be processed one by one and
|
||||
* executed by this command. The name is the last argument
|
||||
* if it does not begin with a "-", otherwise the name is
|
||||
* determined from the environment and must agree with the
|
||||
* real UID. Also, the UID will be checked for any commands
|
||||
* which are restricted to root only.
|
||||
*/
|
||||
|
||||
while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
|
||||
switch (flag) {
|
||||
case 'f':
|
||||
if (!may_change_field('f')) {
|
||||
fprintf(stderr, _("%s: Permission denied.\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
fflg++;
|
||||
STRFCPY(fullnm, optarg);
|
||||
break;
|
||||
case 'r':
|
||||
if (!may_change_field('r')) {
|
||||
fprintf(stderr, _("%s: Permission denied.\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
rflg++;
|
||||
STRFCPY(roomno, optarg);
|
||||
break;
|
||||
case 'w':
|
||||
if (!may_change_field('w')) {
|
||||
fprintf(stderr, _("%s: Permission denied.\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
wflg++;
|
||||
STRFCPY(workph, optarg);
|
||||
break;
|
||||
case 'h':
|
||||
if (!may_change_field('h')) {
|
||||
fprintf(stderr, _("%s: Permission denied.\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
hflg++;
|
||||
STRFCPY(homeph, optarg);
|
||||
break;
|
||||
case 'o':
|
||||
if (!amroot) {
|
||||
fprintf(stderr, _("%s: Permission denied.\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
oflg++;
|
||||
STRFCPY(slop, optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the name of the user to check. It is either
|
||||
* the command line name, or the name getlogin()
|
||||
* returns.
|
||||
*/
|
||||
|
||||
if (optind < argc) {
|
||||
user = argv[optind];
|
||||
pw = getpwnam(user);
|
||||
if (!pw) {
|
||||
fprintf(stderr, _("%s: Unknown user %s\n"), Prog, user);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
pw = get_my_pwent();
|
||||
if (!pw) {
|
||||
fprintf(stderr, _("%s: Cannot determine your user name.\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
user = xstrdup(pw->pw_name);
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
/*
|
||||
* Now we make sure this is a LOCAL password entry for
|
||||
* this user ...
|
||||
*/
|
||||
|
||||
if (__ispwNIS ()) {
|
||||
char *nis_domain;
|
||||
char *nis_master;
|
||||
|
||||
fprintf (stderr, _("%s: cannot change user `%s' on NIS client.\n"), Prog, user);
|
||||
|
||||
if (! yp_get_default_domain (&nis_domain) &&
|
||||
! yp_master (nis_domain, "passwd.byname",
|
||||
&nis_master)) {
|
||||
fprintf (stderr, _("%s: `%s' is the NIS master for this client.\n"), Prog, nis_master);
|
||||
}
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Non-privileged users are only allowed to change the
|
||||
* gecos field if the UID of the user matches the current
|
||||
* real UID.
|
||||
*/
|
||||
|
||||
if (!amroot && pw->pw_uid != getuid()) {
|
||||
fprintf (stderr, _("%s: Permission denied.\n"), Prog);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-privileged users are optionally authenticated
|
||||
* (must enter the password of the user whose information
|
||||
* is being changed) before any changes can be made.
|
||||
* Idea from util-linux chfn/chsh. --marekm
|
||||
*/
|
||||
|
||||
if (!amroot && getdef_bool("CHFN_AUTH"))
|
||||
passwd_check(pw->pw_name, pw->pw_passwd, "chfn");
|
||||
|
||||
/*
|
||||
* Now get the full name. It is the first comma separated field
|
||||
* in the GECOS field.
|
||||
*/
|
||||
|
||||
STRFCPY(old_gecos, pw->pw_gecos);
|
||||
cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop);
|
||||
|
||||
/*
|
||||
* Now get the room number. It is the next comma separated field,
|
||||
* if there is indeed one.
|
||||
*/
|
||||
|
||||
if (cp)
|
||||
cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);
|
||||
|
||||
/*
|
||||
* Now get the work phone number. It is the third field.
|
||||
*/
|
||||
|
||||
if (cp)
|
||||
cp = copy_field (cp, wflg ? (char *) 0:workph, slop);
|
||||
|
||||
/*
|
||||
* Now get the home phone number. It is the fourth field.
|
||||
*/
|
||||
|
||||
if (cp)
|
||||
cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);
|
||||
|
||||
/*
|
||||
* Anything left over is "slop".
|
||||
*/
|
||||
|
||||
if (cp && !oflg) {
|
||||
if (slop[0])
|
||||
strcat (slop, ",");
|
||||
|
||||
strcat (slop, cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* If none of the fields were changed from the command line,
|
||||
* let the user interactively change them.
|
||||
*/
|
||||
|
||||
if (!fflg && !rflg && !wflg && !hflg && !oflg) {
|
||||
printf(_("Changing the user information for %s\n"), user);
|
||||
new_fields();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check all of the fields for valid information
|
||||
*/
|
||||
|
||||
if (valid_field(fullnm, ":,=")) {
|
||||
fprintf(stderr, _("%s: invalid name: \"%s\"\n"), Prog, fullnm);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (valid_field(roomno, ":,=")) {
|
||||
fprintf(stderr, _("%s: invalid room number: \"%s\"\n"), Prog, roomno);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (valid_field(workph, ":,=")) {
|
||||
fprintf(stderr, _("%s: invalid work phone: \"%s\"\n"), Prog, workph);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (valid_field (homeph, ":,=")) {
|
||||
fprintf(stderr, _("%s: invalid home phone: \"%s\"\n"), Prog, homeph);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (valid_field(slop, ":")) {
|
||||
fprintf(stderr, _("%s: \"%s\" contains illegal characters\n"), Prog, slop);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the new GECOS field by plastering all the pieces together,
|
||||
* if they will fit ...
|
||||
*/
|
||||
|
||||
if (strlen(fullnm) + strlen(roomno) + strlen(workph) +
|
||||
strlen(homeph) + strlen(slop) > (unsigned int) 80) {
|
||||
fprintf(stderr, _("%s: fields too long\n"), Prog);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
snprintf(new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
|
||||
fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);
|
||||
|
||||
/*
|
||||
* Before going any further, raise the ulimit to prevent
|
||||
* colliding into a lowered ulimit, and set the real UID
|
||||
* to root to protect against unexpected signals. Any
|
||||
* keyboard signals are set to be ignored.
|
||||
*/
|
||||
|
||||
if (setuid(0)) {
|
||||
fprintf(stderr, _("Cannot change ID to root.\n"));
|
||||
SYSLOG((LOG_ERR, NOTROOT2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
pwd_init();
|
||||
|
||||
/*
|
||||
* The passwd entry is now ready to be committed back to
|
||||
* the password file. Get a lock on the file and open it.
|
||||
*/
|
||||
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("Cannot lock the password file; try again later.\n"));
|
||||
SYSLOG((LOG_WARN, PWDBUSY2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (!pw_open(O_RDWR)) {
|
||||
fprintf(stderr, _("Cannot open the password file.\n"));
|
||||
pw_unlock();
|
||||
SYSLOG((LOG_ERR, OPNERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the entry to update using pw_locate() - we want the real
|
||||
* one from /etc/passwd, not the one from getpwnam() which could
|
||||
* contain the shadow password if (despite the warnings) someone
|
||||
* enables AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm
|
||||
*/
|
||||
pw = pw_locate(user);
|
||||
if (!pw) {
|
||||
pw_unlock();
|
||||
fprintf(stderr,
|
||||
_("%s: %s not found in /etc/passwd\n"), Prog, user);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a copy of the entry, then change the gecos field. The other
|
||||
* fields remain unchanged.
|
||||
*/
|
||||
pwent = *pw;
|
||||
pwent.pw_gecos = new_gecos;
|
||||
|
||||
/*
|
||||
* Update the passwd file entry. If there is a DBM file,
|
||||
* update that entry as well.
|
||||
*/
|
||||
|
||||
if (!pw_update(&pwent)) {
|
||||
fprintf(stderr, _("Error updating the password entry.\n"));
|
||||
pw_unlock();
|
||||
SYSLOG((LOG_ERR, UPDERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
#ifdef NDBM
|
||||
if (pw_dbm_present() && !pw_dbm_update(&pwent)) {
|
||||
fprintf(stderr, _("Error updating the DBM password entry.\n"));
|
||||
pw_unlock ();
|
||||
SYSLOG((LOG_ERR, DBMERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
endpwent();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Changes have all been made, so commit them and unlock the
|
||||
* file.
|
||||
*/
|
||||
|
||||
if (!pw_close()) {
|
||||
fprintf(stderr, _("Cannot commit password file changes.\n"));
|
||||
pw_unlock();
|
||||
SYSLOG((LOG_ERR, CLSERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (!pw_unlock()) {
|
||||
fprintf(stderr, _("Cannot unlock the password file.\n"));
|
||||
SYSLOG((LOG_ERR, UNLKERROR2));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
SYSLOG((LOG_INFO, CHGGECOS, user));
|
||||
closelog();
|
||||
exit (0);
|
||||
}
|
290
src/chpasswd.c
Normal file
290
src/chpasswd.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright 1990 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*
|
||||
* chpasswd - update passwords in batch
|
||||
*
|
||||
* chpasswd reads standard input for a list of colon separated
|
||||
* user names and new passwords. the appropriate password
|
||||
* files are updated to reflect the changes. because the
|
||||
* changes are made in a batch fashion, the user must run
|
||||
* the mkpasswd command after this command terminates since
|
||||
* no password updates occur until the very end.
|
||||
*
|
||||
* 1997/07/29: Modified to take "-e" argument which specifies that
|
||||
* the passwords have already been encrypted.
|
||||
* -- Jay Soffian <jay@lw.net>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: chpasswd.c,v 1.9 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include "pwio.h"
|
||||
#ifdef SHADOWPWD
|
||||
#include "shadowio.h"
|
||||
#endif
|
||||
|
||||
static char *Prog;
|
||||
static int eflg = 0;
|
||||
#ifdef SHADOWPWD
|
||||
static int is_shadow_pwd;
|
||||
#endif
|
||||
|
||||
extern char *crypt_make_salt P_((void));
|
||||
extern char *l64a();
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: %s [-e]\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
char *name;
|
||||
char *newpwd;
|
||||
char *cp;
|
||||
#ifdef SHADOWPWD
|
||||
const struct spwd *sp;
|
||||
struct spwd newsp;
|
||||
#endif
|
||||
const struct passwd *pw;
|
||||
struct passwd newpw;
|
||||
#ifdef ATT_AGE
|
||||
char newage[5];
|
||||
#endif
|
||||
int errors = 0;
|
||||
int line = 0;
|
||||
long now = time ((long *) 0) / (24L*3600L);
|
||||
int ok;
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/* XXX - use getopt() */
|
||||
if (!(argc == 1 || (argc == 2 && !strcmp(argv[1], "-e"))))
|
||||
usage();
|
||||
if (argc == 2)
|
||||
eflg = 1;
|
||||
|
||||
/*
|
||||
* Lock the password file and open it for reading. This will
|
||||
* bring all of the entries into memory where they may be
|
||||
* updated.
|
||||
*/
|
||||
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock password file\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
if (! pw_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open password file\n"), Prog);
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
is_shadow_pwd = spw_file_present();
|
||||
if (is_shadow_pwd) {
|
||||
if (!spw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock shadow file\n"), Prog);
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
if (!spw_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
|
||||
pw_unlock();
|
||||
spw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read each line, separating the user name from the password.
|
||||
* The password entry for each user will be looked up in the
|
||||
* appropriate file (shadow or passwd) and the password changed.
|
||||
* For shadow files the last change date is set directly, for
|
||||
* passwd files the last change date is set in the age only if
|
||||
* aging information is present.
|
||||
*/
|
||||
|
||||
while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
|
||||
line++;
|
||||
if ((cp = strrchr (buf, '\n'))) {
|
||||
*cp = '\0';
|
||||
} else {
|
||||
fprintf(stderr, _("%s: line %d: line too long\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The username is the first field. It is separated
|
||||
* from the password with a ":" character which is
|
||||
* replaced with a NUL to give the new password. The
|
||||
* new password will then be encrypted in the normal
|
||||
* fashion with a new salt generated, unless the '-e'
|
||||
* is given, in which case it is assumed to already be
|
||||
* encrypted.
|
||||
*/
|
||||
|
||||
name = buf;
|
||||
if ((cp = strchr (name, ':'))) {
|
||||
*cp++ = '\0';
|
||||
} else {
|
||||
fprintf(stderr, _("%s: line %d: missing new password\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
newpwd = cp;
|
||||
if (!eflg)
|
||||
cp = pw_encrypt(newpwd, crypt_make_salt());
|
||||
|
||||
/*
|
||||
* Get the password file entry for this user. The user
|
||||
* must already exist.
|
||||
*/
|
||||
|
||||
pw = pw_locate(name);
|
||||
if (!pw) {
|
||||
fprintf (stderr, _("%s: line %d: unknown user %s\n"),
|
||||
Prog, line, name);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd)
|
||||
sp = spw_locate(name);
|
||||
else
|
||||
sp = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The freshly encrypted new password is merged into
|
||||
* the user's password file entry and the last password
|
||||
* change date is set to the current date.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (sp) {
|
||||
newsp = *sp;
|
||||
newsp.sp_pwdp = cp;
|
||||
newsp.sp_lstchg = now;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
newpw = *pw;
|
||||
newpw.pw_passwd = cp;
|
||||
#ifdef ATT_AGE
|
||||
if (newpw.pw_age[0]) {
|
||||
strcpy(newage, newpw.pw_age);
|
||||
strcpy(newage + 2, l64a(now / 7));
|
||||
newpw.pw_age = newage;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The updated password file entry is then put back
|
||||
* and will be written to the password file later, after
|
||||
* all the other entries have been updated as well.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (sp)
|
||||
ok = spw_update(&newsp);
|
||||
else
|
||||
#endif
|
||||
ok = pw_update(&newpw);
|
||||
|
||||
if (!ok) {
|
||||
fprintf(stderr, _("%s: line %d: cannot update password entry\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Any detected errors will cause the entire set of changes
|
||||
* to be aborted. Unlocking the password file will cause
|
||||
* all of the changes to be ignored. Otherwise the file is
|
||||
* closed, causing the changes to be written out all at
|
||||
* once, and then unlocked afterwards.
|
||||
*/
|
||||
|
||||
if (errors) {
|
||||
fprintf(stderr, _("%s: error detected, changes ignored\n"), Prog);
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd)
|
||||
spw_unlock();
|
||||
#endif
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd) {
|
||||
if (!spw_close()) {
|
||||
fprintf(stderr, _("%s: error updating shadow file\n"), Prog);
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
spw_unlock();
|
||||
}
|
||||
#endif
|
||||
if (!pw_close()) {
|
||||
fprintf(stderr, _("%s: error updating password file\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
pw_unlock();
|
||||
|
||||
return (0);
|
||||
}
|
439
src/chsh.c
Normal file
439
src/chsh.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: chsh.c,v 1.15 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include "pwio.h"
|
||||
#include "getdef.h"
|
||||
#include "pwauth.h"
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include "pam_defs.h"
|
||||
#endif
|
||||
|
||||
#ifndef SHELLS_FILE
|
||||
#define SHELLS_FILE "/etc/shells"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global variables.
|
||||
*/
|
||||
|
||||
static char *Prog; /* Program name */
|
||||
static int amroot; /* Real UID is root */
|
||||
static char loginsh[BUFSIZ]; /* Name of new login shell */
|
||||
|
||||
/*
|
||||
* External identifiers
|
||||
*/
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
#ifdef NDBM
|
||||
extern int pw_dbm_mode;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* #defines for messages. This facilitates foreign language conversion
|
||||
* since all messages are defined right here.
|
||||
*/
|
||||
|
||||
#define WRONGPWD2 "incorrect password for `%s'"
|
||||
#define NOPERM2 "can't change shell for `%s'\n"
|
||||
#define PWDBUSY2 "can't lock /etc/passwd\n"
|
||||
#define OPNERROR2 "can't open /etc/passwd\n"
|
||||
#define UPDERROR2 "error updating passwd entry\n"
|
||||
#define DBMERROR2 "error updating DBM passwd entry.\n"
|
||||
#define NOTROOT2 "can't setuid(0).\n"
|
||||
#define CLSERROR2 "can't rewrite /etc/passwd.\n"
|
||||
#define UNLKERROR2 "can't unlock /etc/passwd.\n"
|
||||
#define CHGSHELL "changed user `%s' shell to `%s'\n"
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static void new_fields P_((void));
|
||||
static int restricted_shell P_((const char *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - print command line syntax and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("Usage: %s [ -s shell ] [ name ]\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* new_fields - change the user's login shell information interactively
|
||||
*
|
||||
* prompt the user for the login shell and change it according to the
|
||||
* response, or leave it alone if nothing was entered.
|
||||
*/
|
||||
|
||||
static void
|
||||
new_fields(void)
|
||||
{
|
||||
printf(_("Enter the new value, or press return for the default\n"));
|
||||
change_field(loginsh, sizeof loginsh, _("Login Shell"));
|
||||
}
|
||||
|
||||
/*
|
||||
* restricted_shell - return true if the named shell begins with 'r' or 'R'
|
||||
*
|
||||
* If the first letter of the filename is 'r' or 'R', the shell is
|
||||
* considered to be restricted.
|
||||
*/
|
||||
|
||||
static int
|
||||
restricted_shell(const char *sh)
|
||||
{
|
||||
#if 0
|
||||
char *cp = Basename((char *) sh);
|
||||
return *cp == 'r' || *cp == 'R';
|
||||
#else
|
||||
/*
|
||||
* Shells not listed in /etc/shells are considered to be
|
||||
* restricted. Changed this to avoid confusion with "rc"
|
||||
* (the plan9 shell - not restricted despite the name
|
||||
* starting with 'r'). --marekm
|
||||
*/
|
||||
return !check_shell(sh);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* chsh - this command controls changes to the user's shell
|
||||
*
|
||||
* The only supported option is -s which permits the
|
||||
* the login shell to be set from the command line.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *user; /* User name */
|
||||
int flag; /* Current command line flag */
|
||||
int sflg = 0; /* -s - set shell from command line */
|
||||
const struct passwd *pw; /* Password entry from /etc/passwd */
|
||||
struct passwd pwent; /* New password entry */
|
||||
|
||||
sanitize_env();
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* This command behaves different for root and non-root
|
||||
* users.
|
||||
*/
|
||||
|
||||
amroot = getuid () == 0;
|
||||
#ifdef NDBM
|
||||
pw_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the program name. The program name is used as a
|
||||
* prefix to most error messages. It is also used as input
|
||||
* to the openlog() function for error logging.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
openlog("chsh", LOG_PID, LOG_AUTH);
|
||||
|
||||
/*
|
||||
* There is only one option, but use getopt() anyway to
|
||||
* keep things consistent.
|
||||
*/
|
||||
|
||||
while ((flag = getopt (argc, argv, "s:")) != EOF) {
|
||||
switch (flag) {
|
||||
case 's':
|
||||
sflg++;
|
||||
STRFCPY(loginsh, optarg);
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There should be only one remaining argument at most
|
||||
* and it should be the user's name.
|
||||
*/
|
||||
|
||||
if (argc > optind + 1)
|
||||
usage ();
|
||||
|
||||
/*
|
||||
* Get the name of the user to check. It is either
|
||||
* the command line name, or the name getlogin()
|
||||
* returns.
|
||||
*/
|
||||
|
||||
if (optind < argc) {
|
||||
user = argv[optind];
|
||||
pw = getpwnam(user);
|
||||
if (!pw) {
|
||||
fprintf(stderr,
|
||||
_("%s: Unknown user %s\n"),
|
||||
Prog, user);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
pw = get_my_pwent();
|
||||
if (!pw) {
|
||||
fprintf(stderr,
|
||||
_("%s: Cannot determine your user name.\n"),
|
||||
Prog);
|
||||
exit(1);
|
||||
}
|
||||
user = xstrdup(pw->pw_name);
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
/*
|
||||
* Now we make sure this is a LOCAL password entry for
|
||||
* this user ...
|
||||
*/
|
||||
|
||||
if (__ispwNIS ()) {
|
||||
char *nis_domain;
|
||||
char *nis_master;
|
||||
|
||||
fprintf(stderr,
|
||||
_("%s: cannot change user `%s' on NIS client.\n"),
|
||||
Prog, user);
|
||||
|
||||
if (! yp_get_default_domain (&nis_domain) &&
|
||||
! yp_master (nis_domain, "passwd.byname",
|
||||
&nis_master)) {
|
||||
fprintf(stderr,
|
||||
_("%s: `%s' is the NIS master for this client.\n"),
|
||||
Prog, nis_master);
|
||||
}
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Non-privileged users are only allowed to change the
|
||||
* shell if the UID of the user matches the current
|
||||
* real UID.
|
||||
*/
|
||||
|
||||
if (! amroot && pw->pw_uid != getuid()) {
|
||||
SYSLOG((LOG_WARN, NOPERM2, user));
|
||||
closelog();
|
||||
fprintf(stderr, _("You may not change the shell for %s.\n"),
|
||||
user);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-privileged users are only allowed to change the
|
||||
* shell if it is not a restricted one.
|
||||
*/
|
||||
|
||||
if (! amroot && restricted_shell(pw->pw_shell)) {
|
||||
SYSLOG((LOG_WARN, NOPERM2, user));
|
||||
closelog();
|
||||
fprintf(stderr, _("You may not change the shell for %s.\n"),
|
||||
user);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-privileged users are optionally authenticated
|
||||
* (must enter the password of the user whose information
|
||||
* is being changed) before any changes can be made.
|
||||
* Idea from util-linux chfn/chsh. --marekm
|
||||
*/
|
||||
|
||||
if (!amroot && getdef_bool("CHFN_AUTH"))
|
||||
passwd_check(pw->pw_name, pw->pw_passwd, "chsh");
|
||||
|
||||
/*
|
||||
* Now get the login shell. Either get it from the password
|
||||
* file, or use the value from the command line.
|
||||
*/
|
||||
|
||||
if (! sflg)
|
||||
STRFCPY(loginsh, pw->pw_shell);
|
||||
|
||||
/*
|
||||
* If the login shell was not set on the command line,
|
||||
* let the user interactively change it.
|
||||
*/
|
||||
|
||||
if (! sflg) {
|
||||
printf(_("Changing the login shell for %s\n"), user);
|
||||
new_fields();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check all of the fields for valid information. The shell
|
||||
* field may not contain any illegal characters. Non-privileged
|
||||
* users are restricted to using the shells in /etc/shells.
|
||||
* The shell must be executable by the user.
|
||||
*/
|
||||
|
||||
if (valid_field (loginsh, ":,=")) {
|
||||
fprintf(stderr, _("%s: Invalid entry: %s\n"), Prog, loginsh);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
if (!amroot && (!check_shell(loginsh) || access(loginsh, X_OK) != 0)) {
|
||||
fprintf(stderr, _("%s is an invalid shell.\n"), loginsh);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Before going any further, raise the ulimit to prevent
|
||||
* colliding into a lowered ulimit, and set the real UID
|
||||
* to root to protect against unexpected signals. Any
|
||||
* keyboard signals are set to be ignored.
|
||||
*/
|
||||
|
||||
if (setuid(0)) {
|
||||
SYSLOG((LOG_ERR, NOTROOT2));
|
||||
closelog();
|
||||
fprintf (stderr, _("Cannot change ID to root.\n"));
|
||||
exit(1);
|
||||
}
|
||||
pwd_init();
|
||||
|
||||
/*
|
||||
* The passwd entry is now ready to be committed back to
|
||||
* the password file. Get a lock on the file and open it.
|
||||
*/
|
||||
|
||||
if (!pw_lock()) {
|
||||
SYSLOG((LOG_WARN, PWDBUSY2));
|
||||
closelog();
|
||||
fprintf(stderr,
|
||||
_("Cannot lock the password file; try again later.\n"));
|
||||
exit(1);
|
||||
}
|
||||
if (! pw_open (O_RDWR)) {
|
||||
SYSLOG((LOG_ERR, OPNERROR2));
|
||||
closelog();
|
||||
fprintf(stderr, _("Cannot open the password file.\n"));
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the entry to update using pw_locate() - we want the real
|
||||
* one from /etc/passwd, not the one from getpwnam() which could
|
||||
* contain the shadow password if (despite the warnings) someone
|
||||
* enables AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm
|
||||
*/
|
||||
pw = pw_locate(user);
|
||||
if (!pw) {
|
||||
pw_unlock();
|
||||
fprintf(stderr,
|
||||
_("%s: %s not found in /etc/passwd\n"), Prog, user);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a copy of the entry, then change the shell field. The other
|
||||
* fields remain unchanged.
|
||||
*/
|
||||
pwent = *pw;
|
||||
pwent.pw_shell = loginsh;
|
||||
|
||||
/*
|
||||
* Update the passwd file entry. If there is a DBM file,
|
||||
* update that entry as well.
|
||||
*/
|
||||
|
||||
if (!pw_update(&pwent)) {
|
||||
SYSLOG((LOG_ERR, UPDERROR2));
|
||||
closelog();
|
||||
fprintf(stderr, _("Error updating the password entry.\n"));
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
#ifdef NDBM
|
||||
if (pw_dbm_present() && ! pw_dbm_update (&pwent)) {
|
||||
SYSLOG((LOG_ERR, DBMERROR2));
|
||||
closelog();
|
||||
fprintf (stderr, _("Error updating the DBM password entry.\n"));
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
endpwent();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Changes have all been made, so commit them and unlock the
|
||||
* file.
|
||||
*/
|
||||
|
||||
if (!pw_close()) {
|
||||
SYSLOG((LOG_ERR, CLSERROR2));
|
||||
closelog();
|
||||
fprintf(stderr, _("Cannot commit password file changes.\n"));
|
||||
pw_unlock();
|
||||
exit(1);
|
||||
}
|
||||
if (!pw_unlock()) {
|
||||
SYSLOG((LOG_ERR, UNLKERROR2));
|
||||
closelog();
|
||||
fprintf(stderr, _("Cannot unlock the password file.\n"));
|
||||
exit(1);
|
||||
}
|
||||
SYSLOG((LOG_INFO, CHGSHELL, user, loginsh));
|
||||
closelog();
|
||||
exit (0);
|
||||
}
|
261
src/dpasswd.c
Normal file
261
src/dpasswd.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 1990 - 1993, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: dpasswd.c,v 1.9 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "dialup.h"
|
||||
|
||||
#define DTMP "/etc/d_passwd.tmp"
|
||||
|
||||
/*
|
||||
* Prompts and messages go here.
|
||||
*/
|
||||
|
||||
#define DIALCHG "changed password for %s\n"
|
||||
#define DIALADD "added password for %s\n"
|
||||
#define DIALREM "removed password for %s\n"
|
||||
|
||||
static int aflg = 0;
|
||||
static int dflg = 0;
|
||||
static char *Prog;
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
extern char *crypt_make_salt P_((void));
|
||||
extern char *getpass();
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
int main P_((int, char **));
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("Usage: %s [ -(a|d) ] shell\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct dialup *dial;
|
||||
struct dialup dent;
|
||||
struct stat sb;
|
||||
FILE *fp;
|
||||
char *sh = 0;
|
||||
char *cp;
|
||||
char pass[BUFSIZ];
|
||||
int fd;
|
||||
int found = 0;
|
||||
int opt;
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
while ((opt = getopt (argc, argv, "a:d:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
aflg++;
|
||||
sh = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dflg++;
|
||||
sh = optarg;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
if (! aflg && ! dflg)
|
||||
aflg++;
|
||||
|
||||
if (! sh) {
|
||||
if (optind >= argc)
|
||||
usage ();
|
||||
else
|
||||
sh = argv[optind];
|
||||
}
|
||||
if (aflg + dflg != 1)
|
||||
usage ();
|
||||
|
||||
/*
|
||||
* Add a new shell to the password file, or update an existing
|
||||
* entry. Begin by getting an encrypted password for this
|
||||
* shell.
|
||||
*/
|
||||
|
||||
if (aflg) {
|
||||
int tries = 3;
|
||||
|
||||
dent.du_shell = sh;
|
||||
dent.du_passwd = ""; /* XXX warning: const */
|
||||
|
||||
again:
|
||||
if (! (cp = getpass(_("Shell password:"))))
|
||||
exit (1);
|
||||
|
||||
STRFCPY(pass, cp);
|
||||
strzero(cp);
|
||||
|
||||
if (! (cp = getpass(_("re-enter Shell password:"))))
|
||||
exit (1);
|
||||
|
||||
if (strcmp (pass, cp)) {
|
||||
strzero(pass);
|
||||
strzero(cp);
|
||||
fprintf(stderr,
|
||||
_("%s: Passwords do not match, try again.\n"),
|
||||
Prog);
|
||||
|
||||
if (--tries)
|
||||
goto again;
|
||||
|
||||
exit(1);
|
||||
}
|
||||
strzero(cp);
|
||||
dent.du_passwd = pw_encrypt(pass, crypt_make_salt());
|
||||
strzero(pass);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the temporary file for the updated dialup password
|
||||
* information to be placed into. Turn it into a (FILE *)
|
||||
* for use by putduent().
|
||||
*/
|
||||
|
||||
if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) {
|
||||
snprintf(pass, sizeof pass, _("%s: can't create %s"), Prog, DTMP);
|
||||
perror (pass);
|
||||
exit (1);
|
||||
}
|
||||
if (! (fp = fdopen (fd, "r+"))) {
|
||||
snprintf(pass, sizeof pass, _("%s: can't open %s"), Prog, DTMP);
|
||||
perror (pass);
|
||||
unlink (DTMP);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan the dialup password file for the named entry,
|
||||
* copying out other entries along the way. Copying
|
||||
* stops when a match is found or the file runs out.
|
||||
*/
|
||||
|
||||
while ((dial = getduent ())) {
|
||||
if (strcmp (dial->du_shell, sh) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (putduent (dial, fp))
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* To delete the entry, just don't copy it. To update
|
||||
* the entry, output the modified version - works with
|
||||
* new entries as well.
|
||||
*/
|
||||
|
||||
if (dflg && ! found) {
|
||||
fprintf(stderr, _("%s: Shell %s not found.\n"), Prog, sh);
|
||||
goto failure;
|
||||
}
|
||||
if (aflg)
|
||||
if (putduent (&dent, fp))
|
||||
goto failure;
|
||||
|
||||
/*
|
||||
* Now copy out the remaining entries. Flush and close the
|
||||
* new file before doing anything nasty to the existing
|
||||
* file.
|
||||
*/
|
||||
|
||||
|
||||
while ((dial = getduent ()))
|
||||
if (putduent (dial, fp))
|
||||
goto failure;
|
||||
|
||||
if (fflush (fp))
|
||||
goto failure;
|
||||
|
||||
fclose (fp);
|
||||
|
||||
/*
|
||||
* If the original file did not exist, we must create a new
|
||||
* file with owner "root" and mode 400. Otherwise we copy
|
||||
* the modes from the existing file to the new file.
|
||||
*
|
||||
* After this is done the new file will replace the old file.
|
||||
*/
|
||||
|
||||
pwd_init();
|
||||
|
||||
if (! stat (DIALPWD, &sb)) {
|
||||
chown (DTMP, sb.st_uid, sb.st_gid);
|
||||
chmod (DTMP, sb.st_mode);
|
||||
unlink (DIALPWD);
|
||||
} else {
|
||||
chown (DTMP, 0, 0);
|
||||
chmod (DTMP, 0400);
|
||||
}
|
||||
if (! link (DTMP, DIALPWD))
|
||||
unlink (DTMP);
|
||||
|
||||
if (aflg && ! found)
|
||||
SYSLOG((LOG_INFO, DIALADD, sh));
|
||||
else if (aflg && found)
|
||||
SYSLOG((LOG_INFO, DIALCHG, sh));
|
||||
else if (dflg)
|
||||
SYSLOG((LOG_INFO, DIALREM, sh));
|
||||
|
||||
closelog();
|
||||
sync ();
|
||||
exit (0);
|
||||
|
||||
failure:
|
||||
unlink (DTMP);
|
||||
closelog();
|
||||
exit (1);
|
||||
}
|
211
src/expiry.c
Normal file
211
src/expiry.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: expiry.c,v 1.8 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
|
||||
#ifndef AGING
|
||||
#if defined(HAVE_USERSEC_H) || defined(SHADOWPWD)
|
||||
#define AGING 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main P_((int, char **));
|
||||
|
||||
#if !defined(SHADOWPWD) && !defined(AGING) /*{*/
|
||||
|
||||
/*
|
||||
* Not much to do here ...
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#else /*} AGING || SHADOWPWD {*/
|
||||
|
||||
/* local function prototypes */
|
||||
static RETSIGTYPE catch P_((int));
|
||||
static void usage P_((void));
|
||||
|
||||
/*
|
||||
* catch - signal catcher
|
||||
*/
|
||||
|
||||
static RETSIGTYPE
|
||||
catch(int sig)
|
||||
{
|
||||
exit (10);
|
||||
}
|
||||
|
||||
/*
|
||||
* usage - print syntax message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("Usage: expiry { -f | -c }\n"));
|
||||
exit(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* expiry - check and enforce password expiration policy
|
||||
*
|
||||
* expiry checks (-c) the current password expiraction and
|
||||
* forces (-f) changes when required. It is callable as a
|
||||
* normal user command.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
#ifdef SHADOWPWD
|
||||
struct spwd *spwd;
|
||||
#endif
|
||||
char *Prog = argv[0];
|
||||
|
||||
sanitize_env();
|
||||
|
||||
/*
|
||||
* Start by disabling all of the keyboard signals.
|
||||
*/
|
||||
|
||||
signal (SIGHUP, catch);
|
||||
signal (SIGINT, catch);
|
||||
signal (SIGQUIT, catch);
|
||||
#ifdef SIGTSTP
|
||||
signal (SIGTSTP, catch);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* expiry takes one of two arguments. The default action
|
||||
* is to give the usage message.
|
||||
*/
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc != 2 || (strcmp (argv[1], "-f") && strcmp (argv[1], "-c")))
|
||||
usage ();
|
||||
|
||||
#if 0 /* could be setgid shadow with /etc/shadow mode 0640 */
|
||||
/*
|
||||
* Make sure I am root. Can't open /etc/shadow without root
|
||||
* authority.
|
||||
*/
|
||||
|
||||
if (geteuid () != 0) {
|
||||
fprintf(stderr, _("%s: WARNING! Must be set-UID root!\n"),
|
||||
argv[0]);
|
||||
exit(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get user entries for /etc/passwd and /etc/shadow
|
||||
*/
|
||||
|
||||
if (!(pwd = get_my_pwent())) {
|
||||
fprintf(stderr, _("%s: unknown user\n"), Prog);
|
||||
exit(10);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
spwd = getspnam(pwd->pw_name);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If checking accounts, use agecheck() function.
|
||||
*/
|
||||
|
||||
if (strcmp (argv[1], "-c") == 0) {
|
||||
|
||||
/*
|
||||
* Print out number of days until expiration.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
agecheck (pwd, spwd);
|
||||
#else
|
||||
agecheck (pwd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exit with status indicating state of account --
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
exit (isexpired (pwd, spwd));
|
||||
#else
|
||||
exit (isexpired (pwd));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* If forcing password change, use expire() function.
|
||||
*/
|
||||
|
||||
if (strcmp (argv[1], "-f") == 0) {
|
||||
|
||||
/*
|
||||
* Just call expire(). It will force the change
|
||||
* or give a message indicating what to do. And
|
||||
* it doesn't return at all unless the account
|
||||
* is unexpired.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
expire (pwd, spwd);
|
||||
#else
|
||||
expire (pwd);
|
||||
#endif
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't get here ...
|
||||
*/
|
||||
|
||||
usage ();
|
||||
exit (1);
|
||||
}
|
||||
#endif /*}*/
|
380
src/faillog.c
Normal file
380
src/faillog.c
Normal file
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright 1989 - 1993, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: faillog.c,v 1.9 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "faillog.h"
|
||||
|
||||
static char *Prog; /* program name */
|
||||
static FILE *fail; /* failure file stream */
|
||||
static uid_t user; /* one single user, specified on command line */
|
||||
static int days; /* number of days to consider for print command */
|
||||
static time_t seconds; /* that number of days in seconds */
|
||||
|
||||
static int
|
||||
aflg = 0, /* set if all users are to be printed always */
|
||||
uflg = 0, /* set if user is a valid user id */
|
||||
tflg = 0; /* print is restricted to most recent days */
|
||||
|
||||
static struct stat statbuf; /* fstat buffer for file size */
|
||||
|
||||
#if !defined(UNISTD_H) && !defined(STDLIB_H)
|
||||
extern char *optarg;
|
||||
#endif
|
||||
|
||||
#define NOW (time((time_t *) 0))
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
int main P_((int, char **));
|
||||
static void print P_((void));
|
||||
static void print_one P_((const struct faillog *, uid_t));
|
||||
static void reset P_((void));
|
||||
static int reset_one P_((uid_t));
|
||||
static void setmax P_((int));
|
||||
static void setmax_one P_((uid_t, int));
|
||||
static void set_locktime P_((long));
|
||||
static void set_locktime_one P_((uid_t, long));
|
||||
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
_("usage: %s [-a|-u user] [-m max] [-r] [-t days] [-l locksecs]\n"),
|
||||
Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c, anyflag = 0;
|
||||
struct passwd *pwent;
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/* try to open for read/write, if that fails - read only */
|
||||
|
||||
fail = fopen(FAILLOG_FILE, "r+");
|
||||
if (!fail)
|
||||
fail = fopen(FAILLOG_FILE, "r");
|
||||
if (!fail) {
|
||||
perror(FAILLOG_FILE);
|
||||
exit(1);
|
||||
}
|
||||
while ((c = getopt(argc, argv, "al:m:pru:t:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
aflg++;
|
||||
if (uflg)
|
||||
usage();
|
||||
break;
|
||||
case 'l':
|
||||
set_locktime((long) atoi(optarg));
|
||||
anyflag++;
|
||||
break;
|
||||
case 'm':
|
||||
setmax(atoi(optarg));
|
||||
anyflag++;
|
||||
break;
|
||||
case 'p':
|
||||
print();
|
||||
anyflag++;
|
||||
break;
|
||||
case 'r':
|
||||
reset();
|
||||
anyflag++;
|
||||
break;
|
||||
case 'u':
|
||||
if (aflg)
|
||||
usage();
|
||||
|
||||
pwent = getpwnam(optarg);
|
||||
if (!pwent) {
|
||||
fprintf(stderr, _("Unknown User: %s\n"), optarg);
|
||||
exit(1);
|
||||
}
|
||||
uflg++;
|
||||
user = pwent->pw_uid;
|
||||
break;
|
||||
case 't':
|
||||
days = atoi(optarg);
|
||||
seconds = days * DAY;
|
||||
tflg++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
/* no flags implies -a -p (= print information for all users) */
|
||||
if (!(anyflag || aflg || tflg || uflg))
|
||||
aflg++;
|
||||
/* (-a or -t days or -u user) and no other flags implies -p
|
||||
(= print information for selected users) */
|
||||
if (!anyflag && (aflg || tflg || uflg))
|
||||
print();
|
||||
fclose(fail);
|
||||
return 0;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
static void
|
||||
print(void)
|
||||
{
|
||||
uid_t uid;
|
||||
off_t offset;
|
||||
struct faillog faillog;
|
||||
|
||||
if (uflg) {
|
||||
offset = user * sizeof faillog;
|
||||
if (fstat(fileno(fail), &statbuf)) {
|
||||
perror(FAILLOG_FILE);
|
||||
return;
|
||||
}
|
||||
if (offset >= statbuf.st_size)
|
||||
return;
|
||||
|
||||
fseek(fail, (off_t) user * sizeof faillog, SEEK_SET);
|
||||
if (fread((char *) &faillog, sizeof faillog, 1, fail) == 1)
|
||||
print_one(&faillog, user);
|
||||
else
|
||||
perror(FAILLOG_FILE);
|
||||
} else {
|
||||
for (uid = 0;
|
||||
fread((char *) &faillog, sizeof faillog, 1, fail) == 1;
|
||||
uid++) {
|
||||
|
||||
if (aflg == 0 && faillog.fail_cnt == 0)
|
||||
continue;
|
||||
|
||||
if (aflg == 0 && tflg &&
|
||||
NOW - faillog.fail_time > seconds)
|
||||
continue;
|
||||
|
||||
if (aflg && faillog.fail_time == 0)
|
||||
continue;
|
||||
|
||||
print_one(&faillog, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_one(const struct faillog *fl, uid_t uid)
|
||||
{
|
||||
static int once;
|
||||
char *cp;
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
struct passwd *pwent;
|
||||
#ifdef HAVE_STRFTIME
|
||||
char ptime[80];
|
||||
#endif
|
||||
|
||||
if (!once) {
|
||||
printf(_("Username Failures Maximum Latest\n"));
|
||||
once++;
|
||||
}
|
||||
pwent = getpwuid(uid);
|
||||
time(&now);
|
||||
tm = localtime(&fl->fail_time);
|
||||
#ifdef HAVE_STRFTIME
|
||||
strftime(ptime, sizeof(ptime), "%a %b %e %H:%M:%S %z %Y",tm);
|
||||
cp = ptime;
|
||||
#else
|
||||
cp = asctime(tm);
|
||||
cp[24] = '\0';
|
||||
#endif
|
||||
if (pwent) {
|
||||
printf("%-12s %4d %4d",
|
||||
pwent->pw_name, fl->fail_cnt, fl->fail_max);
|
||||
if (fl->fail_time) {
|
||||
printf(_(" %s on %s"), cp, fl->fail_line);
|
||||
if (fl->fail_locktime) {
|
||||
if (fl->fail_time + fl->fail_locktime > now
|
||||
&& fl->fail_cnt)
|
||||
printf(_(" [%lds left]"),
|
||||
fl->fail_time + fl->fail_locktime - now);
|
||||
else
|
||||
printf(_(" [%lds lock]"), fl->fail_locktime);
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reset(void)
|
||||
{
|
||||
uid_t uid;
|
||||
|
||||
if (uflg)
|
||||
reset_one(user);
|
||||
else
|
||||
for (uid = 0; reset_one(uid); uid++)
|
||||
;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_one(uid_t uid)
|
||||
{
|
||||
off_t offset;
|
||||
struct faillog faillog;
|
||||
|
||||
offset = uid * sizeof faillog;
|
||||
if (fstat(fileno(fail), &statbuf)) {
|
||||
perror(FAILLOG_FILE);
|
||||
return 0;
|
||||
}
|
||||
if (offset >= statbuf.st_size)
|
||||
return 0;
|
||||
|
||||
if (fseek(fail, offset, SEEK_SET) != 0) {
|
||||
perror(FAILLOG_FILE);
|
||||
return 0;
|
||||
}
|
||||
if (fread((char *) &faillog, sizeof faillog, 1, fail) != 1) {
|
||||
if (!feof(fail))
|
||||
perror(FAILLOG_FILE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (faillog.fail_cnt == 0)
|
||||
return 1; /* don't fill in no holes ... */
|
||||
|
||||
faillog.fail_cnt = 0;
|
||||
|
||||
if (fseek(fail, offset, SEEK_SET) == 0
|
||||
&& fwrite((char *) &faillog, sizeof faillog, 1, fail) == 1) {
|
||||
fflush(fail);
|
||||
return 1;
|
||||
} else {
|
||||
perror(FAILLOG_FILE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setmax(int max)
|
||||
{
|
||||
struct passwd *pwent;
|
||||
|
||||
if (uflg) {
|
||||
setmax_one(user, max);
|
||||
} else {
|
||||
setpwent();
|
||||
while ((pwent = getpwent()))
|
||||
setmax_one(pwent->pw_uid, max);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setmax_one(uid_t uid, int max)
|
||||
{
|
||||
off_t offset;
|
||||
struct faillog faillog;
|
||||
|
||||
offset = uid * sizeof faillog;
|
||||
|
||||
if (fseek(fail, offset, SEEK_SET) != 0) {
|
||||
perror(FAILLOG_FILE);
|
||||
return;
|
||||
}
|
||||
if (fread((char *) &faillog, sizeof faillog, 1, fail) != 1) {
|
||||
if (!feof(fail))
|
||||
perror(FAILLOG_FILE);
|
||||
memzero(&faillog, sizeof faillog);
|
||||
}
|
||||
faillog.fail_max = max;
|
||||
|
||||
if (fseek(fail, offset, SEEK_SET) == 0
|
||||
&& fwrite((char *) &faillog, sizeof faillog, 1, fail) == 1)
|
||||
fflush(fail);
|
||||
else
|
||||
perror(FAILLOG_FILE);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - this needs to be written properly some day, right now it is
|
||||
* a quick cut-and-paste hack from the above two functions. --marekm
|
||||
*/
|
||||
static void
|
||||
set_locktime(long locktime)
|
||||
{
|
||||
struct passwd *pwent;
|
||||
|
||||
if (uflg) {
|
||||
set_locktime_one(user, locktime);
|
||||
} else {
|
||||
setpwent();
|
||||
while ((pwent = getpwent()))
|
||||
set_locktime_one(pwent->pw_uid, locktime);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_locktime_one(uid_t uid, long locktime)
|
||||
{
|
||||
off_t offset;
|
||||
struct faillog faillog;
|
||||
|
||||
offset = uid * sizeof faillog;
|
||||
|
||||
if (fseek(fail, offset, SEEK_SET) != 0) {
|
||||
perror(FAILLOG_FILE);
|
||||
return;
|
||||
}
|
||||
if (fread((char *) &faillog, sizeof faillog, 1, fail) != 1) {
|
||||
if (!feof(fail))
|
||||
perror(FAILLOG_FILE);
|
||||
memzero(&faillog, sizeof faillog);
|
||||
}
|
||||
faillog.fail_locktime = locktime;
|
||||
|
||||
if (fseek(fail, offset, SEEK_SET) == 0
|
||||
&& fwrite((char *) &faillog, sizeof faillog, 1, fail) == 1)
|
||||
fflush(fail);
|
||||
else
|
||||
perror(FAILLOG_FILE);
|
||||
}
|
662
src/gpasswd.c
Normal file
662
src/gpasswd.c
Normal file
@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright 1990 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: gpasswd.c,v 1.14 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include "groupio.h"
|
||||
#ifdef SHADOWGRP
|
||||
#include "sgroupio.h"
|
||||
#endif
|
||||
|
||||
static char *Prog;
|
||||
#ifdef SHADOWGRP
|
||||
static int is_shadowgrp;
|
||||
#endif
|
||||
|
||||
static int
|
||||
aflg = 0,
|
||||
Aflg = 0,
|
||||
dflg = 0,
|
||||
Mflg = 0,
|
||||
rflg = 0,
|
||||
Rflg = 0;
|
||||
|
||||
#ifndef RETRIES
|
||||
#define RETRIES 3
|
||||
#endif
|
||||
|
||||
extern char *crypt_make_salt P_((void));
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
#ifdef NDBM
|
||||
#ifdef SHADOWGRP
|
||||
extern int sg_dbm_mode;
|
||||
#endif
|
||||
extern int gr_dbm_mode;
|
||||
#endif
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static RETSIGTYPE die P_((int));
|
||||
static int check_list P_((const char *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: %s [-r|-R] group\n"), Prog);
|
||||
fprintf(stderr, _(" %s [-a user] group\n"), Prog);
|
||||
fprintf(stderr, _(" %s [-d user] group\n"), Prog);
|
||||
#ifdef SHADOWGRP
|
||||
fprintf(stderr, _(" %s [-A user,...] [-M user,...] group\n"),
|
||||
Prog);
|
||||
#else
|
||||
fprintf(stderr, _(" %s [-M user,...] group\n"), Prog);
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* die - set or reset termio modes.
|
||||
*
|
||||
* die() is called before processing begins. signal() is then
|
||||
* called with die() as the signal handler. If signal later
|
||||
* calls die() with a signal number, the terminal modes are
|
||||
* then reset.
|
||||
*/
|
||||
|
||||
static RETSIGTYPE
|
||||
die(int killed)
|
||||
{
|
||||
static TERMIO sgtty;
|
||||
|
||||
if (killed)
|
||||
STTY(0, &sgtty);
|
||||
else
|
||||
GTTY(0, &sgtty);
|
||||
|
||||
if (killed) {
|
||||
putchar ('\n');
|
||||
fflush (stdout);
|
||||
exit (killed);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check_list - check a comma-separated list of user names for validity
|
||||
*
|
||||
* check_list scans a comma-separated list of user names and checks
|
||||
* that each listed name exists.
|
||||
*/
|
||||
|
||||
static int
|
||||
check_list(const char *users)
|
||||
{
|
||||
const char *start, *end;
|
||||
char username[32];
|
||||
int errors = 0;
|
||||
int len;
|
||||
|
||||
for (start = users; start && *start; start = end) {
|
||||
if ((end = strchr (start, ','))) {
|
||||
len = end - start;
|
||||
end++;
|
||||
} else {
|
||||
len = strlen(start);
|
||||
}
|
||||
|
||||
if (len > sizeof(username) - 1)
|
||||
len = sizeof(username) - 1;
|
||||
strncpy(username, start, len);
|
||||
username[len] = '\0';
|
||||
|
||||
/*
|
||||
* This user must exist.
|
||||
*/
|
||||
|
||||
if (!getpwnam(username)) {
|
||||
fprintf(stderr, _("%s: unknown user %s\n"),
|
||||
Prog, username);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
failure(void)
|
||||
{
|
||||
fprintf(stderr, _("Permission denied.\n"));
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* gpasswd - administer the /etc/group file
|
||||
*
|
||||
* -a user add user to the named group
|
||||
* -d user remove user from the named group
|
||||
* -r remove password from the named group
|
||||
* -R restrict access to the named group
|
||||
* -A user,... make list of users the administrative users
|
||||
* -M user,... make list of users the group members
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int flag;
|
||||
char *cp;
|
||||
int amroot;
|
||||
int retries;
|
||||
struct group *gr = NULL;
|
||||
struct group grent;
|
||||
static char pass[BUFSIZ];
|
||||
#ifdef SHADOWGRP
|
||||
struct sgrp *sg = NULL;
|
||||
struct sgrp sgent;
|
||||
char *admins = NULL;
|
||||
#endif
|
||||
struct passwd *pw = NULL;
|
||||
char *myname;
|
||||
char *user = NULL;
|
||||
char *group = NULL;
|
||||
char *members = NULL;
|
||||
|
||||
sanitize_env();
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* Make a note of whether or not this command was invoked
|
||||
* by root. This will be used to bypass certain checks
|
||||
* later on. Also, set the real user ID to match the
|
||||
* effective user ID. This will prevent the invoker from
|
||||
* issuing signals which would interfer with this command.
|
||||
*/
|
||||
|
||||
amroot = getuid () == 0;
|
||||
#ifdef NDBM
|
||||
#ifdef SHADOWGRP
|
||||
sg_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
gr_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
openlog("gpasswd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
setbuf (stdout, (char *) 0);
|
||||
setbuf (stderr, (char *) 0);
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
is_shadowgrp = sgr_file_present();
|
||||
#endif
|
||||
while ((flag = getopt (argc, argv, "a:d:grRA:M:")) != EOF) {
|
||||
switch (flag) {
|
||||
case 'a': /* add a user */
|
||||
user = optarg;
|
||||
if (!getpwnam(user)) {
|
||||
fprintf(stderr, _("%s: unknown user %s\n"),
|
||||
Prog, user);
|
||||
exit(1);
|
||||
}
|
||||
aflg++;
|
||||
break;
|
||||
#ifdef SHADOWGRP
|
||||
case 'A':
|
||||
if (!amroot)
|
||||
failure();
|
||||
if (!is_shadowgrp) {
|
||||
fprintf(stderr,
|
||||
_("%s: shadow group passwords required for -A\n"),
|
||||
Prog);
|
||||
exit(2);
|
||||
}
|
||||
admins = optarg;
|
||||
if (check_list(admins))
|
||||
exit(1);
|
||||
Aflg++;
|
||||
break;
|
||||
#endif
|
||||
case 'd': /* delete a user */
|
||||
dflg++;
|
||||
user = optarg;
|
||||
break;
|
||||
case 'g': /* no-op from normal password */
|
||||
break;
|
||||
case 'M':
|
||||
if (!amroot)
|
||||
failure();
|
||||
members = optarg;
|
||||
if (check_list(members))
|
||||
exit(1);
|
||||
Mflg++;
|
||||
break;
|
||||
case 'r': /* remove group password */
|
||||
rflg++;
|
||||
break;
|
||||
case 'R': /* restrict group password */
|
||||
Rflg++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure exclusive flags are exclusive
|
||||
*/
|
||||
|
||||
if (aflg + dflg + rflg + Rflg + (Aflg || Mflg) > 1)
|
||||
usage ();
|
||||
|
||||
/*
|
||||
* Determine the name of the user that invoked this command.
|
||||
* This is really hit or miss because there are so many ways
|
||||
* that command can be executed and so many ways to trip up
|
||||
* the routines that report the user name.
|
||||
*/
|
||||
|
||||
pw = get_my_pwent();
|
||||
if (!pw) {
|
||||
fprintf(stderr, _("Who are you?\n"));
|
||||
exit(1);
|
||||
}
|
||||
myname = xstrdup(pw->pw_name);
|
||||
|
||||
/*
|
||||
* Get the name of the group that is being affected. The group
|
||||
* entry will be completely replicated so it may be modified
|
||||
* later on.
|
||||
*/
|
||||
|
||||
/*
|
||||
* XXX - should get the entry using gr_locate() and modify
|
||||
* that, getgrnam() could give us a NIS group. --marekm
|
||||
*/
|
||||
|
||||
if (! (group = argv[optind]))
|
||||
usage ();
|
||||
|
||||
if (! (gr = getgrnam (group))) {
|
||||
fprintf (stderr, _("unknown group: %s\n"), group);
|
||||
exit (1);
|
||||
}
|
||||
grent = *gr;
|
||||
grent.gr_name = xstrdup(gr->gr_name);
|
||||
grent.gr_passwd = xstrdup(gr->gr_passwd);
|
||||
|
||||
grent.gr_mem = dup_list(gr->gr_mem);
|
||||
#ifdef SHADOWGRP
|
||||
if ((sg = getsgnam (group))) {
|
||||
sgent = *sg;
|
||||
sgent.sg_name = xstrdup(sg->sg_name);
|
||||
sgent.sg_passwd = xstrdup(sg->sg_passwd);
|
||||
|
||||
sgent.sg_mem = dup_list(sg->sg_mem);
|
||||
sgent.sg_adm = dup_list(sg->sg_adm);
|
||||
} else {
|
||||
sgent.sg_name = xstrdup(group);
|
||||
sgent.sg_passwd = grent.gr_passwd;
|
||||
grent.gr_passwd = "!"; /* XXX warning: const */
|
||||
|
||||
sgent.sg_mem = dup_list(grent.gr_mem);
|
||||
|
||||
sgent.sg_adm = (char **) xmalloc(sizeof(char *) * 2);
|
||||
#ifdef FIRST_MEMBER_IS_ADMIN
|
||||
if (sgent.sg_mem[0]) {
|
||||
sgent.sg_adm[0] = xstrdup(sgent.sg_mem[0]);
|
||||
sgent.sg_adm[1] = 0;
|
||||
} else
|
||||
#endif
|
||||
sgent.sg_adm[0] = 0;
|
||||
|
||||
sg = &sgent;
|
||||
}
|
||||
|
||||
/*
|
||||
* The policy here for changing a group is that 1) you must be
|
||||
* root or 2). you must be listed as an administrative member.
|
||||
* Administrative members can do anything to a group that the
|
||||
* root user can.
|
||||
*/
|
||||
|
||||
if (!amroot && !is_on_list(sgent.sg_adm, myname))
|
||||
failure();
|
||||
#else /* ! SHADOWGRP */
|
||||
|
||||
#ifdef FIRST_MEMBER_IS_ADMIN
|
||||
/*
|
||||
* The policy here for changing a group is that 1) you must bes
|
||||
* root or 2) you must be the first listed member of the group.
|
||||
* The first listed member of a group can do anything to that
|
||||
* group that the root user can. The rationale for this hack is
|
||||
* that the FIRST user is probably the most important user in
|
||||
* this entire group.
|
||||
*/
|
||||
|
||||
if (! amroot) {
|
||||
if (grent.gr_mem[0] == (char *) 0)
|
||||
failure();
|
||||
|
||||
if (strcmp(grent.gr_mem[0], myname) != 0)
|
||||
failure();
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* This feature enabled by default could be a security problem
|
||||
* when installed on existing systems where the first group
|
||||
* member might be just a normal user... --marekm
|
||||
*/
|
||||
|
||||
if (!amroot)
|
||||
failure();
|
||||
#endif
|
||||
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Removing a password is straight forward. Just set the
|
||||
* password field to a "".
|
||||
*/
|
||||
|
||||
if (rflg) {
|
||||
grent.gr_passwd = ""; /* XXX warning: const */
|
||||
#ifdef SHADOWGRP
|
||||
sgent.sg_passwd = ""; /* XXX warning: const */
|
||||
#endif
|
||||
SYSLOG((LOG_INFO, "remove password from group %s by %s\n", group, myname));
|
||||
goto output;
|
||||
} else if (Rflg) {
|
||||
/*
|
||||
* Same thing for restricting the group. Set the password
|
||||
* field to "!".
|
||||
*/
|
||||
|
||||
grent.gr_passwd = "!"; /* XXX warning: const */
|
||||
#ifdef SHADOWGRP
|
||||
sgent.sg_passwd = "!"; /* XXX warning: const */
|
||||
#endif
|
||||
SYSLOG((LOG_INFO, "restrict access to group %s by %s\n", group, myname));
|
||||
goto output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding a member to a member list is pretty straightforward
|
||||
* as well. Call the appropriate routine and split.
|
||||
*/
|
||||
|
||||
if (aflg) {
|
||||
printf(_("Adding user %s to group %s\n"), user, group);
|
||||
grent.gr_mem = add_list (grent.gr_mem, user);
|
||||
#ifdef SHADOWGRP
|
||||
sgent.sg_mem = add_list (sgent.sg_mem, user);
|
||||
#endif
|
||||
SYSLOG((LOG_INFO, "add member %s to group %s by %s\n", user, group, myname));
|
||||
goto output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removing a member from the member list is the same deal
|
||||
* as adding one, except the routine is different.
|
||||
*/
|
||||
|
||||
if (dflg) {
|
||||
int removed = 0;
|
||||
|
||||
printf(_("Removing user %s from group %s\n"), user, group);
|
||||
|
||||
if (is_on_list(grent.gr_mem, user)) {
|
||||
removed = 1;
|
||||
grent.gr_mem = del_list (grent.gr_mem, user);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_on_list(sgent.sg_mem, user)) {
|
||||
removed = 1;
|
||||
sgent.sg_mem = del_list (sgent.sg_mem, user);
|
||||
}
|
||||
#endif
|
||||
if (! removed) {
|
||||
fprintf(stderr, _("%s: unknown member %s\n"),
|
||||
Prog, user);
|
||||
exit (1);
|
||||
}
|
||||
SYSLOG((LOG_INFO, "remove member %s from group %s by %s\n",
|
||||
user, group, myname));
|
||||
goto output;
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
/*
|
||||
* Replacing the entire list of administators is simple. Check the
|
||||
* list to make sure everyone is a real user. Then slap the new
|
||||
* list in place.
|
||||
*/
|
||||
|
||||
if (Aflg) {
|
||||
SYSLOG((LOG_INFO, "set administrators of %s to %s\n",
|
||||
group, admins));
|
||||
sgent.sg_adm = comma_to_list(admins);
|
||||
if (!Mflg)
|
||||
goto output;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Replacing the entire list of members is simple. Check the list
|
||||
* to make sure everyone is a real user. Then slap the new list
|
||||
* in place.
|
||||
*/
|
||||
|
||||
if (Mflg) {
|
||||
SYSLOG((LOG_INFO,"set members of %s to %s\n",group,members));
|
||||
#ifdef SHADOWGRP
|
||||
sgent.sg_mem = comma_to_list(members);
|
||||
#endif
|
||||
grent.gr_mem = comma_to_list(members);
|
||||
goto output;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the password is being changed, the input and output must
|
||||
* both be a tty. The typical keyboard signals are caught
|
||||
* so the termio modes can be restored.
|
||||
*/
|
||||
|
||||
if (! isatty (0) || ! isatty (1)) {
|
||||
fprintf(stderr, _("%s: Not a tty\n"), Prog);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
die (0); /* save tty modes */
|
||||
|
||||
signal (SIGHUP, die);
|
||||
signal (SIGINT, die);
|
||||
signal (SIGQUIT, die);
|
||||
signal (SIGTERM, die);
|
||||
#ifdef SIGTSTP
|
||||
signal (SIGTSTP, die);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A new password is to be entered and it must be encrypted,
|
||||
* etc. The password will be prompted for twice, and both
|
||||
* entries must be identical. There is no need to validate
|
||||
* the old password since the invoker is either the group
|
||||
* owner, or root.
|
||||
*/
|
||||
|
||||
printf(_("Changing the password for group %s\n"), group);
|
||||
|
||||
for (retries = 0; retries < RETRIES; retries++) {
|
||||
if (! (cp = getpass(_("New Password:"))))
|
||||
exit (1);
|
||||
|
||||
STRFCPY(pass, cp);
|
||||
strzero(cp);
|
||||
if (! (cp = getpass (_("Re-enter new password:"))))
|
||||
exit (1);
|
||||
|
||||
if (strcmp(pass, cp) == 0) {
|
||||
strzero(cp);
|
||||
break;
|
||||
}
|
||||
|
||||
strzero(cp);
|
||||
memzero(pass, sizeof pass);
|
||||
|
||||
if (retries + 1 < RETRIES)
|
||||
puts(_("They don't match; try again"));
|
||||
}
|
||||
|
||||
if (retries == RETRIES) {
|
||||
fprintf(stderr, _("%s: Try again later\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cp = pw_encrypt(pass, crypt_make_salt());
|
||||
memzero(pass, sizeof pass);
|
||||
#ifdef SHADOWGRP
|
||||
sgent.sg_passwd = cp;
|
||||
#else
|
||||
grent.gr_passwd = cp;
|
||||
#endif
|
||||
SYSLOG((LOG_INFO, "change the password for group %s by %s\n", group, myname));
|
||||
|
||||
/*
|
||||
* This is the common arrival point to output the new group
|
||||
* file. The freshly crafted entry is in allocated space.
|
||||
* The group file will be locked and opened for writing. The
|
||||
* new entry will be output, etc.
|
||||
*/
|
||||
|
||||
output:
|
||||
if (setuid(0)) {
|
||||
fprintf(stderr, _("Cannot change ID to root.\n"));
|
||||
SYSLOG((LOG_ERR, "can't setuid(0)"));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
pwd_init();
|
||||
|
||||
if (! gr_lock ()) {
|
||||
fprintf(stderr, _("%s: can't get lock\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "failed to get lock for /etc/group\n"));
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadowgrp && ! sgr_lock ()) {
|
||||
fprintf(stderr, _("%s: can't get shadow lock\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "failed to get lock for /etc/gshadow\n"));
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
if (! gr_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open file\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot open /etc/group\n"));
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadowgrp && ! sgr_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot open /etc/gshadow\n"));
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
if (! gr_update (&grent)) {
|
||||
fprintf(stderr, _("%s: can't update entry\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot update /etc/group\n"));
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadowgrp && ! sgr_update (&sgent)) {
|
||||
fprintf(stderr, _("%s: can't update shadow entry\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot update /etc/gshadow\n"));
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
if (! gr_close ()) {
|
||||
fprintf(stderr, _("%s: can't re-write file\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot re-write /etc/group\n"));
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadowgrp && ! sgr_close ()) {
|
||||
fprintf(stderr, _("%s: can't re-write shadow file\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot re-write /etc/gshadow\n"));
|
||||
exit (1);
|
||||
}
|
||||
if (is_shadowgrp)
|
||||
sgr_unlock ();
|
||||
#endif
|
||||
if (! gr_unlock ()) {
|
||||
fprintf(stderr, _("%s: can't unlock file\n"), Prog);
|
||||
exit (1);
|
||||
}
|
||||
#ifdef NDBM
|
||||
if (gr_dbm_present() && ! gr_dbm_update (&grent)) {
|
||||
fprintf(stderr, _("%s: can't update DBM files\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot update /etc/group DBM files\n"));
|
||||
exit (1);
|
||||
}
|
||||
endgrent ();
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadowgrp && sg_dbm_present() && ! sg_dbm_update (&sgent)) {
|
||||
fprintf(stderr, _("%s: can't update DBM shadow files\n"), Prog);
|
||||
SYSLOG((LOG_WARN, "cannot update /etc/gshadow DBM files\n"));
|
||||
exit (1);
|
||||
}
|
||||
endsgent ();
|
||||
#endif
|
||||
#endif
|
||||
exit (0);
|
||||
/*NOTREACHED*/
|
||||
}
|
538
src/groupadd.c
Normal file
538
src/groupadd.c
Normal file
@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright 1991 - 1993, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: groupadd.c,v 1.14 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#include "chkname.h"
|
||||
|
||||
#include "getdef.h"
|
||||
|
||||
#include "groupio.h"
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
#include "sgroupio.h"
|
||||
|
||||
static int is_shadow_grp;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* exit status values
|
||||
*/
|
||||
|
||||
#define E_SUCCESS 0 /* success */
|
||||
#define E_USAGE 2 /* invalid command syntax */
|
||||
#define E_BAD_ARG 3 /* invalid argument to option */
|
||||
#define E_GID_IN_USE 4 /* gid not unique (when -o not used) */
|
||||
#define E_NAME_IN_USE 9 /* group name nut unique */
|
||||
#define E_GRP_UPDATE 10 /* can't update group file */
|
||||
|
||||
static char *group_name;
|
||||
static gid_t group_id;
|
||||
static char *empty_list = NULL;
|
||||
|
||||
static char *Prog;
|
||||
|
||||
static int oflg = 0; /* permit non-unique group ID to be specified with -g */
|
||||
static int gflg = 0; /* ID value for the new group */
|
||||
static int fflg = 0; /* if group already exists, do nothing and exit(0) */
|
||||
|
||||
#ifdef NDBM
|
||||
extern int gr_dbm_mode;
|
||||
extern int sg_dbm_mode;
|
||||
#endif
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static void new_grent P_((struct group *));
|
||||
#ifdef SHADOWGRP
|
||||
static void new_sgent P_((struct sgrp *));
|
||||
#endif
|
||||
static void grp_update P_((void));
|
||||
static void find_new_gid P_((void));
|
||||
static void check_new_name P_((void));
|
||||
static void process_flags P_((int, char **));
|
||||
static void close_files P_((void));
|
||||
static void open_files P_((void));
|
||||
static void fail_exit P_((int));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: groupadd [-g gid [-o]] group\n"));
|
||||
exit(E_USAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* new_grent - initialize the values in a group file entry
|
||||
*
|
||||
* new_grent() takes all of the values that have been entered and
|
||||
* fills in a (struct group) with them.
|
||||
*/
|
||||
|
||||
static void
|
||||
new_grent(struct group *grent)
|
||||
{
|
||||
memzero(grent, sizeof *grent);
|
||||
grent->gr_name = group_name;
|
||||
grent->gr_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
|
||||
grent->gr_gid = group_id;
|
||||
grent->gr_mem = &empty_list;
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
/*
|
||||
* new_sgent - initialize the values in a shadow group file entry
|
||||
*
|
||||
* new_sgent() takes all of the values that have been entered and
|
||||
* fills in a (struct sgrp) with them.
|
||||
*/
|
||||
|
||||
static void
|
||||
new_sgent(struct sgrp *sgent)
|
||||
{
|
||||
memzero(sgent, sizeof *sgent);
|
||||
sgent->sg_name = group_name;
|
||||
sgent->sg_passwd = "!"; /* XXX warning: const */
|
||||
sgent->sg_adm = &empty_list;
|
||||
sgent->sg_mem = &empty_list;
|
||||
}
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* grp_update - add new group file entries
|
||||
*
|
||||
* grp_update() writes the new records to the group files.
|
||||
*/
|
||||
|
||||
static void
|
||||
grp_update(void)
|
||||
{
|
||||
struct group grp;
|
||||
#ifdef SHADOWGRP
|
||||
struct sgrp sgrp;
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Create the initial entries for this new group.
|
||||
*/
|
||||
|
||||
new_grent (&grp);
|
||||
#ifdef SHADOWGRP
|
||||
new_sgent (&sgrp);
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Write out the new group file entry.
|
||||
*/
|
||||
|
||||
if (! gr_update (&grp)) {
|
||||
fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef NDBM
|
||||
|
||||
/*
|
||||
* Update the DBM group file with the new entry as well.
|
||||
*/
|
||||
|
||||
if (gr_dbm_present() && ! gr_dbm_update (&grp)) {
|
||||
fprintf(stderr, _("%s: cannot add new dbm group entry\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
endgrent ();
|
||||
#endif /* NDBM */
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
|
||||
/*
|
||||
* Write out the new shadow group entries as well.
|
||||
*/
|
||||
|
||||
if (is_shadow_grp && ! sgr_update (&sgrp)) {
|
||||
fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef NDBM
|
||||
|
||||
/*
|
||||
* Update the DBM group file with the new entry as well.
|
||||
*/
|
||||
|
||||
if (is_shadow_grp && sg_dbm_present() && ! sg_dbm_update (&sgrp)) {
|
||||
fprintf(stderr, _("%s: cannot add new dbm group entry\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
endsgent ();
|
||||
#endif /* NDBM */
|
||||
#endif /* SHADOWGRP */
|
||||
SYSLOG((LOG_INFO, "new group: name=%s, gid=%d\n",
|
||||
group_name, group_id));
|
||||
}
|
||||
|
||||
/*
|
||||
* find_new_gid - find the next available GID
|
||||
*
|
||||
* find_new_gid() locates the next highest unused GID in the group
|
||||
* file, or checks the given group ID against the existing ones for
|
||||
* uniqueness.
|
||||
*/
|
||||
|
||||
static void
|
||||
find_new_gid(void)
|
||||
{
|
||||
const struct group *grp;
|
||||
gid_t gid_min, gid_max;
|
||||
|
||||
gid_min = getdef_num("GID_MIN", 100);
|
||||
gid_max = getdef_num("GID_MAX", 60000);
|
||||
|
||||
/*
|
||||
* Start with some GID value if the user didn't provide us with
|
||||
* one already.
|
||||
*/
|
||||
|
||||
if (! gflg)
|
||||
group_id = gid_min;
|
||||
|
||||
/*
|
||||
* Search the entire group file, either looking for this
|
||||
* GID (if the user specified one with -g) or looking for the
|
||||
* largest unused value.
|
||||
*/
|
||||
|
||||
#ifdef NO_GETGRENT
|
||||
gr_rewind();
|
||||
while ((grp = gr_next())) {
|
||||
#else
|
||||
setgrent();
|
||||
while ((grp = getgrent())) {
|
||||
#endif
|
||||
if (strcmp(group_name, grp->gr_name) == 0) {
|
||||
if (fflg) {
|
||||
fail_exit(E_SUCCESS);
|
||||
}
|
||||
fprintf(stderr, _("%s: name %s is not unique\n"),
|
||||
Prog, group_name);
|
||||
fail_exit(E_NAME_IN_USE);
|
||||
}
|
||||
if (gflg && group_id == grp->gr_gid) {
|
||||
if (fflg) {
|
||||
/* turn off -g and search again */
|
||||
gflg = 0;
|
||||
#ifdef NO_GETGRENT
|
||||
gr_rewind();
|
||||
#else
|
||||
setgrent();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, _("%s: gid %ld is not unique\n"),
|
||||
Prog, (long) group_id);
|
||||
fail_exit(E_GID_IN_USE);
|
||||
}
|
||||
if (! gflg && grp->gr_gid >= group_id) {
|
||||
if (grp->gr_gid > gid_max)
|
||||
continue;
|
||||
group_id = grp->gr_gid + 1;
|
||||
}
|
||||
}
|
||||
if (!gflg && group_id == gid_max + 1) {
|
||||
for (group_id = gid_min; group_id < gid_max; group_id++) {
|
||||
#ifdef NO_GETGRENT
|
||||
gr_rewind();
|
||||
while ((grp = gr_next()) && grp->gr_gid != group_id)
|
||||
;
|
||||
if (!grp)
|
||||
break;
|
||||
#else
|
||||
if (!getgrgid(group_id))
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (group_id == gid_max) {
|
||||
fprintf(stderr, _("%s: can't get unique gid\n"),
|
||||
Prog);
|
||||
fail_exit(E_GID_IN_USE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check_new_name - check the new name for validity
|
||||
*
|
||||
* check_new_name() insures that the new name doesn't contain
|
||||
* any illegal characters.
|
||||
*/
|
||||
|
||||
static void
|
||||
check_new_name(void)
|
||||
{
|
||||
if (check_group_name(group_name))
|
||||
return;
|
||||
|
||||
/*
|
||||
* All invalid group names land here.
|
||||
*/
|
||||
|
||||
fprintf(stderr, _("%s: %s is a not a valid group name\n"),
|
||||
Prog, group_name);
|
||||
|
||||
exit(E_BAD_ARG);
|
||||
}
|
||||
|
||||
/*
|
||||
* process_flags - perform command line argument setting
|
||||
*
|
||||
* process_flags() interprets the command line arguments and sets
|
||||
* the values that the user will be created with accordingly. The
|
||||
* values are checked for sanity.
|
||||
*/
|
||||
|
||||
static void
|
||||
process_flags(int argc, char **argv)
|
||||
{
|
||||
char *cp;
|
||||
int arg;
|
||||
|
||||
while ((arg = getopt(argc, argv, "og:O:f")) != EOF) {
|
||||
switch (arg) {
|
||||
case 'g':
|
||||
gflg++;
|
||||
if (! isdigit (optarg[0]))
|
||||
usage ();
|
||||
|
||||
group_id = strtol(optarg, &cp, 10);
|
||||
if (*cp != '\0') {
|
||||
fprintf(stderr, _("%s: invalid group %s\n"),
|
||||
Prog, optarg);
|
||||
fail_exit(E_BAD_ARG);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
oflg++;
|
||||
break;
|
||||
case 'O':
|
||||
/*
|
||||
* override login.defs defaults (-O name=value)
|
||||
* example: -O GID_MIN=100 -O GID_MAX=499
|
||||
* note: -O GID_MIN=10,GID_MAX=499 doesn't work yet
|
||||
*/
|
||||
cp = strchr(optarg, '=');
|
||||
if (!cp) {
|
||||
fprintf(stderr,
|
||||
_("%s: -O requires NAME=VALUE\n"),
|
||||
Prog);
|
||||
exit(E_BAD_ARG);
|
||||
}
|
||||
/* terminate name, point to value */
|
||||
*cp++ = '\0';
|
||||
if (putdef_str(optarg, cp) < 0)
|
||||
exit(E_BAD_ARG);
|
||||
break;
|
||||
case 'f':
|
||||
/*
|
||||
* "force" - do nothing, just exit(0), if the
|
||||
* specified group already exists. With -g, if
|
||||
* specified gid already exists, choose another
|
||||
* (unique) gid (turn off -g). Based on the
|
||||
* RedHat's patch from shadow-utils-970616-9.
|
||||
*/
|
||||
fflg++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (oflg && !gflg)
|
||||
usage();
|
||||
|
||||
if (optind != argc - 1)
|
||||
usage();
|
||||
|
||||
group_name = argv[argc - 1];
|
||||
check_new_name();
|
||||
}
|
||||
|
||||
/*
|
||||
* close_files - close all of the files that were opened
|
||||
*
|
||||
* close_files() closes all of the files that were opened for this
|
||||
* new group. This causes any modified entries to be written out.
|
||||
*/
|
||||
|
||||
static void
|
||||
close_files(void)
|
||||
{
|
||||
if (!gr_close()) {
|
||||
fprintf(stderr, _("%s: cannot rewrite group file\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
gr_unlock();
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && !sgr_close()) {
|
||||
fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
|
||||
Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (is_shadow_grp)
|
||||
sgr_unlock ();
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* open_files - lock and open the group files
|
||||
*
|
||||
* open_files() opens the two group files.
|
||||
*/
|
||||
|
||||
static void
|
||||
open_files(void)
|
||||
{
|
||||
if (! gr_lock ()) {
|
||||
fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (! gr_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open group file\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && ! sgr_lock ()) {
|
||||
fprintf(stderr, _("%s: unable to lock shadow group file\n"),
|
||||
Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (is_shadow_grp && ! sgr_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open shadow group file\n"),
|
||||
Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* fail_exit - exit with an error code after unlocking files
|
||||
*/
|
||||
|
||||
static void
|
||||
fail_exit(int code)
|
||||
{
|
||||
(void) gr_unlock ();
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp)
|
||||
sgr_unlock ();
|
||||
#endif
|
||||
exit (code);
|
||||
}
|
||||
|
||||
/*
|
||||
* main - groupadd command
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
||||
/*
|
||||
* Get my name so that I can use it to report errors.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
is_shadow_grp = sgr_file_present();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The open routines for the DBM files don't use read-write
|
||||
* as the mode, so we have to clue them in.
|
||||
*/
|
||||
|
||||
#ifdef NDBM
|
||||
gr_dbm_mode = O_RDWR;
|
||||
#ifdef SHADOWGRP
|
||||
sg_dbm_mode = O_RDWR;
|
||||
#endif /* SHADOWGRP */
|
||||
#endif /* NDBM */
|
||||
process_flags(argc, argv);
|
||||
|
||||
/*
|
||||
* Start with a quick check to see if the group exists.
|
||||
*/
|
||||
|
||||
if (getgrnam(group_name)) {
|
||||
if (fflg) {
|
||||
exit(E_SUCCESS);
|
||||
}
|
||||
fprintf(stderr, _("%s: group %s exists\n"), Prog, group_name);
|
||||
exit(E_NAME_IN_USE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the hard stuff - open the files, create the group entries,
|
||||
* then close and update the files.
|
||||
*/
|
||||
|
||||
open_files();
|
||||
|
||||
if (!gflg || !oflg)
|
||||
find_new_gid();
|
||||
|
||||
grp_update();
|
||||
|
||||
close_files();
|
||||
exit(E_SUCCESS);
|
||||
/*NOTREACHED*/
|
||||
}
|
352
src/groupdel.c
Normal file
352
src/groupdel.c
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 1991 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: groupdel.c,v 1.10 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
static char *group_name;
|
||||
static char *Prog;
|
||||
static int errors;
|
||||
|
||||
#ifdef NDBM
|
||||
extern int gr_dbm_mode;
|
||||
extern int sg_dbm_mode;
|
||||
#endif
|
||||
|
||||
#include "groupio.h"
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
#include "sgroupio.h"
|
||||
|
||||
static int is_shadow_grp;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* exit status values
|
||||
*/
|
||||
|
||||
#define E_SUCCESS 0 /* success */
|
||||
#define E_USAGE 2 /* invalid command syntax */
|
||||
#define E_NOTFOUND 6 /* specified group doesn't exist */
|
||||
#define E_GROUP_BUSY 8 /* can't remove user's primary group */
|
||||
#define E_GRP_UPDATE 10 /* can't update group file */
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static void grp_update P_((void));
|
||||
static void close_files P_((void));
|
||||
static void open_files P_((void));
|
||||
static void group_busy P_((gid_t));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: groupdel group\n"));
|
||||
exit(E_USAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* grp_update - update group file entries
|
||||
*
|
||||
* grp_update() writes the new records to the group files.
|
||||
*/
|
||||
|
||||
static void
|
||||
grp_update(void)
|
||||
{
|
||||
#ifdef NDBM
|
||||
struct group *ogrp;
|
||||
#endif
|
||||
|
||||
if (!gr_remove(group_name)) {
|
||||
fprintf(stderr, _("%s: error removing group entry\n"), Prog);
|
||||
errors++;
|
||||
}
|
||||
#ifdef NDBM
|
||||
|
||||
/*
|
||||
* Update the DBM group file
|
||||
*/
|
||||
|
||||
if (gr_dbm_present()) {
|
||||
if ((ogrp = getgrnam (group_name)) &&
|
||||
! gr_dbm_remove (ogrp)) {
|
||||
fprintf(stderr, _("%s: error removing group dbm entry\n"),
|
||||
Prog);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
endgrent ();
|
||||
#endif /* NDBM */
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
|
||||
/*
|
||||
* Delete the shadow group entries as well.
|
||||
*/
|
||||
|
||||
if (is_shadow_grp && ! sgr_remove (group_name)) {
|
||||
fprintf(stderr, _("%s: error removing shadow group entry\n"),
|
||||
Prog);
|
||||
errors++;
|
||||
}
|
||||
#ifdef NDBM
|
||||
|
||||
/*
|
||||
* Update the DBM shadow group file
|
||||
*/
|
||||
|
||||
if (is_shadow_grp && sg_dbm_present()) {
|
||||
if (! sg_dbm_remove (group_name)) {
|
||||
fprintf(stderr,
|
||||
_("%s: error removing shadow group dbm entry\n"),
|
||||
Prog);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
endsgent ();
|
||||
#endif /* NDBM */
|
||||
#endif /* SHADOWGRP */
|
||||
SYSLOG((LOG_INFO, "remove group `%s'\n", group_name));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* close_files - close all of the files that were opened
|
||||
*
|
||||
* close_files() closes all of the files that were opened for this
|
||||
* new group. This causes any modified entries to be written out.
|
||||
*/
|
||||
|
||||
static void
|
||||
close_files(void)
|
||||
{
|
||||
if (!gr_close()) {
|
||||
fprintf(stderr, _("%s: cannot rewrite group file\n"), Prog);
|
||||
errors++;
|
||||
}
|
||||
gr_unlock();
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && !sgr_close()) {
|
||||
fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
|
||||
Prog);
|
||||
errors++;
|
||||
}
|
||||
if (is_shadow_grp)
|
||||
sgr_unlock();
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* open_files - lock and open the group files
|
||||
*
|
||||
* open_files() opens the two group files.
|
||||
*/
|
||||
|
||||
static void
|
||||
open_files(void)
|
||||
{
|
||||
if (!gr_lock()) {
|
||||
fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (!gr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open group file\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && !sgr_lock()) {
|
||||
fprintf(stderr, _("%s: unable to lock shadow group file\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (is_shadow_grp && !sgr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open shadow group file\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* group_busy - check if this is any user's primary group
|
||||
*
|
||||
* group_busy verifies that this group is not the primary group
|
||||
* for any user. You must remove all users before you remove
|
||||
* the group.
|
||||
*/
|
||||
|
||||
static void
|
||||
group_busy(gid_t gid)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
|
||||
/*
|
||||
* Nice slow linear search.
|
||||
*/
|
||||
|
||||
setpwent ();
|
||||
|
||||
while ((pwd = getpwent ()) && pwd->pw_gid != gid)
|
||||
;
|
||||
|
||||
endpwent ();
|
||||
|
||||
/*
|
||||
* If pwd isn't NULL, it stopped becaues the gid's matched.
|
||||
*/
|
||||
|
||||
if (pwd == (struct passwd *) 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Can't remove the group.
|
||||
*/
|
||||
|
||||
fprintf(stderr, _("%s: cannot remove user's primary group.\n"), Prog);
|
||||
exit(E_GROUP_BUSY);
|
||||
}
|
||||
|
||||
/*
|
||||
* main - groupdel command
|
||||
*
|
||||
* The syntax of the groupdel command is
|
||||
*
|
||||
* groupdel group
|
||||
*
|
||||
* The named group will be deleted.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct group *grp;
|
||||
|
||||
/*
|
||||
* Get my name so that I can use it to report errors.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc != 2)
|
||||
usage ();
|
||||
|
||||
group_name = argv[1];
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
is_shadow_grp = sgr_file_present();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The open routines for the DBM files don't use read-write
|
||||
* as the mode, so we have to clue them in.
|
||||
*/
|
||||
|
||||
#ifdef NDBM
|
||||
gr_dbm_mode = O_RDWR;
|
||||
#ifdef SHADOWGRP
|
||||
sg_dbm_mode = O_RDWR;
|
||||
#endif /* SHADOWGRP */
|
||||
#endif /* NDBM */
|
||||
|
||||
/*
|
||||
* Start with a quick check to see if the group exists.
|
||||
*/
|
||||
|
||||
if (! (grp = getgrnam(group_name))) {
|
||||
fprintf(stderr, _("%s: group %s does not exist\n"),
|
||||
Prog, group_name);
|
||||
exit(E_NOTFOUND);
|
||||
}
|
||||
#ifdef USE_NIS
|
||||
|
||||
/*
|
||||
* Make sure this isn't a NIS group
|
||||
*/
|
||||
|
||||
if (__isgrNIS ()) {
|
||||
char *nis_domain;
|
||||
char *nis_master;
|
||||
|
||||
fprintf(stderr, _("%s: group %s is a NIS group\n"),
|
||||
Prog, group_name);
|
||||
|
||||
if (! yp_get_default_domain (&nis_domain) &&
|
||||
! yp_master (nis_domain, "group.byname",
|
||||
&nis_master)) {
|
||||
fprintf (stderr, _("%s: %s is the NIS master\n"),
|
||||
Prog, nis_master);
|
||||
}
|
||||
exit(E_NOTFOUND);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now check to insure that this isn't the primary group of
|
||||
* anyone.
|
||||
*/
|
||||
|
||||
group_busy (grp->gr_gid);
|
||||
|
||||
/*
|
||||
* Do the hard stuff - open the files, delete the group entries,
|
||||
* then close and update the files.
|
||||
*/
|
||||
|
||||
open_files ();
|
||||
|
||||
grp_update ();
|
||||
|
||||
close_files ();
|
||||
exit(errors == 0 ? E_SUCCESS : E_GRP_UPDATE);
|
||||
/*NOTREACHED*/
|
||||
}
|
549
src/groupmod.c
Normal file
549
src/groupmod.c
Normal file
@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright 1991 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: groupmod.c,v 1.12 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "chkname.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include "groupio.h"
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
#include "sgroupio.h"
|
||||
|
||||
static int is_shadow_grp;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* exit status values
|
||||
*/
|
||||
|
||||
#define E_SUCCESS 0 /* success */
|
||||
#define E_USAGE 2 /* invalid command syntax */
|
||||
#define E_BAD_ARG 3 /* invalid argument to option */
|
||||
#define E_GID_IN_USE 4 /* gid already in use (and no -o) */
|
||||
#define E_NOTFOUND 6 /* specified group doesn't exist */
|
||||
#define E_NAME_IN_USE 9 /* group name already in use */
|
||||
#define E_GRP_UPDATE 10 /* can't update group file */
|
||||
|
||||
static char *group_name;
|
||||
static char *group_newname;
|
||||
static gid_t group_id;
|
||||
static gid_t group_newid;
|
||||
|
||||
static char *Prog;
|
||||
|
||||
static int
|
||||
oflg = 0, /* permit non-unique group ID to be specified with -g */
|
||||
gflg = 0, /* new ID value for the group */
|
||||
nflg = 0; /* a new name has been specified for the group */
|
||||
|
||||
#ifdef NDBM
|
||||
extern int gr_dbm_mode;
|
||||
extern int sg_dbm_mode;
|
||||
#endif
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static void new_grent P_((struct group *));
|
||||
#ifdef SHADOWGRP
|
||||
static void new_sgent P_((struct sgrp *));
|
||||
#endif
|
||||
static void grp_update P_((void));
|
||||
static void check_new_gid P_((void));
|
||||
static void check_new_name P_((void));
|
||||
static void process_flags P_((int, char **));
|
||||
static void close_files P_((void));
|
||||
static void open_files P_((void));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: groupmod [-g gid [-o]] [-n name] group\n"));
|
||||
exit(E_USAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* new_grent - updates the values in a group file entry
|
||||
*
|
||||
* new_grent() takes all of the values that have been entered and
|
||||
* fills in a (struct group) with them.
|
||||
*/
|
||||
|
||||
static void
|
||||
new_grent(struct group *grent)
|
||||
{
|
||||
if (nflg)
|
||||
grent->gr_name = xstrdup (group_newname);
|
||||
|
||||
if (gflg)
|
||||
grent->gr_gid = group_newid;
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
/*
|
||||
* new_sgent - updates the values in a shadow group file entry
|
||||
*
|
||||
* new_sgent() takes all of the values that have been entered and
|
||||
* fills in a (struct sgrp) with them.
|
||||
*/
|
||||
|
||||
static void
|
||||
new_sgent(struct sgrp *sgent)
|
||||
{
|
||||
if (nflg)
|
||||
sgent->sg_name = xstrdup (group_newname);
|
||||
}
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* grp_update - update group file entries
|
||||
*
|
||||
* grp_update() writes the new records to the group files.
|
||||
*/
|
||||
|
||||
static void
|
||||
grp_update(void)
|
||||
{
|
||||
struct group grp;
|
||||
const struct group *ogrp;
|
||||
#ifdef SHADOWGRP
|
||||
struct sgrp sgrp;
|
||||
const struct sgrp *osgrp = NULL;
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Get the current settings for this group.
|
||||
*/
|
||||
|
||||
ogrp = gr_locate(group_name);
|
||||
if (!ogrp) {
|
||||
fprintf(stderr,
|
||||
_("%s: %s not found in /etc/group\n"),
|
||||
Prog, group_name);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
grp = *ogrp;
|
||||
new_grent (&grp);
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && (osgrp = sgr_locate(group_name))) {
|
||||
sgrp = *osgrp;
|
||||
new_sgent (&sgrp);
|
||||
}
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Write out the new group file entry.
|
||||
*/
|
||||
|
||||
if (!gr_update(&grp)) {
|
||||
fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (nflg && !gr_remove(group_name)) {
|
||||
fprintf(stderr, _("%s: error removing group entry\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef NDBM
|
||||
|
||||
/*
|
||||
* Update the DBM group file with the new entry as well.
|
||||
*/
|
||||
|
||||
if (gr_dbm_present()) {
|
||||
if (!gr_dbm_update(&grp)) {
|
||||
fprintf(stderr,
|
||||
_("%s: cannot add new dbm group entry\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (nflg && (ogrp = getgrnam(group_name)) &&
|
||||
!gr_dbm_remove(ogrp)) {
|
||||
fprintf(stderr,
|
||||
_("%s: error removing group dbm entry\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
endgrent ();
|
||||
}
|
||||
#endif /* NDBM */
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
|
||||
/*
|
||||
* Make sure there was a shadow entry to begin with. Skip
|
||||
* down to "out" if there wasn't. Can't just return because
|
||||
* there might be some syslogging to do.
|
||||
*/
|
||||
|
||||
if (! osgrp)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Write out the new shadow group entries as well.
|
||||
*/
|
||||
|
||||
if (!sgr_update(&sgrp)) {
|
||||
fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (nflg && !sgr_remove(group_name)) {
|
||||
fprintf(stderr, _("%s: error removing group entry\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef NDBM
|
||||
|
||||
/*
|
||||
* Update the DBM shadow group file with the new entry as well.
|
||||
*/
|
||||
|
||||
if (sg_dbm_present()) {
|
||||
if (!sg_dbm_update(&sgrp)) {
|
||||
fprintf(stderr,
|
||||
_("%s: cannot add new dbm shadow group entry\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (nflg && ! sg_dbm_remove (group_name)) {
|
||||
fprintf (stderr,
|
||||
_("%s: error removing shadow group dbm entry\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
endsgent ();
|
||||
}
|
||||
#endif /* NDBM */
|
||||
out:
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
if (nflg)
|
||||
SYSLOG((LOG_INFO, "change group `%s' to `%s'\n",
|
||||
group_name, group_newname));
|
||||
|
||||
if (gflg)
|
||||
SYSLOG((LOG_INFO, "change gid for `%s' to %d\n",
|
||||
nflg ? group_newname:group_name, group_newid));
|
||||
}
|
||||
|
||||
/*
|
||||
* check_new_gid - check the new GID value for uniqueness
|
||||
*
|
||||
* check_new_gid() insures that the new GID value is unique.
|
||||
*/
|
||||
|
||||
static void
|
||||
check_new_gid(void)
|
||||
{
|
||||
/*
|
||||
* First, the easy stuff. If the ID can be duplicated, or if
|
||||
* the ID didn't really change, just return. If the ID didn't
|
||||
* change, turn off those flags. No sense doing needless work.
|
||||
*/
|
||||
|
||||
if (group_id == group_newid) {
|
||||
gflg = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oflg || ! getgrgid (group_newid))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Tell the user what they did wrong.
|
||||
*/
|
||||
|
||||
fprintf(stderr,
|
||||
_("%s: %ld is not a unique gid\n"),
|
||||
Prog, (long) group_newid);
|
||||
exit(E_GID_IN_USE);
|
||||
}
|
||||
|
||||
/*
|
||||
* check_new_name - check the new name for uniqueness
|
||||
*
|
||||
* check_new_name() insures that the new name does not exist
|
||||
* already. You can't have the same name twice, period.
|
||||
*/
|
||||
|
||||
static void
|
||||
check_new_name(void)
|
||||
{
|
||||
/*
|
||||
* Make sure they are actually changing the name.
|
||||
*/
|
||||
|
||||
if (strcmp(group_name, group_newname) == 0) {
|
||||
nflg = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_group_name(group_newname)) {
|
||||
|
||||
/*
|
||||
* If the entry is found, too bad.
|
||||
*/
|
||||
|
||||
if (getgrnam(group_newname)) {
|
||||
fprintf(stderr, _("%s: %s is not a unique name\n"),
|
||||
Prog, group_newname);
|
||||
exit(E_NAME_IN_USE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* All invalid group names land here.
|
||||
*/
|
||||
|
||||
fprintf(stderr, _("%s: %s is a not a valid group name\n"),
|
||||
Prog, group_newname);
|
||||
exit(E_BAD_ARG);
|
||||
}
|
||||
|
||||
/*
|
||||
* process_flags - perform command line argument setting
|
||||
*
|
||||
* process_flags() interprets the command line arguments and sets
|
||||
* the values that the user will be created with accordingly. The
|
||||
* values are checked for sanity.
|
||||
*/
|
||||
|
||||
static void
|
||||
process_flags(int argc, char **argv)
|
||||
{
|
||||
char *end;
|
||||
int arg;
|
||||
|
||||
while ((arg = getopt (argc, argv, "og:n:")) != EOF) {
|
||||
switch (arg) {
|
||||
case 'g':
|
||||
gflg++;
|
||||
group_newid = strtol(optarg, &end, 10);
|
||||
if (*end != '\0') {
|
||||
fprintf(stderr,
|
||||
_("%s: invalid group %s\n"),
|
||||
Prog, optarg);
|
||||
exit(E_BAD_ARG);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
nflg++;
|
||||
group_newname = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
oflg++;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
if (oflg && !gflg)
|
||||
usage();
|
||||
|
||||
if (optind != argc - 1)
|
||||
usage();
|
||||
|
||||
group_name = argv[argc - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* close_files - close all of the files that were opened
|
||||
*
|
||||
* close_files() closes all of the files that were opened for this
|
||||
* new group. This causes any modified entries to be written out.
|
||||
*/
|
||||
|
||||
static void
|
||||
close_files(void)
|
||||
{
|
||||
if (!gr_close()) {
|
||||
fprintf(stderr, _("%s: cannot rewrite group file\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
gr_unlock();
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && !sgr_close()) {
|
||||
fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (is_shadow_grp)
|
||||
sgr_unlock ();
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* open_files - lock and open the group files
|
||||
*
|
||||
* open_files() opens the two group files.
|
||||
*/
|
||||
|
||||
static void
|
||||
open_files(void)
|
||||
{
|
||||
if (!gr_lock()) {
|
||||
fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (!gr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open group file\n"), Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && !sgr_lock()) {
|
||||
fprintf(stderr, _("%s: unable to lock shadow group file\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (is_shadow_grp && !sgr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open shadow group file\n"),
|
||||
Prog);
|
||||
exit(E_GRP_UPDATE);
|
||||
}
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* main - groupmod command
|
||||
*
|
||||
* The syntax of the groupmod command is
|
||||
*
|
||||
* groupmod [ -g gid [ -o ]] [ -n name ] group
|
||||
*
|
||||
* The flags are
|
||||
* -g - specify a new group ID value
|
||||
* -o - permit the group ID value to be non-unique
|
||||
* -n - specify a new group name
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct group *grp;
|
||||
|
||||
/*
|
||||
* Get my name so that I can use it to report errors.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
is_shadow_grp = sgr_file_present();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The open routines for the DBM files don't use read-write
|
||||
* as the mode, so we have to clue them in.
|
||||
*/
|
||||
|
||||
#ifdef NDBM
|
||||
gr_dbm_mode = O_RDWR;
|
||||
#ifdef SHADOWGRP
|
||||
sg_dbm_mode = O_RDWR;
|
||||
#endif /* SHADOWGRP */
|
||||
#endif /* NDBM */
|
||||
process_flags (argc, argv);
|
||||
|
||||
/*
|
||||
* Start with a quick check to see if the group exists.
|
||||
*/
|
||||
|
||||
if (!(grp = getgrnam(group_name))) {
|
||||
fprintf(stderr, _("%s: group %s does not exist\n"),
|
||||
Prog, group_name);
|
||||
exit(E_NOTFOUND);
|
||||
} else
|
||||
group_id = grp->gr_gid;
|
||||
|
||||
#ifdef USE_NIS
|
||||
|
||||
/*
|
||||
* Now make sure it isn't an NIS group.
|
||||
*/
|
||||
|
||||
if (__isgrNIS ()) {
|
||||
char *nis_domain;
|
||||
char *nis_master;
|
||||
|
||||
fprintf(stderr, _("%s: group %s is a NIS group\n"),
|
||||
Prog, group_name);
|
||||
|
||||
if (! yp_get_default_domain (&nis_domain) &&
|
||||
! yp_master (nis_domain, "group.byname",
|
||||
&nis_master)) {
|
||||
fprintf(stderr, _("%s: %s is the NIS master\n"),
|
||||
Prog, nis_master);
|
||||
}
|
||||
exit(E_NOTFOUND);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gflg)
|
||||
check_new_gid ();
|
||||
|
||||
if (nflg)
|
||||
check_new_name ();
|
||||
|
||||
/*
|
||||
* Do the hard stuff - open the files, create the group entries,
|
||||
* then close and update the files.
|
||||
*/
|
||||
|
||||
open_files ();
|
||||
|
||||
grp_update ();
|
||||
|
||||
close_files ();
|
||||
exit(E_SUCCESS);
|
||||
/*NOTREACHED*/
|
||||
}
|
184
src/groups.c
Normal file
184
src/groups.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 1991 - 1993, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: groups.c,v 1.5 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static void print_groups P_((const char *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* print_groups - print the groups which the named user is a member of
|
||||
*
|
||||
* print_groups() scans the groups file for the list of groups
|
||||
* which the user is listed as being a member of.
|
||||
*/
|
||||
|
||||
static void
|
||||
print_groups(const char *member)
|
||||
{
|
||||
int groups = 0;
|
||||
struct group *grp;
|
||||
struct passwd *pwd;
|
||||
int flag = 0;
|
||||
|
||||
setgrent ();
|
||||
|
||||
if ((pwd = getpwnam(member)) == 0) {
|
||||
fprintf(stderr, _("unknown user %s\n"), member);
|
||||
exit(1);
|
||||
}
|
||||
while ((grp = getgrent ())) {
|
||||
if (is_on_list(grp->gr_mem, member)) {
|
||||
if (groups++)
|
||||
putchar (' ');
|
||||
|
||||
printf ("%s", grp->gr_name);
|
||||
if (grp->gr_gid == pwd->pw_gid)
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
if (! flag && (grp = getgrgid (pwd->pw_gid))) {
|
||||
if (groups++)
|
||||
putchar (' ');
|
||||
|
||||
printf ("%s", grp->gr_name);
|
||||
}
|
||||
if (groups)
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* groups - print out the groups a process is a member of
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
#ifdef HAVE_GETGROUPS
|
||||
int ngroups;
|
||||
GETGROUPS_T groups[NGROUPS_MAX];
|
||||
int pri_grp;
|
||||
int i;
|
||||
struct group *gr;
|
||||
#else
|
||||
char *logname;
|
||||
char *getlogin();
|
||||
#endif
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc == 1) {
|
||||
|
||||
/*
|
||||
* Called with no arguments - give the group set
|
||||
* for the current user.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
/*
|
||||
* This system supports concurrent group sets, so
|
||||
* I can ask the system to tell me which groups are
|
||||
* currently set for this process.
|
||||
*/
|
||||
|
||||
ngroups = getgroups(NGROUPS_MAX, groups);
|
||||
if (ngroups < 0) {
|
||||
perror("getgroups");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The groupset includes the primary group as well.
|
||||
*/
|
||||
|
||||
pri_grp = getegid ();
|
||||
for (i = 0;i < ngroups;i++)
|
||||
if (pri_grp == (int) groups[i])
|
||||
break;
|
||||
|
||||
if (i != ngroups)
|
||||
pri_grp = -1;
|
||||
|
||||
/*
|
||||
* Print out the name of every group in the current
|
||||
* group set. Unknown groups are printed as their
|
||||
* decimal group ID values.
|
||||
*/
|
||||
|
||||
if (pri_grp != -1) {
|
||||
if ((gr = getgrgid (pri_grp)))
|
||||
printf ("%s", gr->gr_name);
|
||||
else
|
||||
printf ("%d", pri_grp);
|
||||
}
|
||||
|
||||
for (i = 0;i < ngroups;i++) {
|
||||
if (i || pri_grp != -1)
|
||||
putchar (' ');
|
||||
|
||||
if ((gr = getgrgid (groups[i])))
|
||||
printf ("%s", gr->gr_name);
|
||||
else
|
||||
printf ("%ld", (long) groups[i]);
|
||||
}
|
||||
putchar ('\n');
|
||||
#else
|
||||
/*
|
||||
* This system does not have the getgroups() system
|
||||
* call, so I must check the groups file directly.
|
||||
*/
|
||||
|
||||
if ((logname = getlogin ()))
|
||||
print_groups (logname);
|
||||
else
|
||||
exit (1);
|
||||
#endif
|
||||
} else {
|
||||
|
||||
/*
|
||||
* The invoker wanted to know about some other
|
||||
* user. Use that name to look up the groups instead.
|
||||
*/
|
||||
|
||||
print_groups (argv[1]);
|
||||
}
|
||||
exit (0);
|
||||
}
|
650
src/grpck.c
Normal file
650
src/grpck.c
Normal file
@ -0,0 +1,650 @@
|
||||
/*
|
||||
* Copyright 1992 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: grpck.c,v 1.12 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "chkname.h"
|
||||
#include <pwd.h>
|
||||
|
||||
#include "commonio.h"
|
||||
|
||||
#include "groupio.h"
|
||||
extern void __gr_del_entry P_((const struct commonio_entry *));
|
||||
extern struct commonio_entry *__gr_get_head P_((void));
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
#include "sgroupio.h"
|
||||
extern void __sgr_del_entry P_((const struct commonio_entry *));
|
||||
extern struct commonio_entry *__sgr_get_head P_((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exit codes
|
||||
*/
|
||||
|
||||
#define E_OKAY 0
|
||||
#define E_USAGE 1
|
||||
#define E_BAD_ENTRY 2
|
||||
#define E_CANT_OPEN 3
|
||||
#define E_CANT_LOCK 4
|
||||
#define E_CANT_UPDATE 5
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/*
|
||||
* Local variables
|
||||
*/
|
||||
|
||||
static char *Prog;
|
||||
static const char *grp_file = GROUP_FILE;
|
||||
#ifdef SHADOWGRP
|
||||
static const char *sgr_file = SGROUP_FILE;
|
||||
#endif
|
||||
static int read_only = 0;
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static int yes_or_no P_((void));
|
||||
static void delete_member P_((char **, const char *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - print syntax message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#ifdef SHADOWGRP
|
||||
fprintf(stderr, _("Usage: %s [ -r ] [ group [ gshadow ] ]\n"), Prog);
|
||||
#else
|
||||
fprintf(stderr, _("Usage: %s [ -r ] [ group ]\n"), Prog);
|
||||
#endif
|
||||
exit(E_USAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* yes_or_no - get answer to question from the user
|
||||
*/
|
||||
|
||||
static int
|
||||
yes_or_no(void)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
/*
|
||||
* In read-only mode all questions are answered "no".
|
||||
*/
|
||||
|
||||
if (read_only) {
|
||||
puts(_("No"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a line and see what the first character is.
|
||||
*/
|
||||
|
||||
if (fgets(buf, sizeof buf, stdin))
|
||||
return buf[0] == 'y' || buf[0] == 'Y';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_member - delete an entry in a list of members
|
||||
*/
|
||||
|
||||
static void
|
||||
delete_member(char **list, const char *member)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; list[i]; i++)
|
||||
if (list[i] == member)
|
||||
break;
|
||||
|
||||
if (list[i])
|
||||
for (; list[i]; i++)
|
||||
list[i] = list[i + 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* grpck - verify group file integrity
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int arg;
|
||||
int errors = 0;
|
||||
int deleted = 0;
|
||||
int i;
|
||||
struct commonio_entry *gre, *tgre;
|
||||
struct group *grp;
|
||||
#ifdef SHADOWGRP
|
||||
struct commonio_entry *sge, *tsge;
|
||||
struct sgrp *sgr;
|
||||
int is_shadow = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get my name so that I can use it to report errors.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
/*
|
||||
* Parse the command line arguments
|
||||
*/
|
||||
|
||||
while ((arg = getopt(argc, argv, "qr")) != EOF) {
|
||||
switch (arg) {
|
||||
case 'q':
|
||||
/* quiet - ignored for now */
|
||||
break;
|
||||
case 'r':
|
||||
read_only = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make certain we have the right number of arguments
|
||||
*/
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
if (optind != argc && optind + 1 != argc && optind + 2 != argc)
|
||||
#else
|
||||
if (optind != argc && optind + 1 != argc)
|
||||
#endif
|
||||
usage();
|
||||
|
||||
/*
|
||||
* If there are two left over filenames, use those as the
|
||||
* group and group password filenames.
|
||||
*/
|
||||
|
||||
if (optind != argc) {
|
||||
grp_file = argv[optind];
|
||||
gr_name(grp_file);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (optind + 2 == argc) {
|
||||
sgr_file = argv[optind + 1];
|
||||
sgr_name(sgr_file);
|
||||
is_shadow = 1;
|
||||
} else if (optind == argc)
|
||||
is_shadow = sgr_file_present();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lock the files if we aren't in "read-only" mode
|
||||
*/
|
||||
|
||||
if (!read_only) {
|
||||
if (!gr_lock()) {
|
||||
fprintf(stderr, _("%s: cannot lock file %s\n"), Prog, grp_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN,"cannot lock %s\n",grp_file));
|
||||
closelog();
|
||||
exit(E_CANT_LOCK);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow && !sgr_lock()) {
|
||||
fprintf(stderr, _("%s: cannot lock file %s\n"), Prog, sgr_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN,"cannot lock %s\n",sgr_file));
|
||||
closelog();
|
||||
exit(E_CANT_LOCK);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the files. Use O_RDONLY if we are in read_only mode,
|
||||
* O_RDWR otherwise.
|
||||
*/
|
||||
|
||||
if (!gr_open(read_only ? O_RDONLY : O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open file %s\n"), Prog, grp_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN, "cannot open %s\n", grp_file));
|
||||
closelog();
|
||||
exit(E_CANT_OPEN);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow && !sgr_open(read_only ? O_RDONLY : O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open file %s\n"), Prog, sgr_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN, "cannot open %s\n", sgr_file));
|
||||
closelog();
|
||||
exit(E_CANT_OPEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Loop through the entire group file.
|
||||
*/
|
||||
|
||||
for (gre = __gr_get_head(); gre; gre = gre->next) {
|
||||
/*
|
||||
* Skip all NIS entries.
|
||||
*/
|
||||
|
||||
if (gre->line[0] == '+' || gre->line[0] == '-')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Start with the entries that are completely corrupt.
|
||||
* They have no (struct group) entry because they couldn't
|
||||
* be parsed properly.
|
||||
*/
|
||||
|
||||
if (!gre->entry) {
|
||||
|
||||
/*
|
||||
* Tell the user this entire line is bogus and
|
||||
* ask them to delete it.
|
||||
*/
|
||||
|
||||
printf(_("invalid group file entry\n"));
|
||||
printf(_("delete line `%s'? "), gre->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All group file deletions wind up here. This
|
||||
* code removes the current entry from the linked
|
||||
* list. When done, it skips back to the top of
|
||||
* the loop to try out the next list element.
|
||||
*/
|
||||
|
||||
delete_gr:
|
||||
SYSLOG((LOG_INFO, "delete group line `%s'\n",
|
||||
gre->line));
|
||||
deleted++;
|
||||
|
||||
__gr_del_entry(gre);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Group structure is good, start using it.
|
||||
*/
|
||||
|
||||
grp = gre->entry;
|
||||
|
||||
/*
|
||||
* Make sure this entry has a unique name.
|
||||
*/
|
||||
|
||||
for (tgre = __gr_get_head(); tgre; tgre = tgre->next) {
|
||||
|
||||
const struct group *ent = tgre->entry;
|
||||
|
||||
/*
|
||||
* Don't check this entry
|
||||
*/
|
||||
|
||||
if (tgre == gre)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't check invalid entries.
|
||||
*/
|
||||
|
||||
if (!ent)
|
||||
continue;
|
||||
|
||||
if (strcmp(grp->gr_name, ent->gr_name) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Tell the user this entry is a duplicate of
|
||||
* another and ask them to delete it.
|
||||
*/
|
||||
|
||||
puts(_("duplicate group entry\n"));
|
||||
printf(_("delete line `%s'? "), gre->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (yes_or_no())
|
||||
goto delete_gr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for invalid group names. --marekm
|
||||
*/
|
||||
if (!check_group_name(grp->gr_name)) {
|
||||
errors++;
|
||||
printf(_("invalid group name `%s'\n"), grp->gr_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a Slackware bug. Make sure GID is not -1
|
||||
* (it has special meaning for some syscalls). --marekm
|
||||
*/
|
||||
|
||||
if (grp->gr_gid == (gid_t) -1) {
|
||||
errors++;
|
||||
printf(_("group %s: bad GID (%d)\n"),
|
||||
grp->gr_name, (int) grp->gr_gid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for a NYS libc 5.3.12 bug on RedHat 4.2 -
|
||||
* groups with no members are returned as groups with
|
||||
* one member "", causing grpck to fail. --marekm
|
||||
*/
|
||||
|
||||
if (grp->gr_mem[0] && !grp->gr_mem[1] && *(grp->gr_mem[0]) == '\0')
|
||||
grp->gr_mem[0] = (char *) 0;
|
||||
|
||||
/*
|
||||
* Make sure each member exists
|
||||
*/
|
||||
|
||||
for (i = 0; grp->gr_mem[i]; i++) {
|
||||
if (getpwnam(grp->gr_mem[i]))
|
||||
continue;
|
||||
/*
|
||||
* Can't find this user. Remove them
|
||||
* from the list.
|
||||
*/
|
||||
|
||||
errors++;
|
||||
printf(_("group %s: no user %s\n"),
|
||||
grp->gr_name, grp->gr_mem[i]);
|
||||
printf(_("delete member `%s'? "), grp->gr_mem[i]);
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
SYSLOG((LOG_INFO, "delete member `%s' group `%s'\n",
|
||||
grp->gr_mem[i], grp->gr_name));
|
||||
deleted++;
|
||||
delete_member(grp->gr_mem, grp->gr_mem[i]);
|
||||
gre->changed = 1;
|
||||
__gr_set_changed();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
if (!is_shadow)
|
||||
goto shadow_done;
|
||||
|
||||
/*
|
||||
* Loop through the entire shadow group file.
|
||||
*/
|
||||
|
||||
for (sge = __sgr_get_head(); sge; sge = sge->next) {
|
||||
|
||||
/*
|
||||
* Start with the entries that are completely corrupt.
|
||||
* They have no (struct sgrp) entry because they couldn't
|
||||
* be parsed properly.
|
||||
*/
|
||||
|
||||
if (!sge->entry) {
|
||||
|
||||
/*
|
||||
* Tell the user this entire line is bogus and
|
||||
* ask them to delete it.
|
||||
*/
|
||||
|
||||
printf(_("invalid shadow group file entry\n"));
|
||||
printf(_("delete line `%s'? "), sge->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All shadow group file deletions wind up here.
|
||||
* This code removes the current entry from the
|
||||
* linked list. When done, it skips back to the
|
||||
* top of the loop to try out the next list element.
|
||||
*/
|
||||
|
||||
delete_sg:
|
||||
SYSLOG((LOG_INFO, "delete shadow line `%s'\n",
|
||||
sge->line));
|
||||
deleted++;
|
||||
|
||||
__sgr_del_entry(sge);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shadow group structure is good, start using it.
|
||||
*/
|
||||
|
||||
sgr = sge->entry;
|
||||
|
||||
/*
|
||||
* Make sure this entry has a unique name.
|
||||
*/
|
||||
|
||||
for (tsge = __sgr_get_head(); tsge; tsge = tsge->next) {
|
||||
|
||||
const struct sgrp *ent = tsge->entry;
|
||||
|
||||
/*
|
||||
* Don't check this entry
|
||||
*/
|
||||
|
||||
if (tsge == sge)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't check invalid entries.
|
||||
*/
|
||||
|
||||
if (!ent)
|
||||
continue;
|
||||
|
||||
if (strcmp(sgr->sg_name, ent->sg_name) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Tell the user this entry is a duplicate of
|
||||
* another and ask them to delete it.
|
||||
*/
|
||||
|
||||
puts(_("duplicate shadow group entry\n"));
|
||||
printf(_("delete line `%s'? "), sge->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (yes_or_no())
|
||||
goto delete_sg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure this entry exists in the /etc/group file.
|
||||
*/
|
||||
|
||||
if (!gr_locate(sgr->sg_name)) {
|
||||
puts(_("no matching group file entry\n"));
|
||||
printf(_("delete line `%s'? "), sge->line);
|
||||
errors++;
|
||||
if (yes_or_no())
|
||||
goto delete_sg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure each administrator exists
|
||||
*/
|
||||
|
||||
for (i = 0; sgr->sg_adm[i]; i++) {
|
||||
if (getpwnam(sgr->sg_adm[i]))
|
||||
continue;
|
||||
/*
|
||||
* Can't find this user. Remove them
|
||||
* from the list.
|
||||
*/
|
||||
|
||||
errors++;
|
||||
printf(_("shadow group %s: no administrative user %s\n"),
|
||||
sgr->sg_name, sgr->sg_adm[i]);
|
||||
printf(_("delete administrative member `%s'? "), sgr->sg_adm[i]);
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
SYSLOG((LOG_INFO,
|
||||
"delete admin `%s' from shadow group `%s'\n",
|
||||
sgr->sg_adm[i], sgr->sg_name));
|
||||
deleted++;
|
||||
delete_member(sgr->sg_adm, sgr->sg_adm[i]);
|
||||
sge->changed = 1;
|
||||
__sgr_set_changed();
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure each member exists
|
||||
*/
|
||||
|
||||
for (i = 0; sgr->sg_mem[i]; i++) {
|
||||
if (getpwnam(sgr->sg_mem[i]))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Can't find this user. Remove them
|
||||
* from the list.
|
||||
*/
|
||||
|
||||
errors++;
|
||||
printf(_("shadow group %s: no user %s\n"),
|
||||
sgr->sg_name, sgr->sg_mem[i]);
|
||||
printf(_("delete member `%s'? "), sgr->sg_mem[i]);
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
SYSLOG((LOG_INFO,
|
||||
"delete member `%s' from shadow group `%s'\n",
|
||||
sgr->sg_mem[i], sgr->sg_name));
|
||||
deleted++;
|
||||
delete_member(sgr->sg_mem, sgr->sg_mem[i]);
|
||||
sge->changed = 1;
|
||||
__sgr_set_changed();
|
||||
}
|
||||
}
|
||||
|
||||
shadow_done:
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* All done. If there were no deletions we can just abandon any
|
||||
* changes to the files.
|
||||
*/
|
||||
|
||||
if (deleted) {
|
||||
if (!gr_close()) {
|
||||
fprintf(stderr, _("%s: cannot update file %s\n"),
|
||||
Prog, grp_file);
|
||||
exit(E_CANT_UPDATE);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow && !sgr_close()) {
|
||||
fprintf(stderr, _("%s: cannot update file %s\n"),
|
||||
Prog, sgr_file);
|
||||
exit(E_CANT_UPDATE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't be anti-social - unlock the files when you're done.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow)
|
||||
sgr_unlock();
|
||||
#endif
|
||||
(void) gr_unlock();
|
||||
|
||||
/*
|
||||
* Tell the user what we did and exit.
|
||||
*/
|
||||
|
||||
if (errors)
|
||||
#ifdef NDBM
|
||||
printf(deleted ?
|
||||
_("%s: the files have been updated; run mkpasswd\n") :
|
||||
_("%s: no changes\n"), Prog);
|
||||
#else
|
||||
printf(deleted ?
|
||||
_("%s: the files have been updated\n") :
|
||||
_("%s: no changes\n"), Prog);
|
||||
#endif
|
||||
|
||||
exit(errors ? E_BAD_ENTRY : E_OKAY);
|
||||
}
|
174
src/grpconv.c
Normal file
174
src/grpconv.c
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* grpconv - create or update /etc/gshadow with information from
|
||||
* /etc/group.
|
||||
*
|
||||
* Copyright (C) 1996, Marek Michalkiewicz
|
||||
* <marekm@i17linuxb.ists.pwr.wroc.pl>
|
||||
* This program may be freely used and distributed. If you improve
|
||||
* it, please send me your changes. Thanks!
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
|
||||
#include "groupio.h"
|
||||
#include "sgroupio.h"
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: grpconv.c,v 1.10 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
static int group_locked = 0;
|
||||
static int gshadow_locked = 0;
|
||||
|
||||
/* local function prototypes */
|
||||
static void fail_exit P_((int));
|
||||
int main P_((int, char **));
|
||||
|
||||
static void
|
||||
fail_exit(int status)
|
||||
{
|
||||
if (group_locked)
|
||||
gr_unlock();
|
||||
if (gshadow_locked)
|
||||
sgr_unlock();
|
||||
exit(status);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const struct group *gr;
|
||||
struct group grent;
|
||||
const struct sgrp *sg;
|
||||
struct sgrp sgent;
|
||||
char *Prog = argv[0];
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (!gr_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock group file\n"), Prog);
|
||||
fail_exit(5);
|
||||
}
|
||||
group_locked++;
|
||||
if (!gr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open group file\n"), Prog);
|
||||
fail_exit(1);
|
||||
}
|
||||
|
||||
if (!sgr_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock shadow group file\n"), Prog);
|
||||
fail_exit(5);
|
||||
}
|
||||
gshadow_locked++;
|
||||
if (!sgr_open(O_CREAT | O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow group file\n"), Prog);
|
||||
fail_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove /etc/gshadow entries for groups not in /etc/group.
|
||||
*/
|
||||
sgr_rewind();
|
||||
while ((sg = sgr_next())) {
|
||||
if (gr_locate(sg->sg_name))
|
||||
continue;
|
||||
|
||||
if (!sgr_remove(sg->sg_name)) {
|
||||
/*
|
||||
* This shouldn't happen (the entry exists) but...
|
||||
*/
|
||||
fprintf(stderr, _("%s: can't remove shadow group %s\n"),
|
||||
Prog, sg->sg_name);
|
||||
fail_exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update shadow group passwords if non-shadow password is not "x".
|
||||
* Add any missing shadow group entries.
|
||||
*/
|
||||
gr_rewind();
|
||||
while ((gr = gr_next())) {
|
||||
sg = sgr_locate(gr->gr_name);
|
||||
if (sg) {
|
||||
#if 0 /* because of sg_mem, but see below */
|
||||
if (strcmp(gr->gr_passwd, SHADOW_PASSWD_STRING) == 0)
|
||||
continue;
|
||||
#endif
|
||||
/* update existing shadow group entry */
|
||||
sgent = *sg;
|
||||
if (strcmp(gr->gr_passwd, SHADOW_PASSWD_STRING) != 0)
|
||||
sgent.sg_passwd = gr->gr_passwd;
|
||||
} else {
|
||||
static char *empty = 0;
|
||||
|
||||
/* add new shadow group entry */
|
||||
memset(&sgent, 0, sizeof sgent);
|
||||
sgent.sg_name = gr->gr_name;
|
||||
sgent.sg_passwd = gr->gr_passwd;
|
||||
sgent.sg_adm = ∅
|
||||
}
|
||||
/*
|
||||
* XXX - sg_mem is redundant, it is currently always a copy
|
||||
* of gr_mem. Very few programs actually use sg_mem, and
|
||||
* all of them are in the shadow suite... Maybe this field
|
||||
* could be used for something else? Any suggestions?
|
||||
*/
|
||||
sgent.sg_mem = gr->gr_mem;
|
||||
|
||||
if (!sgr_update(&sgent)) {
|
||||
fprintf(stderr,
|
||||
_("%s: can't update shadow entry for %s\n"),
|
||||
Prog, sgent.sg_name);
|
||||
fail_exit(3);
|
||||
}
|
||||
/* remove password from /etc/group */
|
||||
grent = *gr;
|
||||
grent.gr_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
|
||||
if (!gr_update(&grent)) {
|
||||
fprintf(stderr,
|
||||
_("%s: can't update entry for group %s\n"),
|
||||
Prog, grent.gr_name);
|
||||
fail_exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sgr_close()) {
|
||||
fprintf(stderr, _("%s: can't update shadow group file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
if (!gr_close()) {
|
||||
fprintf(stderr, _("%s: can't update group file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
sgr_unlock();
|
||||
gr_unlock();
|
||||
return 0;
|
||||
}
|
||||
#else /* !SHADOWGRP */
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
fprintf(stderr, _("%s: not configured for shadow group support.\n"),
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
#endif /* !SHADOWGRP */
|
132
src/grpunconv.c
Normal file
132
src/grpunconv.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* grpunconv - update /etc/group with information from /etc/gshadow.
|
||||
*
|
||||
* Copyright (C) 1996, Michael Meskes <meskes@debian.org>
|
||||
* using sources from Marek Michalkiewicz
|
||||
* <marekm@i17linuxb.ists.pwr.wroc.pl>
|
||||
* This program may be freely used and distributed. If you improve
|
||||
* it, please send me your changes. Thanks!
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: grpunconv.c,v 1.9 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <grp.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
|
||||
#include "groupio.h"
|
||||
#include "sgroupio.h"
|
||||
|
||||
static int group_locked = 0;
|
||||
static int gshadow_locked = 0;
|
||||
|
||||
/* local function prototypes */
|
||||
static void fail_exit P_((int));
|
||||
int main P_((int, char **));
|
||||
|
||||
static void
|
||||
fail_exit(int status)
|
||||
{
|
||||
if (group_locked)
|
||||
gr_unlock();
|
||||
if (gshadow_locked)
|
||||
sgr_unlock();
|
||||
exit(status);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const struct group *gr;
|
||||
struct group grent;
|
||||
const struct sgrp *sg;
|
||||
char *Prog = argv[0];
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (!sgr_file_present())
|
||||
exit(0); /* no /etc/gshadow, nothing to do */
|
||||
|
||||
if (!gr_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock group file\n"), Prog);
|
||||
fail_exit(5);
|
||||
}
|
||||
group_locked++;
|
||||
if (!gr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open group file\n"), Prog);
|
||||
fail_exit(1);
|
||||
}
|
||||
|
||||
if (!sgr_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock shadow group file\n"), Prog);
|
||||
fail_exit(5);
|
||||
}
|
||||
gshadow_locked++;
|
||||
if (!sgr_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow group file\n"), Prog);
|
||||
fail_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update group passwords if non-shadow password is "x".
|
||||
*/
|
||||
gr_rewind();
|
||||
while ((gr = gr_next())) {
|
||||
sg = sgr_locate(gr->gr_name);
|
||||
if (sg && strcmp(gr->gr_passwd, SHADOW_PASSWD_STRING) == 0) {
|
||||
/* add password to /etc/group */
|
||||
grent = *gr;
|
||||
grent.gr_passwd = sg->sg_passwd;
|
||||
if (!gr_update(&grent)) {
|
||||
fprintf(stderr,
|
||||
_("%s: can't update entry for group %s\n"),
|
||||
Prog, grent.gr_name);
|
||||
fail_exit(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sgr_close()) {
|
||||
fprintf(stderr, _("%s: can't update shadow group file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
|
||||
if (!gr_close()) {
|
||||
fprintf(stderr, _("%s: can't update group file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
|
||||
if (unlink(SGROUP_FILE) != 0) {
|
||||
fprintf(stderr, _("%s: can't delete shadow group file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
|
||||
sgr_unlock();
|
||||
gr_unlock();
|
||||
return 0;
|
||||
}
|
||||
#else /* !SHADOWGRP */
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
fprintf(stderr, _("%s: not configured for shadow group support.\n"), argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
#endif /* !SHADOWGRP */
|
188
src/id.c
Normal file
188
src/id.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 1991 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* id - print current process user identification information
|
||||
*
|
||||
* Print the current process identifiers. This includes the
|
||||
* UID, GID, effective-UID and effective-GID. Optionally print
|
||||
* the concurrent group set if the current system supports it.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: id.c,v 1.5 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include "defines.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
int main P_((int, char **));
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#ifdef HAVE_GETGROUPS
|
||||
fprintf(stderr, _("usage: id [ -a ]\n"));
|
||||
#else
|
||||
fprintf(stderr, _("usage: id\n"));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
uid_t ruid, euid;
|
||||
gid_t rgid, egid;
|
||||
int i;
|
||||
/*
|
||||
* This block of declarations is particularly strained because of several
|
||||
* different ways of doing concurrent groups. Old BSD systems used int
|
||||
* for gid's, but short for the type passed to getgroups(). Newer systems
|
||||
* use gid_t for everything. Some systems have a small and fixed NGROUPS,
|
||||
* usually about 16 or 32. Others use bigger values.
|
||||
*/
|
||||
#ifdef HAVE_GETGROUPS
|
||||
GETGROUPS_T groups[NGROUPS_MAX];
|
||||
int ngroups;
|
||||
int aflg = 0;
|
||||
#endif
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
/*
|
||||
* See if the -a flag has been given to print out the
|
||||
* concurrent group set.
|
||||
*/
|
||||
|
||||
if (argc > 1) {
|
||||
if (argc > 2 || strcmp (argv[1], "-a"))
|
||||
usage();
|
||||
else
|
||||
aflg = 1;
|
||||
}
|
||||
#else
|
||||
if (argc > 1)
|
||||
usage();
|
||||
#endif
|
||||
|
||||
ruid = getuid();
|
||||
euid = geteuid();
|
||||
rgid = getgid();
|
||||
egid = getegid();
|
||||
|
||||
/*
|
||||
* Print out the real user ID and group ID. If the user or
|
||||
* group does not exist, just give the numerical value.
|
||||
*/
|
||||
|
||||
pw = getpwuid(ruid);
|
||||
if (pw)
|
||||
printf(_("uid=%d(%s)"), (int) ruid, pw->pw_name);
|
||||
else
|
||||
printf(_("uid=%d"), (int) ruid);
|
||||
|
||||
gr = getgrgid(rgid);
|
||||
if (gr)
|
||||
printf(_(" gid=%d(%s)"), (int) rgid, gr->gr_name);
|
||||
else
|
||||
printf(_(" gid=%d"), (int) rgid);
|
||||
|
||||
/*
|
||||
* Print out the effective user ID and group ID if they are
|
||||
* different from the real values.
|
||||
*/
|
||||
|
||||
if (ruid != euid) {
|
||||
pw = getpwuid(euid);
|
||||
if (pw)
|
||||
printf(_(" euid=%d(%s)"), (int) euid, pw->pw_name);
|
||||
else
|
||||
printf(_(" euid=%d"), (int) euid);
|
||||
}
|
||||
if (rgid != egid) {
|
||||
gr = getgrgid(egid);
|
||||
if (gr)
|
||||
printf(_(" egid=%d(%s)"), (int) egid, gr->gr_name);
|
||||
else
|
||||
printf(_(" egid=%d"), (int) egid);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
/*
|
||||
* Print out the concurrent group set if the user has requested
|
||||
* it. The group numbers will be printed followed by their
|
||||
* names.
|
||||
*/
|
||||
|
||||
if (aflg && (ngroups = getgroups (NGROUPS_MAX, groups)) != -1) {
|
||||
|
||||
/*
|
||||
* Start off the group message. It will be of the format
|
||||
*
|
||||
* groups=###(aaa),###(aaa),###(aaa)
|
||||
*
|
||||
* where "###" is a numerical value and "aaa" is the
|
||||
* corresponding name for each respective numerical value.
|
||||
*/
|
||||
|
||||
printf(_(" groups="));
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
if (i)
|
||||
putchar(',');
|
||||
|
||||
gr = getgrgid(groups[i]);
|
||||
if (gr)
|
||||
printf("%d(%s)", (int) groups[i], gr->gr_name);
|
||||
else
|
||||
printf("%d", (int) groups[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Finish off the line.
|
||||
*/
|
||||
|
||||
putchar('\n');
|
||||
exit(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
193
src/lastlog.c
Normal file
193
src/lastlog.c
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: lastlog.c,v 1.5 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#if HAVE_LASTLOG_H
|
||||
#include <lastlog.h>
|
||||
#else
|
||||
#include "lastlog_.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Needed for MkLinux DR1/2/2.1 - J.
|
||||
*/
|
||||
#ifndef LASTLOG_FILE
|
||||
#define LASTLOG_FILE "/var/log/lastlog"
|
||||
#endif
|
||||
|
||||
static FILE *lastlogfile; /* lastlog file stream */
|
||||
static off_t user; /* one single user, specified on command line */
|
||||
static int days; /* number of days to consider for print command */
|
||||
static time_t seconds; /* that number of days in seconds */
|
||||
|
||||
static int uflg = 0; /* set if user is a valid user id */
|
||||
static int tflg = 0; /* print is restricted to most recent days */
|
||||
static struct lastlog lastlog; /* scratch structure to play with ... */
|
||||
static struct stat statbuf; /* fstat buffer for file size */
|
||||
static struct passwd *pwent;
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
#define NOW (time ((time_t *) 0))
|
||||
|
||||
/* local function prototypes */
|
||||
int main P_((int, char **));
|
||||
static void print P_((void));
|
||||
static void print_one P_((const struct passwd *));
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if ((lastlogfile = fopen (LASTLOG_FILE,"r")) == (FILE *) 0) {
|
||||
perror (LASTLOG_FILE);
|
||||
exit (1);
|
||||
}
|
||||
while ((c = getopt (argc, argv, "u:t:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
pwent = getpwnam (optarg);
|
||||
if (!pwent) {
|
||||
fprintf(stderr,
|
||||
_("Unknown User: %s\n"),
|
||||
optarg);
|
||||
exit (1);
|
||||
}
|
||||
uflg++;
|
||||
user = pwent->pw_uid;
|
||||
break;
|
||||
case 't':
|
||||
days = atoi (optarg);
|
||||
seconds = days * DAY;
|
||||
tflg++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
print ();
|
||||
fclose (lastlogfile);
|
||||
exit (0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
static void
|
||||
print(void)
|
||||
{
|
||||
off_t offset;
|
||||
|
||||
if (uflg) {
|
||||
offset = (unsigned long) user * sizeof lastlog;
|
||||
if (fstat (fileno (lastlogfile), &statbuf)) {
|
||||
perror(LASTLOG_FILE);
|
||||
return;
|
||||
}
|
||||
if (offset >= statbuf.st_size)
|
||||
return;
|
||||
|
||||
fseek (lastlogfile, offset, SEEK_SET);
|
||||
if (fread ((char *) &lastlog, sizeof lastlog, 1,
|
||||
lastlogfile) == 1)
|
||||
print_one (pwent);
|
||||
else
|
||||
perror (LASTLOG_FILE);
|
||||
} else {
|
||||
setpwent ();
|
||||
while ((pwent = getpwent ())) {
|
||||
user = pwent->pw_uid;
|
||||
offset = (unsigned long) user * sizeof lastlog;
|
||||
fseek (lastlogfile, offset, SEEK_SET);
|
||||
if (fread ((char *) &lastlog, sizeof lastlog, 1,
|
||||
lastlogfile) != 1)
|
||||
continue;
|
||||
|
||||
if (tflg && NOW - lastlog.ll_time > seconds)
|
||||
continue;
|
||||
|
||||
print_one (pwent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_one(const struct passwd *pw)
|
||||
{
|
||||
static int once;
|
||||
char *cp;
|
||||
struct tm *tm;
|
||||
#ifdef HAVE_STRFTIME
|
||||
char ptime[80];
|
||||
#endif
|
||||
|
||||
if (! pw)
|
||||
return;
|
||||
|
||||
if (! once) {
|
||||
#ifdef HAVE_LL_HOST
|
||||
printf(_("Username Port From Latest\n"));
|
||||
#else
|
||||
printf(_("Username Port Latest\n"));
|
||||
#endif
|
||||
once++;
|
||||
}
|
||||
tm = localtime (&lastlog.ll_time);
|
||||
#ifdef HAVE_STRFTIME
|
||||
strftime(ptime, sizeof(ptime), "%a %b %e %H:%M:%S %z %Y", tm);
|
||||
cp = ptime;
|
||||
#else
|
||||
cp = asctime (tm);
|
||||
cp[24] = '\0';
|
||||
#endif
|
||||
|
||||
if(lastlog.ll_time == (time_t) 0)
|
||||
cp = _("**Never logged in**\0");
|
||||
|
||||
#ifdef HAVE_LL_HOST
|
||||
printf ("%-16s %-8.8s %-16.16s %s\n", pw->pw_name,
|
||||
lastlog.ll_line, lastlog.ll_host, cp);
|
||||
#else
|
||||
printf ("%-16s\t%-8.8s %s\n", pw->pw_name,
|
||||
lastlog.ll_line, cp);
|
||||
#endif
|
||||
}
|
1260
src/login.c
Normal file
1260
src/login.c
Normal file
File diff suppressed because it is too large
Load Diff
316
src/logoutd.c
Normal file
316
src/logoutd.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright 1991 - 1993, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: logoutd.c,v 1.13 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <utmp.h>
|
||||
#include <fcntl.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#ifdef SVR4
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifdef SVR4
|
||||
#define signal sigset
|
||||
#endif
|
||||
|
||||
static char *Prog;
|
||||
|
||||
static char *mesg_buf = "login time exceeded\r\n"; /* XXX warning: const */
|
||||
static int mesg_len = 21;
|
||||
static int mesg_size;
|
||||
|
||||
#ifndef HUP_MESG_FILE
|
||||
#define HUP_MESG_FILE "/etc/logoutd.mesg"
|
||||
#endif
|
||||
|
||||
/* local function prototypes */
|
||||
static RETSIGTYPE reload_mesg P_((int));
|
||||
static int check_login P_((const struct utmp *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* reload_mesg - reload the message that is output when killing a process
|
||||
*/
|
||||
|
||||
static RETSIGTYPE
|
||||
reload_mesg(int sig)
|
||||
{
|
||||
int fd;
|
||||
struct stat sb;
|
||||
|
||||
signal (sig, reload_mesg);
|
||||
|
||||
if (stat (HUP_MESG_FILE, &sb))
|
||||
return;
|
||||
|
||||
if ((sb.st_mode & S_IFMT) != S_IFREG)
|
||||
return;
|
||||
|
||||
if ((fd = open (HUP_MESG_FILE, O_RDONLY)) != -1) {
|
||||
if (sb.st_size + 1 > mesg_size) {
|
||||
if (mesg_buf && mesg_size)
|
||||
free (mesg_buf);
|
||||
|
||||
mesg_len = sb.st_size;
|
||||
mesg_size = mesg_len + 1;
|
||||
if (! (mesg_buf = (char *) malloc (mesg_len + 1)))
|
||||
goto end;
|
||||
} else
|
||||
mesg_len = sb.st_size;
|
||||
|
||||
if (read (fd, mesg_buf, mesg_len) != mesg_len) {
|
||||
mesg_len = 0;
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
return;
|
||||
|
||||
end:
|
||||
close (fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* check_login - check if user (struct utmp) allowed to stay logged in
|
||||
*/
|
||||
static int
|
||||
check_login(const struct utmp *ut)
|
||||
{
|
||||
char user[sizeof(ut->ut_user) + 1];
|
||||
time_t now;
|
||||
|
||||
/*
|
||||
* ut_user may not have the terminating NUL.
|
||||
*/
|
||||
strncpy(user, ut->ut_user, sizeof(ut->ut_user));
|
||||
user[sizeof(ut->ut_user)] = '\0';
|
||||
|
||||
time(&now);
|
||||
|
||||
/*
|
||||
* Check if they are allowed to be logged in right now.
|
||||
*/
|
||||
if (!isttytime(user, ut->ut_line, now))
|
||||
return 0;
|
||||
#if 0
|
||||
/*
|
||||
* Check for how long they are allowed to stay logged in.
|
||||
* XXX - not implemented yet. Need to add a new field to
|
||||
* /etc/porttime (login time limit in minutes, or no limit,
|
||||
* based on username, tty, and time of login).
|
||||
*/
|
||||
if (now - ut->ut_time > get_time_limit(user, ut->ut_line, ut->ut_time))
|
||||
return 0;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* logoutd - logout daemon to enforce /etc/porttime file policy
|
||||
*
|
||||
* logoutd is started at system boot time and enforces the login
|
||||
* time and port restrictions specified in /etc/porttime. The
|
||||
* utmp file is periodically scanned and offending users are logged
|
||||
* off from the system.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int status;
|
||||
struct utmp *ut;
|
||||
char user[sizeof(ut->ut_user) + 1]; /* terminating NUL */
|
||||
char tty_name[sizeof(ut->ut_line) + 6]; /* /dev/ + NUL */
|
||||
int tty_fd;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
#ifndef DEBUG
|
||||
for (i = 0;close (i) == 0;i++)
|
||||
;
|
||||
|
||||
#ifdef HAVE_SETPGRP
|
||||
#ifdef SETPGRP_VOID
|
||||
setpgrp(); /* USG */
|
||||
#else
|
||||
setpgrp(getpid(), getpid());
|
||||
#endif
|
||||
#else /* !HAVE_SETPGRP */
|
||||
setpgid(getpid(), getpid()); /* BSD || SUN || SUN4 */
|
||||
#endif /* !HAVE_SETPGRP */
|
||||
|
||||
reload_mesg (SIGHUP);
|
||||
|
||||
/*
|
||||
* Put this process in the background.
|
||||
*/
|
||||
|
||||
if ((i = fork ()))
|
||||
exit (i < 0 ? 1:0);
|
||||
#endif /* !DEBUG */
|
||||
|
||||
/*
|
||||
* Start syslogging everything
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
/*
|
||||
* Scan the UTMP file once per minute looking for users that
|
||||
* are not supposed to still be logged in.
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
#ifndef DEBUG
|
||||
sleep(60);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attempt to re-open the utmp file. The file is only
|
||||
* open while it is being used.
|
||||
*/
|
||||
|
||||
setutent();
|
||||
|
||||
/*
|
||||
* Read all of the entries in the utmp file. The entries
|
||||
* for login sessions will be checked to see if the user
|
||||
* is permitted to be signed on at this time.
|
||||
*/
|
||||
|
||||
while ((ut = getutent())) {
|
||||
#ifdef USER_PROCESS
|
||||
if (ut->ut_type != USER_PROCESS)
|
||||
continue;
|
||||
#endif
|
||||
if (ut->ut_user[0] == '\0')
|
||||
continue;
|
||||
if (check_login(ut))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Put the rest of this in a child process. This
|
||||
* keeps the scan from waiting on other ports to die.
|
||||
*/
|
||||
|
||||
if (fork() != 0)
|
||||
continue;
|
||||
|
||||
if (strncmp(ut->ut_line, "/dev/", 5) != 0)
|
||||
strcpy(tty_name, "/dev/");
|
||||
else
|
||||
tty_name[0] = '\0';
|
||||
|
||||
strcat(tty_name, ut->ut_line);
|
||||
#ifndef O_NOCTTY
|
||||
#define O_NOCTTY 0
|
||||
#endif
|
||||
if ((tty_fd = open (tty_name,
|
||||
O_WRONLY|O_NDELAY|O_NOCTTY)) != -1) {
|
||||
/* Suggested by Ivan Nejgebauar <ian@unsux.ns.ac.yu>: set OPOST
|
||||
before writing the message. --marekm */
|
||||
TERMIO oldt, newt;
|
||||
|
||||
GTTY(tty_fd, &oldt);
|
||||
newt = oldt;
|
||||
#ifdef OPOST
|
||||
newt.c_oflag |= OPOST;
|
||||
#else /* XXX - I'm too young to know bsd sgtty, sorry :). --marekm */
|
||||
#endif
|
||||
STTY(tty_fd, &newt);
|
||||
write (tty_fd, mesg_buf, mesg_len);
|
||||
STTY(tty_fd, &oldt);
|
||||
close (tty_fd);
|
||||
sleep(10);
|
||||
}
|
||||
#ifdef USER_PROCESS /* USG_UTMP */
|
||||
if (ut->ut_pid > 1) {
|
||||
kill(- ut->ut_pid, SIGHUP);
|
||||
sleep(10);
|
||||
kill(- ut->ut_pid, SIGKILL);
|
||||
}
|
||||
#else /* BSD || SUN || SUN4 */
|
||||
/*
|
||||
* vhangup() the line to kill try and kill
|
||||
* whatever is out there using it.
|
||||
*/
|
||||
|
||||
if ((tty_fd = open (tty_name, O_RDONLY|O_NDELAY)) == -1)
|
||||
continue;
|
||||
|
||||
vhangup (tty_fd);
|
||||
close (tty_fd);
|
||||
#endif /* BSD || SUN || SUN4 */
|
||||
|
||||
#if 0
|
||||
SYSLOG((LOG_NOTICE,
|
||||
"logged off user `%.*s' on `%.*s'\n",
|
||||
(int) sizeof(ut->ut_user), ut->ut_user,
|
||||
(int) sizeof(ut->ut_line), ut->ut_line));
|
||||
#else
|
||||
/* avoid gcc warnings about %.*s in syslog() */
|
||||
strncpy(user, ut->ut_line, sizeof(user) - 1);
|
||||
user[sizeof(user) - 1] = '\0';
|
||||
|
||||
SYSLOG((LOG_NOTICE, "logged off user `%s' on `%s'\n",
|
||||
user, tty_name));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This child has done all it can, drop dead.
|
||||
*/
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
endutent();
|
||||
|
||||
/*
|
||||
* Reap any dead babies ...
|
||||
*/
|
||||
|
||||
while (wait (&status) != -1)
|
||||
;
|
||||
}
|
||||
return 1; /* not reached */
|
||||
}
|
395
src/mkpasswd.c
Normal file
395
src/mkpasswd.c
Normal file
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright 1990 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: mkpasswd.c,v 1.6 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(NDBM) /*{*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
fprintf(stderr,
|
||||
_("%s: no DBM database on system - no action performed\n"),
|
||||
argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /*} defined(NDBM) {*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <ndbm.h>
|
||||
#include <grp.h>
|
||||
|
||||
extern DBM *pw_dbm;
|
||||
extern DBM *gr_dbm;
|
||||
#ifdef SHADOWPWD
|
||||
extern DBM *sp_dbm;
|
||||
#endif
|
||||
#ifdef SHADOWGRP
|
||||
extern DBM *sg_dbm;
|
||||
#endif
|
||||
char *fgetsx();
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#ifdef SHADOWGRP
|
||||
#define USAGE _("Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n")
|
||||
#else /* !SHADOWGRP */
|
||||
#define USAGE _("Usage: %s [ -vf ] [ -p|g|sp ] file\n")
|
||||
#endif /* SHADOWGRP */
|
||||
#else /* !SHADOWPWD */
|
||||
#define USAGE _("Usage: %s [ -vf ] [ -p|g ] file\n")
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
char *Progname;
|
||||
int vflg = 0;
|
||||
int fflg = 0;
|
||||
int gflg = 0;
|
||||
int sflg = 0; /* -s flag -- leave in, makes code nicer */
|
||||
int pflg = 0;
|
||||
|
||||
extern struct passwd *sgetpwent();
|
||||
extern int pw_dbm_update();
|
||||
|
||||
extern struct group *sgetgrent();
|
||||
extern int gr_dbm_update();
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
extern struct spwd *sgetspent();
|
||||
extern int sp_dbm_update();
|
||||
#endif
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
extern struct sgrp *sgetsgent();
|
||||
extern int sg_dbm_update();
|
||||
#endif
|
||||
|
||||
/* local function prototypes */
|
||||
int main P_((int, char **));
|
||||
static void usage P_((void));
|
||||
|
||||
/*
|
||||
* mkpasswd - create DBM files for /etc/passwd-like input file
|
||||
*
|
||||
* mkpasswd takes an an argument the name of a file in /etc/passwd format
|
||||
* and creates a DBM file keyed by user ID and name. The output files have
|
||||
* the same name as the input file, with .dir and .pag appended.
|
||||
*
|
||||
* this command will also create look-aside files for
|
||||
* /etc/group, /etc/shadow, and /etc/gshadow.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
FILE *fp; /* File pointer for input file */
|
||||
char *file; /* Name of input file */
|
||||
char *dir; /* Name of .dir file */
|
||||
char *pag; /* Name of .pag file */
|
||||
char *cp; /* Temporary character pointer */
|
||||
int flag; /* Flag for command line option */
|
||||
int cnt = 0; /* Number of entries in database */
|
||||
int longest = 0; /* Longest entry in database */
|
||||
int len; /* Length of input line */
|
||||
int errors = 0; /* Count of errors processing file */
|
||||
char buf[BUFSIZ*8]; /* Input line from file */
|
||||
struct passwd *passwd=NULL; /* Pointer to password file entry */
|
||||
|
||||
struct group *group=NULL; /* Pointer to group file entry */
|
||||
#ifdef SHADOWPWD
|
||||
struct spwd *shadow=NULL; /* Pointer to shadow passwd entry */
|
||||
#endif
|
||||
#ifdef SHADOWGRP
|
||||
struct sgrp *gshadow=NULL; /* Pointer to shadow group entry */
|
||||
#endif
|
||||
DBM *dbm; /* Pointer to new NDBM files */
|
||||
DBM *dbm_open(); /* Function to open NDBM files */
|
||||
|
||||
/*
|
||||
* Figure out what my name is. I will use this later ...
|
||||
*/
|
||||
|
||||
Progname = Basename(argv[0]);
|
||||
|
||||
/*
|
||||
* Figure out what the flags might be ...
|
||||
*/
|
||||
|
||||
while ((flag = getopt (argc, argv, "fvpgs")) != EOF) {
|
||||
switch (flag) {
|
||||
case 'v':
|
||||
vflg++;
|
||||
break;
|
||||
case 'f':
|
||||
fflg++;
|
||||
break;
|
||||
case 'g':
|
||||
gflg++;
|
||||
#ifndef SHADOWGRP
|
||||
if (sflg)
|
||||
usage ();
|
||||
#endif
|
||||
if (pflg)
|
||||
usage ();
|
||||
|
||||
break;
|
||||
#if defined(SHADOWPWD) || defined(SHADOWGRP)
|
||||
case 's':
|
||||
sflg++;
|
||||
#ifndef SHADOWGRP
|
||||
if (gflg)
|
||||
usage ();
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
pflg++;
|
||||
if (gflg)
|
||||
usage ();
|
||||
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Backwards compatibility fix for -p flag ...
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (! sflg && ! gflg)
|
||||
#else
|
||||
if (! gflg)
|
||||
#endif
|
||||
pflg++;
|
||||
|
||||
/*
|
||||
* The last and only remaining argument must be the file name
|
||||
*/
|
||||
|
||||
if (argc - 1 != optind)
|
||||
usage ();
|
||||
|
||||
file = argv[optind];
|
||||
|
||||
if (! (fp = fopen (file, "r"))) {
|
||||
fprintf (stderr, _("%s: cannot open file %s\n"), Progname, file);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the filenames for the two DBM files.
|
||||
*/
|
||||
|
||||
dir = xmalloc (strlen (file) + 5); /* space for .dir file */
|
||||
strcat (strcpy (dir, file), ".dir");
|
||||
|
||||
pag = xmalloc (strlen (file) + 5); /* space for .pag file */
|
||||
strcat (strcpy (pag, file), ".pag");
|
||||
|
||||
/*
|
||||
* Remove existing files if requested.
|
||||
*/
|
||||
|
||||
if (fflg) {
|
||||
(void) unlink (dir);
|
||||
(void) unlink (pag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the two DBM files - it is an error for these files
|
||||
* to have existed already.
|
||||
*/
|
||||
|
||||
if (access(dir, F_OK) == 0) {
|
||||
fprintf (stderr, _("%s: cannot overwrite file %s\n"), Progname, dir);
|
||||
exit (1);
|
||||
}
|
||||
if (access(pag, F_OK) == 0) {
|
||||
fprintf (stderr, _("%s: cannot overwrite file %s\n"), Progname, pag);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (sflg)
|
||||
umask(077);
|
||||
else
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Now the DBM database gets initialized
|
||||
*/
|
||||
|
||||
if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) {
|
||||
fprintf (stderr, _("%s: cannot open DBM files for %s\n"), Progname, file);
|
||||
exit (1);
|
||||
}
|
||||
if (gflg) {
|
||||
#ifdef SHADOWGRP
|
||||
if (sflg)
|
||||
sg_dbm = dbm;
|
||||
else
|
||||
#endif
|
||||
gr_dbm = dbm;
|
||||
} else {
|
||||
#ifdef SHADOWPWD
|
||||
if (sflg)
|
||||
sp_dbm = dbm;
|
||||
else
|
||||
#endif
|
||||
pw_dbm = dbm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read every line in the password file and convert it into a
|
||||
* data structure to be put in the DBM database files.
|
||||
*/
|
||||
|
||||
while (fgetsx (buf, BUFSIZ, fp) != NULL) {
|
||||
|
||||
/*
|
||||
* Get the next line and strip off the trailing newline
|
||||
* character.
|
||||
*/
|
||||
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
if (! (cp = strchr (buf, '\n'))) {
|
||||
fprintf (stderr, _("%s: the beginning with "%.16s ..." is too long\n"), Progname, buf);
|
||||
exit (1);
|
||||
}
|
||||
*cp = '\0';
|
||||
len = strlen (buf);
|
||||
|
||||
#ifdef USE_NIS
|
||||
/*
|
||||
* Parse the password file line into a (struct passwd).
|
||||
* Erroneous lines cause error messages, but that's
|
||||
* all. YP lines are ignored completely.
|
||||
*/
|
||||
|
||||
if (buf[0] == '-' || buf[0] == '+')
|
||||
continue;
|
||||
#endif
|
||||
if (! (((! sflg && pflg) && (passwd = sgetpwent (buf)))
|
||||
#ifdef SHADOWPWD
|
||||
|| ((sflg && pflg) && (shadow = sgetspent (buf)))
|
||||
#endif
|
||||
|| ((! sflg && gflg) && (group = sgetgrent (buf)))
|
||||
#ifdef SHADOWGRP
|
||||
|| ((sflg && gflg) && (gshadow = sgetsgent (buf)))
|
||||
#endif
|
||||
)) {
|
||||
fprintf (stderr, _("%s: error parsing line \"%s\"\n"), Progname, buf);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if (vflg) {
|
||||
if (!sflg && pflg) printf (_("adding record for name "%s"\n"), passwd->pw_name);
|
||||
#ifdef SHADOWPWD
|
||||
if (sflg && pflg) printf (_("adding record for name "%s"\n"), shadow->sp_namp);
|
||||
#endif
|
||||
if (!sflg && gflg) printf (_("adding record for name "%s"\n"), group->gr_name);
|
||||
#ifdef SHADOWGRP
|
||||
if (sflg && gflg) printf (_("adding record for name "%s"\n"), gshadow->sg_name);
|
||||
#endif
|
||||
}
|
||||
if (! sflg && pflg && ! pw_dbm_update (passwd))
|
||||
fprintf (stderr, _("%s: error adding record for "%s"\n"),
|
||||
Progname, passwd->pw_name);
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (sflg && pflg && ! sp_dbm_update (shadow))
|
||||
fprintf (stderr, _("%s: error adding record for "%s"\n"),
|
||||
Progname, shadow->sp_namp);
|
||||
#endif
|
||||
if (! sflg && gflg && ! gr_dbm_update (group))
|
||||
fprintf (stderr, _("%s: error adding record for "%s"\n"),
|
||||
Progname, group->gr_name);
|
||||
#ifdef SHADOWGRP
|
||||
if (sflg && gflg && ! sg_dbm_update (gshadow))
|
||||
fprintf (stderr, _("%s: error adding record for "%s"\n"),
|
||||
Progname, gshadow->sg_name);
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Update the longest record and record count
|
||||
*/
|
||||
|
||||
if (len > longest)
|
||||
longest = len;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the user how things went ...
|
||||
*/
|
||||
|
||||
if (vflg)
|
||||
printf (_("added %d entries, longest was %d\n"), cnt, longest);
|
||||
|
||||
exit (errors);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/*
|
||||
* usage - print error message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#ifdef SHADOWPWD
|
||||
#ifdef SHADOWGRP
|
||||
fprintf (stderr, _("Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"), Progname);
|
||||
#else /* !SHADOWGRP */
|
||||
fprintf (stderr, _("Usage: %s [ -vf ] [ -p|g|sp ] file\n"), Progname);
|
||||
#endif /* SHADOWGRP */
|
||||
#else /* !SHADOWPWD */
|
||||
fprintf (stderr, _("Usage: %s [ -vf ] [ -p|g ] file\n"), Progname);
|
||||
#endif /* SHADOWPWD */
|
||||
|
||||
|
||||
exit (1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif /*} defined(NDBM) */
|
479
src/newgrp.c
Normal file
479
src/newgrp.c
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright 1990 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: newgrp.c,v 1.13 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include "getdef.h"
|
||||
|
||||
extern char **environ;
|
||||
|
||||
#ifdef HAVE_SETGROUPS
|
||||
static int ngroups;
|
||||
static GETGROUPS_T *grouplist;
|
||||
#endif
|
||||
|
||||
static char *Prog;
|
||||
static int is_newgrp;
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - print command usage message
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
if (is_newgrp)
|
||||
fprintf (stderr, _("usage: newgrp [ - ] [ group ]\n"));
|
||||
else
|
||||
fprintf (stderr, _("usage: sg group [ command ]\n"));
|
||||
}
|
||||
|
||||
/*
|
||||
* newgrp - change the invokers current real and effective group id
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int initflag = 0;
|
||||
int needspasswd = 0;
|
||||
int i;
|
||||
int cflag = 0;
|
||||
gid_t gid;
|
||||
char *cp;
|
||||
const char *cpasswd, *name, *prog;
|
||||
char *group = NULL;
|
||||
char *command=NULL;
|
||||
char **envp = environ;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
#ifdef SHADOWPWD
|
||||
struct spwd *spwd;
|
||||
#endif
|
||||
#ifdef SHADOWGRP
|
||||
struct sgrp *sgrp;
|
||||
#endif
|
||||
|
||||
sanitize_env();
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* save my name for error messages and save my real gid incase
|
||||
* of errors. if there is an error i have to exec a new login
|
||||
* shell for the user since her old shell won't have fork'd to
|
||||
* create the process. skip over the program name to the next
|
||||
* command line argument.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
is_newgrp = (strcmp(Prog, "newgrp") == 0);
|
||||
openlog(is_newgrp ? "newgrp" : "sg", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
gid = getgid();
|
||||
argc--; argv++;
|
||||
|
||||
initenv();
|
||||
|
||||
pwd = get_my_pwent();
|
||||
if (!pwd) {
|
||||
fprintf (stderr, _("unknown uid: %d\n"), (int) getuid());
|
||||
SYSLOG((LOG_WARN, "unknown uid %d\n", (int) getuid()));
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
name = pwd->pw_name;
|
||||
|
||||
/*
|
||||
* Parse the command line. There are two accepted flags. The
|
||||
* first is "-", which for newgrp means to re-create the entire
|
||||
* environment as though a login had been performed, and "-c",
|
||||
* which for sg causes a command string to be executed.
|
||||
*
|
||||
* The next argument, if present, must be the new group name.
|
||||
* Any remaining remaining arguments will be used to execute a
|
||||
* command as the named group. If the group name isn't present,
|
||||
* I just use the login group ID of the current user.
|
||||
*
|
||||
* The valid syntax are
|
||||
* newgrp [ - ] [ groupid ]
|
||||
* newgrp [ -l ] [ groupid ]
|
||||
* sg [ - ]
|
||||
* sg [ - ] groupid [ command ]
|
||||
*/
|
||||
|
||||
if (argc > 0 && (!strcmp(argv[0], "-") || !strcmp(argv[0], "-l"))) {
|
||||
argc--; argv++;
|
||||
initflag = 1;
|
||||
}
|
||||
if (!is_newgrp) {
|
||||
/*
|
||||
* Do the command line for everything that is
|
||||
* not "newgrp".
|
||||
*/
|
||||
|
||||
if (argc > 0 && argv[0][0] != '-') {
|
||||
group = argv[0];
|
||||
argc--; argv++;
|
||||
} else {
|
||||
usage ();
|
||||
closelog();
|
||||
exit (1);
|
||||
}
|
||||
if (argc > 0) {
|
||||
command = argv[1];
|
||||
cflag++;
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Do the command line for "newgrp". It's just
|
||||
* making sure there aren't any flags and getting
|
||||
* the new group name.
|
||||
*/
|
||||
|
||||
if (argc > 0 && argv[0][0] == '-') {
|
||||
usage ();
|
||||
goto failure;
|
||||
} else if (argv[0] != (char *) 0) {
|
||||
group = argv[0];
|
||||
} else {
|
||||
|
||||
/*
|
||||
* get the group file entry for her login group id.
|
||||
* the entry must exist, simply to be annoying.
|
||||
*/
|
||||
|
||||
if (! (grp = getgrgid (pwd->pw_gid))) {
|
||||
fprintf(stderr, _("unknown gid: %ld\n"),
|
||||
(long) pwd->pw_gid);
|
||||
SYSLOG((LOG_CRIT, "unknown gid: %ld\n",
|
||||
(long) pwd->pw_gid));
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETGROUPS
|
||||
/*
|
||||
* get the current users groupset. the new group will be
|
||||
* added to the concurrent groupset if there is room, otherwise
|
||||
* you get a nasty message but at least your real and effective
|
||||
* group id's are set.
|
||||
*/
|
||||
|
||||
/* don't use getgroups(0, 0) - it doesn't work on some systems */
|
||||
i = 16;
|
||||
for (;;) {
|
||||
grouplist = (GETGROUPS_T *) xmalloc(i * sizeof(GETGROUPS_T));
|
||||
ngroups = getgroups(i, grouplist);
|
||||
/* XXX Bug#38672
|
||||
login: newgrp/sg fails with user in 17 groups */
|
||||
if (i > ngroups && !(ngroups == -1 && errno == EINVAL))
|
||||
break;
|
||||
/* not enough room, so try allocating a larger buffer */
|
||||
free(grouplist);
|
||||
i *= 2;
|
||||
}
|
||||
if (ngroups < 0) {
|
||||
perror("getgroups");
|
||||
exit(1);
|
||||
}
|
||||
#endif /* HAVE_SETGROUPS */
|
||||
|
||||
/*
|
||||
* now we put her in the new group. the password file entry for
|
||||
* her current user id has been gotten. if there was no optional
|
||||
* group argument she will have her real and effective group id
|
||||
* set to the value from her password file entry. otherwise
|
||||
* we validate her access to the specified group.
|
||||
*/
|
||||
|
||||
if (group == (char *) 0) {
|
||||
if (! (grp = getgrgid (pwd->pw_gid))) {
|
||||
fprintf (stderr, _("unknown gid: %d\n"), pwd->pw_gid);
|
||||
goto failure;
|
||||
}
|
||||
group = grp->gr_name;
|
||||
} else if (! (grp = getgrnam (group))) {
|
||||
fprintf (stderr, _("unknown group: %s\n"), group);
|
||||
goto failure;
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if ((sgrp = getsgnam (group))) {
|
||||
grp->gr_passwd = sgrp->sg_passwd;
|
||||
grp->gr_mem = sgrp->sg_mem;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* see if she is a member of this group.
|
||||
* if she isn't a member, she needs to provide the
|
||||
* group password. if there is no group password, she
|
||||
* will be denied access anyway.
|
||||
*/
|
||||
|
||||
if (!is_on_list(grp->gr_mem, name))
|
||||
needspasswd = 1;
|
||||
|
||||
/*
|
||||
* if she does not have either a shadowed password,
|
||||
* or a regular password, and the group has a password,
|
||||
* she needs to give the group password.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if ((spwd = getspnam (name)))
|
||||
pwd->pw_passwd = spwd->sp_pwdp;
|
||||
#endif
|
||||
|
||||
if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
|
||||
needspasswd = 1;
|
||||
|
||||
/*
|
||||
* now i see about letting her into the group she requested.
|
||||
* if she is the root user, i'll let her in without having to
|
||||
* prompt for the password. otherwise i ask for a password
|
||||
* if she flunked one of the tests above. note that she
|
||||
* won't have to provide the password to her login group even
|
||||
* if she isn't listed as a member.
|
||||
*/
|
||||
|
||||
if (getuid () != 0 && needspasswd) {
|
||||
|
||||
/*
|
||||
* get the password from her, and set the salt for
|
||||
* the decryption from the group file.
|
||||
*/
|
||||
|
||||
if (! (cp = getpass (_("Password:"))))
|
||||
goto failure;
|
||||
|
||||
/*
|
||||
* encrypt the key she gave us using the salt from
|
||||
* the password in the group file. the result of
|
||||
* this encryption must match the previously
|
||||
* encrypted value in the file.
|
||||
*/
|
||||
|
||||
cpasswd = pw_encrypt (cp, grp->gr_passwd);
|
||||
strzero(cp);
|
||||
|
||||
if (grp->gr_passwd[0] == '\0') {
|
||||
/*
|
||||
* there is no password, print out "Sorry" and give up
|
||||
*/
|
||||
sleep(1);
|
||||
fputs (_("Sorry.\n"), stderr);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (strcmp (cpasswd, grp->gr_passwd) != 0) {
|
||||
SYSLOG((LOG_INFO,
|
||||
"Invalid password for group `%s' from `%s'\n",
|
||||
group, name));
|
||||
sleep(1);
|
||||
fputs (_("Sorry.\n"), stderr);
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* all successful validations pass through this point. the
|
||||
* group id will be set, and the group added to the concurrent
|
||||
* groupset.
|
||||
*/
|
||||
|
||||
#ifdef USE_SYSLOG
|
||||
if (getdef_bool ("SYSLOG_SG_ENAB"))
|
||||
SYSLOG((LOG_INFO, "user `%s' switched to group `%s'\n",
|
||||
name, group));
|
||||
#endif
|
||||
gid = grp->gr_gid;
|
||||
|
||||
#ifdef HAVE_SETGROUPS
|
||||
/*
|
||||
* i am going to try to add her new group id to her concurrent
|
||||
* group set. if the group id is already present i'll just
|
||||
* skip this part. if the group doesn't fit, i'll complain
|
||||
* loudly and skip this part ...
|
||||
*/
|
||||
|
||||
for (i = 0;i < ngroups;i++) {
|
||||
if (gid == grouplist[i])
|
||||
break;
|
||||
}
|
||||
if (i == ngroups) {
|
||||
if (ngroups >= NGROUPS_MAX) {
|
||||
fprintf (stderr, _("too many groups\n"));
|
||||
} else {
|
||||
grouplist[ngroups++] = gid;
|
||||
if (setgroups(ngroups, grouplist)) {
|
||||
perror("setgroups");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
okay:
|
||||
/*
|
||||
* i set her group id either to the value she requested, or
|
||||
* to the original value if the newgrp failed.
|
||||
*/
|
||||
|
||||
if (setgid(gid))
|
||||
perror("setgid");
|
||||
|
||||
if (setuid(getuid())) {
|
||||
perror("setuid");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* see if the "-c" flag was used. if it was, i just create a
|
||||
* shell command for her using the argument that followed the
|
||||
* "-c" flag.
|
||||
*/
|
||||
|
||||
if (cflag) {
|
||||
closelog();
|
||||
execl("/bin/sh", "sh", "-c", command, (char *) 0);
|
||||
if (errno == ENOENT) {
|
||||
perror("/bin/sh");
|
||||
exit(127);
|
||||
} else {
|
||||
perror("/bin/sh");
|
||||
exit(126);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* i have to get the pathname of her login shell. as a favor,
|
||||
* i'll try her environment for a $SHELL value first, and
|
||||
* then try the password file entry. obviously this shouldn't
|
||||
* be in the restricted command directory since it could be
|
||||
* used to leave the restricted environment.
|
||||
*/
|
||||
|
||||
if (! initflag && (cp = getenv ("SHELL")))
|
||||
prog = cp;
|
||||
else if (pwd->pw_shell && pwd->pw_shell[0])
|
||||
prog = pwd->pw_shell;
|
||||
else
|
||||
prog = "/bin/sh";
|
||||
|
||||
/*
|
||||
* now i try to find the basename of the login shell. this
|
||||
* will become argv[0] of the spawned command.
|
||||
*/
|
||||
|
||||
cp = Basename((char *) prog);
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
endspent ();
|
||||
#endif
|
||||
#ifdef SHADOWGRP
|
||||
endsgent ();
|
||||
#endif
|
||||
endpwent ();
|
||||
endgrent ();
|
||||
|
||||
/*
|
||||
* switch back to her home directory if i am doing login
|
||||
* initialization.
|
||||
*/
|
||||
|
||||
if (initflag) {
|
||||
if (chdir (pwd->pw_dir))
|
||||
perror("chdir");
|
||||
|
||||
while (*envp) {
|
||||
if (strncmp (*envp, "PATH=", 5) == 0 ||
|
||||
strncmp (*envp, "HOME=", 5) == 0 ||
|
||||
strncmp (*envp, "SHELL=", 6) == 0 ||
|
||||
strncmp (*envp, "TERM=", 5) == 0)
|
||||
addenv(*envp, NULL);
|
||||
|
||||
envp++;
|
||||
}
|
||||
} else {
|
||||
while (*envp)
|
||||
addenv(*envp++, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* exec the login shell and go away. we are trying to get
|
||||
* back to the previous environment which should be the
|
||||
* user's login shell.
|
||||
*/
|
||||
|
||||
shell(prog, initflag ? (char *)0 : cp);
|
||||
/*NOTREACHED*/
|
||||
|
||||
failure:
|
||||
/*
|
||||
* this is where all failures land. the group id will not
|
||||
* have been set, so the setgid() below will set me to the
|
||||
* original group id i had when i was invoked.
|
||||
*/
|
||||
|
||||
/*
|
||||
* only newgrp needs to re-exec the user's shell. that is
|
||||
* because the shell doesn't recognize "sg", so it doesn't
|
||||
* "exec" this command.
|
||||
*/
|
||||
|
||||
if (!is_newgrp) {
|
||||
closelog();
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The GID is still set to the old value, so now I can
|
||||
* give the user back her shell.
|
||||
*/
|
||||
|
||||
goto okay;
|
||||
}
|
571
src/newusers.c
Normal file
571
src/newusers.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Copyright 1990 - 1993, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*
|
||||
* newusers - create users from a batch file
|
||||
*
|
||||
* newusers creates a collection of entries in /etc/passwd
|
||||
* and related files by reading a passwd-format file and
|
||||
* adding entries in the related directories.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: newusers.c,v 1.10 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static char *Prog;
|
||||
|
||||
extern char *crypt_make_salt P_((void));
|
||||
|
||||
#include "getdef.h"
|
||||
#include "pwio.h"
|
||||
#include "groupio.h"
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#include "shadowio.h"
|
||||
|
||||
static int is_shadow;
|
||||
#endif
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static int add_group P_((const char *, const char *, gid_t *));
|
||||
static int add_user P_((const char *, const char *, uid_t *, gid_t));
|
||||
static void update_passwd P_((struct passwd *, const char *));
|
||||
static int add_passwd P_((struct passwd *, const char *));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("Usage: %s [ input ]\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* add_group - create a new group or add a user to an existing group
|
||||
*/
|
||||
|
||||
static int
|
||||
add_group(const char *name, const char *gid, gid_t *ngid)
|
||||
{
|
||||
const struct passwd *pwd;
|
||||
const struct group *grp;
|
||||
struct group grent;
|
||||
char *members[2];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Start by seeing if the named group already exists. This
|
||||
* will be very easy to deal with if it does.
|
||||
*/
|
||||
|
||||
if ((grp = gr_locate (gid))) {
|
||||
add_member:
|
||||
grent = *grp;
|
||||
*ngid = grent.gr_gid;
|
||||
for (i = 0;grent.gr_mem[i] != (char *) 0;i++)
|
||||
if (strcmp (grent.gr_mem[i], name) == 0)
|
||||
return 0;
|
||||
|
||||
grent.gr_mem = (char **) xmalloc (sizeof (char *) * (i + 2));
|
||||
memcpy (grent.gr_mem, grp->gr_mem, sizeof (char *) * (i + 2));
|
||||
grent.gr_mem[i] = xstrdup (name);
|
||||
grent.gr_mem[i + 1] = (char *) 0;
|
||||
|
||||
return ! gr_update (&grent);
|
||||
}
|
||||
|
||||
/*
|
||||
* The group did not exist, so I try to figure out what the
|
||||
* GID is going to be. The gid parameter is probably "", meaning
|
||||
* I figure out the GID from the password file. I want the UID
|
||||
* and GID to match, unless the GID is already used.
|
||||
*/
|
||||
|
||||
if (gid[0] == '\0') {
|
||||
i = 100;
|
||||
for (pw_rewind ();(pwd = pw_next ());) {
|
||||
if (pwd->pw_uid >= i)
|
||||
i = pwd->pw_uid + 1;
|
||||
}
|
||||
for (gr_rewind ();(grp = gr_next ());) {
|
||||
if (grp->gr_gid == i) {
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (gid[0] >= '0' && gid[0] <= '9') {
|
||||
|
||||
/*
|
||||
* The GID is a number, which means either this is a brand new
|
||||
* group, or an existing group. For existing groups I just add
|
||||
* myself as a member, just like I did earlier.
|
||||
*/
|
||||
|
||||
i = atoi (gid);
|
||||
for (gr_rewind ();(grp = gr_next ());)
|
||||
if (grp->gr_gid == i)
|
||||
goto add_member;
|
||||
} else
|
||||
|
||||
/*
|
||||
* The last alternative is that the GID is a name which is not
|
||||
* already the name of an existing group, and I need to figure
|
||||
* out what group ID that group name is going to have.
|
||||
*/
|
||||
|
||||
i = -1;
|
||||
|
||||
/*
|
||||
* If I don't have a group ID by now, I'll go get the
|
||||
* next one.
|
||||
*/
|
||||
|
||||
if (i == -1) {
|
||||
for (i = 100, gr_rewind ();(grp = gr_next ());)
|
||||
if (grp->gr_gid >= i)
|
||||
i = grp->gr_gid + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now I have all of the fields required to create the new
|
||||
* group.
|
||||
*/
|
||||
|
||||
if (gid[0] && (gid[0] <= '0' || gid[0] >= '9'))
|
||||
grent.gr_name = xstrdup(gid);
|
||||
else
|
||||
grent.gr_name = xstrdup(name);
|
||||
|
||||
grent.gr_passwd = "x"; /* XXX warning: const */
|
||||
grent.gr_gid = i;
|
||||
members[0] = xstrdup(name);
|
||||
members[1] = (char *) 0;
|
||||
grent.gr_mem = members;
|
||||
|
||||
*ngid = grent.gr_gid;
|
||||
return ! gr_update (&grent);
|
||||
}
|
||||
|
||||
/*
|
||||
* add_user - create a new user ID
|
||||
*/
|
||||
|
||||
static int
|
||||
add_user(const char *name, const char *uid, uid_t *nuid, gid_t gid)
|
||||
{
|
||||
const struct passwd *pwd;
|
||||
struct passwd pwent;
|
||||
uid_t i;
|
||||
|
||||
/*
|
||||
* The first guess for the UID is either the numerical UID
|
||||
* that the caller provided, or the next available UID.
|
||||
*/
|
||||
|
||||
if (uid[0] >= '0' && uid[0] <= '9') {
|
||||
i = atoi (uid);
|
||||
} else if (uid[0] && (pwd = pw_locate (uid))) {
|
||||
i = pwd->pw_uid;
|
||||
} else {
|
||||
i = 100;
|
||||
for (pw_rewind ();(pwd = pw_next ());)
|
||||
if (pwd->pw_uid >= i)
|
||||
i = pwd->pw_uid + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* I don't want to fill in the entire password structure
|
||||
* members JUST YET, since there is still more data to be
|
||||
* added. So, I fill in the parts that I have.
|
||||
*/
|
||||
|
||||
pwent.pw_name = xstrdup(name);
|
||||
pwent.pw_passwd = "x"; /* XXX warning: const */
|
||||
#ifdef ATT_AGE
|
||||
pwent.pw_age = "";
|
||||
#endif
|
||||
#ifdef ATT_COMMENT
|
||||
pwent.pw_comment = "";
|
||||
#endif
|
||||
#ifdef BSD_QUOTA
|
||||
pwent.pw_quota = 0;
|
||||
#endif
|
||||
pwent.pw_uid = i;
|
||||
pwent.pw_gid = gid;
|
||||
pwent.pw_gecos = ""; /* XXX warning: const */
|
||||
pwent.pw_dir = ""; /* XXX warning: const */
|
||||
pwent.pw_shell = ""; /* XXX warning: const */
|
||||
|
||||
*nuid = i;
|
||||
return ! pw_update (&pwent);
|
||||
}
|
||||
|
||||
static void
|
||||
update_passwd(struct passwd *pwd, const char *passwd)
|
||||
{
|
||||
pwd->pw_passwd = pw_encrypt(passwd, crypt_make_salt());
|
||||
#ifdef ATT_AGE
|
||||
if (strlen(pwd->pw_age) == 4) {
|
||||
static char newage[5];
|
||||
extern char *l64a();
|
||||
|
||||
strcpy(newage, pwd->pw_age);
|
||||
strcpy(newage + 2, l64a(time((time_t *) 0) / WEEK));
|
||||
pwd->pw_age = newage;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* add_passwd - add or update the encrypted password
|
||||
*/
|
||||
|
||||
static int
|
||||
add_passwd(struct passwd *pwd, const char *passwd)
|
||||
{
|
||||
#ifdef SHADOWPWD
|
||||
const struct spwd *sp;
|
||||
struct spwd spent;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In the case of regular password files, this is real
|
||||
* easy - pwd points to the entry in the password file.
|
||||
* Shadow files are harder since there are zillions of
|
||||
* things to do ...
|
||||
*/
|
||||
|
||||
if (!is_shadow) {
|
||||
update_passwd(pwd, passwd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
/*
|
||||
* Do the first and easiest shadow file case. The user
|
||||
* already exists in the shadow password file.
|
||||
*/
|
||||
|
||||
if ((sp = spw_locate (pwd->pw_name))) {
|
||||
spent = *sp;
|
||||
spent.sp_pwdp = pw_encrypt(passwd, crypt_make_salt());
|
||||
return ! spw_update (&spent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick the next easiest case - the user has an encrypted
|
||||
* password which isn't equal to "x". The password was set
|
||||
* to "x" earlier when the entry was created, so this user
|
||||
* would have to have had the password set someplace else.
|
||||
*/
|
||||
|
||||
if (strcmp (pwd->pw_passwd, "x") != 0) {
|
||||
update_passwd(pwd, passwd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the really hard case - I need to create an entirely
|
||||
* new shadow password file entry.
|
||||
*/
|
||||
|
||||
spent.sp_namp = pwd->pw_name;
|
||||
spent.sp_pwdp = pw_encrypt(passwd, crypt_make_salt());
|
||||
spent.sp_lstchg = time((time_t *) 0) / SCALE;
|
||||
spent.sp_min = getdef_num("PASS_MIN_DAYS", 0);
|
||||
/* 10000 is infinity this week */
|
||||
spent.sp_max = getdef_num("PASS_MAX_DAYS", 10000);
|
||||
spent.sp_warn = getdef_num("PASS_WARN_AGE", -1);
|
||||
spent.sp_inact = -1;
|
||||
spent.sp_expire = -1;
|
||||
spent.sp_flag = -1;
|
||||
|
||||
return ! spw_update (&spent);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
char *fields[8];
|
||||
int nfields;
|
||||
char *cp;
|
||||
const struct passwd *pw;
|
||||
struct passwd newpw;
|
||||
int errors = 0;
|
||||
int line = 0;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc > 1 && argv[1][0] == '-')
|
||||
usage ();
|
||||
|
||||
if (argc == 2) {
|
||||
if (! freopen (argv[1], "r", stdin)) {
|
||||
snprintf(buf, sizeof buf, "%s: %s", Prog, argv[1]);
|
||||
perror (buf);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the password files and open them for update. This will
|
||||
* bring all of the entries into memory where they may be
|
||||
* searched for an modified, or new entries added. The password
|
||||
* file is the key - if it gets locked, assume the others can
|
||||
* be locked right away.
|
||||
*/
|
||||
|
||||
if (!pw_lock()) {
|
||||
fprintf (stderr, _("%s: can't lock /etc/passwd.\n"), Prog);
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
is_shadow = spw_file_present();
|
||||
|
||||
if ((is_shadow && !spw_lock()) || !gr_lock())
|
||||
#else
|
||||
if (!gr_lock())
|
||||
#endif
|
||||
{
|
||||
fprintf (stderr, _("%s: can't lock files, try again later\n"),
|
||||
Prog);
|
||||
(void) pw_unlock ();
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow)
|
||||
spw_unlock();
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (!pw_open(O_RDWR) || (is_shadow && !spw_open(O_RDWR)) || !gr_open(O_RDWR))
|
||||
#else
|
||||
if (!pw_open(O_RDWR) || !gr_open(O_RDWR))
|
||||
#endif
|
||||
{
|
||||
fprintf (stderr, _("%s: can't open files\n"), Prog);
|
||||
(void) pw_unlock ();
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow)
|
||||
spw_unlock();
|
||||
#endif
|
||||
(void) gr_unlock ();
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read each line. The line has the same format as a password
|
||||
* file entry, except that certain fields are not contrained to
|
||||
* be numerical values. If a group ID is entered which does
|
||||
* not already exist, an attempt is made to allocate the same
|
||||
* group ID as the numerical user ID. Should that fail, the
|
||||
* next available group ID over 100 is allocated. The pw_gid
|
||||
* field will be updated with that value.
|
||||
*/
|
||||
|
||||
while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
|
||||
line++;
|
||||
if ((cp = strrchr (buf, '\n'))) {
|
||||
*cp = '\0';
|
||||
} else {
|
||||
fprintf (stderr, _("%s: line %d: line too long\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Break the string into fields and screw around with
|
||||
* them. There MUST be 7 colon separated fields,
|
||||
* although the values aren't that particular.
|
||||
*/
|
||||
|
||||
for (cp = buf, nfields = 0;nfields < 7;nfields++) {
|
||||
fields[nfields] = cp;
|
||||
if ((cp = strchr (cp, ':')))
|
||||
*cp++ = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (nfields != 6) {
|
||||
fprintf (stderr, _("%s: line %d: invalid line\n"),
|
||||
Prog, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the fields are processed one by one. The first
|
||||
* field to be processed is the group name. A new
|
||||
* group will be created if the group name is non-numeric
|
||||
* and does not already exist. The named user will be
|
||||
* the only member. If there is no named group to be a
|
||||
* member of, the UID will be figured out and that value
|
||||
* will be a candidate for a new group, if that group ID
|
||||
* exists, a whole new group ID will be made up.
|
||||
*/
|
||||
|
||||
if (! (pw = pw_locate (fields[0])) &&
|
||||
add_group (fields[0], fields[3], &gid)) {
|
||||
fprintf (stderr, _("%s: line %d: can't create GID\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we work on the user ID. It has to be specified
|
||||
* either as a numerical value, or left blank. If it
|
||||
* is a numerical value, that value will be used, otherwise
|
||||
* the next available user ID is computed and used. After
|
||||
* this there will at least be a (struct passwd) for the
|
||||
* user.
|
||||
*/
|
||||
|
||||
if (! pw && add_user (fields[0], fields[2], &uid, gid)) {
|
||||
fprintf (stderr, _("%s: line %d: can't create UID\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The password, gecos field, directory, and shell fields
|
||||
* all come next.
|
||||
*/
|
||||
|
||||
if (! (pw = pw_locate (fields[0]))) {
|
||||
fprintf (stderr, _("%s: line %d: cannot find user %s\n"),
|
||||
Prog, line, fields[0]);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
newpw = *pw;
|
||||
|
||||
if (add_passwd (&newpw, fields[1])) {
|
||||
fprintf (stderr, _("%s: line %d: can't update password\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if (fields[4][0])
|
||||
newpw.pw_gecos = fields[4];
|
||||
|
||||
if (fields[5][0])
|
||||
newpw.pw_dir = fields[5];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the password entry with the new changes made.
|
||||
*/
|
||||
|
||||
if (! pw_update (&newpw)) {
|
||||
fprintf (stderr, _("%s: line %d: can't update entry\n"),
|
||||
Prog, line);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Any detected errors will cause the entire set of changes
|
||||
* to be aborted. Unlocking the password file will cause
|
||||
* all of the changes to be ignored. Otherwise the file is
|
||||
* closed, causing the changes to be written out all at
|
||||
* once, and then unlocked afterwards.
|
||||
*/
|
||||
|
||||
if (errors) {
|
||||
fprintf (stderr, _("%s: error detected, changes ignored\n"), Prog);
|
||||
(void) gr_unlock ();
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow)
|
||||
spw_unlock();
|
||||
#endif
|
||||
(void) pw_unlock ();
|
||||
exit (1);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (!pw_close() || (is_shadow && !spw_close()) || !gr_close())
|
||||
#else
|
||||
if (!pw_close() || ! gr_close())
|
||||
#endif
|
||||
{
|
||||
fprintf (stderr, _("%s: error updating files\n"), Prog);
|
||||
(void) gr_unlock ();
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow)
|
||||
spw_unlock();
|
||||
#endif
|
||||
(void) pw_unlock ();
|
||||
exit (1);
|
||||
}
|
||||
(void) gr_unlock ();
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow)
|
||||
spw_unlock();
|
||||
#endif
|
||||
(void) pw_unlock ();
|
||||
|
||||
exit (0);
|
||||
/*NOTREACHED*/
|
||||
}
|
1417
src/passwd.c
Normal file
1417
src/passwd.c
Normal file
File diff suppressed because it is too large
Load Diff
58
src/patchlevel.h
Normal file
58
src/patchlevel.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1991 - 1995, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*
|
||||
* Revision History
|
||||
* 11/25/91 3.1.1 patchlevel 14
|
||||
* Added "login.defs" to Makefile
|
||||
* 12/02/91 3.1.2 patchlevel 15
|
||||
* Bugs found by users
|
||||
* 12/28/91 3.1.3 patchlevel 16
|
||||
* Changes for SunOS 4.1.1
|
||||
* 02/08/92 3.1.4 patchlevel 17
|
||||
* Changes for SVR4, plus bug fixes
|
||||
* 04/03/92 3.2.1 patchlevel 18
|
||||
* Minor bug fixes, new baseline
|
||||
* 07/07/92 3.2.2 patchlevel 20
|
||||
* Added administrator defined authentication
|
||||
* 11/04/92 3.2.3 patchlevel 21
|
||||
* Bug fixes for SVR4
|
||||
* 07/23/93 3.3.0 patchlevel 23
|
||||
* New baseline release
|
||||
* 08/23/93 3.3.1 patchlevel 24
|
||||
* Bug fixes for SunOS 4.1.1
|
||||
* 08/27/93 3.3.2 patchlevel 25
|
||||
* Initial NIS support changes
|
||||
* 12/03/95 3.3.3 patchlevel 26
|
||||
* This is the Linux beta baseline. Marek will
|
||||
* change the name some other day. -- jfh
|
||||
* $Id: patchlevel.h,v 1.2 1997/05/01 23:07:16 marekm Exp $
|
||||
*/
|
||||
|
||||
#define RELEASE 3
|
||||
#define PATCHLEVEL 26
|
||||
#define VERSION "3.3.3"
|
617
src/pwck.c
Normal file
617
src/pwck.c
Normal file
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright 1992 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: pwck.c,v 1.13 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "chkname.h"
|
||||
#include <pwd.h>
|
||||
|
||||
#include "commonio.h"
|
||||
|
||||
#include "pwio.h"
|
||||
extern void __pw_del_entry P_((const struct commonio_entry *));
|
||||
extern struct commonio_entry *__pw_get_head P_((void));
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#include "shadowio.h"
|
||||
extern void __spw_del_entry P_((const struct commonio_entry *));
|
||||
extern struct commonio_entry *__spw_get_head P_((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exit codes
|
||||
*/
|
||||
|
||||
#define E_OKAY 0
|
||||
#define E_USAGE 1
|
||||
#define E_BADENTRY 2
|
||||
#define E_CANTOPEN 3
|
||||
#define E_CANTLOCK 4
|
||||
#define E_CANTUPDATE 5
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/*
|
||||
* Local variables
|
||||
*/
|
||||
|
||||
static char *Prog;
|
||||
static const char *pwd_file = PASSWD_FILE;
|
||||
#ifdef SHADOWPWD
|
||||
static const char *spw_file = SHADOW_FILE;
|
||||
#endif
|
||||
static int read_only = 0;
|
||||
static int quiet = 0; /* don't report warnings, only errors */
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static int yes_or_no P_((void));
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - print syntax message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#ifdef SHADOWPWD
|
||||
fprintf(stderr, _("Usage: %s [ -qr ] [ passwd [ shadow ] ]\n"), Prog);
|
||||
#else
|
||||
fprintf(stderr, _("Usage: %s [ -qr ] [ passwd ]\n"), Prog);
|
||||
#endif
|
||||
exit(E_USAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* yes_or_no - get answer to question from the user
|
||||
*/
|
||||
|
||||
static int
|
||||
yes_or_no(void)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
/*
|
||||
* In read-only mode all questions are answered "no".
|
||||
*/
|
||||
|
||||
if (read_only) {
|
||||
puts(_("No"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a line and see what the first character is.
|
||||
*/
|
||||
|
||||
if (fgets(buf, sizeof buf, stdin))
|
||||
return buf[0] == 'y' || buf[0] == 'Y';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* pwck - verify password file integrity
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int arg;
|
||||
int errors = 0;
|
||||
int deleted = 0;
|
||||
struct commonio_entry *pfe, *tpfe;
|
||||
struct passwd *pwd;
|
||||
#ifdef SHADOWPWD
|
||||
struct commonio_entry *spe, *tspe;
|
||||
struct spwd *spw;
|
||||
int is_shadow = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get my name so that I can use it to report errors.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
/*
|
||||
* Parse the command line arguments
|
||||
*/
|
||||
|
||||
while ((arg = getopt(argc, argv, "eqr")) != EOF) {
|
||||
switch (arg) {
|
||||
case 'e': /* added for Debian shadow-961025-2 compatibility */
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'r':
|
||||
read_only = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make certain we have the right number of arguments
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (optind != argc && optind + 1 != argc && optind + 2 != argc)
|
||||
#else
|
||||
if (optind != argc && optind + 1 != argc)
|
||||
#endif
|
||||
usage();
|
||||
|
||||
/*
|
||||
* If there are two left over filenames, use those as the
|
||||
* password and shadow password filenames.
|
||||
*/
|
||||
|
||||
if (optind != argc) {
|
||||
pwd_file = argv[optind];
|
||||
pw_name(pwd_file);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (optind + 2 == argc) {
|
||||
spw_file = argv[optind + 1];
|
||||
spw_name(spw_file);
|
||||
is_shadow = 1;
|
||||
} else if (optind == argc)
|
||||
is_shadow = spw_file_present();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lock the files if we aren't in "read-only" mode
|
||||
*/
|
||||
|
||||
if (!read_only) {
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("%s: cannot lock file %s\n"),
|
||||
Prog, pwd_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN,"cannot lock %s\n",pwd_file));
|
||||
closelog();
|
||||
exit(E_CANTLOCK);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow && !spw_lock()) {
|
||||
fprintf(stderr, _("%s: cannot lock file %s\n"),
|
||||
Prog, spw_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN,"cannot lock %s\n",spw_file));
|
||||
closelog();
|
||||
exit(E_CANTLOCK);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the files. Use O_RDONLY if we are in read_only mode,
|
||||
* O_RDWR otherwise.
|
||||
*/
|
||||
|
||||
if (!pw_open(read_only ? O_RDONLY:O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open file %s\n"),
|
||||
Prog, pwd_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN, "cannot open %s\n", pwd_file));
|
||||
closelog();
|
||||
exit(E_CANTOPEN);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow && !spw_open(read_only ? O_RDONLY : O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open file %s\n"),
|
||||
Prog, spw_file);
|
||||
if (optind == argc)
|
||||
SYSLOG((LOG_WARN, "cannot open %s\n", spw_file));
|
||||
closelog();
|
||||
exit(E_CANTOPEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Loop through the entire password file.
|
||||
*/
|
||||
|
||||
for (pfe = __pw_get_head(); pfe; pfe = pfe->next) {
|
||||
/*
|
||||
* If this is a NIS line, skip it. You can't "know" what
|
||||
* NIS is going to do without directly asking NIS ...
|
||||
*/
|
||||
|
||||
if (pfe->line[0] == '+' || pfe->line[0] == '-')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Start with the entries that are completely corrupt.
|
||||
* They have no (struct passwd) entry because they couldn't
|
||||
* be parsed properly.
|
||||
*/
|
||||
|
||||
if (!pfe->entry) {
|
||||
|
||||
/*
|
||||
* Tell the user this entire line is bogus and
|
||||
* ask them to delete it.
|
||||
*/
|
||||
|
||||
printf(_("invalid password file entry\n"));
|
||||
printf(_("delete line `%s'? "), pfe->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All password file deletions wind up here. This
|
||||
* code removes the current entry from the linked
|
||||
* list. When done, it skips back to the top of
|
||||
* the loop to try out the next list element.
|
||||
*/
|
||||
|
||||
delete_pw:
|
||||
SYSLOG((LOG_INFO, "delete passwd line `%s'\n",
|
||||
pfe->line));
|
||||
deleted++;
|
||||
|
||||
__pw_del_entry(pfe);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Password structure is good, start using it.
|
||||
*/
|
||||
|
||||
pwd = pfe->entry;
|
||||
|
||||
/*
|
||||
* Make sure this entry has a unique name.
|
||||
*/
|
||||
|
||||
for (tpfe = __pw_get_head(); tpfe; tpfe = tpfe->next) {
|
||||
const struct passwd *ent = tpfe->entry;
|
||||
|
||||
/*
|
||||
* Don't check this entry
|
||||
*/
|
||||
|
||||
if (tpfe == pfe)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't check invalid entries.
|
||||
*/
|
||||
|
||||
if (!ent)
|
||||
continue;
|
||||
|
||||
if (strcmp(pwd->pw_name, ent->pw_name) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Tell the user this entry is a duplicate of
|
||||
* another and ask them to delete it.
|
||||
*/
|
||||
|
||||
puts(_("duplicate password entry\n"));
|
||||
printf(_("delete line `%s'? "), pfe->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (yes_or_no())
|
||||
goto delete_pw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for invalid usernames. --marekm
|
||||
*/
|
||||
if (!check_user_name(pwd->pw_name)) {
|
||||
printf(_("invalid user name `%s'\n"), pwd->pw_name);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a Slackware bug. Make sure UID is not -1
|
||||
* (it has special meaning for some syscalls). --marekm
|
||||
*/
|
||||
|
||||
if (pwd->pw_uid == (uid_t) -1) {
|
||||
printf(_("user %s: bad UID (%d)\n"),
|
||||
pwd->pw_name, (int) pwd->pw_uid);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the primary group exists
|
||||
*/
|
||||
|
||||
if (!quiet && !getgrgid(pwd->pw_gid)) {
|
||||
|
||||
/*
|
||||
* No primary group, just give a warning
|
||||
*/
|
||||
|
||||
printf(_("user %s: no group %d\n"),
|
||||
pwd->pw_name, (int) pwd->pw_gid);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the home directory exists
|
||||
*/
|
||||
|
||||
if (!quiet && access(pwd->pw_dir, F_OK)) {
|
||||
|
||||
/*
|
||||
* Home directory doesn't exist, give a warning
|
||||
*/
|
||||
|
||||
printf(_("user %s: directory %s does not exist\n"),
|
||||
pwd->pw_name, pwd->pw_dir);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the login shell is executable
|
||||
*/
|
||||
|
||||
if (!quiet && pwd->pw_shell[0] && access(pwd->pw_shell, F_OK)) {
|
||||
|
||||
/*
|
||||
* Login shell doesn't exist, give a warning
|
||||
*/
|
||||
|
||||
printf(_("user %s: program %s does not exist\n"),
|
||||
pwd->pw_name, pwd->pw_shell);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (!is_shadow)
|
||||
goto shadow_done;
|
||||
|
||||
/*
|
||||
* Loop through the entire shadow password file.
|
||||
*/
|
||||
|
||||
for (spe = __spw_get_head(); spe; spe = spe->next) {
|
||||
/*
|
||||
* If this is a NIS line, skip it. You can't "know" what
|
||||
* NIS is going to do without directly asking NIS ...
|
||||
*/
|
||||
|
||||
if (spe->line[0] == '+' || spe->line[0] == '-')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Start with the entries that are completely corrupt.
|
||||
* They have no (struct spwd) entry because they couldn't
|
||||
* be parsed properly.
|
||||
*/
|
||||
|
||||
if (!spe->entry) {
|
||||
|
||||
/*
|
||||
* Tell the user this entire line is bogus and
|
||||
* ask them to delete it.
|
||||
*/
|
||||
|
||||
printf(_("invalid shadow password file entry\n"));
|
||||
printf(_("delete line `%s'? "), spe->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (!yes_or_no())
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All shadow file deletions wind up here. This
|
||||
* code removes the current entry from the linked
|
||||
* list. When done, it skips back to the top of
|
||||
* the loop to try out the next list element.
|
||||
*/
|
||||
|
||||
delete_spw:
|
||||
SYSLOG((LOG_INFO, "delete shadow line `%s'\n",
|
||||
spe->line));
|
||||
deleted++;
|
||||
|
||||
__spw_del_entry(spe);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shadow password structure is good, start using it.
|
||||
*/
|
||||
|
||||
spw = spe->entry;
|
||||
|
||||
/*
|
||||
* Make sure this entry has a unique name.
|
||||
*/
|
||||
|
||||
for (tspe = __spw_get_head(); tspe; tspe = tspe->next) {
|
||||
const struct spwd *ent = tspe->entry;
|
||||
|
||||
/*
|
||||
* Don't check this entry
|
||||
*/
|
||||
|
||||
if (tspe == spe)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't check invalid entries.
|
||||
*/
|
||||
|
||||
if (!ent)
|
||||
continue;
|
||||
|
||||
if (strcmp(spw->sp_namp, ent->sp_namp) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Tell the user this entry is a duplicate of
|
||||
* another and ask them to delete it.
|
||||
*/
|
||||
|
||||
puts(_("duplicate shadow password entry\n"));
|
||||
printf(_("delete line `%s'? "), spe->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (yes_or_no())
|
||||
goto delete_spw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure this entry exists in the /etc/passwd
|
||||
* file.
|
||||
*/
|
||||
|
||||
if (!pw_locate(spw->sp_namp)) {
|
||||
|
||||
/*
|
||||
* Tell the user this entry has no matching
|
||||
* /etc/passwd entry and ask them to delete it.
|
||||
*/
|
||||
|
||||
puts(_("no matching password file entry\n"));
|
||||
printf(_("delete line `%s'? "), spe->line);
|
||||
errors++;
|
||||
|
||||
/*
|
||||
* prompt the user to delete the entry or not
|
||||
*/
|
||||
|
||||
if (yes_or_no())
|
||||
goto delete_spw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn if last password change in the future. --marekm
|
||||
*/
|
||||
|
||||
if (!quiet && spw->sp_lstchg > time((time_t *)0) / SCALE) {
|
||||
printf(_("user %s: last password change in the future\n"), spw->sp_namp);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
shadow_done:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All done. If there were no deletions we can just abandon any
|
||||
* changes to the files.
|
||||
*/
|
||||
|
||||
if (deleted) {
|
||||
if (!pw_close()) {
|
||||
fprintf(stderr, _("%s: cannot update file %s\n"),
|
||||
Prog, pwd_file);
|
||||
SYSLOG((LOG_WARN, "cannot update %s\n", pwd_file));
|
||||
closelog();
|
||||
exit(E_CANTUPDATE);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow && !spw_close()) {
|
||||
fprintf(stderr, _("%s: cannot update file %s\n"),
|
||||
Prog, spw_file);
|
||||
SYSLOG((LOG_WARN, "cannot update %s\n", spw_file));
|
||||
closelog();
|
||||
exit(E_CANTUPDATE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't be anti-social - unlock the files when you're done.
|
||||
*/
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow)
|
||||
spw_unlock();
|
||||
#endif
|
||||
(void) pw_unlock();
|
||||
|
||||
/*
|
||||
* Tell the user what we did and exit.
|
||||
*/
|
||||
|
||||
if (errors)
|
||||
#ifdef NDBM
|
||||
printf(deleted ?
|
||||
_("%s: the files have been updated; run mkpasswd\n") :
|
||||
_("%s: no changes\n"), Prog);
|
||||
#else
|
||||
printf(deleted ?
|
||||
_("%s: the files have been updated\n") :
|
||||
_("%s: no changes\n"), Prog);
|
||||
#endif
|
||||
|
||||
closelog();
|
||||
exit(errors ? E_BADENTRY : E_OKAY);
|
||||
}
|
188
src/pwconv.c
Normal file
188
src/pwconv.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* pwconv - create or update /etc/shadow with information from
|
||||
* /etc/passwd.
|
||||
*
|
||||
* It is more like SysV pwconv, slightly different from the
|
||||
* original Shadow pwconv. Depends on "x" as password in
|
||||
* /etc/passwd which means that the password has already been
|
||||
* moved to /etc/shadow. There is no need to move /etc/npasswd
|
||||
* to /etc/passwd, password files are updated using library
|
||||
* routines with proper locking.
|
||||
*
|
||||
* Can be used to update /etc/shadow after adding/deleting users
|
||||
* by editing /etc/passwd. There is no man page yet, but this
|
||||
* program should be close to pwconv(1M) on Solaris 2.x.
|
||||
*
|
||||
* Warning: make sure that all users have "x" as the password in
|
||||
* /etc/passwd before running this program for the first time on
|
||||
* a system which already has shadow passwords. Anything else
|
||||
* (like "*" from old versions of the shadow suite) will replace
|
||||
* the user's encrypted password in /etc/shadow.
|
||||
*
|
||||
* Doesn't currently support pw_age information in /etc/passwd,
|
||||
* and doesn't support DBM files. Add it if you need it...
|
||||
*
|
||||
* Copyright (C) 1996-1997, Marek Michalkiewicz
|
||||
* <marekm@i17linuxb.ists.pwr.wroc.pl>
|
||||
* This program may be freely used and distributed for any purposes.
|
||||
* If you improve it, please send me your changes. Thanks!
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: pwconv.c,v 1.10 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "pwio.h"
|
||||
#include "shadowio.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* exit status values
|
||||
*/
|
||||
|
||||
#define E_SUCCESS 0 /* success */
|
||||
#define E_NOPERM 1 /* permission denied */
|
||||
#define E_USAGE 2 /* bad command syntax */
|
||||
#define E_FAILURE 3 /* unexpected failure, nothing done */
|
||||
#define E_MISSING 4 /* unexpected failure, passwd file missing */
|
||||
#define E_PWDBUSY 5 /* passwd file(s) busy */
|
||||
#define E_BADENTRY 6 /* bad shadow entry */
|
||||
|
||||
static int
|
||||
shadow_locked = 0,
|
||||
passwd_locked = 0;
|
||||
|
||||
/* local function prototypes */
|
||||
static void fail_exit P_((int));
|
||||
int main P_((int, char **));
|
||||
|
||||
static void
|
||||
fail_exit(int status)
|
||||
{
|
||||
if (shadow_locked)
|
||||
spw_unlock();
|
||||
if (passwd_locked)
|
||||
pw_unlock();
|
||||
exit(status);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const struct passwd *pw;
|
||||
struct passwd pwent;
|
||||
const struct spwd *sp;
|
||||
struct spwd spent;
|
||||
char *Prog = argv[0];
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock passwd file\n"), Prog);
|
||||
fail_exit(E_PWDBUSY);
|
||||
}
|
||||
passwd_locked++;
|
||||
if (!pw_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open passwd file\n"), Prog);
|
||||
fail_exit(E_MISSING);
|
||||
}
|
||||
|
||||
if (!spw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock shadow file\n"), Prog);
|
||||
fail_exit(E_PWDBUSY);
|
||||
}
|
||||
shadow_locked++;
|
||||
if (!spw_open(O_CREAT | O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
|
||||
fail_exit(E_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove /etc/shadow entries for users not in /etc/passwd.
|
||||
*/
|
||||
spw_rewind();
|
||||
while ((sp = spw_next())) {
|
||||
if (pw_locate(sp->sp_namp))
|
||||
continue;
|
||||
|
||||
if (!spw_remove(sp->sp_namp)) {
|
||||
/*
|
||||
* This shouldn't happen (the entry exists) but...
|
||||
*/
|
||||
fprintf(stderr,
|
||||
_("%s: can't remove shadow entry for %s\n"),
|
||||
Prog, sp->sp_namp);
|
||||
fail_exit(E_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update shadow entries which don't have "x" as pw_passwd.
|
||||
* Add any missing shadow entries.
|
||||
*/
|
||||
pw_rewind();
|
||||
while ((pw = pw_next())) {
|
||||
sp = spw_locate(pw->pw_name);
|
||||
if (sp) {
|
||||
/* do we need to update this entry? */
|
||||
if (strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING) == 0)
|
||||
continue;
|
||||
/* update existing shadow entry */
|
||||
spent = *sp;
|
||||
} else {
|
||||
/* add new shadow entry */
|
||||
memset(&spent, 0, sizeof spent);
|
||||
spent.sp_namp = pw->pw_name;
|
||||
spent.sp_min = getdef_num("PASS_MIN_DAYS", -1);
|
||||
spent.sp_max = getdef_num("PASS_MAX_DAYS", -1);
|
||||
spent.sp_warn = getdef_num("PASS_WARN_AGE", -1);
|
||||
spent.sp_inact = -1;
|
||||
spent.sp_expire = -1;
|
||||
spent.sp_flag = -1;
|
||||
}
|
||||
spent.sp_pwdp = pw->pw_passwd;
|
||||
spent.sp_lstchg = time((time_t *) 0) / (24L*3600L);
|
||||
if (!spw_update(&spent)) {
|
||||
fprintf(stderr,
|
||||
_("%s: can't update shadow entry for %s\n"),
|
||||
Prog, spent.sp_namp);
|
||||
fail_exit(E_FAILURE);
|
||||
}
|
||||
/* remove password from /etc/passwd */
|
||||
pwent = *pw;
|
||||
pwent.pw_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
|
||||
if (!pw_update(&pwent)) {
|
||||
fprintf(stderr,
|
||||
_("%s: can't update passwd entry for %s\n"),
|
||||
Prog, pwent.pw_name);
|
||||
fail_exit(E_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!spw_close()) {
|
||||
fprintf(stderr, _("%s: can't update shadow file\n"), Prog);
|
||||
fail_exit(E_FAILURE);
|
||||
}
|
||||
if (!pw_close()) {
|
||||
fprintf(stderr, _("%s: can't update passwd file\n"), Prog);
|
||||
fail_exit(E_FAILURE);
|
||||
}
|
||||
chmod(PASSWD_FILE "-", 0600); /* /etc/passwd- (backup file) */
|
||||
spw_unlock();
|
||||
pw_unlock();
|
||||
exit(E_SUCCESS);
|
||||
}
|
197
src/pwunconv.c
Normal file
197
src/pwunconv.c
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*
|
||||
* pwunconv - restore old password file from shadow password file.
|
||||
*
|
||||
* Pwunconv copies the password file information from the shadow
|
||||
* password file, merging entries from an optional existing shadow
|
||||
* file.
|
||||
*
|
||||
* Modifed by Guy Maor <maor@debian.org> to acquire necessary locks
|
||||
* and modify the files in place.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: pwunconv.c,v 1.8 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include "defines.h"
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include "prototypes.h"
|
||||
#include "pwio.h"
|
||||
#include "shadowio.h"
|
||||
|
||||
#ifndef SHADOWPWD
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
fprintf(stderr, _("%s: Shadow passwords are not configured.\n"),
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#else /*{*/
|
||||
|
||||
char *l64a ();
|
||||
|
||||
static int shadow_locked = 0,
|
||||
passwd_locked = 0;
|
||||
|
||||
/* local function prototypes */
|
||||
static void fail_exit P_((int));
|
||||
int main P_((int, char **));
|
||||
|
||||
static void
|
||||
fail_exit(int status)
|
||||
{
|
||||
if (shadow_locked)
|
||||
spw_unlock();
|
||||
if (passwd_locked)
|
||||
pw_unlock();
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const struct passwd *pw;
|
||||
struct passwd pwent;
|
||||
const struct spwd *spwd;
|
||||
#ifdef ATT_AGE
|
||||
char newage[5];
|
||||
#endif
|
||||
char *Prog = argv[0];
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
if (!spw_file_present())
|
||||
/* shadow not installed, do nothing */
|
||||
exit(0);
|
||||
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("%s: can't lock passwd file\n"), Prog);
|
||||
fail_exit(5);
|
||||
}
|
||||
passwd_locked++;
|
||||
if (!pw_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open passwd file\n"), Prog);
|
||||
fail_exit(1);
|
||||
}
|
||||
|
||||
if (!spw_lock()) {
|
||||
fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
|
||||
fail_exit(5);
|
||||
}
|
||||
shadow_locked++;
|
||||
if (!spw_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
|
||||
fail_exit(1);
|
||||
}
|
||||
|
||||
pw_rewind();
|
||||
while ((pw = pw_next())) {
|
||||
if (!(spwd = spw_locate(pw->pw_name)))
|
||||
continue;
|
||||
|
||||
pwent = *pw;
|
||||
|
||||
/*
|
||||
* Update password if non-shadow is "x".
|
||||
*/
|
||||
if (strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING) == 0)
|
||||
pwent.pw_passwd = spwd->sp_pwdp;
|
||||
|
||||
/*
|
||||
* Password aging works differently in the two different systems.
|
||||
* With shadow password files you apparently must have some aging
|
||||
* information. The maxweeks or minweeks may not map exactly.
|
||||
* In pwconv we set max == 10000, which is about 30 years. Here
|
||||
* we have to undo that kludge. So, if maxdays == 10000, no aging
|
||||
* information is put into the new file. Otherwise, the days are
|
||||
* converted to weeks and so on.
|
||||
*/
|
||||
|
||||
#ifdef ATT_AGE
|
||||
if (spwd->sp_max > (63*WEEK/SCALE) && spwd->sp_max < 10000)
|
||||
spwd->sp_max = (63*WEEK/SCALE); /* 10000 is infinity */
|
||||
|
||||
if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 &&
|
||||
spwd->sp_max >= 0 && spwd->sp_max <= 63*7) {
|
||||
if (spwd->sp_lstchg == -1)
|
||||
spwd->sp_lstchg = 0;
|
||||
|
||||
spwd->sp_max /= WEEK/SCALE; /* turn it into weeks */
|
||||
spwd->sp_min /= WEEK/SCALE;
|
||||
spwd->sp_lstchg /= WEEK/SCALE;
|
||||
|
||||
strncpy (newage, l64a (spwd->sp_lstchg * (64L*64L) +
|
||||
spwd->sp_min * (64L) + spwd->sp_max), 5);
|
||||
pwent.pw_age = newage;
|
||||
} else
|
||||
pwent.pw_age = "";
|
||||
#endif /* ATT_AGE */
|
||||
if (!pw_update(&pwent)) {
|
||||
fprintf(stderr,
|
||||
_("%s: can't update entry for user %s\n"),
|
||||
Prog, pwent.pw_name);
|
||||
fail_exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
if (!spw_close()) {
|
||||
fprintf(stderr, _("%s: can't update shadow password file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
|
||||
if (!pw_close()) {
|
||||
fprintf(stderr, _("%s: can't update password file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
|
||||
if (unlink(SHADOW) != 0) {
|
||||
fprintf(stderr, _("%s: can't delete shadow password file\n"), Prog);
|
||||
fail_exit(3);
|
||||
}
|
||||
|
||||
spw_unlock();
|
||||
pw_unlock();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
67
src/shadowconfig.sh
Executable file
67
src/shadowconfig.sh
Executable file
@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
# turn shadow passwords on or off on a Debian system
|
||||
|
||||
set -e
|
||||
|
||||
permfix () {
|
||||
[ -f $1 ] || return 0
|
||||
chown root:shadow $1
|
||||
chmod 2755 $1
|
||||
}
|
||||
export -f permfix
|
||||
|
||||
shadowon () {
|
||||
bash<<- EOF
|
||||
set -e
|
||||
|
||||
permfix /usr/X11R6/bin/xlock
|
||||
permfix /usr/X11R6/bin/xtrlock
|
||||
permfix /bin/vlock
|
||||
|
||||
pwck -q
|
||||
grpck
|
||||
pwconv
|
||||
grpconv
|
||||
cd /etc
|
||||
chown root:root passwd group
|
||||
chmod 644 passwd group
|
||||
chown root:shadow shadow gshadow
|
||||
chmod 640 shadow gshadow
|
||||
EOF
|
||||
}
|
||||
|
||||
shadowoff () {
|
||||
bash<<- EOF
|
||||
set -e
|
||||
pwck -q
|
||||
grpck
|
||||
pwunconv
|
||||
grpunconv
|
||||
cd /etc
|
||||
# sometimes the passwd perms get munged
|
||||
chown root:root passwd group
|
||||
chmod 644 passwd group
|
||||
EOF
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
"on")
|
||||
if shadowon ; then
|
||||
echo Shadow passwords are now on.
|
||||
else
|
||||
echo Please correct the error and rerun \`$0 on\'
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"off")
|
||||
if shadowoff ; then
|
||||
echo Shadow passwords are now off.
|
||||
else
|
||||
echo Please correct the error and rerun \`$0 off\'
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo Usage: $0 on \| off
|
||||
;;
|
||||
esac
|
633
src/su.c
Normal file
633
src/su.c
Normal file
@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: su.c,v 1.13 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include "pam_defs.h"
|
||||
|
||||
static const struct pam_conv conv = {
|
||||
misc_conv,
|
||||
NULL
|
||||
};
|
||||
|
||||
static pam_handle_t *pamh = NULL;
|
||||
#endif
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <grp.h>
|
||||
#include <signal.h>
|
||||
#include <pwd.h>
|
||||
#include "pwauth.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* Assorted #defines to control su's behavior
|
||||
*/
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
/* needed by sulog.c */
|
||||
char name[BUFSIZ];
|
||||
char oldname[BUFSIZ];
|
||||
|
||||
static char *Prog;
|
||||
|
||||
struct passwd pwent;
|
||||
|
||||
/*
|
||||
* External identifiers
|
||||
*/
|
||||
|
||||
extern char **newenvp;
|
||||
extern size_t newenvc;
|
||||
|
||||
extern void sulog P_((const char *, int));
|
||||
extern void subsystem P_((const struct passwd *));
|
||||
extern char *tz P_((const char *));
|
||||
extern int check_su_auth P_((const char *, const char *));
|
||||
extern char **environ;
|
||||
|
||||
/* local function prototypes */
|
||||
int main P_((int, char **));
|
||||
|
||||
#ifndef USE_PAM
|
||||
|
||||
static RETSIGTYPE die P_((int));
|
||||
static int iswheel P_((const char *));
|
||||
|
||||
/*
|
||||
* die - set or reset termio modes.
|
||||
*
|
||||
* die() is called before processing begins. signal() is then
|
||||
* called with die() as the signal handler. If signal later
|
||||
* calls die() with a signal number, the terminal modes are
|
||||
* then reset.
|
||||
*/
|
||||
|
||||
static RETSIGTYPE
|
||||
die(int killed)
|
||||
{
|
||||
static TERMIO sgtty;
|
||||
|
||||
if (killed)
|
||||
STTY(0, &sgtty);
|
||||
else
|
||||
GTTY(0, &sgtty);
|
||||
|
||||
if (killed) {
|
||||
closelog();
|
||||
exit(killed);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
iswheel(const char *username)
|
||||
{
|
||||
struct group *grp;
|
||||
|
||||
grp = getgrgid(0);
|
||||
if (!grp || !grp->gr_mem)
|
||||
return 0;
|
||||
return is_on_list(grp->gr_mem, username);
|
||||
}
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
|
||||
static void
|
||||
su_failure(const char *tty)
|
||||
{
|
||||
sulog(tty, 0); /* log failed attempt */
|
||||
#ifdef USE_SYSLOG
|
||||
if (getdef_bool("SYSLOG_SU_ENAB"))
|
||||
SYSLOG((pwent.pw_uid ? LOG_INFO:LOG_NOTICE,
|
||||
"- %s %s-%s\n", tty,
|
||||
oldname[0] ? oldname:"???",
|
||||
name[0] ? name:"???"));
|
||||
closelog();
|
||||
#endif
|
||||
puts(_("Sorry."));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* su - switch user id
|
||||
*
|
||||
* su changes the user's ids to the values for the specified user.
|
||||
* if no new user name is specified, "root" is used by default.
|
||||
*
|
||||
* The only valid option is a "-" character, which is interpreted
|
||||
* as requiring a new login session to be simulated.
|
||||
*
|
||||
* Any additional arguments are passed to the user's shell. In
|
||||
* particular, the argument "-c" will cause the next argument to
|
||||
* be interpreted as a command by the common shell programs.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *cp;
|
||||
const char *tty = 0; /* Name of tty SU is run from */
|
||||
int doshell = 0;
|
||||
int fakelogin = 0;
|
||||
int amroot = 0;
|
||||
uid_t my_uid;
|
||||
struct passwd *pw = 0;
|
||||
char **envp = environ;
|
||||
#ifdef USE_PAM
|
||||
int ret;
|
||||
#else /* !USE_PAM */
|
||||
RETSIGTYPE (*oldsig)();
|
||||
int is_console = 0;
|
||||
#ifdef SHADOWPWD
|
||||
struct spwd *spwd = 0;
|
||||
#endif
|
||||
#ifdef SU_ACCESS
|
||||
char *oldpass;
|
||||
#endif
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
sanitize_env();
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
/*
|
||||
* Get the program name. The program name is used as a
|
||||
* prefix to most error messages.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
openlog("su", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
initenv();
|
||||
|
||||
my_uid = getuid();
|
||||
amroot = (my_uid == 0);
|
||||
|
||||
/*
|
||||
* Get the tty name. Entries will be logged indicating that
|
||||
* the user tried to change to the named new user from the
|
||||
* current terminal.
|
||||
*/
|
||||
|
||||
if (isatty(0) && (cp = ttyname(0))) {
|
||||
if (strncmp (cp, "/dev/", 5) == 0)
|
||||
tty = cp + 5;
|
||||
else
|
||||
tty = cp;
|
||||
#ifndef USE_PAM
|
||||
is_console = console(tty);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* Be more paranoid, like su from SimplePAMApps. --marekm
|
||||
*/
|
||||
if (!amroot) {
|
||||
fprintf(stderr, _("%s: must be run from a terminal\n"),
|
||||
Prog);
|
||||
exit(1);
|
||||
}
|
||||
tty = "???";
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the command line arguments.
|
||||
*/
|
||||
|
||||
argc--; argv++; /* shift out command name */
|
||||
|
||||
if (argc > 0 && strcmp(argv[0], "-") == 0) {
|
||||
fakelogin = 1;
|
||||
argc--; argv++; /* shift ... */
|
||||
}
|
||||
|
||||
/*
|
||||
* If a new login is being set up, the old environment will
|
||||
* be ignored and a new one created later on.
|
||||
*/
|
||||
|
||||
if (! fakelogin)
|
||||
while (*envp)
|
||||
addenv(*envp++, NULL);
|
||||
|
||||
if (fakelogin && (cp=getdef_str("ENV_TZ")))
|
||||
addenv(*cp == '/' ? tz(cp) : cp, NULL);
|
||||
|
||||
/*
|
||||
* The clock frequency will be reset to the login value if required
|
||||
*/
|
||||
|
||||
if (fakelogin && (cp=getdef_str("ENV_HZ")) )
|
||||
addenv(cp, NULL); /* set the default $HZ, if one */
|
||||
|
||||
/*
|
||||
* The terminal type will be left alone if it is present in the
|
||||
* environment already.
|
||||
*/
|
||||
|
||||
if (fakelogin && (cp = getenv ("TERM")))
|
||||
addenv("TERM", cp);
|
||||
|
||||
/*
|
||||
* The next argument must be either a user ID, or some flag to
|
||||
* a subshell. Pretty sticky since you can't have an argument
|
||||
* which doesn't start with a "-" unless you specify the new user
|
||||
* name. Any remaining arguments will be passed to the user's
|
||||
* login shell.
|
||||
*/
|
||||
|
||||
if (argc > 0 && argv[0][0] != '-') {
|
||||
STRFCPY(name, argv[0]); /* use this login id */
|
||||
argc--; argv++; /* shift ... */
|
||||
}
|
||||
if (! name[0]) /* use default user ID */
|
||||
(void) strcpy (name, "root");
|
||||
|
||||
doshell = argc == 0; /* any arguments remaining? */
|
||||
|
||||
/*
|
||||
* Get the user's real name. The current UID is used to determine
|
||||
* who has executed su. That user ID must exist.
|
||||
*/
|
||||
|
||||
pw = get_my_pwent();
|
||||
if (!pw) {
|
||||
SYSLOG((LOG_CRIT, "Unknown UID: %d\n", (int) my_uid));
|
||||
su_failure(tty);
|
||||
}
|
||||
STRFCPY(oldname, pw->pw_name);
|
||||
|
||||
#ifndef USE_PAM
|
||||
#ifdef SU_ACCESS
|
||||
/*
|
||||
* Sort out the password of user calling su, in case needed later
|
||||
* -- chris
|
||||
*/
|
||||
#ifdef SHADOWPWD
|
||||
if ((spwd = getspnam(oldname)))
|
||||
pw->pw_passwd = spwd->sp_pwdp;
|
||||
#endif
|
||||
oldpass = xstrdup(pw->pw_passwd);
|
||||
#endif /* SU_ACCESS */
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
#ifdef USE_PAM
|
||||
ret = pam_start("su", name, &conv, &pamh);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
SYSLOG((LOG_ERR, "pam_start: error %d\n", ret);
|
||||
fprintf(stderr, _("%s: pam_start: error %d\n"), Prog, ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = pam_set_item(pamh, PAM_TTY, (const void *) tty);
|
||||
if (ret == PAM_SUCCESS)
|
||||
ret = pam_set_item(pamh, PAM_RUSER, (const void *) oldname);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
SYSLOG((LOG_ERR, "pam_set_item: %s\n", PAM_STRERROR(pamh, ret)));
|
||||
fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
|
||||
pam_end(pamh, ret);
|
||||
exit(1);
|
||||
}
|
||||
#endif /* USE_PAM */
|
||||
|
||||
top:
|
||||
/*
|
||||
* This is the common point for validating a user whose name
|
||||
* is known. It will be reached either by normal processing,
|
||||
* or if the user is to be logged into a subsystem root.
|
||||
*
|
||||
* The password file entries for the user is gotten and the
|
||||
* account validated.
|
||||
*/
|
||||
|
||||
if (!(pw = getpwnam(name))) {
|
||||
(void) fprintf (stderr, _("Unknown id: %s\n"), name);
|
||||
closelog();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef USE_PAM
|
||||
#ifdef SHADOWPWD
|
||||
spwd = NULL;
|
||||
if (strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING) == 0 && (spwd = getspnam(name)))
|
||||
pw->pw_passwd = spwd->sp_pwdp;
|
||||
#endif
|
||||
#endif /* !USE_PAM */
|
||||
pwent = *pw;
|
||||
|
||||
#ifndef USE_PAM
|
||||
/*
|
||||
* BSD systems only allow "wheel" to SU to root. USG systems
|
||||
* don't, so we make this a configurable option.
|
||||
*/
|
||||
|
||||
/* The original Shadow 3.3.2 did this differently. Do it like BSD:
|
||||
|
||||
- check for uid 0 instead of name "root" - there are systems
|
||||
with several root accounts under different names,
|
||||
|
||||
- check the contents of /etc/group instead of the current group
|
||||
set (you must be listed as a member, GID 0 is not sufficient).
|
||||
|
||||
In addition to this traditional feature, we now have complete
|
||||
su access control (allow, deny, no password, own password).
|
||||
Thanks to Chris Evans <lady0110@sable.ox.ac.uk>. */
|
||||
|
||||
if (!amroot) {
|
||||
if (pwent.pw_uid == 0 && getdef_bool("SU_WHEEL_ONLY")
|
||||
&& !iswheel(oldname)) {
|
||||
fprintf(stderr, _("You are not authorized to su %s\n"), name);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef SU_ACCESS
|
||||
switch (check_su_auth(oldname, name)) {
|
||||
case 0: /* normal su, require target user's password */
|
||||
break;
|
||||
case 1: /* require no password */
|
||||
pwent.pw_passwd = ""; /* XXX warning: const */
|
||||
break;
|
||||
case 2: /* require own password */
|
||||
puts(_("(Enter your own password.)"));
|
||||
pwent.pw_passwd = oldpass;
|
||||
break;
|
||||
default: /* access denied (-1) or unexpected value */
|
||||
fprintf(stderr, _("You are not authorized to su %s\n"), name);
|
||||
exit(1);
|
||||
}
|
||||
#endif /* SU_ACCESS */
|
||||
}
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
/*
|
||||
* Set the default shell.
|
||||
*/
|
||||
#if 0
|
||||
/*
|
||||
* XXX - GNU and *BSD versions of su support the -m option.
|
||||
* Need to add some option parsing code.
|
||||
*/
|
||||
if (mflg) {
|
||||
if (!amroot && !check_shell(pwent.pw_shell)) {
|
||||
fprintf(stderr, _("%s: permission denied (shell).\n"), Prog);
|
||||
exit(1);
|
||||
}
|
||||
if ((cp = getenv("SHELL")))
|
||||
pwent.pw_shell = cp;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pwent.pw_shell[0] == '\0')
|
||||
pwent.pw_shell = "/bin/sh"; /* XXX warning: const */
|
||||
|
||||
#ifdef USE_PAM
|
||||
ret = pam_authenticate(pamh, 0);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
SYSLOG((LOG_ERR, "pam_authenticate: %s\n",
|
||||
PAM_STRERROR(pamh, ret)));
|
||||
fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
|
||||
pam_end(pamh, ret);
|
||||
su_failure(tty);
|
||||
}
|
||||
|
||||
ret = pam_acct_mgmt(pamh, 0);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
if (amroot) {
|
||||
fprintf(stderr, _("%s: %s\n(Ignored)\n"), Prog, PAM_STRERROR(pamh, ret));
|
||||
} else {
|
||||
SYSLOG((LOG_ERR, "pam_acct_mgmt: %s\n",
|
||||
PAM_STRERROR(pamh, ret)));
|
||||
fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
|
||||
pam_end(pamh, ret);
|
||||
su_failure(tty);
|
||||
}
|
||||
}
|
||||
#else /* !USE_PAM */
|
||||
/*
|
||||
* Set up a signal handler in case the user types QUIT.
|
||||
*/
|
||||
|
||||
die (0);
|
||||
oldsig = signal (SIGQUIT, die);
|
||||
|
||||
/*
|
||||
* See if the system defined authentication method is being used.
|
||||
* The first character of an administrator defined method is an
|
||||
* '@' character.
|
||||
*/
|
||||
|
||||
if (! amroot && pw_auth (pwent.pw_passwd, name, PW_SU, (char *) 0)) {
|
||||
SYSLOG((pwent.pw_uid ? LOG_NOTICE:LOG_WARN,
|
||||
"Authentication failed for %s\n", name));
|
||||
su_failure(tty);
|
||||
}
|
||||
signal (SIGQUIT, oldsig);
|
||||
|
||||
/*
|
||||
* Check to see if the account is expired. root gets to
|
||||
* ignore any expired accounts, but normal users can't become
|
||||
* a user with an expired password.
|
||||
*/
|
||||
|
||||
if (! amroot) {
|
||||
#ifdef SHADOWPWD
|
||||
if (!spwd)
|
||||
spwd = pwd_to_spwd(&pwent);
|
||||
|
||||
if (isexpired(&pwent, spwd)) {
|
||||
SYSLOG((pwent.pw_uid ? LOG_WARN : LOG_CRIT,
|
||||
"Expired account %s\n", name));
|
||||
su_failure(tty);
|
||||
}
|
||||
#else
|
||||
#if defined(ATT_AGE) && defined(AGING)
|
||||
else if (pwent.pw_age[0] &&
|
||||
isexpired (&pwent)) {
|
||||
SYSLOG((pwent.pw_uid ? LOG_WARN:LOG_CRIT,
|
||||
"Expired account %s\n", name));
|
||||
su_failure(tty);
|
||||
}
|
||||
#endif /* ATT_AGE */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the account permits "su". root gets to
|
||||
* ignore any restricted accounts, but normal users can't become
|
||||
* a user if there is a "SU" entry in the /etc/porttime file
|
||||
* denying access to the account.
|
||||
*/
|
||||
|
||||
if (! amroot) {
|
||||
if (! isttytime (pwent.pw_name, "SU", time ((time_t *) 0))) {
|
||||
SYSLOG((pwent.pw_uid ? LOG_WARN : LOG_CRIT,
|
||||
"SU by %s to restricted account %s\n",
|
||||
oldname, name));
|
||||
su_failure(tty);
|
||||
}
|
||||
}
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
cp = getdef_str(pwent.pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH");
|
||||
addenv(cp ? cp : "PATH=/bin:/usr/bin", NULL);
|
||||
|
||||
environ = newenvp; /* make new environment active */
|
||||
|
||||
if (getenv ("IFS")) /* don't export user IFS ... */
|
||||
addenv("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
|
||||
|
||||
if (pwent.pw_shell[0] == '*') { /* subsystem root required */
|
||||
subsystem (&pwent); /* figure out what to execute */
|
||||
endpwent ();
|
||||
#ifdef SHADOWPWD
|
||||
endspent ();
|
||||
#endif
|
||||
goto top;
|
||||
}
|
||||
|
||||
sulog (tty, 1); /* save SU information */
|
||||
endpwent ();
|
||||
#ifdef SHADOWPWD
|
||||
endspent ();
|
||||
#endif
|
||||
#ifdef USE_SYSLOG
|
||||
if (getdef_bool("SYSLOG_SU_ENAB"))
|
||||
SYSLOG((LOG_INFO, "+ %s %s-%s\n", tty,
|
||||
oldname[0] ? oldname:"???", name[0] ? name:"???"));
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
/* set primary group id and supplementary groups */
|
||||
if (setup_groups(&pwent)) {
|
||||
pam_end(pamh, PAM_ABORT);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* pam_setcred() may do things like resource limits, console groups,
|
||||
and much more, depending on the configured modules */
|
||||
ret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
SYSLOG((LOG_ERR, "pam_setcred: %s\n", PAM_STRERROR(pamh, ret)));
|
||||
fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
|
||||
pam_end(pamh, ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* become the new user */
|
||||
if (change_uid(&pwent)) {
|
||||
pam_setcred(pamh, PAM_DELETE_CRED);
|
||||
pam_end(pamh, PAM_ABORT);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* now we are done using PAM */
|
||||
pam_end(pamh, PAM_SUCCESS);
|
||||
|
||||
#else /* !USE_PAM */
|
||||
if (!amroot) /* no limits if su from root */
|
||||
setup_limits(&pwent);
|
||||
|
||||
if (setup_uid_gid(&pwent, is_console))
|
||||
exit(1);
|
||||
#endif /* !USE_PAM */
|
||||
|
||||
if (fakelogin)
|
||||
setup_env(&pwent);
|
||||
#if 1 /* Suggested by Joey Hess. XXX - is this right? */
|
||||
else
|
||||
addenv("HOME", pwent.pw_dir);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is a workaround for Linux libc bug/feature (?) - the
|
||||
* /dev/log file descriptor is open without the close-on-exec
|
||||
* flag and used to be passed to the new shell. There is
|
||||
* "fcntl(LogFile, F_SETFD, 1)" in libc/misc/syslog.c, but
|
||||
* it is commented out (at least in 5.4.33). Why? --marekm
|
||||
*/
|
||||
closelog();
|
||||
|
||||
/*
|
||||
* See if the user has extra arguments on the command line. In
|
||||
* that case they will be provided to the new user's shell as
|
||||
* arguments.
|
||||
*/
|
||||
|
||||
if (! doshell) {
|
||||
|
||||
/*
|
||||
* Use new user's shell from /etc/passwd and create an
|
||||
* argv with the rest of the command line included.
|
||||
*/
|
||||
|
||||
argv[-1] = pwent.pw_shell;
|
||||
(void) execv (pwent.pw_shell, &argv[-1]);
|
||||
(void) fprintf (stderr, _("No shell\n"));
|
||||
SYSLOG((LOG_WARN, "Cannot execute %s\n", pwent.pw_shell));
|
||||
closelog();
|
||||
exit (1);
|
||||
}
|
||||
if (fakelogin) {
|
||||
char *arg0;
|
||||
|
||||
#if 0 /* XXX - GNU su doesn't do this. --marekm */
|
||||
if (! hushed (&pwent)) {
|
||||
motd ();
|
||||
mailcheck ();
|
||||
}
|
||||
#endif
|
||||
cp = getdef_str("SU_NAME");
|
||||
if (!cp)
|
||||
cp = Basename(pwent.pw_shell);
|
||||
|
||||
arg0 = xmalloc(strlen(cp) + 2);
|
||||
arg0[0] = '-';
|
||||
strcpy(arg0 + 1, cp);
|
||||
cp = arg0;
|
||||
} else
|
||||
cp = Basename(pwent.pw_shell);
|
||||
|
||||
shell(pwent.pw_shell, cp);
|
||||
/*NOTREACHED*/
|
||||
exit(1);
|
||||
}
|
281
src/sulogin.c
Normal file
281
src/sulogin.c
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 1989 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: sulogin.c,v 1.9 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "getdef.h"
|
||||
|
||||
#if HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include "pwauth.h"
|
||||
|
||||
static char name[BUFSIZ];
|
||||
static char pass[BUFSIZ];
|
||||
|
||||
static struct passwd pwent;
|
||||
#if 0
|
||||
#if HAVE_UTMPX_H
|
||||
static struct utmpx utent;
|
||||
#else
|
||||
static struct utmp utent;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
extern char **newenvp;
|
||||
extern size_t newenvc;
|
||||
|
||||
extern char **environ;
|
||||
extern char *tz P_((const char *));
|
||||
|
||||
#ifndef ALARM
|
||||
#define ALARM 60
|
||||
#endif
|
||||
|
||||
/* local function prototypes */
|
||||
static RETSIGTYPE catch P_((int));
|
||||
int main P_((int, char **));
|
||||
|
||||
static RETSIGTYPE
|
||||
catch(int sig)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* syslogd is usually not running at the time when sulogin is typically
|
||||
called, cluttering the screen with unnecessary messages. Suggested
|
||||
by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm */
|
||||
#undef USE_SYSLOG
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *cp;
|
||||
char **envp = environ;
|
||||
TERMIO termio;
|
||||
|
||||
#ifdef USE_SGTTY
|
||||
ioctl (0, TIOCGETP, &termio);
|
||||
termio.sg_flags |= (ECHO|CRMOD);
|
||||
termio.sg_flags &= ~(RAW|CBREAK);
|
||||
ioctl (0, TIOCSETN, &termio);
|
||||
#endif
|
||||
#ifdef USE_TERMIO
|
||||
ioctl (0, TCGETA, &termio);
|
||||
termio.c_iflag |= (ICRNL|IXON);
|
||||
termio.c_oflag |= (OPOST|ONLCR);
|
||||
termio.c_cflag |= (CREAD);
|
||||
termio.c_lflag |= (ISIG|ICANON|ECHO|ECHOE|ECHOK);
|
||||
ioctl (0, TCSETAF, &termio);
|
||||
#endif
|
||||
#ifdef USE_TERMIOS
|
||||
tcgetattr (0, &termio);
|
||||
termio.c_iflag |= (ICRNL|IXON);
|
||||
termio.c_oflag |= (CREAD);
|
||||
termio.c_lflag |= (ECHO|ECHOE|ECHOK|ICANON|ISIG);
|
||||
tcsetattr (0, TCSANOW, &termio);
|
||||
#endif
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
#ifdef USE_SYSLOG
|
||||
openlog ("sulogin", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
#endif
|
||||
initenv();
|
||||
if (argc > 1) {
|
||||
close (0);
|
||||
close (1);
|
||||
close (2);
|
||||
|
||||
if (open (argv[1], O_RDWR) >= 0) {
|
||||
dup (0);
|
||||
dup (0);
|
||||
} else {
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_WARN, "cannot open %s\n", argv[1]);
|
||||
closelog ();
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
if (access(PASSWD_FILE, F_OK) == -1) { /* must be a password file! */
|
||||
printf(_("No password file\n"));
|
||||
#ifdef USE_SYSLOG
|
||||
syslog(LOG_WARN, "No password file\n");
|
||||
closelog ();
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
#if !defined(DEBUG) && defined(SULOGIN_ONLY_INIT)
|
||||
if (getppid () != 1) { /* parent must be INIT */
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_WARN, "Pid == %d, not 1\n", getppid ());
|
||||
closelog ();
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
if (! isatty (0) || ! isatty (1) || ! isatty (2)) {
|
||||
#ifdef USE_SYSLOG
|
||||
closelog ();
|
||||
#endif
|
||||
exit (1); /* must be a terminal */
|
||||
}
|
||||
while (*envp) /* add inherited environment, */
|
||||
addenv(*envp++, NULL); /* some variables change later */
|
||||
|
||||
if ((cp = getdef_str("ENV_TZ")))
|
||||
addenv(*cp == '/' ? tz(cp) : cp, NULL);
|
||||
if ((cp = getdef_str("ENV_HZ")))
|
||||
addenv(cp, NULL); /* set the default $HZ, if one */
|
||||
(void) strcpy (name, "root"); /* KLUDGE!!! */
|
||||
|
||||
signal (SIGALRM, catch); /* exit if the timer expires */
|
||||
alarm (ALARM); /* only wait so long ... */
|
||||
|
||||
while (1) { /* repeatedly get login/password pairs */
|
||||
entry (name, &pwent); /* get entry from password file */
|
||||
if (pwent.pw_name == (char *) 0) {
|
||||
|
||||
/*
|
||||
* Fail secure
|
||||
*/
|
||||
|
||||
printf(_("No password entry for 'root'\n"));
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_WARN, "No password entry for 'root'\n");
|
||||
closelog ();
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we prompt for the root password, or if no password is
|
||||
* given we just exit.
|
||||
*/
|
||||
|
||||
/* get a password for root */
|
||||
cp = getpass(_("\nType control-d to proceed with normal startup,\n(or give root password for system maintenance):"));
|
||||
/*
|
||||
* XXX - can't enter single user mode if root password is empty.
|
||||
* I think this doesn't happen very often :-). But it will work
|
||||
* with standard getpass() (no NULL on EOF). --marekm
|
||||
*/
|
||||
if (!cp || !*cp) {
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_INFO, "Normal startup\n");
|
||||
closelog ();
|
||||
#endif
|
||||
puts("\n");
|
||||
#ifdef TELINIT
|
||||
execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) 0);
|
||||
#endif
|
||||
exit (0);
|
||||
} else {
|
||||
STRFCPY(pass, cp);
|
||||
strzero(cp);
|
||||
}
|
||||
#ifdef AUTH_METHODS
|
||||
if (pwent.pw_name && pwent.pw_passwd[0] == '@') {
|
||||
if (pw_auth (pwent.pw_passwd + 1, name, PW_LOGIN, (char *) 0)) {
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_WARN,
|
||||
"Incorrect root authentication");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
goto auth_done;
|
||||
}
|
||||
#endif
|
||||
if (valid (pass, &pwent)) /* check encrypted passwords ... */
|
||||
break; /* ... encrypted passwords matched */
|
||||
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_WARN, "Incorrect root password\n");
|
||||
#endif
|
||||
sleep(2);
|
||||
puts (_("Login incorrect"));
|
||||
}
|
||||
#ifdef AUTH_METHODS
|
||||
auth_done:
|
||||
#endif
|
||||
strzero(pass);
|
||||
alarm (0);
|
||||
signal (SIGALRM, SIG_DFL);
|
||||
environ = newenvp; /* make new environment active */
|
||||
|
||||
puts(_("Entering System Maintenance Mode\n"));
|
||||
#ifdef USE_SYSLOG
|
||||
syslog (LOG_INFO, "System Maintenance Mode\n");
|
||||
#endif
|
||||
|
||||
#if 0 /* do we need all this? we are logging in as root anyway... --marekm */
|
||||
/*
|
||||
* Normally there would be a utmp entry for login to mung on
|
||||
* to get the tty name, date, etc. from. We don't need all that
|
||||
* stuff because we won't update the utmp or wtmp files. BUT!,
|
||||
* we do need the tty name so we can set the permissions and
|
||||
* ownership.
|
||||
*/
|
||||
|
||||
if ((cp = ttyname (0))) { /* found entry in /dev/ */
|
||||
if (strncmp(cp, "/dev/", 5) == 0)
|
||||
cp += 5;
|
||||
|
||||
strncpy(utent.ut_line, cp, sizeof utent.ut_line);
|
||||
}
|
||||
if (getenv ("IFS")) /* don't export user IFS ... */
|
||||
addenv("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
|
||||
|
||||
setup (&pwent, 0); /* set UID, GID, HOME, etc ... */
|
||||
#endif
|
||||
|
||||
#ifdef USE_SYSLOG
|
||||
closelog ();
|
||||
#endif
|
||||
shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
|
||||
/*NOTREACHED*/
|
||||
return (0);
|
||||
}
|
1746
src/useradd.c
Normal file
1746
src/useradd.c
Normal file
File diff suppressed because it is too large
Load Diff
816
src/userdel.c
Normal file
816
src/userdel.c
Normal file
@ -0,0 +1,816 @@
|
||||
/*
|
||||
* Copyright 1991 - 1994, Julianne Frances Haugh
|
||||
* 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. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: userdel.c,v 1.15 1999/06/07 16:40:45 marekm Exp $")
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include "getdef.h"
|
||||
#include "pwauth.h"
|
||||
|
||||
/*
|
||||
* exit status values
|
||||
*/
|
||||
#define E_SUCCESS 0
|
||||
#define E_PW_UPDATE 1 /* can't update password file */
|
||||
#define E_USAGE 2 /* bad command syntax */
|
||||
#define E_NOTFOUND 6 /* specified user doesn't exist */
|
||||
#define E_USER_BUSY 8 /* user currently logged in */
|
||||
#define E_GRP_UPDATE 10 /* can't update group file */
|
||||
#define E_HOMEDIR 12 /* can't remove home directory */
|
||||
|
||||
static char *user_name;
|
||||
static uid_t user_id;
|
||||
static char *user_home;
|
||||
|
||||
static char *Prog;
|
||||
static int fflg = 0, rflg = 0;
|
||||
|
||||
#ifdef NDBM
|
||||
extern int pw_dbm_mode;
|
||||
#ifdef SHADOWPWD
|
||||
extern int sp_dbm_mode;
|
||||
#endif
|
||||
extern int gr_dbm_mode;
|
||||
#ifdef SHADOWGRP
|
||||
extern int sg_dbm_mode;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "groupio.h"
|
||||
#include "pwio.h"
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
#include "shadowio.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TCFS
|
||||
#include <tcfslib.h>
|
||||
#include "tcfsio.h"
|
||||
#endif
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
#include "sgroupio.h"
|
||||
#endif
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
static int is_shadow_pwd;
|
||||
#endif
|
||||
#ifdef SHADOWGRP
|
||||
static int is_shadow_grp;
|
||||
#endif
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* local function prototypes */
|
||||
static void usage P_((void));
|
||||
static void update_groups P_((void));
|
||||
static void close_files P_((void));
|
||||
static void fail_exit P_((int));
|
||||
static void open_files P_((void));
|
||||
static void update_user P_((void));
|
||||
static void user_busy P_((const char *, uid_t));
|
||||
static void user_cancel P_((const char *));
|
||||
#ifdef EXTRA_CHECK_HOME_DIR
|
||||
static int path_prefix P_((const char *, const char *));
|
||||
#endif
|
||||
static int is_owner P_((uid_t, const char *));
|
||||
#ifndef NO_REMOVE_MAILBOX
|
||||
static void remove_mailbox P_((void));
|
||||
#endif
|
||||
int main P_((int, char **));
|
||||
|
||||
/*
|
||||
* usage - display usage message and exit
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, _("usage: %s [-r] name\n"), Prog);
|
||||
exit(E_USAGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_groups - delete user from secondary group set
|
||||
*
|
||||
* update_groups() takes the user name that was given and searches
|
||||
* the group files for membership in any group.
|
||||
*/
|
||||
|
||||
static void
|
||||
update_groups(void)
|
||||
{
|
||||
const struct group *grp;
|
||||
struct group *ngrp;
|
||||
#ifdef SHADOWGRP
|
||||
const struct sgrp *sgrp;
|
||||
struct sgrp *nsgrp;
|
||||
#endif /* SHADOWGRP */
|
||||
|
||||
/*
|
||||
* Scan through the entire group file looking for the groups that
|
||||
* the user is a member of.
|
||||
*/
|
||||
|
||||
for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
|
||||
|
||||
/*
|
||||
* See if the user specified this group as one of their
|
||||
* concurrent groups.
|
||||
*/
|
||||
|
||||
if (!is_on_list(grp->gr_mem, user_name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Delete the username from the list of group members and
|
||||
* update the group entry to reflect the change.
|
||||
*/
|
||||
|
||||
ngrp = __gr_dup(grp);
|
||||
if (!ngrp) {
|
||||
exit(13); /* XXX */
|
||||
}
|
||||
ngrp->gr_mem = del_list (ngrp->gr_mem, user_name);
|
||||
if (!gr_update(ngrp))
|
||||
fprintf(stderr, _("%s: error updating group entry\n"),
|
||||
Prog);
|
||||
|
||||
/*
|
||||
* Update the DBM group file with the new entry as well.
|
||||
*/
|
||||
|
||||
#ifdef NDBM
|
||||
if (!gr_dbm_update(ngrp))
|
||||
fprintf(stderr,
|
||||
_("%s: cannot update dbm group entry\n"),
|
||||
Prog);
|
||||
#endif /* NDBM */
|
||||
SYSLOG((LOG_INFO, "delete `%s' from group `%s'\n",
|
||||
user_name, ngrp->gr_name));
|
||||
}
|
||||
#ifdef NDBM
|
||||
endgrent ();
|
||||
#endif /* NDBM */
|
||||
#ifdef SHADOWGRP
|
||||
if (!is_shadow_grp)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Scan through the entire shadow group file looking for the groups
|
||||
* that the user is a member of. Both the administrative list and
|
||||
* the ordinary membership list is checked.
|
||||
*/
|
||||
|
||||
for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
|
||||
int was_member, was_admin;
|
||||
|
||||
/*
|
||||
* See if the user specified this group as one of their
|
||||
* concurrent groups.
|
||||
*/
|
||||
|
||||
was_member = is_on_list(sgrp->sg_mem, user_name);
|
||||
was_admin = is_on_list(sgrp->sg_adm, user_name);
|
||||
|
||||
if (!was_member && !was_admin)
|
||||
continue;
|
||||
|
||||
nsgrp = __sgr_dup(sgrp);
|
||||
if (!nsgrp) {
|
||||
exit(13); /* XXX */
|
||||
}
|
||||
|
||||
if (was_member)
|
||||
nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name);
|
||||
|
||||
if (was_admin)
|
||||
nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name);
|
||||
|
||||
if (!sgr_update(nsgrp))
|
||||
fprintf(stderr, _("%s: error updating group entry\n"),
|
||||
Prog);
|
||||
#ifdef NDBM
|
||||
/*
|
||||
* Update the DBM group file with the new entry as well.
|
||||
*/
|
||||
|
||||
if (!sg_dbm_update(nsgrp))
|
||||
fprintf(stderr,
|
||||
_("%s: cannot update dbm group entry\n"),
|
||||
Prog);
|
||||
#endif /* NDBM */
|
||||
SYSLOG((LOG_INFO, "delete `%s' from shadow group `%s'\n",
|
||||
user_name, nsgrp->sg_name));
|
||||
}
|
||||
#ifdef NDBM
|
||||
endsgent ();
|
||||
#endif /* NDBM */
|
||||
#endif /* SHADOWGRP */
|
||||
}
|
||||
|
||||
/*
|
||||
* close_files - close all of the files that were opened
|
||||
*
|
||||
* close_files() closes all of the files that were opened for this
|
||||
* new user. This causes any modified entries to be written out.
|
||||
*/
|
||||
|
||||
static void
|
||||
close_files(void)
|
||||
{
|
||||
if (!pw_close())
|
||||
fprintf(stderr, _("%s: cannot rewrite password file\n"), Prog);
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd && !spw_close())
|
||||
fprintf(stderr, _("%s: cannot rewrite shadow password file\n"),
|
||||
Prog);
|
||||
#endif
|
||||
#ifdef HAVE_TCFS
|
||||
if (!tcfs_close())
|
||||
fprintf(stderr, _("%s: cannot rewrite TCFS key file\n"), Prog);
|
||||
#endif
|
||||
if (! gr_close ())
|
||||
fprintf(stderr, _("%s: cannot rewrite group file\n"),
|
||||
Prog);
|
||||
|
||||
(void) gr_unlock ();
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && !sgr_close())
|
||||
fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
|
||||
Prog);
|
||||
|
||||
if (is_shadow_grp)
|
||||
(void) sgr_unlock();
|
||||
#endif
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd)
|
||||
(void) spw_unlock();
|
||||
#endif
|
||||
#ifdef HAVE_TCFS
|
||||
(void) tcfs_unlock();
|
||||
#endif
|
||||
(void) pw_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* fail_exit - exit with a failure code after unlocking the files
|
||||
*/
|
||||
|
||||
static void
|
||||
fail_exit(int code)
|
||||
{
|
||||
(void) pw_unlock ();
|
||||
(void) gr_unlock ();
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd)
|
||||
spw_unlock ();
|
||||
#endif
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp)
|
||||
sgr_unlock ();
|
||||
#endif
|
||||
#ifdef HAVE_TCFS
|
||||
(void) tcfs_unlock ();
|
||||
#endif
|
||||
|
||||
exit(code);
|
||||
}
|
||||
|
||||
/*
|
||||
* open_files - lock and open the password files
|
||||
*
|
||||
* open_files() opens the two password files.
|
||||
*/
|
||||
|
||||
static void
|
||||
open_files(void)
|
||||
{
|
||||
if (!pw_lock()) {
|
||||
fprintf(stderr, _("%s: unable to lock password file\n"), Prog);
|
||||
exit(E_PW_UPDATE);
|
||||
}
|
||||
if (! pw_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: unable to open password file\n"), Prog);
|
||||
fail_exit(E_PW_UPDATE);
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd && ! spw_lock ()) {
|
||||
fprintf(stderr, _("%s: cannot lock shadow password file\n"),
|
||||
Prog);
|
||||
fail_exit(E_PW_UPDATE);
|
||||
}
|
||||
if (is_shadow_pwd && ! spw_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open shadow password file\n"),
|
||||
Prog);
|
||||
fail_exit(E_PW_UPDATE);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TCFS
|
||||
if (!tcfs_lock()) {
|
||||
fprintf(stderr, _("%s: cannot lock TCFS key file\n"), Prog);
|
||||
fail_exit(E_PW_UPDATE);
|
||||
}
|
||||
if (!tcfs_open(O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open TCFS key file\n"), Prog);
|
||||
fail_exit(E_PW_UPDATE);
|
||||
}
|
||||
#endif
|
||||
if (! gr_lock ()) {
|
||||
fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (! gr_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open group file\n"), Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
#ifdef SHADOWGRP
|
||||
if (is_shadow_grp && ! sgr_lock ()) {
|
||||
fprintf(stderr, _("%s: unable to lock shadow group file\n"),
|
||||
Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
if (is_shadow_grp && ! sgr_open (O_RDWR)) {
|
||||
fprintf(stderr, _("%s: cannot open shadow group file\n"),
|
||||
Prog);
|
||||
fail_exit(E_GRP_UPDATE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* update_user - delete the user entries
|
||||
*
|
||||
* update_user() deletes the password file entries for this user
|
||||
* and will update the group entries as required.
|
||||
*/
|
||||
|
||||
static void
|
||||
update_user(void)
|
||||
{
|
||||
#if defined(AUTH_METHODS) || defined(NDBM)
|
||||
struct passwd *pwd;
|
||||
#endif
|
||||
#ifdef AUTH_METHODS
|
||||
#ifdef SHADOWPWD
|
||||
struct spwd *spwd;
|
||||
|
||||
if (is_shadow_pwd && (spwd = spw_locate (user_name)) &&
|
||||
spwd->sp_pwdp[0] == '@') {
|
||||
if (pw_auth (spwd->sp_pwdp + 1, user_name, PW_DELETE, (char *) 0)) {
|
||||
SYSLOG((LOG_ERR,
|
||||
"failed deleting auth `%s' for user `%s'\n",
|
||||
spwd->sp_pwdp + 1, user_name));
|
||||
fprintf(stderr,
|
||||
_("%s: error deleting authentication\n"),
|
||||
Prog);
|
||||
} else {
|
||||
SYSLOG((LOG_INFO,
|
||||
"delete auth `%s' for user `%s'\n",
|
||||
spwd->sp_pwdp + 1, user_name));
|
||||
}
|
||||
}
|
||||
#endif /* SHADOWPWD */
|
||||
if ((pwd = pw_locate(user_name)) && pwd->pw_passwd[0] == '@') {
|
||||
if (pw_auth(pwd->pw_passwd + 1, user_name, PW_DELETE, (char *) 0)) {
|
||||
SYSLOG((LOG_ERR,
|
||||
"failed deleting auth `%s' for user `%s'\n",
|
||||
pwd->pw_passwd + 1, user_name));
|
||||
fprintf(stderr,
|
||||
_("%s: error deleting authentication\n"),
|
||||
Prog);
|
||||
} else {
|
||||
SYSLOG((LOG_INFO, "delete auth `%s' for user `%s'\n",
|
||||
pwd->pw_passwd + 1, user_name);
|
||||
}
|
||||
}
|
||||
#endif /* AUTH_METHODS */
|
||||
if (!pw_remove(user_name))
|
||||
fprintf(stderr, _("%s: error deleting password entry\n"), Prog);
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd && ! spw_remove (user_name))
|
||||
fprintf(stderr, _("%s: error deleting shadow password entry\n"),
|
||||
Prog);
|
||||
#endif
|
||||
#ifdef HAVE_TCFS
|
||||
if (tcfs_locate (user_name)) {
|
||||
if (!tcfs_remove (user_name)) {
|
||||
SYSLOG((LOG_ERR,
|
||||
"failed deleting TCFS entry for user `%s'\n",
|
||||
user_name));
|
||||
fprintf(stderr, _("%s: error deleting TCFS entry\n"),
|
||||
Prog);
|
||||
} else {
|
||||
SYSLOG((LOG_INFO,
|
||||
"delete TCFS entry for user `%s'\n",
|
||||
user_name));
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_TCFS */
|
||||
#ifdef NDBM
|
||||
if (pw_dbm_present()) {
|
||||
if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
|
||||
fprintf(stderr,
|
||||
_("%s: error deleting password dbm entry\n"),
|
||||
Prog);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user's UID is a duplicate the duplicated entry needs
|
||||
* to be updated so that a UID match can be found in the DBM
|
||||
* files.
|
||||
*/
|
||||
|
||||
for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
|
||||
if (pwd->pw_uid == user_id) {
|
||||
pw_dbm_update (pwd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef SHADOWPWD
|
||||
if (is_shadow_pwd && sp_dbm_present() && !sp_dbm_remove(user_name))
|
||||
fprintf(stderr,
|
||||
_("%s: error deleting shadow passwd dbm entry\n"),
|
||||
Prog);
|
||||
|
||||
endspent ();
|
||||
#endif
|
||||
endpwent ();
|
||||
#endif /* NDBM */
|
||||
SYSLOG((LOG_INFO, "delete user `%s'\n", user_name));
|
||||
}
|
||||
|
||||
/*
|
||||
* user_busy - see if user is logged in.
|
||||
*
|
||||
* XXX - should probably check if there are any processes owned
|
||||
* by this user. Also, I think this check should be in usermod
|
||||
* as well (at least when changing username or uid). --marekm
|
||||
*/
|
||||
|
||||
static void
|
||||
user_busy(const char *name, uid_t uid)
|
||||
{
|
||||
struct utmp *utent;
|
||||
|
||||
/*
|
||||
* We see if the user is logged in by looking for the user name
|
||||
* in the utmp file.
|
||||
*/
|
||||
|
||||
setutent ();
|
||||
|
||||
while ((utent = getutent ())) {
|
||||
#ifdef USER_PROCESS
|
||||
if (utent->ut_type != USER_PROCESS)
|
||||
continue;
|
||||
#else
|
||||
if (utent->ut_user[0] == '\0')
|
||||
continue;
|
||||
#endif
|
||||
if (strncmp(utent->ut_user, name, sizeof utent->ut_user))
|
||||
continue;
|
||||
|
||||
fprintf(stderr, _("%s: user %s is currently logged in\n"),
|
||||
Prog, name);
|
||||
exit(E_USER_BUSY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* user_cancel - cancel cron and at jobs
|
||||
*
|
||||
* user_cancel removes the crontab and any at jobs for a user
|
||||
*/
|
||||
|
||||
/*
|
||||
* We used to have all this stuff hardcoded here, but now
|
||||
* we just run an external script - it may need to do other
|
||||
* things as well (like removing print jobs) and we may not
|
||||
* want to recompile userdel too often. Below is a sample
|
||||
* script (should work at least on Debian 1.1). --marekm
|
||||
==========
|
||||
#! /bin/sh
|
||||
|
||||
# Check for the required argument.
|
||||
if [ $# != 1 ]; then
|
||||
echo Usage: $0 username
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove cron jobs.
|
||||
crontab -r -u $1
|
||||
|
||||
# Remove at jobs. XXX - will remove any jobs owned by the
|
||||
# same UID, even if it was shared by a different username.
|
||||
# at really should store the username somewhere, and atrm
|
||||
# should support an option to remove all jobs owned by the
|
||||
# specified user - for now we have to do this ugly hack...
|
||||
find /var/spool/cron/atjobs -name "[^.]*" -type f -user $1 -exec rm {} \;
|
||||
|
||||
# Remove print jobs.
|
||||
lprm $1
|
||||
|
||||
# All done.
|
||||
exit 0
|
||||
==========
|
||||
*/
|
||||
|
||||
static void
|
||||
user_cancel(const char *user)
|
||||
{
|
||||
char *cmd;
|
||||
int pid, wpid;
|
||||
int status;
|
||||
|
||||
if (!(cmd = getdef_str("USERDEL_CMD")))
|
||||
return;
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
execl(cmd, cmd, user, (char *) 0);
|
||||
if (errno == ENOENT) {
|
||||
perror(cmd);
|
||||
_exit(127);
|
||||
} else {
|
||||
perror(cmd);
|
||||
_exit(126);
|
||||
}
|
||||
} else if (pid == -1) {
|
||||
perror("fork");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
wpid = wait(&status);
|
||||
} while (wpid != pid && wpid != -1);
|
||||
}
|
||||
|
||||
#ifdef EXTRA_CHECK_HOME_DIR
|
||||
static int
|
||||
path_prefix(const char *s1, const char *s2)
|
||||
{
|
||||
return (strncmp(s2, s1, strlen(s1)) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
is_owner(uid_t uid, const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st))
|
||||
return -1;
|
||||
return (st.st_uid == uid);
|
||||
}
|
||||
|
||||
#ifndef NO_REMOVE_MAILBOX
|
||||
static void
|
||||
remove_mailbox(void)
|
||||
{
|
||||
const char *maildir;
|
||||
char mailfile[1024];
|
||||
int i;
|
||||
|
||||
maildir = getdef_str("MAIL_DIR");
|
||||
#ifdef MAIL_SPOOL_DIR
|
||||
if (!maildir && !getdef_str("MAIL_FILE"))
|
||||
maildir = MAIL_SPOOL_DIR;
|
||||
#endif
|
||||
if (!maildir)
|
||||
return;
|
||||
|
||||
snprintf(mailfile, sizeof mailfile, "%s/%s", maildir, user_name);
|
||||
if (fflg) {
|
||||
unlink(mailfile); /* always remove, ignore errors */
|
||||
return;
|
||||
}
|
||||
i = is_owner(user_id, mailfile);
|
||||
if (i == 0) {
|
||||
fprintf(stderr,
|
||||
_("%s: warning: %s not owned by %s, not removing\n"),
|
||||
Prog, mailfile, user_name);
|
||||
return;
|
||||
} else if (i == -1)
|
||||
return; /* mailbox doesn't exist */
|
||||
if (unlink(mailfile)) {
|
||||
fprintf(stderr, _("%s: warning: can't remove "), Prog);
|
||||
perror(mailfile);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* main - userdel command
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
int arg;
|
||||
int errors = 0;
|
||||
|
||||
/*
|
||||
* Get my name so that I can use it to report errors.
|
||||
*/
|
||||
|
||||
Prog = Basename(argv[0]);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||
|
||||
#ifdef SHADOWPWD
|
||||
is_shadow_pwd = spw_file_present();
|
||||
#endif
|
||||
|
||||
#ifdef SHADOWGRP
|
||||
is_shadow_grp = sgr_file_present();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The open routines for the DBM files don't use read-write
|
||||
* as the mode, so we have to clue them in.
|
||||
*/
|
||||
|
||||
#ifdef NDBM
|
||||
pw_dbm_mode = O_RDWR;
|
||||
#ifdef SHADOWPWD
|
||||
sp_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
gr_dbm_mode = O_RDWR;
|
||||
#ifdef SHADOWGRP
|
||||
sg_dbm_mode = O_RDWR;
|
||||
#endif
|
||||
#endif
|
||||
while ((arg = getopt (argc, argv, "fr")) != EOF) {
|
||||
switch (arg) {
|
||||
case 'f': /* force remove even if not owned by user */
|
||||
fflg++;
|
||||
break;
|
||||
case 'r': /* remove home dir and mailbox */
|
||||
rflg++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind + 1 != argc)
|
||||
usage ();
|
||||
|
||||
/*
|
||||
* Start with a quick check to see if the user exists.
|
||||
*/
|
||||
|
||||
user_name = argv[argc - 1];
|
||||
|
||||
if (! (pwd = getpwnam (user_name))) {
|
||||
fprintf(stderr, _("%s: user %s does not exist\n"),
|
||||
Prog, user_name);
|
||||
exit(E_NOTFOUND);
|
||||
}
|
||||
#ifdef USE_NIS
|
||||
|
||||
/*
|
||||
* Now make sure it isn't an NIS user.
|
||||
*/
|
||||
|
||||
if (__ispwNIS ()) {
|
||||
char *nis_domain;
|
||||
char *nis_master;
|
||||
|
||||
fprintf(stderr, _("%s: user %s is a NIS user\n"),
|
||||
Prog, user_name);
|
||||
|
||||
if (! yp_get_default_domain (&nis_domain) &&
|
||||
! yp_master (nis_domain, "passwd.byname",
|
||||
&nis_master)) {
|
||||
fprintf(stderr, _("%s: %s is the NIS master\n"),
|
||||
Prog, nis_master);
|
||||
}
|
||||
exit(E_NOTFOUND);
|
||||
}
|
||||
#endif
|
||||
user_id = pwd->pw_uid;
|
||||
user_home = xstrdup(pwd->pw_dir);
|
||||
|
||||
/*
|
||||
* Check to make certain the user isn't logged in.
|
||||
*/
|
||||
|
||||
user_busy (user_name, user_id);
|
||||
|
||||
/*
|
||||
* Do the hard stuff - open the files, create the user entries,
|
||||
* create the home directory, then close and update the files.
|
||||
*/
|
||||
|
||||
open_files ();
|
||||
|
||||
update_user ();
|
||||
update_groups ();
|
||||
|
||||
#ifndef NO_REMOVE_MAILBOX
|
||||
if (rflg)
|
||||
remove_mailbox();
|
||||
#endif
|
||||
|
||||
if (rflg && !fflg && !is_owner(user_id, user_home)) {
|
||||
fprintf(stderr, _("%s: %s not owned by %s, not removing\n"),
|
||||
Prog, user_home, user_name);
|
||||
rflg = 0;
|
||||
errors++;
|
||||
}
|
||||
|
||||
/* This may be slow, the above should be good enough. */
|
||||
#ifdef EXTRA_CHECK_HOME_DIR
|
||||
if (rflg && !fflg) {
|
||||
/*
|
||||
* For safety, refuse to remove the home directory
|
||||
* if it would result in removing some other user's
|
||||
* home directory. Still not perfect so be careful,
|
||||
* but should prevent accidents if someone has /home
|
||||
* or / as home directory... --marekm
|
||||
*/
|
||||
setpwent();
|
||||
while ((pwd = getpwent())) {
|
||||
if (strcmp(pwd->pw_name, user_name) == 0)
|
||||
continue;
|
||||
|
||||
if (path_prefix(user_home, pwd->pw_dir)) {
|
||||
fprintf(stderr,
|
||||
_("%s: not removing directory %s (would remove home of user %s)\n"),
|
||||
Prog, user_home, pwd->pw_name);
|
||||
|
||||
rflg = 0;
|
||||
errors++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rflg) {
|
||||
if (remove_tree(user_home) || rmdir(user_home)) {
|
||||
fprintf(stderr, _("%s: error removing directory %s\n"),
|
||||
Prog, user_home);
|
||||
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel any crontabs or at jobs. Have to do this before we
|
||||
* remove the entry from /etc/passwd.
|
||||
*/
|
||||
|
||||
user_cancel(user_name);
|
||||
|
||||
close_files ();
|
||||
|
||||
exit(errors ? E_HOMEDIR : E_SUCCESS);
|
||||
/*NOTREACHED*/
|
||||
}
|
1664
src/usermod.c
Normal file
1664
src/usermod.c
Normal file
File diff suppressed because it is too large
Load Diff
239
src/vipw.c
Normal file
239
src/vipw.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
vipw, vigr edit the password or group file
|
||||
with -s will edit shadow or gshadow file
|
||||
|
||||
Copyright (C) 1997 Guy Maor <maor@ece.utexas.edu>
|
||||
|
||||
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 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "rcsid.h"
|
||||
RCSID(PKG_VER "$Id: vipw.c,v 1.1 1999/07/09 18:02:43 marekm Exp $")
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <utime.h>
|
||||
#include "prototypes.h"
|
||||
#include "pwio.h"
|
||||
#include "shadowio.h"
|
||||
#include "groupio.h"
|
||||
#include "sgroupio.h"
|
||||
|
||||
|
||||
static const char *progname, *filename, *fileeditname;
|
||||
static int filelocked = 0, createedit = 0;
|
||||
static int (*unlock)();
|
||||
|
||||
/* local function prototypes */
|
||||
static int create_backup_file P_((FILE *, const char *, struct stat *));
|
||||
static void vipwexit P_((const char *, int, int));
|
||||
static void vipwedit P_((const char *, int (*) P_((void)), int (*) P_((void))));
|
||||
int main P_((int, char **));
|
||||
|
||||
static int
|
||||
create_backup_file(FILE *fp, const char *backup, struct stat *sb)
|
||||
{
|
||||
struct utimbuf ub;
|
||||
FILE *bkfp;
|
||||
int c;
|
||||
mode_t mask;
|
||||
|
||||
mask = umask(077);
|
||||
bkfp = fopen(backup, "w");
|
||||
umask(mask);
|
||||
if (!bkfp) return -1;
|
||||
|
||||
rewind(fp);
|
||||
while ((c = getc(fp)) != EOF) {
|
||||
if (putc(c, bkfp) == EOF) break;
|
||||
}
|
||||
|
||||
if (c != EOF || fflush(bkfp)) {
|
||||
fclose(bkfp);
|
||||
unlink(backup);
|
||||
return -1;
|
||||
}
|
||||
if (fclose(bkfp)) {
|
||||
unlink(backup);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ub.actime = sb->st_atime;
|
||||
ub.modtime = sb->st_mtime;
|
||||
if (utime(backup, &ub) ||
|
||||
chmod(backup, sb->st_mode) ||
|
||||
chown(backup, sb->st_uid, sb->st_gid)) {
|
||||
unlink(backup);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vipwexit(const char *msg, int syserr, int ret)
|
||||
{
|
||||
int err = errno;
|
||||
if (filelocked) (*unlock)();
|
||||
if (createedit) unlink(fileeditname);
|
||||
if (msg) fprintf(stderr, "%s: %s", progname, msg);
|
||||
if (syserr) fprintf(stderr, ": %s", strerror(err));
|
||||
fprintf(stderr, _("\n%s: %s is unchanged\n"), progname, filename);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
#ifndef DEFAULT_EDITOR
|
||||
#define DEFAULT_EDITOR "vi"
|
||||
#endif
|
||||
|
||||
static void
|
||||
vipwedit(const char *file, int (*file_lock) P_((void)), int (*file_unlock) P_((void)))
|
||||
{
|
||||
const char *editor;
|
||||
pid_t pid;
|
||||
struct stat st1, st2;
|
||||
int status;
|
||||
FILE *f;
|
||||
char filebackup[1024], fileedit[1024];
|
||||
|
||||
snprintf(filebackup, sizeof filebackup, "%s-", file);
|
||||
snprintf(fileedit, sizeof fileedit, "%s.edit", file);
|
||||
unlock = file_unlock;
|
||||
filename = file;
|
||||
fileeditname = fileedit;
|
||||
|
||||
if (access(file, F_OK)) vipwexit(file, 1, 1);
|
||||
if (!file_lock()) vipwexit(_("Couldn't lock file"), errno, 5);
|
||||
filelocked = 1;
|
||||
|
||||
/* edited copy has same owners, perm */
|
||||
if (stat(file, &st1)) vipwexit(file, 1, 1);
|
||||
if (!(f = fopen(file, "r"))) vipwexit(file, 1, 1);
|
||||
if (create_backup_file(f, fileedit, &st1))
|
||||
vipwexit(_("Couldn't make backup"), errno, 1);
|
||||
createedit = 1;
|
||||
|
||||
editor = getenv("VISUAL");
|
||||
if (!editor)
|
||||
editor = getenv("EDITOR");
|
||||
if (!editor)
|
||||
editor = DEFAULT_EDITOR;
|
||||
|
||||
if ((pid = fork()) == -1) vipwexit("fork", 1, 1);
|
||||
else if (!pid) {
|
||||
execlp(editor, editor, fileedit, (char *) 0);
|
||||
fprintf(stderr, "%s: %s: %s\n", progname, editor, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pid = waitpid(pid, &status, WUNTRACED);
|
||||
if (WIFSTOPPED(status)) {
|
||||
kill(getpid(), SIGSTOP);
|
||||
kill(getpid(), SIGCONT);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status))
|
||||
vipwexit(editor, 1, 1);
|
||||
|
||||
if (stat(fileedit, &st2)) vipwexit(fileedit, 1, 1);
|
||||
if (st1.st_mtime == st2.st_mtime) vipwexit(0, 0, 0);
|
||||
|
||||
/* XXX - here we should check fileedit for errors; if there are any,
|
||||
ask the user what to do (edit again, save changes anyway, or quit
|
||||
without saving). Use pwck or grpck to do the check. --marekm */
|
||||
|
||||
createedit = 0;
|
||||
unlink(filebackup);
|
||||
link(file, filebackup);
|
||||
if (rename(fileedit, file) == -1) {
|
||||
fprintf(stderr, _("%s: can't restore %s: %s (your changes are in %s)\n"),
|
||||
progname, file, strerror(errno), fileedit);
|
||||
vipwexit(0,0,1);
|
||||
}
|
||||
|
||||
(*file_unlock)();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int flag;
|
||||
int editshadow = 0;
|
||||
char *c;
|
||||
int e = 1;
|
||||
int do_vipw;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
progname = ((c = strrchr(*argv, '/')) ? c+1 : *argv);
|
||||
do_vipw = (strcmp(progname, "vigr") != 0);
|
||||
|
||||
while ((flag = getopt(argc, argv, "ghps")) != EOF) {
|
||||
switch (flag) {
|
||||
case 'p':
|
||||
do_vipw = 1;
|
||||
break;
|
||||
case 'g':
|
||||
do_vipw = 0;
|
||||
break;
|
||||
case 's':
|
||||
editshadow = 1;
|
||||
break;
|
||||
case 'h':
|
||||
e = 0;
|
||||
default:
|
||||
printf(_("Usage:\n\
|
||||
`vipw' edits /etc/passwd `vipw -s' edits /etc/shadow\n\
|
||||
`vigr' edits /etc/group `vigr -s' edits /etc/gshadow\n\
|
||||
"));
|
||||
exit(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_vipw) {
|
||||
#ifdef SHADOWPWD
|
||||
if (editshadow)
|
||||
vipwedit(SHADOW_FILE, spw_lock, spw_unlock);
|
||||
else
|
||||
#endif
|
||||
vipwedit(PASSWD_FILE, pw_lock, pw_unlock);
|
||||
}
|
||||
else {
|
||||
#ifdef SHADOWGRP
|
||||
if (editshadow)
|
||||
vipwedit(SGROUP_FILE, sgr_lock, sgr_unlock);
|
||||
else
|
||||
#endif
|
||||
vipwedit(GROUP_FILE, gr_lock, gr_unlock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user