diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-26 16:18:37 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-26 16:18:37 +0000 |
commit | b6b00dd55e035bfbe311a527b567962ffa77ee43 (patch) | |
tree | cafc4d13785448e5a78bd40a51697ee07f07ac12 /src | |
parent | Adding debian version 1:4.13+dfsg1-5. (diff) | |
download | shadow-b6b00dd55e035bfbe311a527b567962ffa77ee43.tar.xz shadow-b6b00dd55e035bfbe311a527b567962ffa77ee43.zip |
Merging upstream version 1:4.15.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
43 files changed, 2477 insertions, 2578 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a1a2e4e..b6cb09e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,9 +9,11 @@ sgidperms = 2755 AM_CPPFLAGS = \ -I${top_srcdir}/lib \ - -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -DLOCALEDIR=\"$(datadir)/locale\" + -DLOCALEDIR=\"$(datadir)/locale\" \ + $(ECONF_CPPFLAGS) + +AM_CFLAGS = $(LIBBSD_CFLAGS) # XXX why are login and su in /bin anyway (other than for # historical reasons)? @@ -26,10 +28,13 @@ AM_CPPFLAGS = \ bin_PROGRAMS = groups login sbin_PROGRAMS = nologin -ubin_PROGRAMS = faillog lastlog chage chfn chsh expiry gpasswd newgrp passwd +ubin_PROGRAMS = faillog chage chfn chsh expiry gpasswd newgrp passwd if ENABLE_SUBIDS ubin_PROGRAMS += newgidmap newuidmap endif +if ENABLE_LASTLOG +ubin_PROGRAMS += lastlog +endif if WITH_SU bin_PROGRAMS += su endif @@ -79,7 +84,6 @@ shadowsgidubins = passwd endif LDADD = $(INTLLIBS) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la \ $(LIBTCB) @@ -95,13 +99,13 @@ else LIBCRYPT_NOPAM = $(LIBCRYPT) endif -chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) +chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) -ldl newuidmap_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCAP) $(LIBECONF) -ldl newgidmap_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCAP) $(LIBECONF) -ldl chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) -chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) +chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) -ldl expiry_LDADD = $(LDADD) $(LIBECONF) gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) -ldl @@ -115,18 +119,18 @@ lastlog_LDADD = $(LDADD) $(LIBAUDIT) $(LIBECONF) login_SOURCES = \ login.c \ login_nopam.c -login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) +login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) $(LIBSELINUX) newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT) $(LIBECONF) newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) -ldl nologin_LDADD = -passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBECONF) +passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBECONF) -ldl pwck_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) pwconv_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) pwunconv_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) su_SOURCES = \ su.c \ suauth.c -su_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) +su_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) $(LIBSELINUX) sulogin_LDADD = $(LDADD) $(LIBCRYPT) $(LIBECONF) useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) $(LIBECONF) -ldl userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBECONF) -ldl @@ -177,59 +181,49 @@ MISCLIBS = \ getsubids_LDADD = \ $(top_builddir)/lib/libshadow.la \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/libsubid/libsubid.la \ $(MISCLIBS) -ldl getsubids_CPPFLAGS = \ -I$(top_srcdir)/lib \ - -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -I$(top_srcdir)/libsubid + -I$(top_builddir)/libsubid get_subid_owners_LDADD = \ $(top_builddir)/lib/libshadow.la \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/libsubid/libsubid.la \ $(MISCLIBS) -ldl get_subid_owners_CPPFLAGS = \ -I$(top_srcdir)/lib \ - -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -I$(top_srcdir)/libsubid + -I$(top_builddir)/libsubid new_subid_range_CPPFLAGS = \ -I$(top_srcdir)/lib \ - -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -I$(top_srcdir)/libsubid + -I$(top_builddir)/libsubid new_subid_range_LDADD = \ $(top_builddir)/lib/libshadow.la \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/libsubid/libsubid.la \ $(MISCLIBS) -ldl free_subid_range_CPPFLAGS = \ -I$(top_srcdir)/lib \ - -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -I$(top_srcdir)/libsubid + -I$(top_builddir)/libsubid free_subid_range_LDADD = \ $(top_builddir)/lib/libshadow.la \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/libsubid/libsubid.la \ $(MISCLIBS) -ldl check_subid_range_CPPFLAGS = \ -I$(top_srcdir)/lib \ - -I$(top_srcdir) \ - -I$(top_srcdir)/libmisc + -I$(top_srcdir) check_subid_range_LDADD = \ $(top_builddir)/lib/libshadow.la \ - $(top_builddir)/libmisc/libmisc.la \ $(MISCLIBS) -ldl endif diff --git a/src/Makefile.in b/src/Makefile.in index da31572..f62a5cf 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -91,11 +91,12 @@ host_triplet = @host@ bin_PROGRAMS = groups$(EXEEXT) login$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) sbin_PROGRAMS = nologin$(EXEEXT) -ubin_PROGRAMS = faillog$(EXEEXT) lastlog$(EXEEXT) chage$(EXEEXT) \ - chfn$(EXEEXT) chsh$(EXEEXT) expiry$(EXEEXT) gpasswd$(EXEEXT) \ - newgrp$(EXEEXT) passwd$(EXEEXT) $(am__EXEEXT_4) +ubin_PROGRAMS = faillog$(EXEEXT) chage$(EXEEXT) chfn$(EXEEXT) \ + chsh$(EXEEXT) expiry$(EXEEXT) gpasswd$(EXEEXT) newgrp$(EXEEXT) \ + passwd$(EXEEXT) $(am__EXEEXT_4) $(am__EXEEXT_5) @ENABLE_SUBIDS_TRUE@am__append_1 = newgidmap newuidmap -@WITH_SU_TRUE@am__append_2 = su +@ENABLE_LASTLOG_TRUE@am__append_2 = lastlog +@WITH_SU_TRUE@am__append_3 = su usbin_PROGRAMS = chgpasswd$(EXEEXT) chpasswd$(EXEEXT) \ groupadd$(EXEEXT) groupdel$(EXEEXT) groupmems$(EXEEXT) \ groupmod$(EXEEXT) grpck$(EXEEXT) grpconv$(EXEEXT) \ @@ -104,12 +105,12 @@ usbin_PROGRAMS = chgpasswd$(EXEEXT) chpasswd$(EXEEXT) \ useradd$(EXEEXT) userdel$(EXEEXT) usermod$(EXEEXT) \ vipw$(EXEEXT) noinst_PROGRAMS = id$(EXEEXT) sulogin$(EXEEXT) $(am__EXEEXT_3) -@WITH_SU_TRUE@am__append_3 = su -@WITH_TCB_FALSE@am__append_4 = passwd -@ACCT_TOOLS_SETUID_TRUE@am__append_5 = chgpasswd chpasswd groupadd groupdel groupmod newusers useradd userdel usermod -@ENABLE_SUBIDS_TRUE@@FCAPS_FALSE@am__append_6 = newgidmap newuidmap -@ENABLE_SUBIDS_TRUE@am__append_7 = getsubids -@ENABLE_SUBIDS_TRUE@am__append_8 = get_subid_owners \ +@WITH_SU_TRUE@am__append_4 = su +@WITH_TCB_FALSE@am__append_5 = passwd +@ACCT_TOOLS_SETUID_TRUE@am__append_6 = chgpasswd chpasswd groupadd groupdel groupmod newusers useradd userdel usermod +@ENABLE_SUBIDS_TRUE@@FCAPS_FALSE@am__append_7 = newgidmap newuidmap +@ENABLE_SUBIDS_TRUE@am__append_8 = getsubids +@ENABLE_SUBIDS_TRUE@am__append_9 = get_subid_owners \ @ENABLE_SUBIDS_TRUE@ new_subid_range \ @ENABLE_SUBIDS_TRUE@ free_subid_range \ @ENABLE_SUBIDS_TRUE@ check_subid_range @@ -142,13 +143,13 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ @ENABLE_SUBIDS_TRUE@ check_subid_range$(EXEEXT) @ENABLE_SUBIDS_TRUE@am__EXEEXT_4 = newgidmap$(EXEEXT) \ @ENABLE_SUBIDS_TRUE@ newuidmap$(EXEEXT) +@ENABLE_LASTLOG_TRUE@am__EXEEXT_5 = lastlog$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(sbin_PROGRAMS) \ $(ubin_PROGRAMS) $(usbin_PROGRAMS) chage_SOURCES = chage.c chage_OBJECTS = chage.$(OBJEXT) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la $(am__DEPENDENCIES_1) @ACCT_TOOLS_SETUID_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) chage_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ @@ -173,7 +174,6 @@ check_subid_range_OBJECTS = \ @ENABLE_SUBIDS_TRUE@ $(am__DEPENDENCIES_1) @ENABLE_SUBIDS_TRUE@check_subid_range_DEPENDENCIES = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(am__DEPENDENCIES_5) chfn_SOURCES = chfn.c chfn_OBJECTS = chfn.$(OBJEXT) @@ -204,14 +204,12 @@ faillog_SOURCES = faillog.c faillog_OBJECTS = faillog.$(OBJEXT) faillog_LDADD = $(LDADD) faillog_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la $(am__DEPENDENCIES_1) free_subid_range_SOURCES = free_subid_range.c free_subid_range_OBJECTS = \ free_subid_range-free_subid_range.$(OBJEXT) @ENABLE_SUBIDS_TRUE@free_subid_range_DEPENDENCIES = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(am__DEPENDENCIES_5) get_subid_owners_SOURCES = get_subid_owners.c @@ -219,14 +217,12 @@ get_subid_owners_OBJECTS = \ get_subid_owners-get_subid_owners.$(OBJEXT) @ENABLE_SUBIDS_TRUE@get_subid_owners_DEPENDENCIES = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(am__DEPENDENCIES_5) getsubids_SOURCES = getsubids.c getsubids_OBJECTS = getsubids-getsubids.$(OBJEXT) @ENABLE_SUBIDS_TRUE@getsubids_DEPENDENCIES = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(am__DEPENDENCIES_5) gpasswd_SOURCES = gpasswd.c @@ -258,7 +254,6 @@ groups_SOURCES = groups.c groups_OBJECTS = groups.$(OBJEXT) groups_LDADD = $(LDADD) groups_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la $(am__DEPENDENCIES_1) grpck_SOURCES = grpck.c grpck_OBJECTS = grpck.$(OBJEXT) @@ -276,7 +271,6 @@ id_SOURCES = id.c id_OBJECTS = id.$(OBJEXT) id_LDADD = $(LDADD) id_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la $(am__DEPENDENCIES_1) lastlog_SOURCES = lastlog.c lastlog_OBJECTS = lastlog.$(OBJEXT) @@ -287,18 +281,16 @@ login_OBJECTS = $(am_login_OBJECTS) login_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_4) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) logoutd_SOURCES = logoutd.c logoutd_OBJECTS = logoutd.$(OBJEXT) logoutd_LDADD = $(LDADD) logoutd_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la $(am__DEPENDENCIES_1) new_subid_range_SOURCES = new_subid_range.c new_subid_range_OBJECTS = new_subid_range-new_subid_range.$(OBJEXT) @ENABLE_SUBIDS_TRUE@new_subid_range_DEPENDENCIES = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(am__DEPENDENCIES_5) newgidmap_SOURCES = newgidmap.c @@ -325,8 +317,7 @@ passwd_SOURCES = passwd.c passwd_OBJECTS = passwd.$(OBJEXT) passwd_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_4) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1) pwck_SOURCES = pwck.c pwck_OBJECTS = pwck.$(OBJEXT) pwck_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ @@ -344,7 +335,7 @@ su_OBJECTS = $(am_su_OBJECTS) su_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_4) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) sulogin_SOURCES = sulogin.c sulogin_OBJECTS = sulogin.$(OBJEXT) sulogin_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ @@ -478,6 +469,8 @@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ +CMOCKA_CFLAGS = @CMOCKA_CFLAGS@ +CMOCKA_LIBS = @CMOCKA_LIBS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ @@ -496,6 +489,7 @@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +FILECMD = @FILECMD@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ @@ -511,9 +505,15 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBACL = @LIBACL@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBATTR = @LIBATTR@ LIBAUDIT = @LIBAUDIT@ -LIBCRACK = @LIBCRACK@ +LIBBSD = @LIBBSD@ +LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ +LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPT = @LIBCRYPT@ LIBECONF = @LIBECONF@ LIBICONV = @LIBICONV@ @@ -529,6 +529,7 @@ LIBSUBID_ABI = @LIBSUBID_ABI@ LIBSUBID_ABI_MAJOR = @LIBSUBID_ABI_MAJOR@ LIBSUBID_ABI_MICRO = @LIBSUBID_ABI_MICRO@ LIBSUBID_ABI_MINOR = @LIBSUBID_ABI_MINOR@ +LIBSYSTEMD = @LIBSYSTEMD@ LIBTCB = @LIBTCB@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ @@ -537,6 +538,8 @@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -559,6 +562,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ RANLIB = @RANLIB@ SED = @SED@ @@ -639,17 +645,17 @@ suidperms = 4755 sgidperms = 2755 AM_CPPFLAGS = \ -I${top_srcdir}/lib \ - -I$(top_srcdir)/libmisc \ -I$(top_srcdir) \ - -DLOCALEDIR=\"$(datadir)/locale\" - -suidusbins = $(am__append_5) -suidbins = $(am__append_3) -suidubins = chage chfn chsh expiry gpasswd newgrp $(am__append_4) \ - $(am__append_6) + -DLOCALEDIR=\"$(datadir)/locale\" \ + $(ECONF_CPPFLAGS) + +AM_CFLAGS = $(LIBBSD_CFLAGS) +suidusbins = $(am__append_6) +suidbins = $(am__append_4) +suidubins = chage chfn chsh expiry gpasswd newgrp $(am__append_5) \ + $(am__append_7) @WITH_TCB_TRUE@shadowsgidubins = passwd LDADD = $(INTLLIBS) \ - $(top_builddir)/libmisc/libmisc.la \ $(top_builddir)/lib/libshadow.la \ $(LIBTCB) @@ -657,13 +663,13 @@ LDADD = $(INTLLIBS) \ @ACCT_TOOLS_SETUID_TRUE@LIBPAM_SUID = $(LIBPAM) @USE_PAM_FALSE@LIBCRYPT_NOPAM = $(LIBCRYPT) @USE_PAM_TRUE@LIBCRYPT_NOPAM = -chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) +chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) -ldl newuidmap_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCAP) $(LIBECONF) -ldl newgidmap_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCAP) $(LIBECONF) -ldl chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) -chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) +chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) -ldl expiry_LDADD = $(LDADD) $(LIBECONF) gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) -ldl @@ -678,11 +684,11 @@ login_SOURCES = \ login.c \ login_nopam.c -login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) +login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) $(LIBSELINUX) newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT) $(LIBECONF) newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) -ldl nologin_LDADD = -passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBECONF) +passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBECONF) -ldl pwck_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) pwconv_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) pwunconv_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) @@ -690,7 +696,7 @@ su_SOURCES = \ su.c \ suauth.c -su_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) +su_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) $(LIBECONF) $(LIBSELINUX) sulogin_LDADD = $(LDADD) $(LIBCRYPT) $(LIBECONF) useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) $(LIBECONF) -ldl userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBECONF) -ldl @@ -709,60 +715,50 @@ vipw_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) @ENABLE_SUBIDS_TRUE@getsubids_LDADD = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(MISCLIBS) -ldl @ENABLE_SUBIDS_TRUE@getsubids_CPPFLAGS = \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/lib \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libmisc \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir) \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libsubid +@ENABLE_SUBIDS_TRUE@ -I$(top_builddir)/libsubid @ENABLE_SUBIDS_TRUE@get_subid_owners_LDADD = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(MISCLIBS) -ldl @ENABLE_SUBIDS_TRUE@get_subid_owners_CPPFLAGS = \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/lib \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libmisc \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir) \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libsubid +@ENABLE_SUBIDS_TRUE@ -I$(top_builddir)/libsubid @ENABLE_SUBIDS_TRUE@new_subid_range_CPPFLAGS = \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/lib \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libmisc \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir) \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libsubid +@ENABLE_SUBIDS_TRUE@ -I$(top_builddir)/libsubid @ENABLE_SUBIDS_TRUE@new_subid_range_LDADD = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(MISCLIBS) -ldl @ENABLE_SUBIDS_TRUE@free_subid_range_CPPFLAGS = \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/lib \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libmisc \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir) \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libsubid +@ENABLE_SUBIDS_TRUE@ -I$(top_builddir)/libsubid @ENABLE_SUBIDS_TRUE@free_subid_range_LDADD = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/libsubid/libsubid.la \ @ENABLE_SUBIDS_TRUE@ $(MISCLIBS) -ldl @ENABLE_SUBIDS_TRUE@check_subid_range_CPPFLAGS = \ @ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/lib \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir) \ -@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir)/libmisc +@ENABLE_SUBIDS_TRUE@ -I$(top_srcdir) @ENABLE_SUBIDS_TRUE@check_subid_range_LDADD = \ @ENABLE_SUBIDS_TRUE@ $(top_builddir)/lib/libshadow.la \ -@ENABLE_SUBIDS_TRUE@ $(top_builddir)/libmisc/libmisc.la \ @ENABLE_SUBIDS_TRUE@ $(MISCLIBS) -ldl all: all-am @@ -1220,22 +1216,25 @@ $(am__depfiles_remade): am--depfiles: $(am__depfiles_remade) .c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< diff --git a/src/chage.c b/src/chage.c index 01570d7..1edab47 100644 --- a/src/chage.c +++ b/src/chage.c @@ -25,21 +25,31 @@ #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ #include <pwd.h> -#include "prototypes.h" + +#include "alloc.h" +#include "atoi/str2i.h" #include "defines.h" +#include "memzero.h" +#include "prototypes.h" #include "pwio.h" #include "shadowio.h" #include "shadowlog.h" +#include "string/sprintf.h" +#include "string/strftime.h" +#include "string/strtcpy.h" +#include "time/day_to_str.h" +/*@-exitarg@*/ +#include "exitcodes.h" + #ifdef WITH_TCB #include "tcbfuncs.h" #endif -/*@-exitarg@*/ -#include "exitcodes.h" + /* * Global variables */ -const char *Prog; +static const char Prog[] = "chage"; static bool dflg = false, /* set last password change date */ @@ -52,6 +62,8 @@ static bool Wflg = false; /* set expiration warning days */ static bool amroot = false; +static const char *prefix = ""; + static bool pw_locked = false; /* Indicate if the password file is locked */ static bool spw_locked = false; /* Indicate if the shadow file is locked */ /* The name and UID of the user being worked on */ @@ -66,21 +78,23 @@ static long inactdays; static long expdate; /* local function prototypes */ -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static int new_fields (void); -static void print_date (time_t date); +static void print_day_as_date (long day); static void list_fields (void); static void process_flags (int argc, char **argv); static void check_flags (int argc, int opt_index); static void check_perms (void); static void open_files (bool readonly); static void close_files (void); -static /*@noreturn@*/void fail_exit (int code); +NORETURN static void fail_exit (int code); /* * fail_exit - do some cleanup and exit with the given error code */ -static /*@noreturn@*/void fail_exit (int code) +NORETURN +static void +fail_exit (int code) { if (spw_locked) { if (spw_unlock () == 0) { @@ -101,8 +115,7 @@ static /*@noreturn@*/void fail_exit (int code) #ifdef WITH_AUDIT if (E_SUCCESS != code) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "change age", - user_name, (unsigned int) user_uid, 0); + "change age", user_name, user_uid, 0); } #endif @@ -112,7 +125,9 @@ static /*@noreturn@*/void fail_exit (int code) /* * usage - print command line syntax and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -132,6 +147,7 @@ static /*@noreturn@*/void usage (int status) (void) fputs (_(" -M, --maxdays MAX_DAYS set maximum number of days before password\n" " change to MAX_DAYS\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); + (void) fputs (_(" -P, --prefix PREFIX_DIR directory prefix\n"), usageout); (void) fputs (_(" -W, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"), usageout); (void) fputs ("\n", usageout); exit (status); @@ -148,30 +164,29 @@ static /*@noreturn@*/void usage (int status) */ static int new_fields (void) { - char buf[200]; + char buf[200]; (void) puts (_("Enter the new value, or press ENTER for the default")); (void) puts (""); - (void) snprintf (buf, sizeof buf, "%ld", mindays); + SNPRINTF(buf, "%ld", mindays); change_field (buf, sizeof buf, _("Minimum Password Age")); - if ( (getlong (buf, &mindays) == 0) + if ( (str2sl(&mindays, buf) == -1) || (mindays < -1)) { return 0; } - (void) snprintf (buf, sizeof buf, "%ld", maxdays); + SNPRINTF(buf, "%ld", maxdays); change_field (buf, sizeof buf, _("Maximum Password Age")); - if ( (getlong (buf, &maxdays) == 0) + if ( (str2sl(&maxdays, buf) == -1) || (maxdays < -1)) { return 0; } - if (-1 == lstchgdate || lstchgdate > LONG_MAX / SCALE) { - strcpy (buf, "-1"); - } else { - date_to_str (sizeof(buf), buf, lstchgdate * SCALE); - } + if (-1 == lstchgdate || lstchgdate > LONG_MAX / DAY) + strcpy(buf, "-1"); + else + DAY_TO_STR(buf, lstchgdate); change_field (buf, sizeof buf, _("Last Password Change (YYYY-MM-DD)")); @@ -184,25 +199,24 @@ static int new_fields (void) } } - (void) snprintf (buf, sizeof buf, "%ld", warndays); + SNPRINTF(buf, "%ld", warndays); change_field (buf, sizeof buf, _("Password Expiration Warning")); - if ( (getlong (buf, &warndays) == 0) + if ( (str2sl(&warndays, buf) == -1) || (warndays < -1)) { return 0; } - (void) snprintf (buf, sizeof buf, "%ld", inactdays); + SNPRINTF(buf, "%ld", inactdays); change_field (buf, sizeof buf, _("Password Inactive")); - if ( (getlong (buf, &inactdays) == 0) + if ( (str2sl(&inactdays, buf) == -1) || (inactdays < -1)) { return 0; } - if (-1 == expdate || LONG_MAX / SCALE < expdate) { - strcpy (buf, "-1"); - } else { - date_to_str (sizeof(buf), buf, expdate * SCALE); - } + if (-1 == expdate || LONG_MAX / DAY < expdate) + strcpy(buf, "-1"); + else + DAY_TO_STR(buf, expdate); change_field (buf, sizeof buf, _("Account Expiration Date (YYYY-MM-DD)")); @@ -219,20 +233,33 @@ static int new_fields (void) return 1; } -static void print_date (time_t date) + +static void +print_day_as_date(long day) { - struct tm *tp; - char buf[80]; + char buf[80]; + time_t date; + struct tm tm; - tp = gmtime (&date); - if (NULL == tp) { + if (day < 0) { + puts(_("never")); + return; + } + if (__builtin_mul_overflow(day, DAY, &date)) { + puts(_("future")); + return; + } + + if (gmtime_r(&date, &tm) == NULL) { (void) printf ("time_t: %lu\n", (unsigned long)date); - } else { - (void) strftime (buf, sizeof buf, iflg ? "%Y-%m-%d" : "%b %d, %Y", tp); - (void) puts (buf); + return; } + + STRFTIME(buf, iflg ? "%Y-%m-%d" : "%b %d, %Y", &tm); + (void) puts (buf); } + /* * list_fields - display the current values of the expiration fields * @@ -242,21 +269,15 @@ static void print_date (time_t date) */ static void list_fields (void) { - long changed = 0; - long expires; - /* * 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. */ (void) fputs (_("Last password change\t\t\t\t\t: "), stdout); - if (lstchgdate < 0 || lstchgdate > LONG_MAX / SCALE) { - (void) puts (_("never")); - } else if (lstchgdate == 0) { + if (lstchgdate == 0) { (void) puts (_("password must be changed")); } else { - changed = lstchgdate * SCALE; - print_date ((time_t) changed); + print_day_as_date(lstchgdate); } /* @@ -267,13 +288,13 @@ static void list_fields (void) if (lstchgdate == 0) { (void) puts (_("password must be changed")); } else if ( (lstchgdate < 0) - || (maxdays >= (10000 * (DAY / SCALE))) + || (maxdays >= 10000) || (maxdays < 0) - || ((LONG_MAX - changed) / SCALE < maxdays)) { + || (LONG_MAX - lstchgdate < maxdays)) + { (void) puts (_("never")); } else { - expires = changed + maxdays * SCALE; - print_date ((time_t) expires); + print_day_as_date(lstchgdate + maxdays); } /* @@ -287,14 +308,14 @@ static void list_fields (void) (void) puts (_("password must be changed")); } else if ( (lstchgdate < 0) || (inactdays < 0) - || (maxdays >= (10000 * (DAY / SCALE))) + || (maxdays >= 10000) || (maxdays < 0) - || (maxdays > LONG_MAX - inactdays) - || ((LONG_MAX - changed) / SCALE < maxdays + inactdays)) { + || (LONG_MAX - inactdays < maxdays) + || (LONG_MAX - lstchgdate < maxdays + inactdays)) + { (void) puts (_("never")); } else { - expires = changed + (maxdays + inactdays) * SCALE; - print_date ((time_t) expires); + print_day_as_date(lstchgdate + maxdays + inactdays); } /* @@ -302,12 +323,7 @@ static void list_fields (void) * password expiring or not. */ (void) fputs (_("Account expires\t\t\t\t\t\t: "), stdout); - if (expdate < 0 || LONG_MAX / SCALE < expdate) { - (void) puts (_("never")); - } else { - expires = expdate * SCALE; - print_date ((time_t) expires); - } + print_day_as_date(expdate); /* * Start with the easy numbers - the number of days before the @@ -344,12 +360,13 @@ static void process_flags (int argc, char **argv) {"mindays", required_argument, NULL, 'm'}, {"maxdays", required_argument, NULL, 'M'}, {"root", required_argument, NULL, 'R'}, + {"prefix", required_argument, NULL, 'P'}, {"warndays", required_argument, NULL, 'W'}, {"iso8601", no_argument, NULL, 'i'}, {NULL, 0, NULL, '\0'} }; - while ((c = getopt_long (argc, argv, "d:E:hiI:lm:M:R:W:", + while ((c = getopt_long (argc, argv, "d:E:hiI:lm:M:R:P:W:", long_options, NULL)) != -1) { switch (c) { case 'd': @@ -380,7 +397,7 @@ static void process_flags (int argc, char **argv) break; case 'I': Iflg = true; - if ( (getlong (optarg, &inactdays) == 0) + if ( (str2sl(&inactdays, optarg) == -1) || (inactdays < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -393,7 +410,7 @@ static void process_flags (int argc, char **argv) break; case 'm': mflg = true; - if ( (getlong (optarg, &mindays) == 0) + if ( (str2sl(&mindays, optarg) == -1) || (mindays < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -403,7 +420,7 @@ static void process_flags (int argc, char **argv) break; case 'M': Mflg = true; - if ( (getlong (optarg, &maxdays) == 0) + if ( (str2sl(&maxdays, optarg) == -1) || (maxdays < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -413,9 +430,11 @@ static void process_flags (int argc, char **argv) break; case 'R': /* no-op, handled in process_root_flag () */ break; + case 'P': /* no-op, handled in process_prefix_flag () */ + break; case 'W': Wflg = true; - if ( (getlong (optarg, &warndays) == 0) + if ( (str2sl(&warndays, optarg) == -1) || (warndays < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -500,7 +519,7 @@ static void check_perms (void) exit (E_NOPERM); } - retval = pam_start ("chage", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -751,24 +770,23 @@ int main (int argc, char **argv) gid_t rgid; const struct passwd *pw; - /* - * Get the program name so that error messages can use it. - */ - Prog = Basename (argv[0]); + sanitize_env (); + check_fds (); + log_set_progname(Prog); log_set_logfd(stderr); - sanitize_env (); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); + prefix = process_prefix_flag ("-P", argc, argv); #ifdef WITH_AUDIT audit_help_open (); #endif - OPENLOG ("chage"); + OPENLOG (Prog); ruid = getuid (); rgid = getgid (); @@ -809,7 +827,7 @@ int main (int argc, char **argv) fail_exit (E_NOPERM); } - STRFCPY (user_name, pw->pw_name); + STRTCPY(user_name, pw->pw_name); #ifdef WITH_TCB if (shadowtcb_set_user (pw->pw_name) == SHADOWTCB_FAILURE) { fail_exit (E_NOPERM); @@ -831,8 +849,7 @@ int main (int argc, char **argv) } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "display aging info", - user_name, (unsigned int) user_uid, 1); + "display aging info", user_name, user_uid, 1); #endif list_fields (); fail_exit (E_SUCCESS); @@ -854,40 +871,38 @@ int main (int argc, char **argv) else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change all aging information", - user_name, (unsigned int) user_uid, 1); + user_name, user_uid, 1); } #endif } else { #ifdef WITH_AUDIT if (Mflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "change max age", - user_name, (unsigned int) user_uid, 1); + "change max age", user_name, user_uid, 1); } if (mflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "change min age", - user_name, (unsigned int) user_uid, 1); + "change min age", user_name, user_uid, 1); } if (dflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change last change date", - user_name, (unsigned int) user_uid, 1); + user_name, user_uid, 1); } if (Wflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change passwd warning", - user_name, (unsigned int) user_uid, 1); + user_name, user_uid, 1); } if (Iflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change inactive days", - user_name, (unsigned int) user_uid, 1); + user_name, user_uid, 1); } if (Eflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change passwd expiration", - user_name, (unsigned int) user_uid, 1); + user_name, user_uid, 1); } #endif } diff --git a/src/check_subid_range.c b/src/check_subid_range.c index 38703b6..68266f5 100644 --- a/src/check_subid_range.c +++ b/src/check_subid_range.c @@ -12,20 +12,21 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> + +#include "atoi/str2i.h" #include "defines.h" #include "prototypes.h" #include "subordinateio.h" #include "idmapping.h" #include "shadowlog.h" -const char *Prog; +static const char Prog[] = "check_subid_range"; int main(int argc, char **argv) { char *owner; unsigned long start, count; bool check_uids; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -34,11 +35,10 @@ int main(int argc, char **argv) owner = argv[1]; check_uids = argv[2][0] == 'u'; - start = strtoul(argv[3], NULL, 10); - if (start == ULONG_MAX && errno == ERANGE) + errno = 0; + if (str2ul(&start, argv[3]) == -1) exit(1); - count = strtoul(argv[4], NULL, 10); - if (count == ULONG_MAX && errno == ERANGE) + if (str2ul(&count, argv[4]) == -1) exit(1); if (check_uids) { if (have_sub_uids(owner, start, count)) @@ -17,6 +17,8 @@ #include <stdio.h> #include <sys/types.h> #include <getopt.h> + +#include "alloc.h" #include "defines.h" #include "getdef.h" #include "nscd.h" @@ -30,11 +32,14 @@ /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/sprintf.h" +#include "string/strtcpy.h" + /* * Global variables. */ -const char *Prog; +static const char Prog[] = "chfn"; static char fullnm[BUFSIZ]; static char roomno[BUFSIZ]; static char workph[BUFSIZ]; @@ -54,8 +59,8 @@ static bool pw_locked = false; */ /* local function prototypes */ -static void fail_exit (int code); -static /*@noreturn@*/void usage (int status); +NORETURN static void fail_exit (int code); +NORETURN static void usage (int status); static bool may_change_field (int); static void new_fields (void); static char *copy_field (char *, char *, char *); @@ -86,7 +91,9 @@ static void fail_exit (int code) /* * usage - print command line syntax and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -175,19 +182,19 @@ static void new_fields (void) if (may_change_field ('r')) { change_field (roomno, sizeof roomno, _("Room Number")); } else { - printf (_("\t%s: %s\n"), _("Room Number"), fullnm); + printf (_("\t%s: %s\n"), _("Room Number"), roomno); } if (may_change_field ('w')) { change_field (workph, sizeof workph, _("Work Phone")); } else { - printf (_("\t%s: %s\n"), _("Work Phone"), fullnm); + printf (_("\t%s: %s\n"), _("Work Phone"), workph); } if (may_change_field ('h')) { change_field (homeph, sizeof homeph, _("Home Phone")); } else { - printf (_("\t%s: %s\n"), _("Home Phone"), fullnm); + printf (_("\t%s: %s\n"), _("Home Phone"), homeph); } if (amroot) { @@ -271,7 +278,7 @@ static void process_flags (int argc, char **argv) exit (E_NOPERM); } fflg = true; - STRFCPY (fullnm, optarg); + STRTCPY(fullnm, optarg); break; case 'h': if (!may_change_field ('h')) { @@ -280,7 +287,7 @@ static void process_flags (int argc, char **argv) exit (E_NOPERM); } hflg = true; - STRFCPY (homeph, optarg); + STRTCPY(homeph, optarg); break; case 'o': if (!amroot) { @@ -294,7 +301,7 @@ static void process_flags (int argc, char **argv) _("%s: fields too long\n"), Prog); exit (E_NOPERM); } - STRFCPY (slop, optarg); + STRTCPY(slop, optarg); break; case 'r': if (!may_change_field ('r')) { @@ -303,7 +310,7 @@ static void process_flags (int argc, char **argv) exit (E_NOPERM); } rflg = true; - STRFCPY (roomno, optarg); + STRTCPY(roomno, optarg); break; case 'R': /* no-op, handled in process_root_flag () */ break; @@ -317,7 +324,7 @@ static void process_flags (int argc, char **argv) exit (E_NOPERM); } wflg = true; - STRFCPY (workph, optarg); + STRTCPY(workph, optarg); break; default: usage (E_USAGE); @@ -358,7 +365,7 @@ static void check_perms (const struct passwd *pw) * check if the change is allowed by SELinux policy. */ if ((pw->pw_uid != getuid ()) - && (check_selinux_permit ("chfn") != 0)) { + && (check_selinux_permit (Prog) != 0)) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); closelog (); exit (E_NOPERM); @@ -373,7 +380,7 @@ static void check_perms (const struct passwd *pw) * --marekm */ if (!amroot && getdef_bool ("CHFN_AUTH")) { - passwd_check (pw->pw_name, pw->pw_passwd, "chfn"); + passwd_check (pw->pw_name, pw->pw_passwd, Prog); } #else /* !USE_PAM */ @@ -385,7 +392,7 @@ static void check_perms (const struct passwd *pw) exit (E_NOPERM); } - retval = pam_start ("chfn", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -504,34 +511,35 @@ static void get_old_fields (const char *gecos) { char *cp; /* temporary character pointer */ char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */ - STRFCPY (old_gecos, gecos); + + STRTCPY(old_gecos, gecos); /* * Now get the full name. It is the first comma separated field in * the GECOS field. */ - cp = copy_field (old_gecos, fflg ? (char *) 0 : fullnm, slop); + cp = copy_field (old_gecos, fflg ? NULL : fullnm, slop); /* * Now get the room number. It is the next comma separated field, * if there is indeed one. */ if (NULL != cp) { - cp = copy_field (cp, rflg ? (char *) 0 : roomno, slop); + cp = copy_field (cp, rflg ? NULL : roomno, slop); } /* * Now get the work phone number. It is the third field. */ if (NULL != cp) { - cp = copy_field (cp, wflg ? (char *) 0 : workph, slop); + cp = copy_field (cp, wflg ? NULL : workph, slop); } /* * Now get the home phone number. It is the fourth field. */ if (NULL != cp) { - cp = copy_field (cp, hflg ? (char *) 0 : homeph, slop); + cp = copy_field (cp, hflg ? NULL : homeph, slop); } /* @@ -608,19 +616,16 @@ static void check_fields (void) */ int main (int argc, char **argv) { - const struct passwd *pw; /* password file entry */ - char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */ - char *user; + char new_gecos[BUFSIZ]; + char *user; + const struct passwd *pw; + + sanitize_env (); + check_fds (); - /* - * Get the program name. The program name is used as a - * prefix to most error messages. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); - sanitize_env (); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); @@ -633,7 +638,7 @@ int main (int argc, char **argv) */ amroot = (getuid () == 0); - OPENLOG ("chfn"); + OPENLOG (Prog); /* parse the command line options */ process_flags (argc, argv); @@ -663,29 +668,6 @@ int main (int argc, char **argv) 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); - } - fail_exit (E_NOPERM); - } -#endif - /* Check that the caller is allowed to change the gecos of the * specified user */ check_perms (pw); @@ -717,9 +699,9 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: fields too long\n"), Prog); fail_exit (E_NOPERM); } - snprintf (new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s", - fullnm, roomno, workph, homeph, - ('\0' != slop[0]) ? "," : "", slop); + SNPRINTF(new_gecos, "%s,%s,%s,%s%s%s", + fullnm, roomno, workph, homeph, + ('\0' != slop[0]) ? "," : "", slop); /* Rewrite the user's gecos in the passwd file */ update_gecos (user, new_gecos); diff --git a/src/chgpasswd.c b/src/chgpasswd.c index d17acb6..1ff6776 100644 --- a/src/chgpasswd.c +++ b/src/chgpasswd.c @@ -16,11 +16,13 @@ #include <pwd.h> #include <stdio.h> #include <stdlib.h> + #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM #include "pam_defs.h" #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ +#include "atoi/str2i.h" #include "defines.h" #include "nscd.h" #include "sssd.h" @@ -33,10 +35,11 @@ #include "exitcodes.h" #include "shadowlog.h" + /* * Global variables */ -const char *Prog; +static const char Prog[] = "chgpasswd"; static bool eflg = false; static bool md5flg = false; #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) @@ -62,8 +65,8 @@ static bool sgr_locked = false; static bool gr_locked = false; /* local function prototypes */ -static void fail_exit (int code); -static /*@noreturn@*/void usage (int status); +NORETURN static void fail_exit (int code); +NORETURN static void usage (int status); static void process_flags (int argc, char **argv); static void check_flags (void); static void check_perms (void); @@ -99,7 +102,9 @@ static void fail_exit (int code) /* * usage - display usage message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -184,21 +189,28 @@ static void process_flags (int argc, char **argv) case 's': sflg = true; bad_s = 0; + + if (!crypt_method) { + fprintf (stderr, + _("%s: no crypt method defined\n"), + Prog); + usage (E_USAGE); + } #if defined(USE_SHA_CRYPT) if ( ( ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512"))) - && (0 == getlong(optarg, &sha_rounds)))) { + && (-1 == str2sl(&sha_rounds, optarg)))) { bad_s = 1; } #endif /* USE_SHA_CRYPT */ #if defined(USE_BCRYPT) if (( (0 == strcmp (crypt_method, "BCRYPT")) - && (0 == getlong(optarg, &bcrypt_rounds)))) { + && (-1 == str2sl(&bcrypt_rounds, optarg)))) { bad_s = 1; } #endif /* USE_BCRYPT */ #if defined(USE_YESCRYPT) if (( (0 == strcmp (crypt_method, "YESCRYPT")) - && (0 == getlong(optarg, &yescrypt_cost)))) { + && (-1 == str2sl(&yescrypt_cost, optarg)))) { bad_s = 1; } #endif /* USE_YESCRYPT */ @@ -294,7 +306,7 @@ static void check_perms (void) exit (1); } - retval = pam_start ("chgpasswd", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -414,7 +426,6 @@ int main (int argc, char **argv) int errors = 0; int line = 0; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -422,11 +433,17 @@ int main (int argc, char **argv) (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); +#ifdef WITH_SELINUX + if (check_selinux_permit ("passwd") != 0) { + return (E_NOPERM); + } +#endif /* WITH_SELINUX */ + process_root_flag ("-R", argc, argv); process_flags (argc, argv); - OPENLOG ("chgpasswd"); + OPENLOG (Prog); check_perms (); @@ -441,7 +458,7 @@ int main (int argc, char **argv) * group entry for each group will be looked up in the appropriate * file (gshadow or group) and the password changed. */ - while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) { + while (fgets (buf, (int) sizeof buf, stdin) != NULL) { line++; cp = strrchr (buf, '\n'); if (NULL != cp) { diff --git a/src/chpasswd.c b/src/chpasswd.c index 48d5178..79880f5 100644 --- a/src/chpasswd.c +++ b/src/chpasswd.c @@ -16,9 +16,11 @@ #include <pwd.h> #include <stdio.h> #include <stdlib.h> + #ifdef USE_PAM #include "pam_defs.h" #endif /* USE_PAM */ +#include "atoi/str2i.h" #include "defines.h" #include "nscd.h" #include "sssd.h" @@ -30,12 +32,13 @@ #include "exitcodes.h" #include "shadowlog.h" + #define IS_CRYPT_METHOD(str) ((crypt_method != NULL && strcmp(crypt_method, str) == 0) ? true : false) /* * Global variables */ -const char *Prog; +static const char Prog[] = "chpasswd"; static bool eflg = false; static bool md5flg = false; #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) @@ -54,13 +57,15 @@ static long bcrypt_rounds = 13; static long yescrypt_cost = 5; #endif +static const char *prefix = ""; + static bool is_shadow_pwd; static bool pw_locked = false; static bool spw_locked = false; /* local function prototypes */ -static void fail_exit (int code); -static /*@noreturn@*/void usage (int status); +NORETURN static void fail_exit (int code); +NORETURN static void usage (int status); static void process_flags (int argc, char **argv); static void check_flags (void); static void check_perms (void); @@ -94,7 +99,9 @@ static void fail_exit (int code) /* * usage - display usage message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -121,6 +128,7 @@ static /*@noreturn@*/void usage (int status) " the MD5 algorithm\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); + (void) fputs (_(" -P, --prefix PREFIX_DIR directory prefix\n"), usageout); #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) (void) fputs (_(" -s, --sha-rounds number of rounds for the SHA, BCRYPT\n" " or YESCRYPT crypt algorithms\n"), @@ -148,6 +156,7 @@ static void process_flags (int argc, char **argv) {"help", no_argument, NULL, 'h'}, {"md5", no_argument, NULL, 'm'}, {"root", required_argument, NULL, 'R'}, + {"prefix", required_argument, NULL, 'P'}, #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) {"sha-rounds", required_argument, NULL, 's'}, #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ @@ -156,9 +165,9 @@ static void process_flags (int argc, char **argv) while ((c = getopt_long (argc, argv, #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - "c:ehmR:s:", + "c:ehmR:P:s:", #else - "c:ehmR:", + "c:ehmR:P:", #endif long_options, NULL)) != -1) { switch (c) { @@ -176,25 +185,27 @@ static void process_flags (int argc, char **argv) break; case 'R': /* no-op, handled in process_root_flag () */ break; + case 'P': /* no-op, handled in process_prefix_flag () */ + break; #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) case 's': sflg = true; bad_s = 0; #if defined(USE_SHA_CRYPT) if ((IS_CRYPT_METHOD("SHA256") || IS_CRYPT_METHOD("SHA512")) - && (0 == getlong(optarg, &sha_rounds))) { + && (-1 == str2sl(&sha_rounds, optarg))) { bad_s = 1; } #endif /* USE_SHA_CRYPT */ #if defined(USE_BCRYPT) if (IS_CRYPT_METHOD("BCRYPT") - && (0 == getlong(optarg, &bcrypt_rounds))) { + && (-1 == str2sl(&bcrypt_rounds, optarg))) { bad_s = 1; } #endif /* USE_BCRYPT */ #if defined(USE_YESCRYPT) if (IS_CRYPT_METHOD("YESCRYPT") - && (0 == getlong(optarg, &yescrypt_cost))) { + && (-1 == str2sl(&yescrypt_cost, optarg))) { bad_s = 1; } #endif /* USE_YESCRYPT */ @@ -294,7 +305,7 @@ static void check_perms (void) exit (1); } - retval = pam_start ("chpasswd", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -442,7 +453,6 @@ int main (int argc, char **argv) int errors = 0; int line = 0; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -450,18 +460,25 @@ int main (int argc, char **argv) (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); +#ifdef WITH_SELINUX + if (check_selinux_permit ("passwd") != 0) { + return (E_NOPERM); + } +#endif /* WITH_SELINUX */ + process_flags (argc, argv); salt = get_salt(); process_root_flag ("-R", argc, argv); + prefix = process_prefix_flag ("-P", argc, argv); #ifdef USE_PAM - if (md5flg || eflg || cflg) { + if (md5flg || eflg || cflg || prefix[0]) { use_pam = false; } #endif /* USE_PAM */ - OPENLOG ("chpasswd"); + OPENLOG (Prog); check_perms (); @@ -482,7 +499,7 @@ int main (int argc, char **argv) * last change date is set in the age only if aging information is * present. */ - while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) { + while (fgets (buf, sizeof buf, stdin) != NULL) { line++; cp = strrchr (buf, '\n'); if (NULL != cp) { @@ -491,7 +508,7 @@ int main (int argc, char **argv) if (feof (stdin) == 0) { // Drop all remaining characters on this line. - while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) { + while (fgets (buf, sizeof buf, stdin) != NULL) { cp = strchr (buf, '\n'); if (cp != NULL) { break; @@ -531,7 +548,7 @@ int main (int argc, char **argv) #ifdef USE_PAM if (use_pam) { - if (do_pam_passwd_non_interactive ("chpasswd", name, newpwd) != 0) { + if (do_pam_passwd_non_interactive (Prog, name, newpwd) != 0) { fprintf (stderr, _("%s: (line %d, user %s) password not changed\n"), Prog, line, name); @@ -606,7 +623,7 @@ int main (int argc, char **argv) if (NULL != sp) { newsp = *sp; newsp.sp_pwdp = cp; - newsp.sp_lstchg = (long) gettime () / SCALE; + newsp.sp_lstchg = gettime () / DAY; if (0 == newsp.sp_lstchg) { /* Better disable aging than requiring a * password change */ @@ -16,6 +16,8 @@ #include <pwd.h> #include <stdio.h> #include <sys/types.h> + +#include "alloc.h" #include "defines.h" #include "getdef.h" #include "nscd.h" @@ -29,14 +31,22 @@ /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/strtcpy.h" #ifndef SHELLS_FILE #define SHELLS_FILE "/etc/shells" #endif + +#ifdef HAVE_VENDORDIR +#include <libeconf.h> +#define SHELLS "shells" +#define ETCDIR "/etc" +#endif + /* * Global variables */ -const char *Prog; /* Program name */ +static const char Prog[] = "chsh"; /* Program name */ static bool amroot; /* Real UID is root */ static char loginsh[BUFSIZ]; /* Name of new login shell */ /* command line options */ @@ -46,8 +56,8 @@ static bool pw_locked = false; /* external identifiers */ /* local function prototypes */ -static /*@noreturn@*/void fail_exit (int code); -static /*@noreturn@*/void usage (int status); +NORETURN static void fail_exit (int code); +NORETURN static void usage (int status); static void new_fields (void); static bool shell_is_listed (const char *); static bool is_restricted_shell (const char *); @@ -58,7 +68,9 @@ static void update_shell (const char *user, char *loginsh); /* * fail_exit - do some cleanup and exit with the given error code */ -static /*@noreturn@*/void fail_exit (int code) +NORETURN +static void +fail_exit (int code) { if (pw_locked) { if (pw_unlock () == 0) { @@ -76,7 +88,9 @@ static /*@noreturn@*/void fail_exit (int code) /* * usage - print command line syntax and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -127,17 +141,60 @@ static bool is_restricted_shell (const char *sh) * If getusershell() is available (Linux, *BSD, possibly others), use it * instead of re-implementing it. */ + +#ifdef HAVE_VENDORDIR static bool shell_is_listed (const char *sh) { - char *cp; bool found = false; -#ifndef HAVE_GETUSERSHELL - char buf[BUFSIZ]; - FILE *fp; -#endif + size_t size = 0; + econf_err error; + char **keys; + econf_file *key_file; + + error = econf_readDirs(&key_file, + VENDORDIR, + ETCDIR, + SHELLS, + NULL, + "", /* key only */ + "#" /* comment */); + if (error) { + fprintf (stderr, + _("Cannot parse shell files: %s"), + econf_errString(error)); + fail_exit (1); + } + + error = econf_getKeys(key_file, NULL, &size, &keys); + if (error) { + fprintf (stderr, + _("Cannot evaluate entries in shell files: %s"), + econf_errString(error)); + econf_free (key_file); + fail_exit (1); + } + + for (size_t i = 0; i < size; i++) { + if (strcmp (keys[i], sh) == 0) { + found = true; + break; + } + } + econf_free (keys); + econf_free (key_file); + + return found; +} + +#else /* without HAVE_VENDORDIR */ + +static bool shell_is_listed (const char *sh) +{ + bool found = false; #ifdef HAVE_GETUSERSHELL + char *cp; setusershell (); while ((cp = getusershell ())) { if (strcmp (cp, sh) == 0) { @@ -147,18 +204,17 @@ static bool shell_is_listed (const char *sh) } endusershell (); #else + char *buf = NULL; + FILE *fp; + size_t n = 0; + fp = fopen (SHELLS_FILE, "r"); if (NULL == fp) { return false; } - while (fgets (buf, sizeof (buf), fp) == buf) { - cp = strrchr (buf, '\n'); - if (NULL != cp) { - *cp = '\0'; - } - - if (buf[0] == '#') { + while (getline (&buf, &n, fp) != -1) { + if (buf[0] != '/') { continue; } @@ -167,10 +223,13 @@ static bool shell_is_listed (const char *sh) break; } } + + free(buf); fclose (fp); #endif return found; } +#endif /* with HAVE_VENDORDIR */ /* * process_flags - parse the command line options @@ -197,7 +256,7 @@ static void process_flags (int argc, char **argv) break; case 's': sflg = true; - STRFCPY (loginsh, optarg); + STRTCPY(loginsh, optarg); break; default: usage (E_USAGE); @@ -260,7 +319,7 @@ static void check_perms (const struct passwd *pw) * check if the change is allowed by SELinux policy. */ if ((pw->pw_uid != getuid ()) - && (check_selinux_permit("chsh") != 0)) { + && (check_selinux_permit(Prog) != 0)) { SYSLOG ((LOG_WARN, "can't change shell for '%s'", pw->pw_name)); fprintf (stderr, _("You may not change the shell for '%s'.\n"), @@ -277,7 +336,7 @@ static void check_perms (const struct passwd *pw) * chfn/chsh. --marekm */ if (!amroot && getdef_bool ("CHSH_AUTH")) { - passwd_check (pw->pw_name, pw->pw_passwd, "chsh"); + passwd_check (pw->pw_name, pw->pw_passwd, Prog); } #else /* !USE_PAM */ @@ -289,7 +348,7 @@ static void check_perms (const struct passwd *pw) exit (E_NOPERM); } - retval = pam_start ("chsh", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -413,12 +472,8 @@ int main (int argc, char **argv) const struct passwd *pw; /* Password entry from /etc/passwd */ sanitize_env (); + check_fds (); - /* - * Get the program name. The program name is used as a prefix to - * most error messages. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -433,7 +488,7 @@ int main (int argc, char **argv) */ amroot = (getuid () == 0); - OPENLOG ("chsh"); + OPENLOG (Prog); /* parse the command line options */ process_flags (argc, argv); @@ -463,28 +518,6 @@ int main (int argc, char **argv) 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); - } - fail_exit (1); - } -#endif - check_perms (pw); /* @@ -492,7 +525,7 @@ int main (int argc, char **argv) * file, or use the value from the command line. */ if (!sflg) { - STRFCPY (loginsh, pw->pw_shell); + STRTCPY(loginsh, pw->pw_shell); } /* @@ -514,11 +547,15 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: Invalid entry: %s\n"), Prog, loginsh); fail_exit (1); } - if ( !amroot - && ( is_restricted_shell (loginsh) - || (access (loginsh, X_OK) != 0))) { - fprintf (stderr, _("%s: %s is an invalid shell\n"), Prog, loginsh); - fail_exit (1); + if (loginsh[0] != '/' + || is_restricted_shell (loginsh) + || (access (loginsh, X_OK) != 0)) { + if (amroot) { + fprintf (stderr, _("%s: Warning: %s is an invalid shell\n"), Prog, loginsh); + } else { + fprintf (stderr, _("%s: %s is an invalid shell\n"), Prog, loginsh); + fail_exit (1); + } } /* Even for root, warn if an invalid shell is specified. */ diff --git a/src/expiry.c b/src/expiry.c index dc20b90..12647a2 100644 --- a/src/expiry.c +++ b/src/expiry.c @@ -16,6 +16,8 @@ #include <stdio.h> #include <sys/types.h> #include <getopt.h> + +#include "attr.h" #include "defines.h" #include "prototypes.h" /*@-exitarg@*/ @@ -23,18 +25,18 @@ #include "shadowlog.h" /* Global variables */ -const char *Prog; +static const char Prog[] = "expiry"; static bool cflg = false; /* local function prototypes */ -static void catch_signals (unused int sig); -static /*@noreturn@*/void usage (int status); +static void catch_signals (MAYBE_UNUSED int sig); +NORETURN static void usage (int status); static void process_flags (int argc, char **argv); /* * catch_signals - signal catcher */ -static void catch_signals (unused int sig) +static void catch_signals (MAYBE_UNUSED int sig) { _exit (10); } @@ -42,7 +44,9 @@ static void catch_signals (unused int sig) /* * usage - print syntax message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -121,21 +125,19 @@ int main (int argc, char **argv) struct passwd *pwd; struct spwd *spwd; - Prog = Basename (argv[0]); + sanitize_env (); + check_fds (); + log_set_progname(Prog); log_set_logfd(stderr); - sanitize_env (); - /* * Start by disabling all of the keyboard signals. */ (void) signal (SIGHUP, catch_signals); (void) signal (SIGINT, catch_signals); (void) signal (SIGQUIT, catch_signals); -#ifdef SIGTSTP (void) signal (SIGTSTP, catch_signals); -#endif /* * expiry takes one of two arguments. The default action is to give @@ -145,7 +147,7 @@ int main (int argc, char **argv) (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); - OPENLOG ("expiry"); + OPENLOG (Prog); process_flags (argc, argv); diff --git a/src/faillog.c b/src/faillog.c index 0f94836..77c25b8 100644 --- a/src/faillog.c +++ b/src/faillog.c @@ -18,15 +18,21 @@ #include <sys/types.h> #include <time.h> #include <assert.h> + +#include "atoi/str2i.h" #include "defines.h" #include "faillog.h" +#include "memzero.h" #include "prototypes.h" /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/strftime.h" + + /* local function prototypes */ -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void print_one (/*@null@*/const struct passwd *pw, bool force); static void set_locktime (long locktime); static bool set_locktime_one (uid_t uid, long locktime); @@ -39,7 +45,7 @@ static void reset (void); /* * Global variables */ -const char *Prog; /* Program name */ +static const char Prog[] = "faillog"; /* Program name */ static FILE *fail; /* failure file stream */ static time_t seconds; /* that number of days in seconds */ static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */ @@ -57,9 +63,11 @@ static bool rflg = false; /* reset the counters of login failures */ static struct stat statbuf; /* fstat buffer for file size */ -#define NOW (time((time_t *) 0)) +#define NOW time(NULL) -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -81,34 +89,36 @@ static /*@noreturn@*/void usage (int status) exit (status); } -static void print_one (/*@null@*/const struct passwd *pw, bool force) +/* + * Looks up the offset in the faillog file for the given uid. + * Returns -1 on error. + */ +static off_t lookup_faillog(struct faillog *fl, uid_t uid) { - static bool once = false; - struct tm *tm; - off_t offset; - struct faillog fl; - time_t now; - char *cp; - char ptime[80]; - - if (NULL == pw) { - return; + off_t offset, size; + + /* Ensure multiplication does not overflow and retrieving a wrong entry */ + if (__builtin_mul_overflow(uid, sizeof(*fl), &offset)) { + fprintf(stderr, + _("%s: Failed to get the entry for UID %lu\n"), + Prog, (unsigned long)uid); + return -1; } - offset = (off_t) pw->pw_uid * sizeof (fl); - if (offset + sizeof (fl) <= statbuf.st_size) { + if (!__builtin_add_overflow(offset, sizeof(*fl), &size) + && size <= statbuf.st_size) { /* fseeko errors are not really relevant for us. */ - int err = fseeko (fail, offset, SEEK_SET); - assert (0 == err); + int err = fseeko(fail, offset, SEEK_SET); + assert(0 == err); /* faillog is a sparse file. Even if no entries were * entered for this user, which should be able to get the * empty entry in this case. */ - if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) { - fprintf (stderr, - _("%s: Failed to get the entry for UID %lu\n"), - Prog, (unsigned long int)pw->pw_uid); - return; + if (fread(fl, sizeof(*fl), 1, fail) != 1) { + fprintf(stderr, + _("%s: Failed to get the entry for UID %lu\n"), + Prog, (unsigned long)uid); + return -1; } } else { /* Outsize of the faillog file. @@ -116,7 +126,27 @@ static void print_one (/*@null@*/const struct passwd *pw, bool force) * as if we were reading an non existing entry in the * sparse faillog file). */ - memzero (&fl, sizeof (fl)); + memzero(fl, sizeof(*fl)); + } + + return offset; +} + +static void print_one (/*@null@*/const struct passwd *pw, bool force) +{ + static bool once = false; + struct tm *tm; + struct faillog fl; + time_t now; + char *cp; + char ptime[80]; + + if (NULL == pw) { + return; + } + + if (lookup_faillog(&fl, pw->pw_uid) < 0) { + return; } /* Nothing to report */ @@ -142,7 +172,7 @@ static void print_one (/*@null@*/const struct passwd *pw, bool force) fprintf (stderr, "Cannot read time from faillog.\n"); return; } - strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm); + STRFTIME(ptime, "%D %H:%M:%S %z", tm); cp = ptime; printf ("%-9s %5d %5d ", @@ -164,7 +194,7 @@ static void print_one (/*@null@*/const struct passwd *pw, bool force) static void print (void) { if (uflg && has_umin && has_umax && (umin==umax)) { - print_one (getpwuid ((uid_t)umin), true); + print_one (getpwuid (umin), true); } else { /* We only print records for existing users. * Loop based on the user database instead of reading the @@ -197,28 +227,10 @@ static bool reset_one (uid_t uid) off_t offset; struct faillog fl; - offset = (off_t) uid * sizeof (fl); - if (offset + sizeof (fl) <= statbuf.st_size) { - /* fseeko errors are not really relevant for us. */ - int err = fseeko (fail, offset, SEEK_SET); - assert (0 == err); - /* faillog is a sparse file. Even if no entries were - * entered for this user, which should be able to get the - * empty entry in this case. - */ - if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) { - fprintf (stderr, - _("%s: Failed to get the entry for UID %lu\n"), - Prog, (unsigned long int)uid); - return true; - } - } else { - /* Outsize of the faillog file. - * Behave as if there were a missing entry (same behavior - * as if we were reading an non existing entry in the - * sparse faillog file). - */ - memzero (&fl, sizeof (fl)); + offset = lookup_faillog(&fl, uid); + if (offset < 0) { + /* failure */ + return true; } if (0 == fl.fail_cnt) { @@ -232,21 +244,21 @@ static bool reset_one (uid_t uid) fl.fail_cnt = 0; if ( (fseeko (fail, offset, SEEK_SET) == 0) - && (fwrite ((char *) &fl, sizeof (fl), 1, fail) == 1)) { + && (fwrite (&fl, sizeof (fl), 1, fail) == 1)) { (void) fflush (fail); return false; } fprintf (stderr, _("%s: Failed to reset fail count for UID %lu\n"), - Prog, (unsigned long int)uid); + Prog, (unsigned long)uid); return true; } static void reset (void) { if (uflg && has_umin && has_umax && (umin==umax)) { - if (reset_one ((uid_t)umin)) { + if (reset_one (umin)) { errors = true; } } else { @@ -258,7 +270,7 @@ static void reset (void) uidmax--; } if (has_umax && (uid_t)umax < uidmax) { - uidmax = (uid_t)umax; + uidmax = umax; } /* Reset all entries in the specified range. @@ -271,7 +283,7 @@ static void reset (void) /* Make sure we stay in the umin-umax range if specified */ if (has_umin) { - uid = (uid_t)umin; + uid = umin; } while (uid <= uidmax) { @@ -289,7 +301,7 @@ static void reset (void) while ( (pwent = getpwent ()) != NULL ) { if ( uflg && ( (has_umin && (pwent->pw_uid < (uid_t)umin)) - || (pwent->pw_uid > (uid_t)uidmax))) { + || (pwent->pw_uid > uidmax))) { continue; } if (reset_one (pwent->pw_uid)) { @@ -311,28 +323,9 @@ static bool setmax_one (uid_t uid, short max) off_t offset; struct faillog fl; - offset = (off_t) uid * sizeof (fl); - if (offset + sizeof (fl) <= statbuf.st_size) { - /* fseeko errors are not really relevant for us. */ - int err = fseeko (fail, offset, SEEK_SET); - assert (0 == err); - /* faillog is a sparse file. Even if no entries were - * entered for this user, which should be able to get the - * empty entry in this case. - */ - if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) { - fprintf (stderr, - _("%s: Failed to get the entry for UID %lu\n"), - Prog, (unsigned long int)uid); - return true; - } - } else { - /* Outsize of the faillog file. - * Behave as if there were a missing entry (same behavior - * as if we were reading an non existing entry in the - * sparse faillog file). - */ - memzero (&fl, sizeof (fl)); + offset = lookup_faillog(&fl, uid); + if (offset < 0) { + return true; } if (max == fl.fail_max) { @@ -347,21 +340,21 @@ static bool setmax_one (uid_t uid, short max) fl.fail_max = max; if ( (fseeko (fail, offset, SEEK_SET) == 0) - && (fwrite ((char *) &fl, sizeof (fl), 1, fail) == 1)) { + && (fwrite (&fl, sizeof (fl), 1, fail) == 1)) { (void) fflush (fail); return false; } fprintf (stderr, _("%s: Failed to set max for UID %lu\n"), - Prog, (unsigned long int)uid); + Prog, (unsigned long)uid); return true; } static void setmax (short max) { if (uflg && has_umin && has_umax && (umin==umax)) { - if (setmax_one ((uid_t)umin, max)) { + if (setmax_one (umin, max)) { errors = true; } } else { @@ -385,10 +378,10 @@ static void setmax (short max) /* Make sure we stay in the umin-umax range if specified */ if (has_umin) { - uid = (uid_t)umin; + uid = umin; } if (has_umax) { - uidmax = (uid_t)umax; + uidmax = umax; } while (uid <= uidmax) { @@ -428,28 +421,9 @@ static bool set_locktime_one (uid_t uid, long locktime) off_t offset; struct faillog fl; - offset = (off_t) uid * sizeof (fl); - if (offset + sizeof (fl) <= statbuf.st_size) { - /* fseeko errors are not really relevant for us. */ - int err = fseeko (fail, offset, SEEK_SET); - assert (0 == err); - /* faillog is a sparse file. Even if no entries were - * entered for this user, which should be able to get the - * empty entry in this case. - */ - if (fread ((char *) &fl, sizeof (fl), 1, fail) != 1) { - fprintf (stderr, - _("%s: Failed to get the entry for UID %lu\n"), - Prog, (unsigned long int)uid); - return true; - } - } else { - /* Outsize of the faillog file. - * Behave as if there were a missing entry (same behavior - * as if we were reading an non existing entry in the - * sparse faillog file). - */ - memzero (&fl, sizeof (fl)); + offset = lookup_faillog(&fl, uid); + if (offset < 0) { + return true; } if (locktime == fl.fail_locktime) { @@ -464,21 +438,21 @@ static bool set_locktime_one (uid_t uid, long locktime) fl.fail_locktime = locktime; if ( (fseeko (fail, offset, SEEK_SET) == 0) - && (fwrite ((char *) &fl, sizeof (fl), 1, fail) == 1)) { + && (fwrite (&fl, sizeof (fl), 1, fail) == 1)) { (void) fflush (fail); return false; } fprintf (stderr, _("%s: Failed to set locktime for UID %lu\n"), - Prog, (unsigned long int)uid); + Prog, (unsigned long)uid); return true; } static void set_locktime (long locktime) { if (uflg && has_umin && has_umax && (umin==umax)) { - if (set_locktime_one ((uid_t)umin, locktime)) { + if (set_locktime_one (umin, locktime)) { errors = true; } } else { @@ -502,10 +476,10 @@ static void set_locktime (long locktime) /* Make sure we stay in the umin-umax range if specified */ if (has_umin) { - uid = (uid_t)umin; + uid = umin; } if (has_umax) { - uidmax = (uid_t)umax; + uidmax = umax; } while (uid <= uidmax) { @@ -541,11 +515,6 @@ int main (int argc, char **argv) short fail_max = 0; // initialize to silence compiler warning long days = 0; - /* - * Get the program name. The program name is used as a prefix to - * most error messages. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -578,7 +547,7 @@ int main (int argc, char **argv) usage (E_SUCCESS); /*@notreached@*/break; case 'l': - if (getlong (optarg, &fail_locktime) == 0) { + if (str2sl(&fail_locktime, optarg) == -1) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); @@ -588,15 +557,16 @@ int main (int argc, char **argv) break; case 'm': { - long int lmax; - if ( (getlong (optarg, &lmax) == 0) - || ((long int)(short) lmax != lmax)) { + long lmax; + + if ( (str2sl(&lmax, optarg) == -1) + || ((long)(short) lmax != lmax)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); exit (E_BAD_ARG); } - fail_max = (short) lmax; + fail_max = lmax; mflg = true; break; } @@ -606,7 +576,7 @@ int main (int argc, char **argv) case 'R': /* no-op, handled in process_root_flag () */ break; case 't': - if (getlong (optarg, &days) == 0) { + if (str2sl(&days, optarg) == -1) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); @@ -630,14 +600,14 @@ int main (int argc, char **argv) /* local, no need for xgetpwnam */ pwent = getpwnam (optarg); if (NULL != pwent) { - umin = (unsigned long) pwent->pw_uid; + umin = pwent->pw_uid; has_umin = true; umax = umin; has_umax = true; } else { - if (getrange (optarg, - &umin, &has_umin, - &umax, &has_umax) == 0) { + if (getrange(optarg, + &umin, &has_umin, + &umax, &has_umax) == -1) { fprintf (stderr, _("%s: Unknown user or range: %s\n"), Prog, optarg); diff --git a/src/free_subid_range.c b/src/free_subid_range.c index d9a2cd8..441c227 100644 --- a/src/free_subid_range.c +++ b/src/free_subid_range.c @@ -9,7 +9,7 @@ /* Test program for the subid freeing routine */ -const char *Prog; +static const char Prog[] = "free_subid_range"; static void usage(void) { @@ -25,7 +25,6 @@ int main(int argc, char *argv[]) struct subordinate_range range; bool group = false; // get subuids by default - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); while ((c = getopt(argc, argv, "g")) != EOF) { diff --git a/src/get_subid_owners.c b/src/get_subid_owners.c index 36974b8..e1c1e79 100644 --- a/src/get_subid_owners.c +++ b/src/get_subid_owners.c @@ -6,7 +6,7 @@ #include "prototypes.h" #include "shadowlog.h" -const char *Prog; +static const char Prog[] = "get_subid_owners"; static void usage(void) { @@ -21,7 +21,6 @@ int main(int argc, char *argv[]) int i, n; uid_t *uids; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); if (argc < 2) { diff --git a/src/getsubids.c b/src/getsubids.c index c91ae39..0753abd 100644 --- a/src/getsubids.c +++ b/src/getsubids.c @@ -7,7 +7,7 @@ #include "prototypes.h" #include "shadowlog.h" -const char *Prog; +static const char Prog[] = "getsubids"; static void usage(void) { @@ -23,7 +23,6 @@ int main(int argc, char *argv[]) struct subid_range *ranges; const char *owner; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); if (argc < 2) @@ -45,5 +44,6 @@ int main(int argc, char *argv[]) printf("%d: %s %lu %lu\n", i, owner, ranges[i].start, ranges[i].count); } + free(ranges); return 0; } diff --git a/src/gpasswd.c b/src/gpasswd.c index 5983f78..de6b1c4 100644 --- a/src/gpasswd.c +++ b/src/gpasswd.c @@ -19,8 +19,13 @@ #include <signal.h> #include <stdio.h> #include <sys/types.h> + +#include "agetpass.h" +#include "alloc.h" +#include "attr.h" #include "defines.h" #include "groupio.h" +#include "memzero.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -29,13 +34,16 @@ #endif /*@-exitarg@*/ #include "exitcodes.h" - #include "shadowlog.h" +#include "string/sprintf.h" +#include "string/strtcpy.h" + + /* * Global variables */ /* The name of this command, as it is invoked */ -const char *Prog; +static const char Prog[] = "gpasswd"; #ifdef SHADOWGRP /* Indicate if shadow groups are enabled on the system @@ -73,6 +81,7 @@ static uid_t bywho; #endif /* local function prototypes */ +NORETURN static void failure(void); static void usage (int status); static void catch_signals (int killed); static bool is_valid_user_list (const char *users); @@ -92,14 +101,14 @@ static void update_group (struct group *gr); static void change_passwd (struct group *gr); #endif static void log_gpasswd_failure (const char *suffix); -static void log_gpasswd_failure_system (/*@null@*/unused void *arg); -static void log_gpasswd_failure_group (/*@null@*/unused void *arg); +static void log_gpasswd_failure_system (/*@null@*/MAYBE_UNUSED void *arg); +static void log_gpasswd_failure_group (/*@null@*/MAYBE_UNUSED void *arg); #ifdef SHADOWGRP -static void log_gpasswd_failure_gshadow (/*@null@*/unused void *arg); +static void log_gpasswd_failure_gshadow (/*@null@*/MAYBE_UNUSED void *arg); #endif static void log_gpasswd_success (const char *suffix); -static void log_gpasswd_success_system (/*@null@*/unused void *arg); -static void log_gpasswd_success_group (/*@null@*/unused void *arg); +static void log_gpasswd_success_system (/*@null@*/MAYBE_UNUSED void *arg); +static void log_gpasswd_success_group (/*@null@*/MAYBE_UNUSED void *arg); /* * usage - display usage message @@ -194,11 +203,11 @@ static bool is_valid_user_list (const char *users) return is_valid; } -static void failure (void) +static void failure(void) { - fprintf (stderr, _("%s: Permission denied.\n"), Prog); - log_gpasswd_failure (": Permission denied"); - exit (E_NOPERM); + fprintf(stderr, _("%s: Permission denied.\n"), Prog); + log_gpasswd_failure(": Permission denied"); + exit(E_NOPERM); } /* @@ -376,17 +385,16 @@ static void open_files (void) static void log_gpasswd_failure (const char *suffix) { #ifdef WITH_AUDIT - char buf[1024]; + char buf[1024]; #endif + if (aflg) { SYSLOG ((LOG_ERR, "%s failed to add user %s to group %s%s", myname, user, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to add user %s to group %s%s", - myname, user, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to add user %s to group %s%s", + myname, user, group, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -397,10 +405,8 @@ static void log_gpasswd_failure (const char *suffix) "%s failed to remove user %s from group %s%s", myname, user, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to remove user %s from group %s%s", - myname, user, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to remove user %s from group %s%s", + myname, user, group, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -411,10 +417,8 @@ static void log_gpasswd_failure (const char *suffix) "%s failed to remove password of group %s%s", myname, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to remove password of group %s%s", - myname, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to remove password of group %s%s", + myname, group, suffix); audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, @@ -425,10 +429,8 @@ static void log_gpasswd_failure (const char *suffix) "%s failed to restrict access to group %s%s", myname, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to restrict access to group %s%s", - myname, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to restrict access to group %s%s", + myname, group, suffix); audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, @@ -441,10 +443,8 @@ static void log_gpasswd_failure (const char *suffix) "%s failed to set the administrators of group %s to %s%s", myname, group, admins, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to set the administrators of group %s to %s%s", - myname, group, admins, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to set the administrators of group %s to %s%s", + myname, group, admins, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -457,10 +457,8 @@ static void log_gpasswd_failure (const char *suffix) "%s failed to set the members of group %s to %s%s", myname, group, members, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to set the members of group %s to %s%s", - myname, group, members, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to set the members of group %s to %s%s", + myname, group, members, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -472,10 +470,8 @@ static void log_gpasswd_failure (const char *suffix) "%s failed to change password of group %s%s", myname, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "%s failed to change password of group %s%s", - myname, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "%s failed to change password of group %s%s", + myname, group, suffix); audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, @@ -484,25 +480,25 @@ static void log_gpasswd_failure (const char *suffix) } } -static void log_gpasswd_failure_system (unused void *arg) +static void log_gpasswd_failure_system (MAYBE_UNUSED void *arg) { log_gpasswd_failure (""); } -static void log_gpasswd_failure_group (unused void *arg) +static void log_gpasswd_failure_group (MAYBE_UNUSED void *arg) { - char buf[1024]; - snprintf (buf, 1023, " in %s", gr_dbname ()); - buf[1023] = '\0'; + char buf[1024]; + + SNPRINTF(buf, " in %s", gr_dbname()); log_gpasswd_failure (buf); } #ifdef SHADOWGRP -static void log_gpasswd_failure_gshadow (unused void *arg) +static void log_gpasswd_failure_gshadow (MAYBE_UNUSED void *arg) { - char buf[1024]; - snprintf (buf, 1023, " in %s", sgr_dbname ()); - buf[1023] = '\0'; + char buf[1024]; + + SNPRINTF(buf, " in %s", sgr_dbname()); log_gpasswd_failure (buf); } #endif /* SHADOWGRP */ @@ -510,17 +506,16 @@ static void log_gpasswd_failure_gshadow (unused void *arg) static void log_gpasswd_success (const char *suffix) { #ifdef WITH_AUDIT - char buf[1024]; + char buf[1024]; #endif + if (aflg) { SYSLOG ((LOG_INFO, "user %s added by %s to group %s%s", user, myname, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "user %s added by %s to group %s%s", - user, myname, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "user %s added by %s to group %s%s", + user, myname, group, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -531,10 +526,8 @@ static void log_gpasswd_success (const char *suffix) "user %s removed by %s from group %s%s", user, myname, group, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "user %s removed by %s from group %s%s", - user, myname, group, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "user %s removed by %s from group %s%s", + user, myname, group, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -545,10 +538,8 @@ static void log_gpasswd_success (const char *suffix) "password of group %s removed by %s%s", group, myname, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "password of group %s removed by %s%s", - group, myname, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "password of group %s removed by %s%s", + group, myname, suffix); audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, @@ -559,10 +550,8 @@ static void log_gpasswd_success (const char *suffix) "access to group %s restricted by %s%s", group, myname, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "access to group %s restricted by %s%s", - group, myname, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "access to group %s restricted by %s%s", + group, myname, suffix); audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, @@ -575,10 +564,8 @@ static void log_gpasswd_success (const char *suffix) "administrators of group %s set by %s to %s%s", group, myname, admins, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "administrators of group %s set by %s to %s%s", - group, myname, admins, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "administrators of group %s set by %s to %s%s", + group, myname, admins, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -591,10 +578,8 @@ static void log_gpasswd_success (const char *suffix) "members of group %s set by %s to %s%s", group, myname, members, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "members of group %s set by %s to %s%s", - group, myname, members, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "members of group %s set by %s to %s%s", + group, myname, members, suffix); audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, @@ -606,10 +591,8 @@ static void log_gpasswd_success (const char *suffix) "password of group %s changed by %s%s", group, myname, suffix)); #ifdef WITH_AUDIT - snprintf (buf, 1023, - "password of group %s changed by %s%s", - group, myname, suffix); - buf[1023] = '\0'; + SNPRINTF(buf, "password of group %s changed by %s%s", + group, myname, suffix); audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, @@ -618,16 +601,16 @@ static void log_gpasswd_success (const char *suffix) } } -static void log_gpasswd_success_system (unused void *arg) +static void log_gpasswd_success_system (MAYBE_UNUSED void *arg) { log_gpasswd_success (""); } -static void log_gpasswd_success_group (unused void *arg) +static void log_gpasswd_success_group (MAYBE_UNUSED void *arg) { - char buf[1024]; - snprintf (buf, 1023, " in %s", gr_dbname ()); - buf[1023] = '\0'; + char buf[1024]; + + SNPRINTF(buf, " in %s", gr_dbname()); log_gpasswd_success (buf); } @@ -704,8 +687,7 @@ static void check_perms (const struct group *gr) } } else #endif /* SHADOWGRP */ - { -#ifdef FIRST_MEMBER_IS_ADMIN + if (!amroot) { /* * The policy here for changing a group is that * 1) you must be root or @@ -720,20 +702,14 @@ static void check_perms (const struct group *gr) * first group member might be just a normal user. * --marekm */ - if (!amroot) { - if (gr->gr_mem[0] == (char *) 0) { - failure (); - } - - if (strcmp (gr->gr_mem[0], myname) != 0) { - failure (); - } - } -#else /* ! FIRST_MEMBER_IS_ADMIN */ - if (!amroot) { - failure (); - } +#if !defined(FIRST_MEMBER_IS_ADMIN) + failure(); #endif + if (gr->gr_mem[0] == NULL) + failure(); + + if (strcmp(gr->gr_mem[0], myname) != 0) + failure(); } } @@ -834,7 +810,7 @@ static void get_group (struct group *gr) sg->sg_mem = dup_list (gr->gr_mem); - sg->sg_adm = (char **) xmalloc (sizeof (char *) * 2); + sg->sg_adm = XMALLOC(2, char *); #ifdef FIRST_MEMBER_IS_ADMIN if (sg->sg_mem[0]) { sg->sg_adm[0] = xstrdup (sg->sg_mem[0]); @@ -887,25 +863,26 @@ static void change_passwd (struct group *gr) printf (_("Changing the password for group %s\n"), group); for (retries = 0; retries < RETRIES; retries++) { - cp = getpass (_("New Password: ")); + cp = agetpass (_("New Password: ")); if (NULL == cp) { exit (1); } - STRFCPY (pass, cp); - strzero (cp); - cp = getpass (_("Re-enter new password: ")); + STRTCPY(pass, cp); + erase_pass (cp); + cp = agetpass (_("Re-enter new password: ")); if (NULL == cp) { + MEMZERO(pass); exit (1); } if (strcmp (pass, cp) == 0) { - strzero (cp); + erase_pass (cp); break; } - strzero (cp); - memzero (pass, sizeof pass); + erase_pass (cp); + MEMZERO(pass); if (retries + 1 < RETRIES) { puts (_("They don't match; try again")); @@ -925,7 +902,7 @@ static void change_passwd (struct group *gr) Prog, salt, strerror (errno)); exit (1); } - memzero (pass, sizeof pass); + MEMZERO(pass); #ifdef SHADOWGRP if (is_shadowgrp) { gr->gr_passwd = SHADOW_PASSWD_STRING; @@ -953,6 +930,8 @@ int main (int argc, char **argv) #endif sanitize_env (); + check_fds (); + (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); @@ -965,11 +944,10 @@ int main (int argc, char **argv) * with this command. */ bywho = getuid (); - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); - OPENLOG ("gpasswd"); + OPENLOG (Prog); setbuf (stdout, NULL); setbuf (stderr, NULL); @@ -1145,9 +1123,7 @@ int main (int argc, char **argv) (void) signal (SIGINT, catch_signals); (void) signal (SIGQUIT, catch_signals); (void) signal (SIGTERM, catch_signals); -#ifdef SIGTSTP (void) signal (SIGTSTP, catch_signals); -#endif /* Prompt for the new password */ #ifdef SHADOWGRP diff --git a/src/groupadd.c b/src/groupadd.c index 66ccb53..46e6550 100644 --- a/src/groupadd.c +++ b/src/groupadd.c @@ -27,6 +27,7 @@ #include "defines.h" #include "getdef.h" #include "groupio.h" +#include "memzero.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -34,6 +35,7 @@ #include "sgroupio.h" #endif #include "shadowlog.h" +#include "run_part.h" /* * exit status values @@ -49,7 +51,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "groupadd"; static /*@null@*/char *group_name; static gid_t group_id; @@ -70,7 +72,7 @@ static bool is_shadow_grp; #endif /* local function prototypes */ -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void new_grent (struct group *grent); #ifdef SHADOWGRP @@ -87,7 +89,9 @@ static void check_perms (void); /* * usage - display usage message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -105,7 +109,7 @@ static /*@noreturn@*/void usage (int status) (void) fputs (_(" -p, --password PASSWORD use this encrypted password for the new group\n"), usageout); (void) fputs (_(" -r, --system create a system account\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); - (void) fputs (_(" -P, --prefix PREFIX_DI directory prefix\n"), usageout); + (void) fputs (_(" -P, --prefix PREFIX_DIR directory prefix\n"), usageout); (void) fputs (_(" -U, --users USERS list of user members of this group\n"), usageout); (void) fputs ("\n", usageout); exit (status); @@ -262,8 +266,7 @@ static void close_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_GROUP, Prog, "adding group to /etc/group", - group_name, (unsigned int) group_id, - SHADOW_AUDIT_SUCCESS); + group_name, group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group added to %s: name=%s, GID=%u", gr_dbname (), group_name, (unsigned int) group_id)); @@ -284,8 +287,7 @@ static void close_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_GROUP, Prog, "adding group to /etc/gshadow", - group_name, (unsigned int) group_id, - SHADOW_AUDIT_SUCCESS); + group_name, group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group added to %s: name=%s", sgr_dbname (), group_name)); @@ -299,9 +301,7 @@ static void close_files (void) /* Report success at the system level */ #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_GROUP, Prog, - "", - group_name, (unsigned int) group_id, - SHADOW_AUDIT_SUCCESS); + "", group_name, group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u", group_name, (unsigned int) group_id)); @@ -344,8 +344,8 @@ static void open_files (void) /* And now open the databases */ if (gr_open (O_CREAT | O_RDWR) == 0) { - fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); - SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ())); + fprintf (stderr, _("%s: cannot open %s: %s\n"), Prog, gr_dbname (), strerror(errno)); + SYSLOG ((LOG_WARN, "cannot open %s: %s", gr_dbname (), strerror(errno))); exit (E_GRP_UPDATE); } @@ -353,9 +353,9 @@ static void open_files (void) if (is_shadow_grp) { if (sgr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, - _("%s: cannot open %s\n"), - Prog, sgr_dbname ()); - SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ())); + _("%s: cannot open %s: %s\n"), + Prog, sgr_dbname (), strerror(errno)); + SYSLOG ((LOG_WARN, "cannot open %s: %s", sgr_dbname (), strerror(errno))); exit (E_GRP_UPDATE); } } @@ -403,7 +403,7 @@ static void process_flags (int argc, char **argv) break; case 'g': gflg = true; - if ( (get_gid (optarg, &group_id) == 0) + if ( (get_gid(optarg, &group_id) == -1) || (group_id == (gid_t)-1)) { fprintf (stderr, _("%s: invalid group ID '%s'\n"), @@ -429,7 +429,7 @@ static void process_flags (int argc, char **argv) } /* terminate name, point to value */ *cp++ = '\0'; - if (putdef_str (optarg, cp) < 0) { + if (putdef_str (optarg, cp, NULL) < 0) { exit (E_BAD_ARG); } break; @@ -511,7 +511,7 @@ static void check_flags (void) } else { fprintf (stderr, _("%s: GID '%lu' already exists\n"), - Prog, (unsigned long int) group_id); + Prog, (unsigned long) group_id); exit (E_GID_IN_USE); } } @@ -543,7 +543,7 @@ static void check_perms (void) exit (1); } - retval = pam_start ("groupadd", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -572,10 +572,6 @@ static void check_perms (void) */ int main (int argc, char **argv) { - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -586,7 +582,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); prefix = process_prefix_flag ("-P", argc, argv); - OPENLOG ("groupadd"); + OPENLOG (Prog); #ifdef WITH_AUDIT audit_help_open (); #endif @@ -605,6 +601,11 @@ int main (int argc, char **argv) check_perms (); + if (run_parts ("/etc/shadow-maint/groupadd-pre.d", group_name, + Prog)) { + exit(1); + } + #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif @@ -623,6 +624,11 @@ int main (int argc, char **argv) grp_update (); close_files (); + if (run_parts ("/etc/shadow-maint/groupadd-post.d", group_name, + Prog)) { + exit(1); + } + nscd_flush_cache ("group"); sssd_flush_cache (SSSD_DB_GROUP); diff --git a/src/groupdel.c b/src/groupdel.c index c84faa7..4bc58aa 100644 --- a/src/groupdel.c +++ b/src/groupdel.c @@ -32,10 +32,11 @@ #include "sgroupio.h" #endif #include "shadowlog.h" +#include "run_part.h" /* * Global variables */ -const char *Prog; +static const char Prog[] = "groupdel"; static char *group_name; static gid_t group_id = -1; @@ -58,7 +59,7 @@ static bool is_shadow_grp; #define E_GRP_UPDATE 10 /* can't update group file */ /* local function prototypes */ -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void grp_update (void); static void close_files (void); static void open_files (void); @@ -68,7 +69,9 @@ static void process_flags (int argc, char **argv); /* * usage - display usage message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -147,8 +150,7 @@ static void close_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "removing group from /etc/group", - group_name, (unsigned int) group_id, - SHADOW_AUDIT_SUCCESS); + group_name, group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group '%s' removed from %s", @@ -172,8 +174,7 @@ static void close_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "removing group from /etc/gshadow", - group_name, (unsigned int) group_id, - SHADOW_AUDIT_SUCCESS); + group_name, group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group '%s' removed from %s", @@ -188,9 +189,7 @@ static void close_files (void) /* Report success at the system level */ #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, - "", - group_name, (unsigned int) group_id, - SHADOW_AUDIT_SUCCESS); + "", group_name, group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group '%s' removed\n", group_name)); del_cleanup (cleanup_report_del_group); @@ -275,7 +274,7 @@ static void group_busy (gid_t gid) * If pwd isn't NULL, it stopped because the gid's matched. */ - if (pwd == (struct passwd *) 0) { + if (pwd == NULL) { return; } @@ -350,10 +349,6 @@ int main (int argc, char **argv) #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -364,7 +359,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); prefix = process_prefix_flag ("-P", argc, argv); - OPENLOG ("groupdel"); + OPENLOG (Prog); #ifdef WITH_AUDIT audit_help_open (); #endif @@ -390,7 +385,7 @@ int main (int argc, char **argv) exit (1); } - retval = pam_start ("groupdel", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); } if (PAM_SUCCESS == retval) { @@ -434,28 +429,6 @@ int main (int argc, char **argv) group_id = grp->gr_gid; } -#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 - /* * Make sure this isn't the primary group of anyone. */ @@ -463,6 +436,11 @@ int main (int argc, char **argv) group_busy (group_id); } + if (run_parts ("/etc/shadow-maint/groupdel-pre.d", group_name, + Prog)) { + exit(1); + } + /* * Do the hard stuff - open the files, delete the group entries, * then close and update the files. @@ -473,6 +451,11 @@ int main (int argc, char **argv) close_files (); + if (run_parts ("/etc/shadow-maint/groupdel-post.d", group_name, + Prog)) { + exit(1); + } + nscd_flush_cache ("group"); sssd_flush_cache (SSSD_DB_GROUP); diff --git a/src/groupmems.c b/src/groupmems.c index a0e3266..a369a61 100644 --- a/src/groupmems.c +++ b/src/groupmems.c @@ -18,6 +18,8 @@ #include "pam_defs.h" #endif /* USE_PAM */ #include <pwd.h> + +#include "alloc.h" #include "defines.h" #include "prototypes.h" #include "groupio.h" @@ -42,7 +44,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "groupmems"; static char *adduser = NULL; static char *deluser = NULL; @@ -66,10 +68,10 @@ static void remove_user (const char *user, const struct group *grp); static void purge_members (const struct group *grp); static void display_members (const char *const *members); -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void process_flags (int argc, char **argv); static void check_perms (void); -static void fail_exit (int code); +NORETURN static void fail_exit (int code); #define isroot() (getuid () == 0) static char *whoami (void) @@ -89,7 +91,7 @@ static char *whoami (void) } /* - * add_user - Add an user to the specified group + * add_user - Add a user to the specified group */ static void add_user (const char *user, const struct group *grp) @@ -125,7 +127,7 @@ static void add_user (const char *user, static struct sgrp sgrent; sgrent.sg_name = xstrdup (newgrp->gr_name); sgrent.sg_mem = dup_list (newgrp->gr_mem); - sgrent.sg_adm = (char **) xmalloc (sizeof (char *)); + sgrent.sg_adm = XMALLOC(1, char *); #ifdef FIRST_MEMBER_IS_ADMIN if (sgrent.sg_mem[0]) { sgrent.sg_adm[0] = xstrdup (sgrent.sg_mem[0]); @@ -172,7 +174,7 @@ static void add_user (const char *user, } /* - * remove_user - Remove an user from a given group + * remove_user - Remove a user from a given group */ static void remove_user (const char *user, const struct group *grp) @@ -208,7 +210,7 @@ static void remove_user (const char *user, static struct sgrp sgrent; sgrent.sg_name = xstrdup (newgrp->gr_name); sgrent.sg_mem = dup_list (newgrp->gr_mem); - sgrent.sg_adm = (char **) xmalloc (sizeof (char *)); + sgrent.sg_adm = XMALLOC(1, char *); #ifdef FIRST_MEMBER_IS_ADMIN if (sgrent.sg_mem[0]) { sgrent.sg_adm[0] = xstrdup (sgrent.sg_mem[0]); @@ -281,9 +283,9 @@ static void purge_members (const struct group *grp) /* Create a shadow group based on this group */ static struct sgrp sgrent; sgrent.sg_name = xstrdup (newgrp->gr_name); - sgrent.sg_mem = (char **) xmalloc (sizeof (char *)); + sgrent.sg_mem = XMALLOC(1, char *); sgrent.sg_mem[0] = NULL; - sgrent.sg_adm = (char **) xmalloc (sizeof (char *)); + sgrent.sg_adm = XMALLOC(1, char *); sgrent.sg_adm[0] = NULL; /* Move any password to gshadow */ @@ -339,7 +341,9 @@ static void display_members (const char *const *members) } } -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (EXIT_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -439,7 +443,7 @@ static void check_perms (void) fail_exit (1); } - retval = pam_start ("groupmems", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); @@ -569,10 +573,6 @@ int main (int argc, char **argv) char *name; const struct group *grp; - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -582,7 +582,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("groupmems"); + OPENLOG (Prog); #ifdef SHADOWGRP is_shadowgrp = sgr_file_present (); diff --git a/src/groupmod.c b/src/groupmod.c index 006eca1..989d7ea 100644 --- a/src/groupmod.c +++ b/src/groupmod.c @@ -15,7 +15,9 @@ #include <fcntl.h> #include <getopt.h> #include <grp.h> +#include <stdint.h> #include <stdio.h> +#include <strings.h> #include <sys/types.h> #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM @@ -23,6 +25,8 @@ #include <pwd.h> #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ + +#include "alloc.h" #include "chkname.h" #include "defines.h" #include "groupio.h" @@ -34,6 +38,8 @@ #include "sgroupio.h" #endif #include "shadowlog.h" +#include "string/stpecpy.h" +#include "string/stpeprintf.h" /* * exit status values */ @@ -53,7 +59,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "groupmod"; #ifdef SHADOWGRP static bool is_shadow_grp; @@ -224,7 +230,7 @@ static void grp_update (void) * shadowed password, we force the creation of a * gshadow entry when a new password is requested. */ - memset (&sgrp, 0, sizeof sgrp); + bzero(&sgrp, sizeof sgrp); sgrp.sg_name = xstrdup (grp.gr_name); sgrp.sg_passwd = xstrdup (grp.gr_passwd); sgrp.sg_adm = ∅ @@ -244,10 +250,8 @@ static void grp_update (void) if (!aflg) { // requested to replace the existing groups - if (NULL != grp.gr_mem[0]) - gr_free_members(&grp); - grp.gr_mem = (char **)xmalloc(sizeof(char *)); - grp.gr_mem[0] = (char *)0; + grp.gr_mem = XMALLOC(1, char *); + grp.gr_mem[0] = NULL; } else { // append to existing groups if (NULL != grp.gr_mem[0]) @@ -333,7 +337,7 @@ static void check_new_gid (void) */ fprintf (stderr, _("%s: GID '%lu' already exists\n"), - Prog, (unsigned long int) group_newid); + Prog, (unsigned long) group_newid); exit (E_GID_IN_USE); } @@ -408,7 +412,7 @@ static void process_flags (int argc, char **argv) break; case 'g': gflg = true; - if ( (get_gid (optarg, &group_newid) == 0) + if ( (get_gid(optarg, &group_newid) == -1) || (group_newid == (gid_t)-1)) { fprintf (stderr, _("%s: invalid group ID '%s'\n"), @@ -542,95 +546,74 @@ static void close_files (void) */ static void prepare_failure_reports (void) { + char *gr, *gr_end; +#ifdef SHADOWGRP + char *sgr, *sgr_end; +#endif + char *pw, *pw_end; + info_group.name = group_name; #ifdef SHADOWGRP info_gshadow.name = group_name; #endif info_passwd.name = group_name; - info_group.audit_msg = xmalloc (512); + gr = XMALLOC(512, char); + info_group.audit_msg = gr; + gr_end = gr + 512; #ifdef SHADOWGRP - info_gshadow.audit_msg = xmalloc (512); + sgr = XMALLOC(512, char); + info_gshadow.audit_msg = sgr; + sgr_end = sgr + 512; #endif - info_passwd.audit_msg = xmalloc (512); + pw = XMALLOC(512, char); + info_passwd.audit_msg = pw; + pw_end = pw + 512; - (void) snprintf (info_group.audit_msg, 511, - "changing %s; ", gr_dbname ()); + gr = stpeprintf(gr, gr_end, "changing %s; ", gr_dbname ()); #ifdef SHADOWGRP - (void) snprintf (info_gshadow.audit_msg, 511, - "changing %s; ", sgr_dbname ()); + sgr = stpeprintf(sgr, sgr_end, "changing %s; ", sgr_dbname ()); #endif - (void) snprintf (info_passwd.audit_msg, 511, - "changing %s; ", pw_dbname ()); + pw = stpeprintf(pw, pw_end, "changing %s; ", pw_dbname ()); - info_group.action = info_group.audit_msg - + strlen (info_group.audit_msg); + info_group.action = gr; #ifdef SHADOWGRP - info_gshadow.action = info_gshadow.audit_msg - + strlen (info_gshadow.audit_msg); + info_gshadow.action = sgr; #endif - info_passwd.action = info_passwd.audit_msg - + strlen (info_passwd.audit_msg); + info_passwd.action = pw; - (void) snprintf (info_group.action, - 511 - strlen (info_group.audit_msg), - "group %s/%lu", - group_name, (unsigned long int) group_id); + gr = stpeprintf(gr, gr_end, + "group %s/%ju", group_name, (uintmax_t) group_id); #ifdef SHADOWGRP - (void) snprintf (info_gshadow.action, - 511 - strlen (info_group.audit_msg), + sgr = stpeprintf(sgr, sgr_end, "group %s", group_name); #endif - (void) snprintf (info_passwd.action, - 511 - strlen (info_group.audit_msg), - "group %s/%lu", - group_name, (unsigned long int) group_id); + pw = stpeprintf(pw, pw_end, + "group %s/%ju", group_name, (uintmax_t) group_id); if (nflg) { - strncat (info_group.action, ", new name: ", - 511 - strlen (info_group.audit_msg)); - strncat (info_group.action, group_newname, - 511 - strlen (info_group.audit_msg)); - + gr = stpecpy(gr, gr_end, ", new name: "); + gr = stpecpy(gr, gr_end, group_newname); #ifdef SHADOWGRP - strncat (info_gshadow.action, ", new name: ", - 511 - strlen (info_gshadow.audit_msg)); - strncat (info_gshadow.action, group_newname, - 511 - strlen (info_gshadow.audit_msg)); + sgr = stpecpy(sgr, sgr_end, ", new name: "); + sgr = stpecpy(sgr, sgr_end, group_newname); #endif - - strncat (info_passwd.action, ", new name: ", - 511 - strlen (info_passwd.audit_msg)); - strncat (info_passwd.action, group_newname, - 511 - strlen (info_passwd.audit_msg)); + pw = stpecpy(pw, pw_end, ", new name: "); + pw = stpecpy(pw, pw_end, group_newname); } if (pflg) { - strncat (info_group.action, ", new password", - 511 - strlen (info_group.audit_msg)); - + gr = stpecpy(gr, gr_end, ", new password"); #ifdef SHADOWGRP - strncat (info_gshadow.action, ", new password", - 511 - strlen (info_gshadow.audit_msg)); + sgr = stpecpy(sgr, sgr_end, ", new password"); #endif } if (gflg) { - strncat (info_group.action, ", new gid: ", - 511 - strlen (info_group.audit_msg)); - (void) snprintf (info_group.action+strlen (info_group.action), - 511 - strlen (info_group.audit_msg), - "%lu", (unsigned long int) group_newid); - - strncat (info_passwd.action, ", new gid: ", - 511 - strlen (info_passwd.audit_msg)); - (void) snprintf (info_passwd.action+strlen (info_passwd.action), - 511 - strlen (info_passwd.audit_msg), - "%lu", (unsigned long int) group_newid); - } - info_group.audit_msg[511] = '\0'; -#ifdef SHADOWGRP - info_gshadow.audit_msg[511] = '\0'; -#endif - info_passwd.audit_msg[511] = '\0'; + gr = stpecpy(gr, gr_end, ", new gid: "); + stpeprintf(gr, gr_end, "%ju", (uintmax_t) group_newid); + + pw = stpecpy(pw, pw_end, ", new gid: "); + stpeprintf(pw, pw_end, "%ju", (uintmax_t) group_newid); + } // FIXME: add a system cleanup add_cleanup (cleanup_report_mod_group, &info_group); @@ -766,10 +749,6 @@ int main (int argc, char **argv) #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -780,7 +759,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); prefix = process_prefix_flag ("-P", argc, argv); - OPENLOG ("groupmod"); + OPENLOG (Prog); #ifdef WITH_AUDIT audit_help_open (); #endif @@ -806,7 +785,7 @@ int main (int argc, char **argv) exit (E_PAM_USERNAME); } - retval = pam_start ("groupmod", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); } if (PAM_SUCCESS == retval) { @@ -849,28 +828,6 @@ int main (int argc, char **argv) } } -#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 (); } diff --git a/src/groups.c b/src/groups.c index 12bd224..d19a80a 100644 --- a/src/groups.c +++ b/src/groups.c @@ -14,13 +14,16 @@ #include <grp.h> #include <pwd.h> #include <stdio.h> + +#include "alloc.h" #include "defines.h" #include "prototypes.h" #include "shadowlog.h" + /* * Global variables */ -const char *Prog; +static const char Prog[] = "groups"; /* local function prototypes */ static void print_groups (const char *member); @@ -88,16 +91,12 @@ int main (int argc, char **argv) GETGROUPS_T *groups; sys_ngroups = sysconf (_SC_NGROUPS_MAX); - groups = (GETGROUPS_T *) malloc (sizeof (GETGROUPS_T) * sys_ngroups); + groups = XMALLOC(sys_ngroups, GETGROUPS_T); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); - /* - * Get the program name so that error messages can use it. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); diff --git a/src/grpck.c b/src/grpck.c index 881fb4d..4ef1b15 100644 --- a/src/grpck.c +++ b/src/grpck.c @@ -43,7 +43,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "grpck"; static const char *grp_file = GROUP_FILE; static bool use_system_grp_file = true; @@ -62,7 +62,7 @@ static bool silence_warnings = false; /* local function prototypes */ static void fail_exit (int status); -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void delete_member (char **, const char *); static void process_flags (int argc, char **argv); static void open_files (void); @@ -114,7 +114,9 @@ static void fail_exit (int status) /* * usage - print syntax message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; #ifdef SHADOWGRP @@ -814,10 +816,6 @@ int main (int argc, char **argv) int errors = 0; bool changed = false; - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -827,7 +825,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("grpck"); + OPENLOG (Prog); /* Parse the command line arguments */ process_flags (argc, argv); diff --git a/src/grpconv.c b/src/grpconv.c index 57d8d58..4d941cd 100644 --- a/src/grpconv.c +++ b/src/grpconv.c @@ -21,9 +21,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <time.h> #include <unistd.h> #include <getopt.h> + +#include "attr.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -36,7 +39,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "grpconv"; static bool gr_locked = false; static bool sgr_locked = false; @@ -123,7 +126,6 @@ int main (int argc, char **argv) const struct sgrp *sg; struct sgrp sgent; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -133,7 +135,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("grpconv"); + OPENLOG (Prog); process_flags (argc, argv); @@ -198,7 +200,7 @@ int main (int argc, char **argv) static char *empty = 0; /* add new shadow group entry */ - memset (&sgent, 0, sizeof sgent); + bzero(&sgent, sizeof sgent); sgent.sg_name = gr->gr_name; sgent.sg_passwd = gr->gr_passwd; sgent.sg_adm = ∅ @@ -259,7 +261,7 @@ int main (int argc, char **argv) return 0; } #else /* !SHADOWGRP */ -int main (int unused(argc), char **argv) +int main (MAYBE_UNUSED int argc, char **argv) { fprintf (stderr, "%s: not configured for shadow group support.\n", argv[0]); diff --git a/src/grpunconv.c b/src/grpunconv.c index fc6cecf..d001ece 100644 --- a/src/grpunconv.c +++ b/src/grpunconv.c @@ -24,6 +24,8 @@ #include <unistd.h> #include <grp.h> #include <getopt.h> + +#include "attr.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -36,7 +38,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "grpunconv"; static bool gr_locked = false; static bool sgr_locked = false; @@ -122,7 +124,6 @@ int main (int argc, char **argv) struct group grent; const struct sgrp *sg; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -132,7 +133,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("grpunconv"); + OPENLOG (Prog); process_flags (argc, argv); @@ -222,7 +223,7 @@ int main (int argc, char **argv) return 0; } #else /* !SHADOWGRP */ -int main (int unused(argc), char **argv) +int main (MAYBE_UNUSED int argc, char **argv) { fprintf (stderr, "%s: not configured for shadow group support.\n", argv[0]); @@ -23,7 +23,10 @@ #include <pwd.h> #include <stdio.h> #include <sys/types.h> + +#include "alloc.h" #include "defines.h" + /* local function prototypes */ static void usage (void); @@ -33,7 +36,8 @@ static void usage (void) exit (EXIT_FAILURE); } - /*ARGSUSED*/ int main (int argc, char **argv) +int +main(int argc, char *argv[]) { uid_t ruid, euid; gid_t rgid, egid; @@ -63,7 +67,7 @@ static void usage (void) * work if the system library is recompiled. */ sys_ngroups = sysconf (_SC_NGROUPS_MAX); - groups = (GETGROUPS_T *) malloc (sizeof (GETGROUPS_T) * sys_ngroups); + groups = MALLOC(sys_ngroups, GETGROUPS_T); /* * See if the -a flag has been given to print out the concurrent @@ -71,11 +75,10 @@ static void usage (void) */ if (argc > 1) { - if ((argc > 2) || (strcmp (argv[1], "-a") != 0)) { - usage (); - } else { + if (argc > 2 || strcmp(argv[1], "-a") != 0) + usage(); + else aflg = true; - } } ruid = getuid (); diff --git a/src/lastlog.c b/src/lastlog.c index f5c0a5c..3914b72 100644 --- a/src/lastlog.c +++ b/src/lastlog.c @@ -22,12 +22,18 @@ #ifdef HAVE_LL_HOST #include <net/if.h> #endif + +#include "atoi/str2i.h" #include "defines.h" #include "prototypes.h" #include "getdef.h" +#include "memzero.h" /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/strftime.h" + + /* * Needed for MkLinux DR1/2/2.1 - J. @@ -39,7 +45,7 @@ /* * Global variables */ -const char *Prog; /* Program name */ +static const char Prog[] = "lastlog"; /* Program name */ static FILE *lastlogfile; /* lastlog file stream */ static unsigned long umin; /* if uflg and has_umin, only display users with uid >= umin */ static bool has_umin = false; @@ -50,15 +56,17 @@ static time_t inverse_seconds; /* that number of days in seconds */ static struct stat statbuf; /* fstat buffer for file size */ -static bool uflg = false; /* print only an user of range of users */ +static bool uflg = false; /* print only a user of range of users */ static bool tflg = false; /* print is restricted to most recent days */ static bool bflg = false; /* print excludes most recent days */ static bool Cflg = false; /* clear record for user */ static bool Sflg = false; /* set record for user */ -#define NOW (time ((time_t *) 0)) +#define NOW time(NULL) -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -67,7 +75,7 @@ static /*@noreturn@*/void usage (int status) "Options:\n"), Prog); (void) fputs (_(" -b, --before DAYS print only lastlog records older than DAYS\n"), usageout); - (void) fputs (_(" -C, --clear clear lastlog record of an user (usable only with -u)\n"), usageout); + (void) fputs (_(" -C, --clear clear lastlog record of a user (usable only with -u)\n"), usageout); (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); (void) fputs (_(" -S, --set set lastlog record to current time (usable only with -u)\n"), usageout); @@ -114,10 +122,10 @@ static void print_one (/*@null@*/const struct passwd *pw) * entered for this user, which should be able to get the * empty entry in this case. */ - if (fread ((char *) &ll, sizeof (ll), 1, lastlogfile) != 1) { + if (fread (&ll, sizeof (ll), 1, lastlogfile) != 1) { fprintf (stderr, _("%s: Failed to get the entry for UID %lu\n"), - Prog, (unsigned long int)pw->pw_uid); + Prog, (unsigned long)pw->pw_uid); exit (EXIT_FAILURE); } } else { @@ -141,7 +149,7 @@ static void print_one (/*@null@*/const struct passwd *pw) /* Print the header only once */ if (!once) { #ifdef HAVE_LL_HOST - printf (_("Username Port From%*sLatest\n"), maxIPv6Addrlen-3, " "); + printf (_("Username Port From%*sLatest\n"), maxIPv6Addrlen-4, " "); #else puts (_("Username Port Latest")); #endif @@ -153,7 +161,7 @@ static void print_one (/*@null@*/const struct passwd *pw) if (tm == NULL) { cp = "(unknown)"; } else { - strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", tm); + STRFTIME(ptime, "%a %b %e %H:%M:%S %z %Y", tm); cp = ptime; } if (ll.ll_time == (time_t) 0) { @@ -182,7 +190,7 @@ static void print (void) } if (uflg && has_umin && has_umax && (umin == umax)) { - print_one (getpwuid ((uid_t)umin)); + print_one (getpwuid (umin)); } else { setpwent (); while ( (pwent = getpwent ()) != NULL ) { @@ -225,21 +233,21 @@ static void update_one (/*@null@*/const struct passwd *pw) #ifdef WITH_AUDIT audit_logger (AUDIT_ACCT_UNLOCK, Prog, "clearing-lastlog", - pw->pw_name, (unsigned int) pw->pw_uid, SHADOW_AUDIT_SUCCESS); + pw->pw_name, pw->pw_uid, SHADOW_AUDIT_SUCCESS); #endif } #ifdef WITH_AUDIT else { audit_logger (AUDIT_ACCT_UNLOCK, Prog, "refreshing-lastlog", - pw->pw_name, (unsigned int) pw->pw_uid, SHADOW_AUDIT_SUCCESS); + pw->pw_name, pw->pw_uid, SHADOW_AUDIT_SUCCESS); } #endif if (fwrite (&ll, sizeof(ll), 1, lastlogfile) != 1) { fprintf (stderr, _("%s: Failed to update the entry for UID %lu\n"), - Prog, (unsigned long int)pw->pw_uid); + Prog, (unsigned long)pw->pw_uid); exit (EXIT_FAILURE); } } @@ -261,7 +269,7 @@ static void update (void) } if (has_umin && has_umax && (umin == umax)) { - update_one (getpwuid ((uid_t)umin)); + update_one (getpwuid (umin)); } else { setpwent (); while ( (pwent = getpwent ()) != NULL ) { @@ -288,7 +296,6 @@ int main (int argc, char **argv) * Get the program name. The program name is used as a prefix to * most error messages. */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -321,7 +328,7 @@ int main (int argc, char **argv) case 'b': { unsigned long inverse_days; - if (getulong (optarg, &inverse_days) == 0) { + if (str2ul(&inverse_days, optarg) == -1) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); @@ -349,7 +356,7 @@ int main (int argc, char **argv) case 't': { unsigned long days; - if (getulong (optarg, &days) == 0) { + if (str2ul(&days, optarg) == -1) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); @@ -373,14 +380,14 @@ int main (int argc, char **argv) /* local, no need for xgetpwnam */ pwent = getpwnam (optarg); if (NULL != pwent) { - umin = (unsigned long) pwent->pw_uid; + umin = pwent->pw_uid; has_umin = true; umax = umin; has_umax = true; } else { - if (getrange (optarg, - &umin, &has_umin, - &umax, &has_umax) == 0) { + if (getrange(optarg, + &umin, &has_umin, + &umax, &has_umax) == -1) { fprintf (stderr, _("%s: Unknown user or range: %s\n"), Prog, optarg); diff --git a/src/login.c b/src/login.c index 0048281..9fed7b3 100644 --- a/src/login.c +++ b/src/login.c @@ -14,7 +14,9 @@ #include <errno.h> #include <grp.h> #ifndef USE_PAM +#ifdef ENABLE_LASTLOG #include <lastlog.h> +#endif /* ENABLE_LASTLOG */ #endif /* !USE_PAM */ #include <pwd.h> #include <signal.h> @@ -22,15 +24,24 @@ #include <sys/stat.h> #include <sys/ioctl.h> #include <assert.h> + +#include "alloc.h" +#include "attr.h" +#include "chkname.h" #include "defines.h" #include "faillog.h" #include "failure.h" #include "getdef.h" +#include "memzero.h" #include "prototypes.h" #include "pwauth.h" /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/sprintf.h" +#include "string/strftime.h" +#include "string/strtcpy.h" + #ifdef USE_PAM #include "pam_defs.h" @@ -60,14 +71,16 @@ static pam_handle_t *pamh = NULL; /* * Global variables */ -const char *Prog; +static const char Prog[] = "login"; static const char *hostname = ""; static /*@null@*/ /*@only@*/char *username = NULL; static int reason = PW_LOGIN; #ifndef USE_PAM +#ifdef ENABLE_LASTLOG static struct lastlog ll; +#endif /* ENABLE_LASTLOG */ #endif /* !USE_PAM */ static bool pflg = false; static bool fflg = false; @@ -89,7 +102,6 @@ static char tmsg[256]; extern char **newenvp; extern size_t newenvc; -extern char **environ; #ifndef ALARM #define ALARM 60 @@ -104,15 +116,6 @@ static void usage (void); static void setup_tty (void); static void process_flags (int argc, char *const *argv); static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user); -static void update_utmp (const char *user, - const char *tty, - const char *host, -#ifdef USE_UTMPX - /*@null@*/const struct utmpx *utent -#else - /*@null@*/const struct utmp *utent -#endif - ); #ifndef USE_PAM static struct faillog faillog; @@ -125,6 +128,7 @@ static void get_pam_user (char **ptr_pam_user); static void init_env (void); static void alarm_handler (int); +static void exit_handler (int); /* * usage - print login command usage and exit @@ -172,10 +176,10 @@ static void setup_tty (void) #endif /* leave these values unchanged if not specified in login.defs */ - erasechar = getdef_num ("ERASECHAR", (int) termio.c_cc[VERASE]); - killchar = getdef_num ("KILLCHAR", (int) termio.c_cc[VKILL]); - termio.c_cc[VERASE] = (cc_t) erasechar; - termio.c_cc[VKILL] = (cc_t) killchar; + erasechar = getdef_num ("ERASECHAR", termio.c_cc[VERASE]); + killchar = getdef_num ("KILLCHAR", termio.c_cc[VKILL]); + termio.c_cc[VERASE] = erasechar; + termio.c_cc[VKILL] = killchar; /* Make sure the values were valid. * getdef_num cannot validate this. */ @@ -396,13 +400,18 @@ static void init_env (void) #endif /* !USE_PAM */ } - -static void alarm_handler (unused int sig) +static void exit_handler (MAYBE_UNUSED int sig) { - write (STDERR_FILENO, tmsg, strlen (tmsg)); _exit (0); } +static void alarm_handler (MAYBE_UNUSED int sig) +{ + write_full(STDERR_FILENO, tmsg, strlen(tmsg)); + signal(SIGALRM, exit_handler); + alarm(2); +} + #ifdef USE_PAM /* * get_pam_user - Get the username according to PAM @@ -411,17 +420,17 @@ static void alarm_handler (unused int sig) */ static void get_pam_user (char **ptr_pam_user) { - int retcode; - void *ptr_user; + int retcode; + const void *ptr_user; assert (NULL != ptr_pam_user); - retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user); + retcode = pam_get_item (pamh, PAM_USER, &ptr_user); PAM_FAIL_CHECK; free (*ptr_pam_user); if (NULL != ptr_user) { - *ptr_pam_user = xstrdup ((const char *)ptr_user); + *ptr_pam_user = xstrdup (ptr_user); } else { *ptr_pam_user = NULL; } @@ -430,7 +439,7 @@ static void get_pam_user (char **ptr_pam_user) /* * get_failent_user - Return a string that can be used to log failure - * from an user. + * from a user. * * This will be either the user argument, or "UNKNOWN". * @@ -453,38 +462,6 @@ static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *use } /* - * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and - * wtmpx - * - * utent should be the utmp entry returned by get_current_utmp (or - * NULL). - */ -static void update_utmp (const char *user, - const char *tty, - const char *host, -#ifdef USE_UTMPX - /*@null@*/const struct utmpx *utent -#else - /*@null@*/const struct utmp *utent -#endif - ) -{ -#ifdef USE_UTMPX - struct utmpx *utx = prepare_utmpx (user, tty, host, utent); -#else - struct utmp *ut = prepare_utmp (user, tty, host, utent); -#endif /* USE_UTMPX */ - -#ifndef USE_UTMPX - (void) setutmp (ut); /* make entry in the utmp & wtmp files */ - free (ut); -#else - (void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */ - free (utx); -#endif /* USE_UTMPX */ -} - -/* * login - create a new login session for a user * * login is typically called by getty as the second step of a @@ -503,42 +480,36 @@ static void update_utmp (const char *user, */ int main (int argc, char **argv) { - const char *tmptty; - char tty[BUFSIZ]; - -#ifdef RLOGIN - char term[128] = ""; -#endif /* RLOGIN */ -#if !defined(USE_PAM) - char ptime[80]; -#endif - unsigned int delay; - unsigned int retries; - bool subroot = false; -#ifndef USE_PAM + int err; + bool subroot = false; + char **envp = environ; + char *host = NULL; + char tty[BUFSIZ]; + char fromhost[512]; + const char *failent_user; + const char *tmptty; + const char *cp; + const char *tmp; + unsigned int delay; + unsigned int retries; + unsigned int timeout; + struct passwd *pwd = NULL; + +#if defined(USE_PAM) + int retcode; + char *pam_user = NULL; + pid_t child; +#else bool is_console; + struct spwd *spwd = NULL; +# if defined(ENABLE_LASTLOG) + char ptime[80]; +# endif #endif - int err; - unsigned int timeout; - const char *cp; - const char *tmp; - char fromhost[512]; - struct passwd *pwd = NULL; - char **envp = environ; - const char *failent_user; -#ifdef USE_UTMPX - /*@null@*/struct utmpx *utent; -#else - /*@null@*/struct utmp *utent; +#if defined(RLOGIN) + char term[128] = ""; #endif -#ifdef USE_PAM - int retcode; - pid_t child; - char *pam_user = NULL; -#else - struct spwd *spwd = NULL; -#endif /* * Some quick initialization. */ @@ -552,7 +523,6 @@ int main (int argc, char **argv) initenv (); amroot = (getuid () == 0); - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -567,25 +537,23 @@ int main (int argc, char **argv) exit (1); /* must be a terminal */ } - utent = get_current_utmp (); + err = get_session_host(&host); /* * Be picky if run by normal users (possible if installed setuid - * root), but not if run by root. This way it still allows logins - * even if your getty is broken, or if something corrupts utmp, - * but users must "exec login" which will use the existing utmp - * entry (will not overwrite remote hostname). --marekm + * root), but not if run by root. */ - if (!amroot && (NULL == utent)) { - (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\"")); + if (!amroot && (err != 0)) { + SYSLOG ((LOG_ERR, + "No session entry, error %d. You must exec \"login\" from the lowest level \"sh\"", + err)); exit (1); } - /* NOTE: utent might be NULL afterwards */ tmptty = ttyname (0); if (NULL == tmptty) { tmptty = "UNKNOWN"; } - STRFCPY (tty, tmptty); + STRTCPY(tty, tmptty); #ifndef USE_PAM is_console = console (tty); @@ -606,10 +574,14 @@ int main (int argc, char **argv) } #ifdef RLOGIN if (rflg) { + size_t max_size; + + max_size = login_name_max_size(); assert (NULL == username); - username = xmalloc (USER_NAME_MAX_LENGTH + 1); - username[USER_NAME_MAX_LENGTH] = '\0'; - if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) { + username = XMALLOC(max_size, char); + username[max_size - 1] = '\0'; + if (do_rlogin(hostname, username, max_size, term, sizeof(term))) + { preauth_flag = true; } else { free (username); @@ -618,7 +590,7 @@ int main (int argc, char **argv) } #endif /* RLOGIN */ - OPENLOG ("login"); + OPENLOG (Prog); setup_tty (); @@ -674,27 +646,23 @@ int main (int argc, char **argv) if (rflg || hflg) { cp = hostname; -#if defined(HAVE_STRUCT_UTMP_UT_HOST) || defined(USE_UTMPX) - } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) { - cp = utent->ut_host; -#endif /* HAVE_STRUCT_UTMP_UT_HOST */ + } else if ((host != NULL) && (host[0] != '\0')) { + cp = host; } else { cp = ""; } if ('\0' != *cp) { - snprintf (fromhost, sizeof fromhost, - " on '%.100s' from '%.200s'", tty, cp); + SNPRINTF(fromhost, " on '%.100s' from '%.200s'", tty, cp); } else { - snprintf (fromhost, sizeof fromhost, - " on '%.100s'", tty); + SNPRINTF(fromhost, " on '%.100s'", tty); } + free(host); top: /* only allow ALARM sec. for login */ timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM); - snprintf (tmsg, sizeof tmsg, - _("\nLogin timed out after %u seconds.\n"), timeout); + SNPRINTF(tmsg, _("\nLogin timed out after %u seconds.\n"), timeout); (void) signal (SIGALRM, alarm_handler); if (timeout > 0) { (void) alarm (timeout); @@ -705,7 +673,7 @@ int main (int argc, char **argv) retries = getdef_unum ("LOGIN_RETRIES", RETRIES); #ifdef USE_PAM - retcode = pam_start ("login", username, &conv, &pamh); + retcode = pam_start (Prog, username, &conv, &pamh); if (retcode != PAM_SUCCESS) { fprintf (stderr, _("login: PAM Failure, aborting: %s\n"), @@ -733,18 +701,15 @@ int main (int argc, char **argv) #endif /* if fflg, then the user has already been authenticated */ if (!fflg) { - unsigned int failcount = 0; - char hostn[256]; - char loginprompt[256]; /* That's one hell of a prompt :) */ + char hostn[256]; + char loginprompt[256]; //That's one hell of a prompt :) + unsigned int failcount = 0; /* Make the login prompt look like we want it */ if (gethostname (hostn, sizeof (hostn)) == 0) { - snprintf (loginprompt, - sizeof (loginprompt), - _("%s login: "), hostn); + SNPRINTF(loginprompt, _("%s login: "), hostn); } else { - strncpy (loginprompt, _("login: "), - sizeof (loginprompt)); + STRTCPY(loginprompt, _("login: ")); } retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt); @@ -919,14 +884,17 @@ int main (int argc, char **argv) failed = false; /* haven't failed authentication yet */ if (NULL == username) { /* need to get a login id */ + size_t max_size; + + max_size = login_name_max_size(); if (subroot) { closelog (); exit (1); } preauth_flag = false; - username = xmalloc (USER_NAME_MAX_LENGTH + 1); - username[USER_NAME_MAX_LENGTH] = '\0'; - login_prompt (_("\n%s login: "), username, USER_NAME_MAX_LENGTH); + username = XMALLOC(max_size, char); + username[max_size - 1] = '\0'; + login_prompt(username, max_size); if ('\0' == username[0]) { /* Prompt for a new login */ @@ -956,7 +924,8 @@ int main (int argc, char **argv) } if (strcmp (user_passwd, "") == 0) { - char *prevent_no_auth = getdef_str("PREVENT_NO_AUTH"); + const char *prevent_no_auth = getdef_str("PREVENT_NO_AUTH"); + if (prevent_no_auth == NULL) { prevent_no_auth = "superuser"; } @@ -992,7 +961,7 @@ int main (int argc, char **argv) goto auth_ok; } - if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) { + if (pw_auth (user_passwd, username, reason, NULL) == 0) { goto auth_ok; } @@ -1035,23 +1004,9 @@ int main (int argc, char **argv) if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) { failure (pwd->pw_uid, tty, &faillog); } - if (getdef_str ("FTMP_FILE") != NULL) { -#ifdef USE_UTMPX - struct utmpx *failent = - prepare_utmpx (failent_user, - tty, - /* FIXME: or fromhost? */hostname, - utent); -#else /* !USE_UTMPX */ - struct utmp *failent = - prepare_utmp (failent_user, - tty, - hostname, - utent); -#endif /* !USE_UTMPX */ - failtmp (failent_user, failent); - free (failent); - } +#ifndef ENABLE_LOGIND + record_failure(failent_user, tty, hostname); +#endif /* ENABLE_LOGIND */ retries--; if (retries <= 0) { @@ -1067,7 +1022,7 @@ int main (int argc, char **argv) * all). --marekm */ if (user_passwd[0] == '\0') { - pw_auth ("!", username, reason, (char *) 0); + pw_auth ("!", username, reason, NULL); } /* @@ -1107,7 +1062,7 @@ int main (int argc, char **argv) * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm */ if ( getdef_bool ("PORTTIME_CHECKS_ENAB") - && !isttytime (username, tty, time ((time_t *) 0))) { + && !isttytime (username, tty, time (NULL))) { SYSLOG ((LOG_WARN, "invalid login time for '%s'%s", username, fromhost)); closelog (); @@ -1151,11 +1106,13 @@ int main (int argc, char **argv) #endif /* WITH_AUDIT */ #ifndef USE_PAM /* pam_lastlog handles this */ +#ifdef ENABLE_LASTLOG if ( getdef_bool ("LASTLOG_ENAB") && pwd->pw_uid <= (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL)) { /* give last login and log this one */ dolastlog (&ll, pwd, tty, hostname); } +#endif /* ENABLE_LASTLOG */ #endif #ifndef USE_PAM /* PAM handles this as well */ @@ -1220,11 +1177,16 @@ int main (int argc, char **argv) } } +#ifndef ENABLE_LOGIND /* * The utmp entry needs to be updated to indicate the new status * of the session, the new PID and SID. */ - update_utmp (username, tty, hostname, utent); + err = update_utmp (username, tty, hostname); + if (err != 0) { + SYSLOG ((LOG_WARN, "Unable to update utmp entry for %s", username)); + } +#endif /* ENABLE_LOGIND */ /* The pwd and spwd entries for the user have been copied. * @@ -1289,14 +1251,16 @@ int main (int argc, char **argv) username, (int) faillog.fail_cnt)); } } +#ifdef ENABLE_LASTLOG if ( getdef_bool ("LASTLOG_ENAB") && pwd->pw_uid <= (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL) - && (ll.ll_time != 0)) { - time_t ll_time = ll.ll_time; + && (ll.ll_time != 0)) + { + time_t ll_time = ll.ll_time; + struct tm tm; - (void) strftime (ptime, sizeof (ptime), - "%a %b %e %H:%M:%S %z %Y", - localtime (&ll_time)); + localtime_r(&ll_time, &tm); + STRFTIME(ptime, "%a %b %e %H:%M:%S %z %Y", &tm); printf (_("Last login: %s on %s"), ptime, ll.ll_line); #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */ @@ -1307,6 +1271,7 @@ int main (int argc, char **argv) #endif printf (".\n"); } +#endif /* ENABLE_LASTLOG */ agecheck (spwd); mailcheck (); /* report on the status of mail */ @@ -1334,7 +1299,7 @@ int main (int argc, char **argv) err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */ } else { /* exec the shell finally */ - err = shell (pwd->pw_shell, (char *) 0, newenvp); + err = shell (pwd->pw_shell, NULL, newenvp); } return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); diff --git a/src/login_nopam.c b/src/login_nopam.c index df6ba88..e6f77d1 100644 --- a/src/login_nopam.c +++ b/src/login_nopam.c @@ -39,12 +39,11 @@ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ #include <sys/types.h> +#include <stddef.h> #include <stdio.h> #include <syslog.h> #include <ctype.h> -#ifdef HAVE_NETDB_H #include <netdb.h> -#endif #include <grp.h> #ifdef PRIMARY_GROUP_MATCH #include <pwd.h> @@ -57,6 +56,8 @@ #include <netinet/in.h> #include <arpa/inet.h> /* for inet_ntoa() */ +#include "sizeof.h" + #if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 64) #undef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 @@ -98,11 +99,11 @@ int login_access (const char *user, const char *from) if (NULL != fp) { int lineno = 0; /* for diagnostics */ while ( !match - && (fgets (line, (int) sizeof (line), fp) == line)) { - int end; + && (fgets (line, sizeof (line), fp) == line)) { + ptrdiff_t end; lineno++; - end = (int) strlen (line) - 1; - if (line[end] != '\n') { + end = strlen (line) - 1; + if (line[0] == '\0' || line[end] != '\n') { SYSLOG ((LOG_ERR, "%s: line %d: missing newline or line too long", TABLE, lineno)); @@ -119,9 +120,9 @@ int login_access (const char *user, const char *from) continue; } if ( ((perm = strtok (line, fs)) == NULL) - || ((users = strtok ((char *) 0, fs)) == NULL) - || ((froms = strtok ((char *) 0, fs)) == NULL) - || (strtok ((char *) 0, fs) != NULL)) { + || ((users = strtok (NULL, fs)) == NULL) + || ((froms = strtok (NULL, fs)) == NULL) + || (strtok (NULL, fs) != NULL)) { SYSLOG ((LOG_ERR, "%s: line %d: bad field count", TABLE, lineno)); @@ -156,7 +157,7 @@ static bool list_match (char *list, const char *item, bool (*match_fn) (const ch * a match, look for an "EXCEPT" list and recurse to determine whether * the match is affected by any exceptions. */ - for (tok = strtok (list, sep); tok != NULL; tok = strtok ((char *) 0, sep)) { + for (tok = strtok (list, sep); tok != NULL; tok = strtok (NULL, sep)) { if (strcasecmp (tok, "EXCEPT") == 0) { /* EXCEPT: give up */ break; } @@ -168,10 +169,10 @@ static bool list_match (char *list, const char *item, bool (*match_fn) (const ch /* Process exceptions to matches. */ if (match) { - while ( ((tok = strtok ((char *) 0, sep)) != NULL) + while ( ((tok = strtok (NULL, sep)) != NULL) && (strcasecmp (tok, "EXCEPT") != 0)) /* VOID */ ; - if (tok == 0 || !list_match ((char *) 0, item, match_fn)) { + if (tok == 0 || !list_match (NULL, item, match_fn)) { return (match); } } @@ -195,9 +196,9 @@ static char *myhostname (void) static bool netgroup_match (const char *group, const char *machine, const char *user) { - static char *mydomain = (char *)0; + static char *mydomain = NULL; - if (mydomain == (char *)0) { + if (mydomain == NULL) { static char domain[MAXHOSTNAMELEN + 1]; getdomainname (domain, MAXHOSTNAMELEN); @@ -230,7 +231,7 @@ static bool user_match (const char *tok, const char *string) && from_match (at + 1, myhostname ())); #if HAVE_INNETGR } else if (tok[0] == '@') { /* netgroup */ - return (netgroup_match (tok + 1, (char *) 0, string)); + return (netgroup_match (tok + 1, NULL, string)); #endif } else if (string_match (tok, string)) { /* ALL or exact match */ return true; @@ -244,7 +245,7 @@ static bool user_match (const char *tok, const char *string) } #ifdef PRIMARY_GROUP_MATCH /* - * If the string is an user whose initial GID matches the token, + * If the string is a user whose initial GID matches the token, * accept it. May avoid excessively long lines in /etc/group. * Radu-Adrian Feurdean <raf@licj.soroscj.ro> * @@ -265,19 +266,28 @@ static bool user_match (const char *tok, const char *string) static const char *resolve_hostname (const char *string) { - /* - * Resolve hostname to numeric IP address, as suggested - * by Dave Hagewood <admin@arrowweb.com>. --marekm - */ - struct hostent *hp; + int gai_err; + const char *addr_str; + struct addrinfo *addrs; + + static char host[MAXHOSTNAMELEN]; + + gai_err = getaddrinfo(string, NULL, NULL, &addrs); + if (gai_err != 0) { + SYSLOG ((LOG_ERR, "getaddrinfo(%s): %s", string, gai_strerror(gai_err))); + return string; + } - hp = gethostbyname (string); - if (NULL != hp) { - return inet_ntoa (*((struct in_addr *) *(hp->h_addr_list))); + addr_str = host; + gai_err = getnameinfo(addrs[0].ai_addr, addrs[0].ai_addrlen, + host, NITEMS(host), NULL, 0, NI_NUMERICHOST); + if (gai_err != 0) { + SYSLOG ((LOG_ERR, "getnameinfo(%s): %s", string, gai_strerror(gai_err))); + addr_str = string; } - SYSLOG ((LOG_ERR, "%s - unknown host", string)); - return string; + freeaddrinfo(addrs); + return addr_str; } /* from_match - match a host or tty against a list of tokens */ @@ -296,7 +306,7 @@ static bool from_match (const char *tok, const char *string) */ #if HAVE_INNETGR if (tok[0] == '@') { /* netgroup */ - return (netgroup_match (tok + 1, string, (char *) 0)); + return (netgroup_match (tok + 1, string, NULL)); } else #endif if (string_match (tok, string)) { /* ALL or exact match */ @@ -313,7 +323,7 @@ static bool from_match (const char *tok, const char *string) if (strchr (string, '.') == NULL) { return true; } - } else if ( (tok[(tok_len = strlen (tok)) - 1] == '.') /* network */ + } else if ( (tok[0] != '\0' && tok[(tok_len = strlen (tok)) - 1] == '.') /* network */ && (strncmp (tok, resolve_hostname (string), tok_len) == 0)) { return true; } @@ -337,5 +347,5 @@ static bool string_match (const char *tok, const char *string) } #else /* !USE_PAM */ -extern int errno; /* warning: ANSI C forbids an empty source file */ +extern int ISO_C_forbids_an_empty_translation_unit; #endif /* !USE_PAM */ diff --git a/src/logoutd.c b/src/logoutd.c index 03680f3..c870510 100644 --- a/src/logoutd.c +++ b/src/logoutd.c @@ -15,13 +15,16 @@ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> +#include <utmpx.h> #include "defines.h" #include "prototypes.h" #include "shadowlog.h" +#include "sizeof.h" +#include "string/zustr2stp.h" /* * Global variables */ -const char *Prog; +static const char Prog[] = "logoutd"; #ifndef DEFAULT_HUP_MESG #define DEFAULT_HUP_MESG _("login time exceeded\n\n") @@ -31,38 +34,31 @@ const char *Prog; #define HUP_MESG_FILE "/etc/logoutd.mesg" #endif + /* local function prototypes */ -#ifdef USE_UTMPX static int check_login (const struct utmpx *ut); -#else /* !USE_UTMPX */ -static int check_login (const struct utmp *ut); -#endif /* !USE_UTMPX */ static void send_mesg_to_tty (int tty_fd); + /* - * check_login - check if user (struct utmpx/utmp) allowed to stay logged in + * check_login - check if user (struct utmpx) allowed to stay logged in */ -#ifdef USE_UTMPX -static int check_login (const struct utmpx *ut) -#else /* !USE_UTMPX */ -static int check_login (const struct utmp *ut) -#endif /* !USE_UTMPX */ +static int +check_login(const struct utmpx *ut) { - char user[sizeof (ut->ut_user) + 1]; - time_t now; + char user[sizeof(ut->ut_user) + 1]; + char line[sizeof(ut->ut_line) + 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'; + ZUSTR2STP(user, ut->ut_user); + ZUSTR2STP(line, ut->ut_line); (void) time (&now); /* * Check if they are allowed to be logged in right now. */ - if (!isttytime (user, ut->ut_line, now)) { + if (!isttytime(user, line, now)) { return 0; } return 1; @@ -116,23 +112,20 @@ static void send_mesg_to_tty (int tty_fd) * * logoutd is started at system boot time and enforces the login * time and port restrictions specified in /etc/porttime. The - * utmpx/utmp file is periodically scanned and offending users are logged + * utmp file is periodically scanned and offending users are logged * off from the system. */ -int main (int argc, char **argv) +int +main(int argc, char **argv) { - int i; - int status; - pid_t pid; - -#ifdef USE_UTMPX - struct utmpx *ut; -#else /* !USE_UTMPX */ - struct utmp *ut; -#endif /* !USE_UTMPX */ - char user[sizeof (ut->ut_user) + 1]; /* terminating NUL */ - char tty_name[sizeof (ut->ut_line) + 6]; /* /dev/ + NUL */ - int tty_fd; + int i; + int status; + pid_t pid; + + struct utmpx *ut; + char user[sizeof (ut->ut_user) + 1]; /* terminating NUL */ + char tty_name[sizeof (ut->ut_line) + 6]; /* /dev/ + NUL */ + int tty_fd; if (1 != argc) { (void) fputs (_("Usage: logoutd\n"), stderr); @@ -164,39 +157,29 @@ int main (int argc, char **argv) /* * Start syslogging everything */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); - OPENLOG ("logoutd"); + OPENLOG (Prog); /* - * Scan the utmpx/utmp file once per minute looking for users that + * Scan the utmp file once per minute looking for users that * are not supposed to still be logged in. */ while (true) { /* - * Attempt to re-open the utmpx/utmp file. The file is only + * Attempt to re-open the utmp file. The file is only * open while it is being used. */ -#ifdef USE_UTMPX - setutxent (); -#else /* !USE_UTMPX */ - setutent (); -#endif /* !USE_UTMPX */ + setutxent(); /* - * Read all of the entries in the utmpx/utmp file. The entries + * 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. */ -#ifdef USE_UTMPX - while ((ut = getutxent ()) != NULL) -#else /* !USE_UTMPX */ - while ((ut = getutent ()) != NULL) -#endif /* !USE_UTMPX */ - { + while ((ut = getutxent()) != NULL) { if (ut->ut_type != USER_PROCESS) { continue; } @@ -228,7 +211,7 @@ int main (int argc, char **argv) tty_name[0] = '\0'; } - strncat (tty_name, ut->ut_line, UT_LINESIZE); + strncat(tty_name, ut->ut_line, NITEMS(ut->ut_line)); #ifndef O_NOCTTY #define O_NOCTTY 0 #endif @@ -246,8 +229,7 @@ int main (int argc, char **argv) kill (-ut->ut_pid, SIGKILL); } - strncpy (user, ut->ut_user, sizeof (user) - 1); - user[sizeof (user) - 1] = '\0'; + ZUSTR2STP(user, ut->ut_user); SYSLOG ((LOG_NOTICE, "logged off user '%s' on '%s'", user, @@ -259,11 +241,7 @@ int main (int argc, char **argv) exit (EXIT_SUCCESS); } -#ifdef USE_UTMPX - endutxent (); -#else /* !USE_UTMPX */ - endutent (); -#endif /* !USE_UTMPX */ + endutxent(); #ifndef DEBUG sleep (60); diff --git a/src/new_subid_range.c b/src/new_subid_range.c index 523d480..1ef71f3 100644 --- a/src/new_subid_range.c +++ b/src/new_subid_range.c @@ -9,7 +9,7 @@ /* Test program for the subid creation routine */ -const char *Prog; +static const char Prog[] = "new_subid_range"; static void usage(void) { @@ -28,7 +28,6 @@ int main(int argc, char *argv[]) bool group = false; // get subuids by default bool ok; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); while ((c = getopt(argc, argv, "gn")) != EOF) { diff --git a/src/newgidmap.c b/src/newgidmap.c index 5b42431..96a89de 100644 --- a/src/newgidmap.c +++ b/src/newgidmap.c @@ -23,7 +23,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "newgidmap"; static bool verify_range(struct passwd *pw, struct map_range *range, bool *allow_setgroups) @@ -69,7 +69,7 @@ static void verify_ranges(struct passwd *pw, int ranges, static void usage(void) { - fprintf(stderr, _("usage: %s <pid> <gid> <lowergid> <count> [ <gid> <lowergid> <count> ] ... \n"), Prog); + fprintf(stderr, _("usage: %s [<pid|fd:<pidfd>] <gid> <lowergid> <count> [ <gid> <lowergid> <count> ] ... \n"), Prog); exit(EXIT_FAILURE); } @@ -143,18 +143,14 @@ out: */ int main(int argc, char **argv) { - char proc_dir_name[32]; char *target_str; - pid_t target; int proc_dir_fd; int ranges; struct map_range *mappings; struct stat st; struct passwd *pw; - int written; bool allow_setgroups = false; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -168,25 +164,19 @@ int main(int argc, char **argv) /* Find the process that needs its user namespace * gid mapping set. */ - target_str = argv[1]; - if (!get_pid(target_str, &target)) - usage(); - /* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */ - written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/", - target); - if ((written <= 0) || (written >= sizeof(proc_dir_name))) { - fprintf(stderr, "%s: snprintf of proc path failed: %s\n", - Prog, strerror(errno)); - } - - proc_dir_fd = open(proc_dir_name, O_DIRECTORY); - if (proc_dir_fd < 0) { - fprintf(stderr, _("%s: Could not open proc directory for target %u\n"), - Prog, target); - return EXIT_FAILURE; + target_str = argv[1]; + if (strlen(target_str) > 3 && strncmp(target_str, "fd:", 3) == 0) { + /* the user passed in a /proc/pid fd for the process */ + target_str = &target_str[3]; + proc_dir_fd = get_pidfd_from_fd(target_str); + if (proc_dir_fd < 0) + usage(); + } else { + proc_dir_fd = open_pidfd(target_str); + if (proc_dir_fd < 0) + usage(); } - /* Who am i? */ pw = get_my_pwent (); if (NULL == pw) { @@ -200,8 +190,8 @@ int main(int argc, char **argv) /* Get the effective uid and effective gid of the target process */ if (fstat(proc_dir_fd, &st) < 0) { - fprintf(stderr, _("%s: Could not stat directory for target %u\n"), - Prog, target); + fprintf(stderr, _("%s: Could not stat directory for process\n"), + Prog); return EXIT_FAILURE; } @@ -213,10 +203,10 @@ int main(int argc, char **argv) (!getdef_bool("GRANT_AUX_GROUP_SUBIDS") && (getgid() != pw->pw_gid)) || (pw->pw_uid != st.st_uid) || (getgid() != st.st_gid)) { - fprintf(stderr, _( "%s: Target %u is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), - Prog, target, - (unsigned long int)getuid(), (unsigned long int)pw->pw_uid, (unsigned long int)st.st_uid, - (unsigned long int)getgid(), (unsigned long int)pw->pw_gid, (unsigned long int)st.st_gid); + fprintf(stderr, _( "%s: Target process is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), + Prog, + (unsigned long)getuid(), (unsigned long)pw->pw_uid, (unsigned long)st.st_uid, + (unsigned long)getgid(), (unsigned long)pw->pw_gid, (unsigned long)st.st_gid); return EXIT_FAILURE; } diff --git a/src/newgrp.c b/src/newgrp.c index 9982083..1b3d76b 100644 --- a/src/newgrp.c +++ b/src/newgrp.c @@ -16,20 +16,24 @@ #include <pwd.h> #include <stdio.h> #include <assert.h> + +#include "agetpass.h" +#include "alloc.h" #include "defines.h" #include "getdef.h" #include "prototypes.h" /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/sprintf.h" + /* * Global variables */ -const char *Prog; +static const char *Prog; extern char **newenvp; -extern char **environ; #ifdef HAVE_SETGROUPS static int ngroups; @@ -158,7 +162,7 @@ static void check_perms (const struct group *grp, * get the password from her, and set the salt for * the decryption from the group file. */ - cp = getpass (_("Password: ")); + cp = agetpass (_("Password: ")); if (NULL == cp) { goto failure; } @@ -169,7 +173,7 @@ static void check_perms (const struct group *grp, * must match the previously encrypted value in the file. */ cpasswd = pw_encrypt (cp, grp->gr_passwd); - strzero (cp); + erase_pass (cp); if (NULL == cpasswd) { fprintf (stderr, @@ -184,12 +188,10 @@ static void check_perms (const struct group *grp, if (grp->gr_passwd[0] == '\0' || strcmp (cpasswd, grp->gr_passwd) != 0) { #ifdef WITH_AUDIT - snprintf (audit_buf, sizeof(audit_buf), - "authentication new-gid=%lu", - (unsigned long) grp->gr_gid); + SNPRINTF(audit_buf, "authentication new-gid=%lu", + (unsigned long) grp->gr_gid); audit_logger (AUDIT_GRP_AUTH, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); #endif SYSLOG ((LOG_INFO, "Invalid password for group '%s' from '%s'", @@ -199,12 +201,10 @@ static void check_perms (const struct group *grp, goto failure; } #ifdef WITH_AUDIT - snprintf (audit_buf, sizeof(audit_buf), - "authentication new-gid=%lu", - (unsigned long) grp->gr_gid); + SNPRINTF(audit_buf, "authentication new-gid=%lu", + (unsigned long) grp->gr_gid); audit_logger (AUDIT_GRP_AUTH, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 1); + audit_buf, NULL, getuid (), 1); #endif } @@ -217,21 +217,17 @@ failure: closelog (); #ifdef WITH_AUDIT if (groupname) { - snprintf (audit_buf, sizeof(audit_buf), - "changing new-group=%s", groupname); + SNPRINTF(audit_buf, "changing new-group=%s", groupname); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); } else { audit_logger (AUDIT_CHGRP_ID, Prog, - "changing", NULL, - (unsigned int) getuid (), 0); + "changing", NULL, getuid (), 0); } #endif exit (EXIT_FAILURE); } -#ifdef USE_SYSLOG /* * syslog_sg - log the change of group to syslog * @@ -292,6 +288,9 @@ static void syslog_sg (const char *name, const char *group) (void) signal (SIGTSTP, SIG_IGN); (void) signal (SIGTTIN, SIG_IGN); (void) signal (SIGTTOU, SIG_IGN); + /* set SIGCHLD to default for waitpid */ + (void) signal(SIGCHLD, SIG_DFL); + child = fork (); if ((pid_t)-1 == child) { /* error in fork() */ @@ -299,15 +298,13 @@ static void syslog_sg (const char *name, const char *group) is_newgrp ? "newgrp" : "sg", strerror (errno)); #ifdef WITH_AUDIT if (group) { - snprintf (audit_buf, sizeof(audit_buf), - "changing new-group=%s", group); + SNPRINTF(audit_buf, + "changing new-group=%s", group); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); } else { audit_logger (AUDIT_CHGRP_ID, Prog, - "changing", NULL, - (unsigned int) getuid (), 0); + "changing", NULL, getuid (), 0); } #endif exit (EXIT_FAILURE); @@ -365,7 +362,6 @@ static void syslog_sg (const char *name, const char *group) free(free_login); free(free_tty); } -#endif /* USE_SYSLOG */ /* * newgrp - change the invokers current real and effective group id @@ -394,12 +390,15 @@ int main (int argc, char **argv) #ifdef WITH_AUDIT audit_help_open (); #endif + + check_fds (); + (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); /* - * Save my name for error messages and save my real gid incase of + * Save my name for error messages and save my real gid in case 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 @@ -421,11 +420,18 @@ int main (int argc, char **argv) * but we do not need to restore the previous process persona and we * don't need to re-exec anything. -- JWP */ - Prog = Basename (argv[0]); + + /* + * Ensure that "Prog" is always either "newgrp" or "sg" to avoid + * injecting arbitrary strings into our stderr/stdout, as this can + * be an exploit vector. + */ + is_newgrp = (strcmp (Basename (argv[0]), "newgrp") == 0); + Prog = is_newgrp ? "newgrp" : "sg"; + log_set_progname(Prog); log_set_logfd(stderr); - is_newgrp = (strcmp (Prog, "newgrp") == 0); - OPENLOG (is_newgrp ? "newgrp" : "sg"); + OPENLOG (Prog); argc--; argv++; @@ -437,8 +443,7 @@ int main (int argc, char **argv) Prog); #ifdef WITH_AUDIT audit_logger (AUDIT_CHGRP_ID, Prog, - "changing", NULL, - (unsigned int) getuid (), 0); + "changing", NULL, getuid (), 0); #endif SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", (unsigned long) getuid ())); @@ -507,7 +512,7 @@ int main (int argc, char **argv) if ((argc > 0) && (argv[0][0] == '-')) { usage (); goto failure; - } else if (argv[0] != (char *) 0) { + } else if (argv[0] != NULL) { group = argv[0]; } else { /* @@ -541,7 +546,7 @@ int main (int argc, char **argv) /* don't use getgroups(0, 0) - it doesn't work on some systems */ i = 16; for (;;) { - grouplist = (GETGROUPS_T *) xmalloc (i * sizeof (GETGROUPS_T)); + grouplist = XMALLOC(i, GETGROUPS_T); ngroups = getgroups (i, grouplist); if (i > ngroups && !(ngroups == -1 && errno == EINVAL)) { break; @@ -554,15 +559,12 @@ int main (int argc, char **argv) perror ("getgroups"); #ifdef WITH_AUDIT if (group) { - snprintf (audit_buf, sizeof(audit_buf), - "changing new-group=%s", group); + SNPRINTF(audit_buf, "changing new-group=%s", group); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); } else { audit_logger (AUDIT_CHGRP_ID, Prog, - "changing", NULL, - (unsigned int) getuid (), 0); + "changing", NULL, getuid (), 0); } #endif exit (EXIT_FAILURE); @@ -628,7 +630,7 @@ int main (int argc, char **argv) } #endif /* HAVE_SETGROUPS */ /* - * For splitted groups (due to limitations of NIS), check all + * For split groups (due to limitations of NIS), check all * groups of the same GID like the requested group for * membership of the current user. */ @@ -665,11 +667,9 @@ int main (int argc, char **argv) * 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_sg (name, group); } -#endif /* USE_SYSLOG */ gid = grp->gr_gid; @@ -718,11 +718,9 @@ int main (int argc, char **argv) if (setgid (gid) != 0) { perror ("setgid"); #ifdef WITH_AUDIT - snprintf (audit_buf, sizeof(audit_buf), - "changing new-gid=%lu", (unsigned long) gid); + SNPRINTF(audit_buf, "changing new-gid=%lu", (unsigned long) gid); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); #endif exit (EXIT_FAILURE); } @@ -730,11 +728,9 @@ int main (int argc, char **argv) if (setuid (getuid ()) != 0) { perror ("setuid"); #ifdef WITH_AUDIT - snprintf (audit_buf, sizeof(audit_buf), - "changing new-gid=%lu", (unsigned long) gid); + SNPRINTF(audit_buf, "changing new-gid=%lu", (unsigned long) gid); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); #endif exit (EXIT_FAILURE); } @@ -745,13 +741,11 @@ int main (int argc, char **argv) */ if (cflag) { closelog (); - execl (SHELL, "sh", "-c", command, (char *) 0); + execl (SHELL, "sh", "-c", command, (char *) NULL); #ifdef WITH_AUDIT - snprintf (audit_buf, sizeof(audit_buf), - "changing new-gid=%lu", (unsigned long) gid); + SNPRINTF(audit_buf, "changing new-gid=%lu", (unsigned long) gid); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); #endif perror (SHELL); exit ((errno == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); @@ -815,17 +809,15 @@ int main (int argc, char **argv) } #ifdef WITH_AUDIT - snprintf (audit_buf, sizeof(audit_buf), "changing new-gid=%lu", - (unsigned long) gid); + SNPRINTF(audit_buf, "changing new-gid=%lu", (unsigned long) gid); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 1); + audit_buf, NULL, getuid (), 1); #endif /* * 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. */ - err = shell (prog, initflag ? (char *) 0 : progbase, newenvp); + err = shell (prog, initflag ? NULL : progbase, newenvp); exit ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); /*@notreached@*/ failure: @@ -843,15 +835,12 @@ int main (int argc, char **argv) closelog (); #ifdef WITH_AUDIT if (NULL != group) { - snprintf (audit_buf, sizeof(audit_buf), - "changing new-group=%s", group); + SNPRINTF(audit_buf, "changing new-group=%s", group); audit_logger (AUDIT_CHGRP_ID, Prog, - audit_buf, NULL, - (unsigned int) getuid (), 0); + audit_buf, NULL, getuid (), 0); } else { audit_logger (AUDIT_CHGRP_ID, Prog, - "changing", NULL, - (unsigned int) getuid (), 0); + "changing", NULL, getuid (), 0); } #endif exit (EXIT_FAILURE); diff --git a/src/newuidmap.c b/src/newuidmap.c index 546856a..e2652b5 100644 --- a/src/newuidmap.c +++ b/src/newuidmap.c @@ -23,7 +23,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "newuidmap"; static bool verify_range(struct passwd *pw, struct map_range *range) { @@ -64,7 +64,7 @@ static void verify_ranges(struct passwd *pw, int ranges, static void usage(void) { - fprintf(stderr, _("usage: %s <pid> <uid> <loweruid> <count> [ <uid> <loweruid> <count> ] ... \n"), Prog); + fprintf(stderr, _("usage: %s [<pid>|fd:<pidfd>] <uid> <loweruid> <count> [ <uid> <loweruid> <count> ] ... \n"), Prog); exit(EXIT_FAILURE); } @@ -73,17 +73,13 @@ static void usage(void) */ int main(int argc, char **argv) { - char proc_dir_name[32]; char *target_str; - pid_t target; int proc_dir_fd; int ranges; struct map_range *mappings; struct stat st; struct passwd *pw; - int written; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -94,26 +90,20 @@ int main(int argc, char **argv) if (argc < 2) usage(); + target_str = argv[1]; /* Find the process that needs its user namespace * uid mapping set. */ - target_str = argv[1]; - if (!get_pid(target_str, &target)) - usage(); - - /* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */ - written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/", - target); - if ((written <= 0) || (written >= sizeof(proc_dir_name))) { - fprintf(stderr, "%s: snprintf of proc path failed: %s\n", - Prog, strerror(errno)); - } - - proc_dir_fd = open(proc_dir_name, O_DIRECTORY); - if (proc_dir_fd < 0) { - fprintf(stderr, _("%s: Could not open proc directory for target %u\n"), - Prog, target); - return EXIT_FAILURE; + if (strlen(target_str) > 3 && strncmp(target_str, "fd:", 3) == 0) { + /* the user passed in a /proc/pid fd for the process */ + target_str = &target_str[3]; + proc_dir_fd = get_pidfd_from_fd(target_str); + if (proc_dir_fd < 0) + usage(); + } else { + proc_dir_fd = open_pidfd(target_str); + if (proc_dir_fd < 0) + usage(); } /* Who am i? */ @@ -129,8 +119,7 @@ int main(int argc, char **argv) /* Get the effective uid and effective gid of the target process */ if (fstat(proc_dir_fd, &st) < 0) { - fprintf(stderr, _("%s: Could not stat directory for target %u\n"), - Prog, target); + fprintf(stderr, _("%s: Could not stat directory for target process\n"), Prog); return EXIT_FAILURE; } @@ -142,10 +131,10 @@ int main(int argc, char **argv) (!getdef_bool("GRANT_AUX_GROUP_SUBIDS") && (getgid() != pw->pw_gid)) || (pw->pw_uid != st.st_uid) || (getgid() != st.st_gid)) { - fprintf(stderr, _( "%s: Target process %u is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), - Prog, target, - (unsigned long int)getuid(), (unsigned long int)pw->pw_uid, (unsigned long int)st.st_uid, - (unsigned long int)getgid(), (unsigned long int)pw->pw_gid, (unsigned long int)st.st_gid); + fprintf(stderr, _( "%s: Target process is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), + Prog, + (unsigned long)getuid(), (unsigned long)pw->pw_uid, (unsigned long)st.st_uid, + (unsigned long)getgid(), (unsigned long)pw->pw_gid, (unsigned long)st.st_gid); return EXIT_FAILURE; } diff --git a/src/newusers.c b/src/newusers.c index deeb361..0705b57 100644 --- a/src/newusers.c +++ b/src/newusers.c @@ -29,6 +29,9 @@ #include <ctype.h> #include <errno.h> #include <string.h> + +#include "alloc.h" +#include "atoi/str2i.h" #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM #include "pam_defs.h" @@ -48,17 +51,19 @@ #endif /* ENABLE_SUBIDS */ #include "chkname.h" #include "shadowlog.h" +#include "string/sprintf.h" + /* * Global variables */ -const char *Prog; +static const char Prog[] = "newusers"; static bool rflg = false; /* create a system account */ #ifndef USE_PAM static /*@null@*//*@observer@*/char *crypt_method = NULL; #define cflg (NULL != crypt_method) -#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) static bool sflg = false; #endif #ifdef USE_SHA_CRYPT @@ -88,8 +93,8 @@ static bool sub_gid_locked = false; #endif /* ENABLE_SUBIDS */ /* local function prototypes */ -static void usage (int status); -static void fail_exit (int); +NORETURN static void usage (int status); +NORETURN static void fail_exit (int); static int add_group (const char *, const char *, gid_t *, gid_t); static int get_user_id (const char *, uid_t *); static int add_user (const char *, uid_t, gid_t); @@ -235,7 +240,7 @@ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid) * new group, or an existing group. */ - if (get_gid (gid, &grent.gr_gid) == 0) { + if (get_gid(gid, &grent.gr_gid) == -1) { fprintf (stderr, _("%s: invalid group ID '%s'\n"), Prog, gid); @@ -245,11 +250,11 @@ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid) /* Look in both the system database (getgrgid) and in the * internal database (gr_locate_gid), which may contain * uncommitted changes */ - if ( (getgrgid ((gid_t) grent.gr_gid) != NULL) - || (gr_locate_gid ((gid_t) grent.gr_gid) != NULL)) { + if ( (getgrgid (grent.gr_gid) != NULL) + || (gr_locate_gid (grent.gr_gid) != NULL)) { /* The user will use this ID for her * primary group */ - *ngid = (gid_t) grent.gr_gid; + *ngid = grent.gr_gid; return 0; } @@ -339,7 +344,7 @@ static int get_user_id (const char *uid, uid_t *nuid) { * caller provided, or the next available UID. */ if (isdigit (uid[0])) { - if ((get_uid (uid, nuid) == 0) || (*nuid == (uid_t)-1)) { + if ((get_uid(uid, nuid) == -1) || (*nuid == (uid_t)-1)) { fprintf (stderr, _("%s: invalid user ID '%s'\n"), Prog, uid); @@ -350,22 +355,20 @@ static int get_user_id (const char *uid, uid_t *nuid) { const struct passwd *pwd; /* local, no need for xgetpwnam */ pwd = getpwnam (uid); - if (NULL == pwd) { + if (pwd == NULL) pwd = pw_locate (uid); - } - if (NULL != pwd) { - *nuid = pwd->pw_uid; - } else { + if (pwd == NULL) { fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog, uid); return -1; } + + *nuid = pwd->pw_uid; } else { - if (find_new_uid (rflg, nuid, NULL) < 0) { + if (find_new_uid (rflg, nuid, NULL) < 0) return -1; - } } } @@ -527,7 +530,7 @@ static int add_passwd (struct passwd *pwd, const char *password) } spent.sp_pwdp = cp; } - spent.sp_lstchg = (long) gettime () / SCALE; + spent.sp_lstchg = gettime () / DAY; if (0 == spent.sp_lstchg) { /* Better disable aging than requiring a password * change */ @@ -584,7 +587,7 @@ static int add_passwd (struct passwd *pwd, const char *password) */ spent.sp_pwdp = "!"; #endif - spent.sp_lstchg = (long) gettime () / SCALE; + spent.sp_lstchg = gettime () / DAY; if (0 == spent.sp_lstchg) { /* Better disable aging than requiring a password change */ spent.sp_lstchg = -1; @@ -662,21 +665,28 @@ static void process_flags (int argc, char **argv) case 's': sflg = true; bad_s = 0; + + if (!crypt_method){ + fprintf(stderr, + _("%s: Provide '--crypt-method' before number of rounds\n"), + Prog); + usage (EXIT_FAILURE); + } #if defined(USE_SHA_CRYPT) if ( ( ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512"))) - && (0 == getlong(optarg, &sha_rounds)))) { + && (-1 == str2sl(&sha_rounds, optarg)))) { bad_s = 1; } #endif /* USE_SHA_CRYPT */ #if defined(USE_BCRYPT) if (( (0 == strcmp (crypt_method, "BCRYPT")) - && (0 == getlong(optarg, &bcrypt_rounds)))) { + && (-1 == str2sl(&bcrypt_rounds, optarg)))) { bad_s = 1; } #endif /* USE_BCRYPT */ #if defined(USE_YESCRYPT) if (( (0 == strcmp (crypt_method, "YESCRYPT")) - && (0 == getlong(optarg, &yescrypt_cost)))) { + && (-1 == str2sl(&yescrypt_cost, optarg)))) { bad_s = 1; } #endif /* USE_YESCRYPT */ @@ -702,8 +712,9 @@ static void process_flags (int argc, char **argv) if (argv[optind] != NULL) { if (freopen (argv[optind], "r", stdin) == NULL) { - char buf[BUFSIZ]; - snprintf (buf, sizeof buf, "%s: %s", Prog, argv[1]); + char buf[BUFSIZ]; + + SNPRINTF(buf, "%s: %s", Prog, argv[1]); perror (buf); fail_exit (EXIT_FAILURE); } @@ -1039,7 +1050,6 @@ int main (int argc, char **argv) char *cp; const struct passwd *pw; struct passwd newpw; - int errors = 0; int line = 0; uid_t uid; gid_t gid; @@ -1050,7 +1060,6 @@ int main (int argc, char **argv) unsigned int nusers = 0; #endif /* USE_PAM */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -1088,19 +1097,16 @@ int main (int argc, char **argv) * over 100 is allocated. The pw_gid field will be updated with that * value. */ - while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) { + while (fgets (buf, sizeof buf, stdin) != NULL) { line++; cp = strrchr (buf, '\n'); - if (NULL != cp) { + if (cp == NULL && feof (stdin) == 0) { + fprintf (stderr, _("%s: line %d: line too long\n"), + Prog, line); + fail_exit (EXIT_FAILURE); + } + if (cp != NULL) { *cp = '\0'; - } else { - if (feof (stdin) == 0) { - fprintf (stderr, - _("%s: line %d: line too long\n"), - Prog, line); - errors++; - continue; - } } /* @@ -1111,39 +1117,35 @@ int main (int argc, char **argv) for (cp = buf, nfields = 0; nfields < 7; nfields++) { fields[nfields] = cp; cp = strchr (cp, ':'); - if (NULL != cp) { - *cp = '\0'; - cp++; - } else { + if (cp == NULL) break; - } + + *cp = '\0'; + cp++; } if (nfields != 6) { fprintf (stderr, _("%s: line %d: invalid line\n"), Prog, line); - errors++; - continue; + fail_exit (EXIT_FAILURE); } /* - * First check if we have to create or update an user + * First check if we have to create or update a user */ pw = pw_locate (fields[0]); /* local, no need for xgetpwnam */ - if ( (NULL == pw) - && (getpwnam (fields[0]) != NULL)) { - fprintf (stderr, _("%s: cannot update the entry of user %s (not in the passwd database)\n"), Prog, fields[0]); - errors++; - continue; + if (NULL == pw && getpwnam(fields[0]) != NULL) { + fprintf (stderr, + _("%s: cannot update the entry of user %s (not in the passwd database)\n"), + Prog, fields[0]); + fail_exit (EXIT_FAILURE); } - if ( (NULL == pw) - && (get_user_id (fields[2], &uid) != 0)) { + if (NULL == pw && get_user_id(fields[2], &uid) != 0) { fprintf (stderr, _("%s: line %d: can't create user\n"), Prog, line); - errors++; - continue; + fail_exit (EXIT_FAILURE); } /* @@ -1163,8 +1165,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %d: can't create group\n"), Prog, line); - errors++; - continue; + fail_exit (EXIT_FAILURE); } /* @@ -1179,8 +1180,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %d: can't create user\n"), Prog, line); - errors++; - continue; + fail_exit (EXIT_FAILURE); } /* @@ -1192,17 +1192,22 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %d: user '%s' does not exist in %s\n"), Prog, line, fields[0], pw_dbname ()); - errors++; - continue; + fail_exit (EXIT_FAILURE); } newpw = *pw; #ifdef USE_PAM /* keep the list of user/password for later update by PAM */ nusers++; - lines = realloc (lines, sizeof (lines[0]) * nusers); - usernames = realloc (usernames, sizeof (usernames[0]) * nusers); - passwords = realloc (passwords, sizeof (passwords[0]) * nusers); + lines = REALLOCF(lines, nusers, int); + usernames = REALLOCF(usernames, nusers, char *); + passwords = REALLOCF(passwords, nusers, char *); + if (lines == NULL || usernames == NULL || passwords == NULL) { + fprintf (stderr, + _("%s: line %d: %s\n"), + Prog, line, strerror(errno)); + fail_exit (EXIT_FAILURE); + } lines[nusers-1] = line; usernames[nusers-1] = strdup (fields[0]); passwords[nusers-1] = strdup (fields[1]); @@ -1211,8 +1216,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %d: can't update password\n"), Prog, line); - errors++; - continue; + fail_exit (EXIT_FAILURE); } if ('\0' != fields[4][0]) { newpw.pw_gecos = fields[4]; @@ -1235,21 +1239,24 @@ int main (int argc, char **argv) fprintf(stderr, _("%s: line %d: homedir must be an absolute path\n"), Prog, line); - errors++; - continue; - }; + fail_exit (EXIT_FAILURE); + } if (mkdir (newpw.pw_dir, mode) != 0) { fprintf (stderr, _("%s: line %d: mkdir %s failed: %s\n"), Prog, line, newpw.pw_dir, strerror (errno)); - } else if (chown (newpw.pw_dir, - newpw.pw_uid, - newpw.pw_gid) != 0) { + if (errno != EEXIST) { + fail_exit (EXIT_FAILURE); + } + } + if (chown(newpw.pw_dir, newpw.pw_uid, newpw.pw_gid) != 0) + { fprintf (stderr, _("%s: line %d: chown %s failed: %s\n"), Prog, line, newpw.pw_dir, strerror (errno)); + fail_exit (EXIT_FAILURE); } } @@ -1260,8 +1267,7 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: line %d: can't update entry\n"), Prog, line); - errors++; - continue; + fail_exit (EXIT_FAILURE); } #ifdef ENABLE_SUBIDS @@ -1271,17 +1277,19 @@ int main (int argc, char **argv) if (is_sub_uid && want_subuids() && !local_sub_uid_assigned(fields[0])) { uid_t sub_uid_start = 0; unsigned long sub_uid_count = 0; - if (find_new_sub_uids(&sub_uid_start, &sub_uid_count) == 0) { - if (sub_uid_add(fields[0], sub_uid_start, sub_uid_count) == 0) { - fprintf (stderr, - _("%s: failed to prepare new %s entry\n"), - Prog, sub_uid_dbname ()); - } - } else { + if (find_new_sub_uids(&sub_uid_start, &sub_uid_count) != 0) + { fprintf (stderr, _("%s: can't find subordinate user range\n"), Prog); - errors++; + fail_exit (EXIT_FAILURE); + } + if (sub_uid_add(fields[0], sub_uid_start, sub_uid_count) == 0) + { + fprintf (stderr, + _("%s: failed to prepare new %s entry\n"), + Prog, sub_uid_dbname ()); + fail_exit (EXIT_FAILURE); } } @@ -1291,17 +1299,17 @@ int main (int argc, char **argv) if (is_sub_gid && want_subgids() && !local_sub_gid_assigned(fields[0])) { gid_t sub_gid_start = 0; unsigned long sub_gid_count = 0; - if (find_new_sub_gids(&sub_gid_start, &sub_gid_count) == 0) { - if (sub_gid_add(fields[0], sub_gid_start, sub_gid_count) == 0) { - fprintf (stderr, - _("%s: failed to prepare new %s entry\n"), - Prog, sub_uid_dbname ()); - } - } else { + if (find_new_sub_gids(&sub_gid_start, &sub_gid_count) != 0) { fprintf (stderr, _("%s: can't find subordinate group range\n"), Prog); - errors++; + fail_exit (EXIT_FAILURE); + } + if (sub_gid_add(fields[0], sub_gid_start, sub_gid_count) == 0) { + fprintf (stderr, + _("%s: failed to prepare new %s entry\n"), + Prog, sub_uid_dbname ()); + fail_exit (EXIT_FAILURE); } } #endif /* ENABLE_SUBIDS */ @@ -1314,12 +1322,6 @@ int main (int argc, char **argv) * changes to be written out all at once, and then unlocked * afterwards. */ - if (0 != errors) { - fprintf (stderr, - _("%s: error detected, changes ignored\n"), Prog); - fail_exit (EXIT_FAILURE); - } - close_files (); nscd_flush_cache ("passwd"); @@ -1334,11 +1336,11 @@ int main (int argc, char **argv) fprintf (stderr, _("%s: (line %d, user %s) password not changed\n"), Prog, lines[i], usernames[i]); - errors++; + exit (EXIT_FAILURE); } } #endif /* USE_PAM */ - return ((0 == errors) ? EXIT_SUCCESS : EXIT_FAILURE); + exit (EXIT_SUCCESS); } diff --git a/src/passwd.c b/src/passwd.c index 8c6f81a..2999a3c 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -19,8 +19,13 @@ #include <stdio.h> #include <sys/types.h> #include <time.h> + +#include "agetpass.h" +#include "alloc.h" +#include "atoi/str2i.h" #include "defines.h" #include "getdef.h" +#include "memzero.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -28,6 +33,10 @@ #include "pwio.h" #include "shadowio.h" #include "shadowlog.h" +#include "string/strtcpy.h" +#include "time/day_to_str.h" + + /* * exit status values @@ -43,12 +52,14 @@ /* * Global variables */ -const char *Prog; /* Program name */ +static const char Prog[] = "passwd"; /* Program name */ static char *name; /* The name of user whose password is being changed */ static char *myname; /* The current user's name */ static bool amroot; /* The caller's real UID was 0 */ +static const char *prefix = ""; + static bool aflg = false, /* -a - show status for all users */ dflg = false, /* -d - delete password */ @@ -61,7 +72,8 @@ static bool Sflg = false, /* -S - show password status */ uflg = false, /* -u - unlock the user's password */ wflg = false, /* -w - set warning days */ - xflg = false; /* -x - set maximum days */ + xflg = false, /* -x - set maximum days */ + sflg = false; /* -s - read passwd from stdin */ /* * set to 1 if there are any flags which require root privileges, @@ -74,14 +86,16 @@ static long age_max = 0; /* Maximum days until change */ static long warn = 0; /* Warning days before change */ static long inact = 0; /* Days without change before locked */ -#ifndef USE_PAM static bool do_update_age = false; -#endif /* ! USE_PAM */ +#ifdef USE_PAM +static bool use_pam = true; +#else +static bool use_pam = false; +#endif /* USE_PAM */ static bool pw_locked = false; static bool spw_locked = false; -#ifndef USE_PAM /* * Size of the biggest passwd: * $6$ 3 @@ -97,25 +111,21 @@ static bool spw_locked = false; */ static char crypt_passwd[256]; static bool do_update_pwd = false; -#endif /* !USE_PAM */ /* * External identifiers */ /* local function prototypes */ -static /*@noreturn@*/void usage (int); +NORETURN static void usage (int); -#ifndef USE_PAM -static bool reuse (const char *, const struct passwd *); static int new_password (const struct passwd *); static void check_password (const struct passwd *, const struct spwd *); -#endif /* !USE_PAM */ static /*@observer@*/const char *pw_status (const char *); static void print_status (const struct passwd *); -static /*@noreturn@*/void fail_exit (int); -static /*@noreturn@*/void oom (void); +NORETURN static void fail_exit (int); +NORETURN static void oom (void); static char *update_crypt_pw (char *); static void update_noshadow (void); @@ -124,7 +134,9 @@ static void update_shadow (void); /* * usage - print command usage and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -145,37 +157,17 @@ static /*@noreturn@*/void usage (int status) (void) fputs (_(" -q, --quiet quiet mode\n"), usageout); (void) fputs (_(" -r, --repository REPOSITORY change password in REPOSITORY repository\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); + (void) fputs (_(" -P, --prefix PREFIX_DIR directory prefix\n"), usageout); (void) fputs (_(" -S, --status report password status on the named account\n"), usageout); (void) fputs (_(" -u, --unlock unlock the password of the named account\n"), usageout); (void) fputs (_(" -w, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"), usageout); (void) fputs (_(" -x, --maxdays MAX_DAYS set maximum number of days before password\n" " change to MAX_DAYS\n"), usageout); + (void) fputs (_(" -s, --stdin read new token from stdin\n"), usageout); (void) fputs ("\n", usageout); exit (status); } -#ifndef USE_PAM -static bool reuse (const char *pass, const struct passwd *pw) -{ -#ifdef HAVE_LIBCRACK_HIST - const char *reason; - -#ifdef HAVE_LIBCRACK_PW - const char *FascistHistoryPw (const char *, const struct passwd *); - - reason = FascistHistory (pass, pw); -#else /* !HAVE_LIBCRACK_PW */ - const char *FascistHistory (const char *, int); - - reason = FascistHistory (pass, pw->pw_uid); -#endif /* !HAVE_LIBCRACK_PW */ - if (NULL != reason) { - (void) printf (_("Bad password: %s. "), reason); - return true; - } -#endif /* HAVE_LIBCRACK_HIST */ - return false; -} /* * new_password - validate old password and replace with new (both old and @@ -186,25 +178,22 @@ static int new_password (const struct passwd *pw) char *clear; /* Pointer to clear text */ char *cipher; /* Pointer to cipher text */ const char *salt; /* Pointer to new salt */ - char *cp; /* Pointer to getpass() response */ - char orig[200]; /* Original password */ - char pass[200]; /* New password */ + char *cp; /* Pointer to agetpass() response */ + char orig[PASS_MAX + 1]; /* Original password */ + char pass[PASS_MAX + 1]; /* New password */ int i; /* Counter for retries */ + int ret; bool warned; int pass_max_len = -1; const char *method; -#ifdef HAVE_LIBCRACK_HIST - int HistUpdate (const char *, const char *); -#endif /* HAVE_LIBCRACK_HIST */ - /* * Authenticate the user. The user will be prompted for their own * password. */ if (!amroot && ('\0' != crypt_passwd[0])) { - clear = getpass (_("Old password: ")); + clear = agetpass (_("Old password: ")); if (NULL == clear) { return -1; } @@ -212,7 +201,7 @@ static int new_password (const struct passwd *pw) cipher = pw_encrypt (clear, crypt_passwd); if (NULL == cipher) { - strzero (clear); + erase_pass (clear); fprintf (stderr, _("%s: failed to crypt password with previous salt: %s\n"), Prog, strerror (errno)); @@ -223,7 +212,7 @@ static int new_password (const struct passwd *pw) } if (strcmp (cipher, crypt_passwd) != 0) { - strzero (clear); + erase_pass (clear); strzero (cipher); SYSLOG ((LOG_WARN, "incorrect password for %s", pw->pw_name)); @@ -233,8 +222,8 @@ static int new_password (const struct passwd *pw) pw->pw_name); return -1; } - STRFCPY (orig, clear); - strzero (clear); + STRTCPY(orig, clear); + erase_pass (clear); strzero (cipher); } else { orig[0] = '\0'; @@ -270,7 +259,7 @@ static int new_password (const struct passwd *pw) pass_max_len = getdef_num ("PASS_MAX_LEN", 8); } } - if (!qflg) { + if (!qflg && !sflg) { if (pass_max_len == -1) { (void) printf (_( "Enter the new password (minimum of %d characters)\n" @@ -284,62 +273,87 @@ static int new_password (const struct passwd *pw) } } - warned = false; - for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) { - cp = getpass (_("New password: ")); + if (sflg) { + /* + * root is setting the passphrase from stdin + */ + cp = agetpass_stdin (); if (NULL == cp) { - memzero (orig, sizeof orig); - memzero (pass, sizeof pass); return -1; } - if (warned && (strcmp (pass, cp) != 0)) { - warned = false; + ret = STRTCPY (pass, cp); + erase_pass (cp); + if (ret == -1) { + (void) fputs (_("Password is too long.\n"), stderr); + MEMZERO(pass); + return -1; } - STRFCPY (pass, cp); - strzero (cp); + } else { + warned = false; + for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) { + cp = agetpass (_("New password: ")); + if (NULL == cp) { + MEMZERO(orig); + MEMZERO(pass); + return -1; + } + if (warned && (strcmp (pass, cp) != 0)) { + warned = false; + } + ret = STRTCPY (pass, cp); + erase_pass (cp); + if (ret == -1) { + (void) fputs (_("Password is too long.\n"), stderr); + MEMZERO(orig); + MEMZERO(pass); + return -1; + } - if (!amroot && (!obscure (orig, pass, pw) || reuse (pass, pw))) { - (void) puts (_("Try again.")); - continue; - } + if (!amroot && !obscure(orig, pass, pw)) { + (void) puts (_("Try again.")); + continue; + } - /* - * If enabled, warn about weak passwords even if you are - * root (enter this password again to use it anyway). - * --marekm - */ - if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN") - && (!obscure (orig, pass, pw) || reuse (pass, pw))) { - (void) puts (_("\nWarning: weak password (enter it again to use it anyway).")); - warned = true; - continue; + /* + * If enabled, warn about weak passwords even if you are + * root (enter this password again to use it anyway). + * --marekm + */ + if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN") + && !obscure(orig, pass, pw)) { + (void) puts (_("\nWarning: weak password (enter it again to use it anyway).")); + warned = true; + continue; + } + cp = agetpass (_("Re-enter new password: ")); + if (NULL == cp) { + MEMZERO(orig); + MEMZERO(pass); + return -1; + } + if (strcmp (cp, pass) != 0) { + erase_pass (cp); + (void) fputs (_("They don't match; try again.\n"), stderr); + } else { + erase_pass (cp); + break; + } } - cp = getpass (_("Re-enter new password: ")); - if (NULL == cp) { - memzero (orig, sizeof orig); - memzero (pass, sizeof pass); + MEMZERO(orig); + + if (i == 0) { + MEMZERO(pass); return -1; } - if (strcmp (cp, pass) != 0) { - (void) fputs (_("They don't match; try again.\n"), stderr); - } else { - strzero (cp); - break; - } } - memzero (orig, sizeof orig); - if (i == 0) { - memzero (pass, sizeof pass); - return -1; - } /* * Encrypt the password, then wipe the cleartext password. */ salt = crypt_make_salt (NULL, NULL); cp = pw_encrypt (pass, salt); - memzero (pass, sizeof pass); + MEMZERO(pass); if (NULL == cp) { fprintf (stderr, @@ -348,10 +362,7 @@ static int new_password (const struct passwd *pw) return -1; } -#ifdef HAVE_LIBCRACK_HIST - HistUpdate (pw->pw_name, crypt_passwd); -#endif /* HAVE_LIBCRACK_HIST */ - STRFCPY (crypt_passwd, cp); + STRTCPY(crypt_passwd, cp); return 0; } @@ -363,7 +374,6 @@ static int new_password (const struct passwd *pw) */ static void check_password (const struct passwd *pw, const struct spwd *sp) { - time_t now; int exp_status; exp_status = isexpired (pw, sp); @@ -383,8 +393,6 @@ static void check_password (const struct passwd *pw, const struct spwd *sp) return; } - (void) time (&now); - /* * Expired accounts cannot be changed ever. Passwords which are * locked may not be changed. Passwords where min > max may not be @@ -407,10 +415,12 @@ static void check_password (const struct passwd *pw, const struct spwd *sp) * Passwords may only be changed after sp_min time is up. */ if (sp->sp_lstchg > 0) { - time_t ok; - ok = (time_t) sp->sp_lstchg * SCALE; - if (sp->sp_min > 0) { - ok += (time_t) sp->sp_min * SCALE; + long now, ok; + now = time(NULL) / DAY; + ok = sp->sp_lstchg; + if ( (sp->sp_min > 0) + && __builtin_add_overflow(ok, sp->sp_min, &ok)) { + ok = LONG_MAX; } if (now < ok) { @@ -423,7 +433,6 @@ static void check_password (const struct passwd *pw, const struct spwd *sp) } } } -#endif /* !USE_PAM */ static /*@observer@*/const char *pw_status (const char *pass) { @@ -444,17 +453,17 @@ static void print_status (const struct passwd *pw) char date[80]; struct spwd *sp; - sp = getspnam (pw->pw_name); /* local, no need for xgetspnam */ + sp = prefix_getspnam (pw->pw_name); /* local, no need for xprefix_getspnam */ if (NULL != sp) { - date_to_str (sizeof(date), date, sp->sp_lstchg * SCALE), - (void) printf ("%s %s %s %lld %lld %lld %lld\n", + DAY_TO_STR(date, sp->sp_lstchg); + (void) printf ("%s %s %s %ld %ld %ld %ld\n", pw->pw_name, pw_status (sp->sp_pwdp), date, - ((long long)sp->sp_min * SCALE) / DAY, - ((long long)sp->sp_max * SCALE) / DAY, - ((long long)sp->sp_warn * SCALE) / DAY, - ((long long)sp->sp_inact * SCALE) / DAY); + sp->sp_min, + sp->sp_max, + sp->sp_warn, + sp->sp_inact); } else if (NULL != pw->pw_passwd) { (void) printf ("%s %s\n", pw->pw_name, pw_status (pw->pw_passwd)); @@ -465,7 +474,9 @@ static void print_status (const struct passwd *pw) } -static /*@noreturn@*/void fail_exit (int status) +NORETURN +static void +fail_exit (int status) { if (pw_locked) { if (pw_unlock () == 0) { @@ -486,7 +497,9 @@ static /*@noreturn@*/void fail_exit (int status) exit (status); } -static /*@noreturn@*/void oom (void) +NORETURN +static void +oom (void) { (void) fprintf (stderr, _("%s: out of memory\n"), Prog); fail_exit (E_FAILURE); @@ -494,11 +507,12 @@ static /*@noreturn@*/void oom (void) static char *update_crypt_pw (char *cp) { -#ifndef USE_PAM - if (do_update_pwd) { - cp = xstrdup (crypt_passwd); + if (!use_pam) + { + if (do_update_pwd) { + cp = xstrdup (crypt_passwd); + } } -#endif /* !USE_PAM */ if (dflg) { *cp = '\0'; @@ -517,15 +531,16 @@ static char *update_crypt_pw (char *cp) } if (lflg && *cp != '!') { - char *newpw = xmalloc (strlen (cp) + 2); + char *newpw = XMALLOC(strlen(cp) + 2, char); strcpy (newpw, "!"); strcat (newpw, cp); -#ifndef USE_PAM - if (do_update_pwd) { - free (cp); + if (!use_pam) + { + if (do_update_pwd) { + free (cp); + } } -#endif /* USE_PAM */ cp = newpw; } return cp; @@ -626,27 +641,28 @@ static void update_shadow (void) } nsp->sp_pwdp = update_crypt_pw (nsp->sp_pwdp); if (xflg) { - nsp->sp_max = (age_max * DAY) / SCALE; + nsp->sp_max = age_max; } if (nflg) { - nsp->sp_min = (age_min * DAY) / SCALE; + nsp->sp_min = age_min; } if (wflg) { - nsp->sp_warn = (warn * DAY) / SCALE; + nsp->sp_warn = warn; } if (iflg) { - nsp->sp_inact = (inact * DAY) / SCALE; + nsp->sp_inact = inact; } -#ifndef USE_PAM - if (do_update_age) { - nsp->sp_lstchg = (long) gettime () / SCALE; - if (0 == nsp->sp_lstchg) { - /* Better disable aging than requiring a password - * change */ - nsp->sp_lstchg = -1; + if (!use_pam) + { + if (do_update_age) { + nsp->sp_lstchg = gettime () / DAY; + if (0 == nsp->sp_lstchg) { + /* Better disable aging than requiring a password + * change */ + nsp->sp_lstchg = -1; + } } } -#endif /* !USE_PAM */ /* * Force change on next login, like SunOS 4.x passwd -e or Solaris @@ -690,18 +706,16 @@ static void update_shadow (void) * * -d delete the password for the named account (*) * -e expire the password for the named account (*) - * -f execute chfn command to interpret flags - * -g execute gpasswd command to interpret flags * -i # set sp_inact to # days (*) * -k change password only if expired * -l lock the password of the named account (*) * -n # set sp_min to # days (*) * -r # change password in # repository - * -s execute chsh command to interpret flags * -S show password status of named account * -u unlock the password of the named account (*) * -w # set sp_warn to # days (*) * -x # set sp_max to # days (*) + * -s read password from stdin (*) * * (*) requires root permission to execute. * @@ -713,19 +727,13 @@ int main (int argc, char **argv) { const struct passwd *pw; /* Password file entry for user */ -#ifndef USE_PAM char *cp; /* Miscellaneous character pointing */ const struct spwd *sp; /* Shadow file entry for user */ -#endif /* !USE_PAM */ sanitize_env (); + check_fds (); - /* - * Get the program name. The program name is used as a prefix to - * most error messages. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -734,6 +742,12 @@ int main (int argc, char **argv) (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); + prefix = process_prefix_flag ("-P", argc, argv); + + if (prefix[0]) { + use_pam = false; + do_update_age = true; + } /* * The program behaves differently when executed by root than when @@ -741,7 +755,7 @@ int main (int argc, char **argv) */ amroot = (getuid () == 0); - OPENLOG ("passwd"); + OPENLOG (Prog); { /* @@ -760,14 +774,16 @@ int main (int argc, char **argv) {"quiet", no_argument, NULL, 'q'}, {"repository", required_argument, NULL, 'r'}, {"root", required_argument, NULL, 'R'}, + {"prefix", required_argument, NULL, 'P'}, {"status", no_argument, NULL, 'S'}, {"unlock", no_argument, NULL, 'u'}, {"warndays", required_argument, NULL, 'w'}, {"maxdays", required_argument, NULL, 'x'}, + {"stdin", no_argument, NULL, 's'}, {NULL, 0, NULL, '\0'} }; - while ((c = getopt_long (argc, argv, "adehi:kln:qr:R:Suw:x:", + while ((c = getopt_long (argc, argv, "adehi:kln:qr:R:P:Suw:x:s", long_options, NULL)) != -1) { switch (c) { case 'a': @@ -785,7 +801,7 @@ int main (int argc, char **argv) usage (E_SUCCESS); /*@notreached@*/break; case 'i': - if ( (getlong (optarg, &inact) == 0) + if ( (str2sl(&inact, optarg) == -1) || (inact < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -804,7 +820,7 @@ int main (int argc, char **argv) anyflag = true; break; case 'n': - if ( (getlong (optarg, &age_min) == 0) + if ( (str2sl(&age_min, optarg) == -1) || (age_min < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -829,6 +845,8 @@ int main (int argc, char **argv) break; case 'R': /* no-op, handled in process_root_flag () */ break; + case 'P': /* no-op, handled in process_prefix_flag () */ + break; case 'S': Sflg = true; /* ok for users */ break; @@ -837,7 +855,7 @@ int main (int argc, char **argv) anyflag = true; break; case 'w': - if ( (getlong (optarg, &warn) == 0) + if ( (str2sl(&warn, optarg) == -1) || (warn < -1)) { (void) fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -848,7 +866,7 @@ int main (int argc, char **argv) anyflag = true; break; case 'x': - if ( (getlong (optarg, &age_max) == 0) + if ( (str2sl(&age_max, optarg) == -1) || (age_max < -1)) { (void) fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -858,6 +876,15 @@ int main (int argc, char **argv) xflg = true; anyflag = true; break; + case 's': + if (!amroot) { + (void) fprintf (stderr, + _("%s: only root can use --stdin/-s option\n"), + Prog); + usage (E_BAD_ARG); + } + sflg = true; + break; default: usage (E_BAD_ARG); } @@ -906,11 +933,11 @@ int main (int argc, char **argv) Prog); exit (E_NOPERM); } - setpwent (); - while ( (pw = getpwent ()) != NULL ) { + prefix_setpwent (); + while ( (pw = prefix_getpwent ()) != NULL ) { print_status (pw); } - endpwent (); + prefix_endpwent (); exit (E_SUCCESS); } #if 0 @@ -947,7 +974,7 @@ int main (int argc, char **argv) exit (E_NOPERM); } - pw = xgetpwnam (name); + pw = xprefix_getpwnam (name); if (NULL == pw) { (void) fprintf (stderr, _("%s: user '%s' does not exist\n"), @@ -957,7 +984,7 @@ int main (int argc, char **argv) #ifdef WITH_SELINUX /* only do this check when getuid()==0 because it's a pre-condition for changing a password without entering the old one */ - if (amroot && (check_selinux_permit ("passwd") != 0)) { + if (amroot && (check_selinux_permit (Prog) != 0)) { SYSLOG ((LOG_ALERT, "root is not authorized by SELinux to change the password of %s", name)); @@ -977,8 +1004,8 @@ int main (int argc, char **argv) _("%s: You may not view or modify password information for %s.\n"), Prog, name); SYSLOG ((LOG_WARN, - "%s: can't view or modify password information for %s", - Prog, name)); + "can't view or modify password information for %s", + name)); closelog (); exit (E_NOPERM); } @@ -987,53 +1014,55 @@ int main (int argc, char **argv) print_status (pw); exit (E_SUCCESS); } -#ifndef USE_PAM - /* - * The user name is valid, so let's get the shadow file entry. - */ - sp = getspnam (name); /* !USE_PAM, no need for xgetspnam */ - if (NULL == sp) { - if (errno == EACCES) { - (void) fprintf (stderr, - _("%s: Permission denied.\n"), - Prog); - exit (E_NOPERM); - } - sp = pwd_to_spwd (pw); - } - - cp = sp->sp_pwdp; - - /* - * If there are no other flags, just change the password. - */ - if (!anyflag) { - STRFCPY (crypt_passwd, cp); - + if (!use_pam) + { /* - * See if the user is permitted to change the password. - * Otherwise, go ahead and set a new password. + * The user name is valid, so let's get the shadow file entry. */ - check_password (pw, sp); + sp = prefix_getspnam (name); /* !use_pam, no need for xprefix_getspnam */ + if (NULL == sp) { + if (errno == EACCES) { + (void) fprintf (stderr, + _("%s: Permission denied.\n"), + Prog); + exit (E_NOPERM); + } + sp = pwd_to_spwd (pw); + } + + cp = sp->sp_pwdp; /* - * Let the user know whose password is being changed. + * If there are no other flags, just change the password. */ - if (!qflg) { - (void) printf (_("Changing password for %s\n"), name); - } + if (!anyflag) { + STRTCPY(crypt_passwd, cp); + + /* + * See if the user is permitted to change the password. + * Otherwise, go ahead and set a new password. + */ + check_password (pw, sp); + + /* + * Let the user know whose password is being changed. + */ + if (!qflg) { + (void) printf (_("Changing password for %s\n"), name); + } - if (new_password (pw) != 0) { - (void) fprintf (stderr, - _("The password for %s is unchanged.\n"), - name); - closelog (); - exit (E_NOPERM); + if (new_password (pw) != 0) { + (void) fprintf (stderr, + _("The password for %s is unchanged.\n"), + name); + closelog (); + exit (E_NOPERM); + } + do_update_pwd = true; + do_update_age = true; } - do_update_pwd = true; - do_update_age = true; } -#endif /* !USE_PAM */ + /* * Before going any further, raise the ulimit to prevent colliding * into a lowered ulimit, and set the real UID to root to protect @@ -1046,8 +1075,17 @@ int main (int argc, char **argv) /* * Don't set the real UID for PAM... */ - if (!anyflag) { - do_pam_passwd (name, qflg, kflg); + if (!anyflag && use_pam) { + if (sflg) { + cp = agetpass_stdin (); + if (cp == NULL) { + exit (E_FAILURE); + } + do_pam_passwd_non_interactive ("passwd", name, cp); + erase_pass (cp); + } else { + do_pam_passwd (name, qflg, kflg); + } exit (E_SUCCESS); } #endif /* USE_PAM */ @@ -1081,4 +1119,3 @@ int main (int argc, char **argv) return E_SUCCESS; } - @@ -47,7 +47,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "pwck"; static bool use_system_pw_file = true; static bool use_system_spw_file = true; @@ -66,7 +66,7 @@ static bool quiet = false; /* don't report warnings, only errors */ /* local function prototypes */ static void fail_exit (int code); -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void process_flags (int argc, char **argv); static void open_files (void); static void close_files (bool changed); @@ -109,7 +109,9 @@ static void fail_exit (int code) /* * usage - print syntax message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; #ifdef WITH_TCB @@ -367,8 +369,8 @@ static void check_pw_file (int *errors, bool *changed) struct commonio_entry *pfe, *tpfe; struct passwd *pwd; const struct spwd *spw; - uid_t min_sys_id = (uid_t) getdef_ulong ("SYS_UID_MIN", 101UL); - uid_t max_sys_id = (uid_t) getdef_ulong ("SYS_UID_MAX", 999UL); + uid_t min_sys_id = getdef_ulong ("SYS_UID_MIN", 101UL); + uid_t max_sys_id = getdef_ulong ("SYS_UID_MAX", 999UL); /* * Loop through the entire password file. @@ -607,7 +609,7 @@ static void check_pw_file (int *errors, bool *changed) sp.sp_inact = -1; sp.sp_expire = -1; sp.sp_flag = SHADOW_SP_FLAG_UNSET; - sp.sp_lstchg = (long) gettime () / SCALE; + sp.sp_lstchg = gettime () / DAY; if (0 == sp.sp_lstchg) { /* Better disable aging than * requiring a password change @@ -812,9 +814,9 @@ static void check_spw_file (int *errors, bool *changed) * Warn if last password change in the future. --marekm */ if (!quiet) { - time_t t = time ((time_t *) 0); + time_t t = time (NULL); if ( (t != 0) - && (spw->sp_lstchg > (long) t / SCALE)) { + && (spw->sp_lstchg > t / DAY)) { printf (_("user %s: last password change in the future\n"), spw->sp_namp); *errors += 1; @@ -831,10 +833,6 @@ int main (int argc, char **argv) int errors = 0; bool changed = false; - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -844,7 +842,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("pwck"); + OPENLOG (Prog); /* Parse the command line arguments */ process_flags (argc, argv); diff --git a/src/pwconv.c b/src/pwconv.c index 21d36e7..7dd327a 100644 --- a/src/pwconv.c +++ b/src/pwconv.c @@ -40,9 +40,11 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <time.h> #include <unistd.h> #include <getopt.h> + #include "defines.h" #include "getdef.h" #include "prototypes.h" @@ -66,7 +68,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "pwconv"; static bool spw_locked = false; static bool pw_locked = false; @@ -153,7 +155,6 @@ int main (int argc, char **argv) const struct spwd *sp; struct spwd spent; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -163,7 +164,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("pwconv"); + OPENLOG (Prog); process_flags (argc, argv); @@ -237,7 +238,7 @@ int main (int argc, char **argv) spent = *sp; } else { /* add new shadow entry */ - memset (&spent, 0, sizeof spent); + bzero(&spent, 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); @@ -247,7 +248,7 @@ int main (int argc, char **argv) spent.sp_flag = SHADOW_SP_FLAG_UNSET; } spent.sp_pwdp = pw->pw_passwd; - spent.sp_lstchg = (long) gettime () / SCALE; + spent.sp_lstchg = gettime () / DAY; if (0 == spent.sp_lstchg) { /* Better disable aging than requiring a password * change */ diff --git a/src/pwunconv.c b/src/pwunconv.c index b862435..fe18113 100644 --- a/src/pwunconv.c +++ b/src/pwunconv.c @@ -18,6 +18,7 @@ #include <unistd.h> #include <getopt.h> #include "defines.h" +#include "getdef.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -30,7 +31,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "pwunconv"; static bool spw_locked = false; static bool pw_locked = false; @@ -114,7 +115,6 @@ int main (int argc, char **argv) struct passwd pwent; const struct spwd *spwd; - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -124,7 +124,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - OPENLOG ("pwunconv"); + OPENLOG (Prog); process_flags (argc, argv); @@ -45,6 +45,10 @@ #include <sys/stat.h> #include <fcntl.h> #endif /* !USE_PAM */ + +#include "alloc.h" +#include "attr.h" +#include "cast.h" #include "prototypes.h" #include "defines.h" #include "pwauth.h" @@ -55,11 +59,14 @@ /*@-exitarg@*/ #include "exitcodes.h" #include "shadowlog.h" +#include "string/sprintf.h" +#include "string/strtcpy.h" + /* * Global variables */ -const char *Prog; +static const char Prog[] = "su"; static /*@observer@*/const char *caller_tty = NULL; /* Name of tty SU is run from */ static bool caller_is_root = false; static uid_t caller_uid; @@ -95,8 +102,8 @@ static pid_t pid_child = 0; * External identifiers */ -extern char **newenvp; /* libmisc/env.c */ -extern size_t newenvc; /* libmisc/env.c */ +extern char **newenvp; /* lib/env.c */ +extern size_t newenvc; /* lib/env.c */ /* local function prototypes */ @@ -104,15 +111,16 @@ static void execve_shell (const char *shellname, char *args[], char *const envp[]); #ifdef USE_PAM -static void kill_child (int unused(s)); +static void kill_child (MAYBE_UNUSED int s); static void prepare_pam_close_session (void); #else /* !USE_PAM */ static void die (int); static bool iswheel (const char *); #endif /* !USE_PAM */ static bool restricted_shell (const char *shellname); -static /*@noreturn@*/void su_failure (const char *tty, bool su_to_root); +NORETURN static void su_failure (const char *tty, bool su_to_root); static /*@only@*/struct passwd * check_perms (void); +static /*@only@*/struct passwd * do_check_perms (void); #ifdef USE_PAM static void check_perms_pam (const struct passwd *pw); #else /* !USE_PAM */ @@ -157,13 +165,13 @@ static bool iswheel (const char *username) return is_on_list (grp->gr_mem, username); } #else /* USE_PAM */ -static void kill_child (int unused(s)) +static void kill_child (MAYBE_UNUSED int s) { if (0 != pid_child) { (void) kill (-pid_child, SIGKILL); - (void) write (STDERR_FILENO, kill_msg, strlen (kill_msg)); + (void) write_full(STDERR_FILENO, kill_msg, strlen(kill_msg)); } else { - (void) write (STDERR_FILENO, wait_msg, strlen (wait_msg)); + (void) write_full(STDERR_FILENO, wait_msg, strlen(wait_msg)); } _exit (255); } @@ -185,10 +193,11 @@ static bool restricted_shell (const char *shellname) return true; } -static /*@noreturn@*/void su_failure (const char *tty, bool su_to_root) +NORETURN +static void +su_failure (const char *tty, bool su_to_root) { sulog (tty, false, caller_name, name); /* log failed attempt */ -#ifdef USE_SYSLOG if (getdef_bool ("SYSLOG_SU_ENAB")) { SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO, "- %s %s:%s", tty, @@ -196,7 +205,6 @@ static /*@noreturn@*/void su_failure (const char *tty, bool su_to_root) ('\0' != name[0]) ? name : "???")); } closelog (); -#endif #ifdef WITH_AUDIT audit_fd = audit_open (); @@ -225,7 +233,7 @@ static void execve_shell (const char *shellname, char *const envp[]) { int err; - (void) execve (shellname, (char **) args, envp); + (void) execve (shellname, args, envp); err = errno; if (access (shellname, R_OK|X_OK) == 0) { @@ -238,7 +246,7 @@ static void execve_shell (const char *shellname, while (NULL != args[n_args]) { n_args++; } - targs = (char **) xmalloc ((n_args + 3) * sizeof (args[0])); + targs = XMALLOC(n_args + 3, char *); targs[0] = "sh"; targs[1] = "-"; targs[2] = xstrdup (shellname); @@ -382,8 +390,8 @@ static void prepare_pam_close_session (void) stderr); (void) kill (-pid_child, caught); - snprintf (kill_msg, sizeof kill_msg, _(" ...killed.\n")); - snprintf (wait_msg, sizeof wait_msg, _(" ...waiting for child to terminate.\n")); + SNPRINTF(kill_msg, _(" ...killed.\n")); + SNPRINTF(wait_msg, _(" ...waiting for child to terminate.\n")); /* Any signals other than SIGCHLD and SIGALRM will no longer have any effect, * so it's time to block all of them. */ @@ -430,6 +438,7 @@ static void prepare_pam_close_session (void) /* * usage - print command line syntax and exit */ +NORETURN static void usage (int status) { (void) @@ -501,7 +510,8 @@ static void check_perms_nopam (const struct passwd *pw) } if (strcmp (pw->pw_passwd, "") == 0) { - char *prevent_no_auth = getdef_str("PREVENT_NO_AUTH"); + const char *prevent_no_auth = getdef_str("PREVENT_NO_AUTH"); + if (prevent_no_auth == NULL) { prevent_no_auth = "superuser"; } @@ -577,7 +587,7 @@ static void check_perms_nopam (const struct passwd *pw) * The first character of an administrator defined method is an '@' * character. */ - if (pw_auth (password, name, PW_SU, (char *) 0) != 0) { + if (pw_auth (password, name, PW_SU, NULL) != 0) { SYSLOG (((pw->pw_uid != 0)? LOG_NOTICE : LOG_WARN, "Authentication failed for %s", name)); fprintf(stderr, _("%s: Authentication failure\n"), Prog); @@ -600,7 +610,7 @@ static void check_perms_nopam (const struct passwd *pw) * there is a "SU" entry in the /etc/porttime file denying access to * the account. */ - if (!isttytime (name, "SU", time ((time_t *) 0))) { + if (!isttytime (name, "SU", time (NULL))) { SYSLOG (((0 != pw->pw_uid) ? LOG_WARN : LOG_CRIT, "SU by %s to restricted account %s", caller_name, name)); @@ -615,14 +625,30 @@ static void check_perms_nopam (const struct passwd *pw) /* * check_perms - check permissions to switch to the user 'name' * - * In case of subsystem login, the user is first authenticated in the - * caller's root subsystem, and then in the user's target subsystem. + * The user is authenticated in all subsystems iterately. */ static /*@only@*/struct passwd * check_perms (void) { + struct passwd *pw = NULL; + + while (pw == NULL) + pw = do_check_perms(); + return pw; +} + +/* + * do_check_perms - check permissions to switch to the user 'name' + * + * The user is authenticated in current subsystem, if any. Returns + * NULL if permissions have to be checked in next subsystem, in + * which case the subsystem has already been entered. + */ +static /*@only@*/struct passwd * do_check_perms (void) +{ #ifdef USE_PAM - const char *tmp_name; - int ret; + int ret; + const char *tmp_name; + const void *item; #endif /* !USE_PAM */ /* * The password file entries for the user is gotten and the account @@ -642,7 +668,7 @@ static /*@only@*/struct passwd * check_perms (void) #ifdef USE_PAM check_perms_pam (pw); /* PAM authentication can request a change of account */ - ret = pam_get_item(pamh, PAM_USER, (const void **) &tmp_name); + ret = pam_get_item(pamh, PAM_USER, &item); if (ret != PAM_SUCCESS) { SYSLOG((LOG_ERR, "pam_get_item: internal PAM error\n")); (void) fprintf (stderr, @@ -651,12 +677,18 @@ static /*@only@*/struct passwd * check_perms (void) (void) pam_end (pamh, ret); su_failure (caller_tty, 0 == pw->pw_uid); } + tmp_name = item; if (strcmp (name, tmp_name) != 0) { SYSLOG ((LOG_INFO, "Change user from '%s' to '%s' as requested by PAM", name, tmp_name)); - strncpy (name, tmp_name, sizeof(name) - 1); - name[sizeof(name) - 1] = '\0'; + if (STRTCPY(name, tmp_name) == -1) { + fprintf (stderr, _("Overlong user name '%s'\n"), + tmp_name); + SYSLOG ((LOG_NOTICE, "Overlong user name '%s'", + tmp_name)); + su_failure (caller_tty, true); + } pw = xgetpwnam (name); if (NULL == pw) { (void) fprintf (stderr, @@ -684,7 +716,7 @@ static /*@only@*/struct passwd * check_perms (void) endpwent (); /* close the old password databases */ endspent (); pw_free (pw); - return check_perms (); /* authenticate in the subsystem */ + return NULL; /* authenticate in the subsystem */ } return pw; @@ -706,11 +738,6 @@ static void save_caller_context (char **argv) const char *password = NULL; #endif /* SU_ACCESS */ #endif /* !USE_PAM */ - /* - * Get the program name. The program name is used as a prefix to - * most error messages. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -752,7 +779,7 @@ static void save_caller_context (char **argv) (unsigned long) caller_uid)); su_failure (caller_tty, true); /* unknown target UID*/ } - STRFCPY (caller_name, pw->pw_name); + STRTCPY(caller_name, pw->pw_name); #ifndef USE_PAM #ifdef SU_ACCESS @@ -808,7 +835,7 @@ static void process_flags (int argc, char **argv) case 'm': case 'p': /* This will only have an effect if the target - * user do not have a restricted shell, or if + * user does not have a restricted shell, or if * su is called by root. */ change_environment = false; @@ -827,7 +854,7 @@ static void process_flags (int argc, char **argv) } if (optind < argc) { - STRFCPY (name, argv[optind++]); /* use this login id */ + STRTCPY(name, argv[optind++]); /* use this login id */ } if ('\0' == name[0]) { /* use default user */ struct passwd *root_pw = getpwnam ("root"); @@ -980,20 +1007,22 @@ int main (int argc, char **argv) int ret; #endif /* USE_PAM */ + check_fds (); + (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); save_caller_context (argv); - OPENLOG ("su"); + OPENLOG (Prog); process_flags (argc, argv); initenv (); #ifdef USE_PAM - ret = pam_start ("su", name, &conv, &pamh); + ret = pam_start (Prog, name, &conv, &pamh); if (PAM_SUCCESS != ret) { SYSLOG ((LOG_ERR, "pam_start: error %d", ret); fprintf (stderr, @@ -1002,9 +1031,9 @@ int main (int argc, char **argv) exit (1); } - ret = pam_set_item (pamh, PAM_TTY, (const void *) caller_tty); + ret = pam_set_item (pamh, PAM_TTY, caller_tty); if (PAM_SUCCESS == ret) { - ret = pam_set_item (pamh, PAM_RUSER, (const void *) caller_name); + ret = pam_set_item (pamh, PAM_RUSER, caller_name); } if (PAM_SUCCESS != ret) { SYSLOG ((LOG_ERR, "pam_set_item: %s", @@ -1017,7 +1046,7 @@ int main (int argc, char **argv) pw = check_perms (); - /* If the user do not want to change the environment, + /* If the user does not want to change the environment, * use the current SHELL. * (unless another shell is required by the command line) */ @@ -1050,13 +1079,11 @@ int main (int argc, char **argv) } sulog (caller_tty, true, caller_name, name); /* save SU information */ -#ifdef USE_SYSLOG if (getdef_bool ("SYSLOG_SU_ENAB")) { SYSLOG ((LOG_INFO, "+ %s %s:%s", caller_tty, ('\0' != caller_name[0]) ? caller_name : "???", ('\0' != name[0]) ? name : "???")); } -#endif #ifdef USE_PAM /* set primary group id and supplementary groups */ @@ -1135,7 +1162,7 @@ int main (int argc, char **argv) int fd = open ("/dev/tty", O_RDWR); if (fd >= 0) { - err = ioctl (fd, TIOCNOTTY, (char *) 0); + err = ioctl (fd, TIOCNOTTY, (char *) NULL); (void) close (fd); } else if (ENXIO == errno) { /* There are no controlling terminal already */ @@ -1178,7 +1205,7 @@ int main (int argc, char **argv) cp = Basename (shellstr); } - arg0 = xmalloc (strlen (cp) + 2); + arg0 = XMALLOC(strlen(cp) + 2, char); arg0[0] = '-'; strcpy (arg0 + 1, cp); cp = arg0; @@ -1199,7 +1226,7 @@ int main (int argc, char **argv) * Use the shell and create an argv * with the rest of the command line included. */ - argv[-1] = cp; + argv[-1] = const_cast(char *, cp); execve_shell (shellstr, &argv[-1], environ); err = errno; (void) fprintf (stderr, diff --git a/src/suauth.c b/src/suauth.c index 2641d33..4d63190 100644 --- a/src/suauth.c +++ b/src/suauth.c @@ -68,8 +68,9 @@ int check_su_auth (const char *actual_id, while (fgets (temp, sizeof (temp), authfile_fd) != NULL) { lines++; + endline = strlen(temp) - 1; - if (temp[endline = strlen (temp) - 1] != '\n') { + if (temp[0] == '\0' || temp[endline] != '\n') { SYSLOG ((LOG_ERR, "%s, line %d: line too long or missing newline", SUAUTHFILE, lines)); @@ -91,9 +92,9 @@ int check_su_auth (const char *actual_id, continue; } if (!(to_users = strtok (temp + posn, field)) - || !(from_users = strtok ((char *) NULL, field)) - || !(action = strtok ((char *) NULL, field)) - || strtok ((char *) NULL, field)) { + || !(from_users = strtok (NULL, field)) + || !(action = strtok (NULL, field)) + || strtok (NULL, field)) { SYSLOG ((LOG_ERR, "%s, line %d. Bad number of fields.\n", SUAUTHFILE, lines)); diff --git a/src/sulogin.c b/src/sulogin.c index 2c5e094..2097174 100644 --- a/src/sulogin.c +++ b/src/sulogin.c @@ -16,6 +16,11 @@ #include <signal.h> #include <stdio.h> #include <sys/ioctl.h> +#include <sys/types.h> + +#include "agetpass.h" +#include "alloc.h" +#include "attr.h" #include "defines.h" #include "getdef.h" #include "prototypes.h" @@ -24,113 +29,76 @@ #include "exitcodes.h" #include "shadowlog.h" + /* * Global variables */ -const char *Prog; - -static char name[BUFSIZ]; -static char pass[BUFSIZ]; +static const char Prog[] = "sulogin"; -static struct passwd pwent; extern char **newenvp; -extern size_t newenvc; - -extern char **environ; #ifndef ALARM #define ALARM 60 #endif -/* local function prototypes */ + static void catch_signals (int); +static int pw_entry(const char *name, struct passwd *pwent); -static void catch_signals (unused int sig) + +static void catch_signals (MAYBE_UNUSED 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) +int +main(int argc, char *argv[]) { + int err = 0; + char **envp = environ; + TERMIO termio; + struct passwd pwent = {}; + bool done; #ifndef USE_PAM - const char *env; -#endif /* !USE_PAM */ - char **envp = environ; - TERMIO termio; - int err = 0; - -#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); + const char *env; #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 - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); -#ifdef USE_SYSLOG - OPENLOG ("sulogin"); -#endif - initenv (); + 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); - } + close(0); + close(1); + close(2); + + if (open(argv[1], O_RDWR) == -1) + exit(1); + dup(0); + dup(0); } if (access (PASSWD_FILE, F_OK) == -1) { /* must be a password file! */ (void) puts (_("No password file")); -#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) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) { -#ifdef USE_SYSLOG - closelog (); -#endif exit (1); /* must be a terminal */ } /* If we were init, we need to start a new session */ @@ -156,24 +124,17 @@ static void catch_signals (unused int sig) } #endif /* !USE_PAM */ - (void) strcpy (name, "root"); /* KLUDGE!!! */ - (void) signal (SIGALRM, catch_signals); /* exit if the timer expires */ (void) alarm (ALARM); /* only wait so long ... */ - while (true) { /* repeatedly get login/password pairs */ - char *cp; - pw_entry (name, &pwent); /* get entry from password file */ - if (pwent.pw_name == (char *) 0) { + do { /* repeatedly get login/password pairs */ + char *pass; + if (pw_entry("root", &pwent) == -1) { /* get entry from password file */ /* * Fail secure */ - (void) puts (_("No password entry for 'root'")); -#ifdef USE_SYSLOG - SYSLOG (LOG_WARN, "No password entry for 'root'\n"); - closelog (); -#endif - exit (1); + (void) puts(_("No password entry for 'root'")); + exit(1); } /* @@ -182,7 +143,7 @@ static void catch_signals (unused int sig) */ /* get a password for root */ - cp = getpass (_( + pass = agetpass (_( "\n" "Type control-d to proceed with normal startup,\n" "(or give root password for system maintenance):")); @@ -192,46 +153,65 @@ static void catch_signals (unused int sig) * it will work with standard getpass() (no NULL on EOF). * --marekm */ - if ((NULL == cp) || ('\0' == *cp)) { -#ifdef USE_SYSLOG - SYSLOG (LOG_INFO, "Normal startup\n"); - closelog (); -#endif + if ((NULL == pass) || ('\0' == *pass)) { + erase_pass (pass); (void) puts (""); #ifdef TELINIT - execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) 0); + execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) NULL); #endif exit (0); - } else { - STRFCPY (pass, cp); - strzero (cp); - } - if (valid (pass, &pwent)) { /* check encrypted passwords ... */ - break; /* ... encrypted passwords matched */ } -#ifdef USE_SYSLOG - SYSLOG (LOG_WARN, "Incorrect root password\n"); -#endif - sleep (2); - (void) puts (_("Login incorrect")); - } - memzero (pass, sizeof pass); + done = valid(pass, &pwent); + erase_pass (pass); + + if (!done) { /* check encrypted passwords ... */ + /* ... encrypted passwords did not match */ + sleep (2); + (void) puts (_("Login incorrect")); + } + } while (!done); (void) alarm (0); (void) signal (SIGALRM, SIG_DFL); environ = newenvp; /* make new environment active */ (void) puts (_("Entering System Maintenance Mode")); -#ifdef USE_SYSLOG - SYSLOG (LOG_INFO, "System Maintenance Mode\n"); -#endif -#ifdef USE_SYSLOG - closelog (); -#endif /* exec the shell finally. */ - err = shell (pwent.pw_shell, (char *) 0, environ); + err = shell (pwent.pw_shell, NULL, environ); return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); } + +static int +pw_entry(const char *name, struct passwd *pwent) +{ + struct spwd *spwd; + struct passwd *passwd; + + if (!(passwd = getpwnam(name))) /* local, no need for xgetpwnam */ + return -1; + + free(pwent->pw_name); + pwent->pw_name = xstrdup(passwd->pw_name); + pwent->pw_uid = passwd->pw_uid; + pwent->pw_gid = passwd->pw_gid; + free(pwent->pw_gecos); + pwent->pw_gecos = xstrdup(passwd->pw_gecos); + free(pwent->pw_dir); + pwent->pw_dir = xstrdup(passwd->pw_dir); + free(pwent->pw_shell); + pwent->pw_shell = xstrdup(passwd->pw_shell); +#if !defined(AUTOSHADOW) + /* local, no need for xgetspnam */ + if ((spwd = getspnam(name))) { + free(pwent->pw_passwd); + pwent->pw_passwd = xstrdup(spwd->sp_pwdp); + return 0; + } +#endif + free(pwent->pw_passwd); + pwent->pw_passwd = xstrdup(passwd->pw_passwd); + return 0; +} diff --git a/src/useradd.c b/src/useradd.c index 7ea0a9c..347334a 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -17,9 +17,12 @@ #include <fcntl.h> #include <getopt.h> #include <grp.h> +#ifdef ENABLE_LASTLOG #include <lastlog.h> +#endif /* ENABLE_LASTLOG */ #include <libgen.h> #include <pwd.h> +#include <signal.h> #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM #include "pam_defs.h" @@ -32,11 +35,15 @@ #include <sys/wait.h> #include <time.h> #include <unistd.h> + +#include "alloc.h" +#include "atoi/str2i.h" #include "chkname.h" #include "defines.h" #include "faillog.h" #include "getdef.h" #include "groupio.h" +#include "memzero.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -57,10 +64,15 @@ #include "tcbfuncs.h" #endif #include "shadowlog.h" +#include "string/sprintf.h" + #ifndef SKEL_DIR #define SKEL_DIR "/etc/skel" #endif +#ifndef USRSKELDIR +#define USRSKELDIR "/usr/etc/skel" +#endif #ifndef USER_DEFAULTS_FILE #define USER_DEFAULTS_FILE "/etc/default/useradd" #define NEW_USER_FILE "/etc/default/nuaddXXXXXX" @@ -74,16 +86,18 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "useradd"; /* * These defaults are used if there is no defaults file. */ static gid_t def_group = 1000; +static const char *def_groups = ""; static const char *def_gname = "other"; static const char *def_home = "/home"; static const char *def_shell = "/bin/bash"; static const char *def_template = SKEL_DIR; +static const char *def_usrtemplate = USRSKELDIR; static const char *def_create_mail_spool = "yes"; static const char *def_log_init = "yes"; @@ -106,6 +120,7 @@ static const char *prefix_user_home = NULL; #ifdef WITH_SELINUX static /*@notnull@*/const char *user_selinux = ""; +static const char *user_selinux_range = NULL; #endif /* WITH_SELINUX */ static long user_expire = -1; @@ -183,25 +198,26 @@ static bool home_added = false; #endif /* ENABLE_SUBIDS */ #define DGROUP "GROUP=" +#define DGROUPS "GROUPS=" #define DHOME "HOME=" #define DSHELL "SHELL=" #define DINACT "INACTIVE=" #define DEXPIRE "EXPIRE=" #define DSKEL "SKEL=" +#define DUSRSKEL "USRSKEL=" #define DCREATE_MAIL_SPOOL "CREATE_MAIL_SPOOL=" #define DLOG_INIT "LOG_INIT=" /* local function prototypes */ -static void fail_exit (int); +NORETURN static void fail_exit (int); static void get_defaults (void); static void show_defaults (void); static int set_defaults (void); static int get_groups (char *); static struct group * get_local_group (char * grp_name); -static void usage (int status); +NORETURN static void usage (int status); static void new_pwent (struct passwd *); -static long scale_age (long); static void new_spent (struct spwd *); static void grp_update (void); @@ -213,118 +229,97 @@ static void open_files (void); static void open_group_files (void); static void open_shadow (void); static void faillog_reset (uid_t); +#ifdef ENABLE_LASTLOG static void lastlog_reset (uid_t); +#endif /* ENABLE_LASTLOG */ static void tallylog_reset (const char *); static void usr_update (unsigned long subuid_count, unsigned long subgid_count); static void create_home (void); static void create_mail (void); static void check_uid_range(int rflg, uid_t user_id); +static FILE *fmkstemp(char *template); + + /* * fail_exit - undo as much as possible */ static void fail_exit (int code) { - if (home_added) { - if (rmdir (prefix_user_home) != 0) { - fprintf (stderr, - _("%s: %s was created, but could not be removed\n"), - Prog, prefix_user_home); - SYSLOG ((LOG_ERR, "failed to remove %s", prefix_user_home)); - } + if (home_added && rmdir(prefix_user_home) != 0) { + fprintf(stderr, + _("%s: %s was created, but could not be removed\n"), + Prog, prefix_user_home); + SYSLOG((LOG_ERR, "failed to remove %s", prefix_user_home)); } - if (spw_locked) { - if (spw_unlock () == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); - SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); + if (spw_locked && spw_unlock() == 0) { + fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname()); + SYSLOG((LOG_ERR, "failed to unlock %s", spw_dbname())); #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "unlocking shadow file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); + audit_logger(AUDIT_ADD_USER, Prog, "unlocking shadow file", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif - /* continue */ - } + /* continue */ } - if (pw_locked) { - if (pw_unlock () == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); - SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); + if (pw_locked && pw_unlock() == 0) { + fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname()); + SYSLOG((LOG_ERR, "failed to unlock %s", pw_dbname())); #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "unlocking passwd file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); + audit_logger(AUDIT_ADD_USER, Prog, "unlocking passwd file", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif - /* continue */ - } + /* continue */ } - if (gr_locked) { - if (gr_unlock () == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); - SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); + if (gr_locked && gr_unlock() == 0) { + fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname()); + SYSLOG((LOG_ERR, "failed to unlock %s", gr_dbname())); #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "unlocking group file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); + audit_logger(AUDIT_ADD_USER, Prog, "unlocking group file", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif - /* continue */ - } + /* continue */ } -#ifdef SHADOWGRP - if (sgr_locked) { - if (sgr_unlock () == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); - SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); -#ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "unlocking gshadow file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); -#endif - /* continue */ - } +#ifdef SHADOWGRP + if (sgr_locked && sgr_unlock() == 0) { + fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname()); + SYSLOG((LOG_ERR, "failed to unlock %s", sgr_dbname())); +# ifdef WITH_AUDIT + audit_logger(AUDIT_ADD_USER, Prog, "unlocking gshadow file", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); +# endif + /* continue */ } #endif #ifdef ENABLE_SUBIDS - if (sub_uid_locked) { - if (sub_uid_unlock () == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ()); - SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ())); -#ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "unlocking subordinate user file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); -#endif - /* continue */ - } + if (sub_uid_locked && sub_uid_unlock() == 0) { + fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname()); + SYSLOG((LOG_ERR, "failed to unlock %s", sub_uid_dbname())); +# ifdef WITH_AUDIT + audit_logger(AUDIT_ADD_USER, Prog, + "unlocking subordinate user file", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); +# endif + /* continue */ } - if (sub_gid_locked) { - if (sub_gid_unlock () == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ()); - SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ())); -#ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "unlocking subordinate group file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); -#endif - /* continue */ - } + if (sub_gid_locked && sub_gid_unlock() == 0) { + fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname()); + SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname())); +# ifdef WITH_AUDIT + audit_logger(AUDIT_ADD_USER, Prog, + "unlocking subordinate group file", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); +# endif + /* continue */ } -#endif /* ENABLE_SUBIDS */ +#endif /* ENABLE_SUBIDS */ #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "adding user", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); + audit_logger(AUDIT_ADD_USER, Prog, "adding user", + user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif - SYSLOG ((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code)); - exit (code); + SYSLOG((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code)); + exit(code); } #define MATCH(x,y) (strncmp((x),(y),strlen(y)) == 0) @@ -338,21 +333,15 @@ static void fail_exit (int code) */ static void get_defaults (void) { - FILE *fp; - char *default_file = USER_DEFAULTS_FILE; - char buf[1024]; - char *cp; + FILE *fp; + char *default_file = USER_DEFAULTS_FILE; + char buf[1024]; + char *cp; + const char *ccp; if (prefix[0]) { - size_t len; - int wlen; - - len = strlen(prefix) + strlen(USER_DEFAULTS_FILE) + 2; - default_file = malloc(len); - if (default_file == NULL) - return; - wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE); - assert (wlen == (int) len -1); + if (asprintf(&default_file, "%s/%s", prefix, USER_DEFAULTS_FILE) == -1) + return; } /* @@ -368,7 +357,7 @@ static void get_defaults (void) * Read the file a line at a time. Only the lines that have relevant * values are used, everything else can be ignored. */ - while (fgets (buf, (int) sizeof buf, fp) == buf) { + while (fgets (buf, sizeof buf, fp) == buf) { cp = strrchr (buf, '\n'); if (NULL != cp) { *cp = '\0'; @@ -399,29 +388,42 @@ static void get_defaults (void) } } + ccp = cp; + + if (MATCH (buf, DGROUPS)) { + if (get_groups (cp) != 0) { + fprintf (stderr, + _("%s: the '%s' configuration in %s has an invalid group, ignoring the bad group\n"), + Prog, DGROUPS, default_file); + } + if (user_groups[0] != NULL) { + do_grp_update = true; + def_groups = xstrdup (cp); + } + } /* * Default HOME filesystem */ else if (MATCH (buf, DHOME)) { - def_home = xstrdup (cp); + def_home = xstrdup(ccp); } /* * Default Login Shell command */ else if (MATCH (buf, DSHELL)) { - def_shell = xstrdup (cp); + def_shell = xstrdup(ccp); } /* * Default Password Inactive value */ else if (MATCH (buf, DINACT)) { - if ( (getlong (cp, &def_inactive) == 0) + if ( (str2sl(&def_inactive, ccp) == -1) || (def_inactive < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), - Prog, cp); + Prog, ccp); fprintf (stderr, _("%s: the %s configuration in %s will be ignored\n"), Prog, DINACT, default_file); @@ -433,52 +435,60 @@ static void get_defaults (void) * Default account expiration date */ else if (MATCH (buf, DEXPIRE)) { - def_expire = xstrdup (cp); + def_expire = xstrdup(ccp); } /* * Default Skeleton information */ else if (MATCH (buf, DSKEL)) { - if ('\0' == *cp) { - cp = SKEL_DIR; /* XXX warning: const */ - } + if ('\0' == *ccp) + ccp = SKEL_DIR; if (prefix[0]) { - size_t len; - int wlen; - char* _def_template; /* avoid const warning */ - - len = strlen(prefix) + strlen(cp) + 2; - _def_template = xmalloc(len); - wlen = snprintf(_def_template, len, "%s/%s", prefix, cp); - assert (wlen == (int) len -1); - def_template = _def_template; - } - else { - def_template = xstrdup (cp); + char *dt; + + xasprintf(&dt, "%s/%s", prefix, ccp); + def_template = dt; + } else { + def_template = xstrdup(ccp); } } /* + * Default Usr Skeleton information + */ + else if (MATCH (buf, DUSRSKEL)) { + if ('\0' == *ccp) + ccp = USRSKELDIR; + + if (prefix[0]) { + char *dut; + + xasprintf(&dut, "%s/%s", prefix, ccp); + def_usrtemplate = dut; + } else { + def_usrtemplate = xstrdup(ccp); + } + } + /* * Create by default user mail spool or not ? */ else if (MATCH (buf, DCREATE_MAIL_SPOOL)) { - if (*cp == '\0') { - cp = "no"; /* XXX warning: const */ - } + if (*ccp == '\0') + ccp = "no"; - def_create_mail_spool = xstrdup (cp); + def_create_mail_spool = xstrdup(ccp); } /* * By default do we add the user to the lastlog and faillog databases ? */ else if (MATCH (buf, DLOG_INIT)) { - if (*cp == '\0') { - cp = def_log_init; /* XXX warning: const */ - } - def_log_init = xstrdup (cp); + if (*ccp == '\0') + ccp = def_log_init; + + def_log_init = xstrdup(ccp); } } (void) fclose (fp); @@ -497,11 +507,13 @@ static void get_defaults (void) static void show_defaults (void) { printf ("GROUP=%u\n", (unsigned int) def_group); + printf ("GROUPS=%s\n", def_groups); printf ("HOME=%s\n", def_home); printf ("INACTIVE=%ld\n", def_inactive); printf ("EXPIRE=%s\n", def_expire); printf ("SHELL=%s\n", def_shell); printf ("SKEL=%s\n", def_template); + printf ("USRSKEL=%s\n", def_usrtemplate); printf ("CREATE_MAIL_SPOOL=%s\n", def_create_mail_spool); printf ("LOG_INIT=%s\n", def_log_init); } @@ -515,49 +527,41 @@ static void show_defaults (void) */ static int set_defaults (void) { - FILE *ifp; - FILE *ofp; - char buf[1024]; - char *new_file = NULL; - char *new_file_dup = NULL; - char *default_file = USER_DEFAULTS_FILE; - char *cp; - int ofd; - int wlen; - bool out_group = false; - bool out_home = false; - bool out_inactive = false; - bool out_expire = false; - bool out_shell = false; - bool out_skel = false; - bool out_create_mail_spool = false; - bool out_log_init = false; - size_t len; - int ret = -1; - - - len = strlen(prefix) + strlen(NEW_USER_FILE) + 2; - new_file = malloc(len); - if (new_file == NULL) { - fprintf (stderr, - _("%s: cannot create new defaults file: %s\n"), - Prog, strerror(errno)); + int ret = -1; + bool out_group = false; + bool out_groups = false; + bool out_home = false; + bool out_inactive = false; + bool out_expire = false; + bool out_shell = false; + bool out_skel = false; + bool out_usrskel = false; + bool out_create_mail_spool = false; + bool out_log_init = false; + char buf[1024]; + char *new_file = NULL; + char *new_file_dup = NULL; + char *default_file = USER_DEFAULTS_FILE; + char *cp; + FILE *ifp; + FILE *ofp; + + + if (asprintf(&new_file, "%s%s%s", prefix, prefix[0]?"/":"", NEW_USER_FILE) == -1) + { + fprintf(stderr, _("%s: cannot create new defaults file: %s\n"), + Prog, strerror(errno)); return -1; } - wlen = snprintf(new_file, len, "%s%s%s", prefix, prefix[0]?"/":"", NEW_USER_FILE); - assert (wlen <= (int) len -1); if (prefix[0]) { - len = strlen(prefix) + strlen(USER_DEFAULTS_FILE) + 2; - default_file = malloc(len); - if (default_file == NULL) { - fprintf (stderr, - _("%s: cannot create new defaults file: %s\n"), - Prog, strerror(errno)); - goto setdef_err; + if (asprintf(&default_file, "%s/%s", prefix, USER_DEFAULTS_FILE) == -1) + { + fprintf(stderr, + _("%s: cannot create new defaults file: %s\n"), + Prog, strerror(errno)); + goto err_free_new; } - wlen = snprintf(default_file, len, "%s/%s", prefix, USER_DEFAULTS_FILE); - assert (wlen == (int) len -1); } new_file_dup = strdup(new_file); @@ -565,36 +569,27 @@ static int set_defaults (void) fprintf (stderr, _("%s: cannot create directory for defaults file\n"), Prog); - goto setdef_err; + goto err_free_def; } ret = mkdir(dirname(new_file_dup), 0755); + free(new_file_dup); if (-1 == ret && EEXIST != errno) { fprintf (stderr, _("%s: cannot create directory for defaults file\n"), Prog); - free(new_file_dup); - goto setdef_err; + goto err_free_def; } - free(new_file_dup); /* * Create a temporary file to copy the new output to. */ - ofd = mkstemp (new_file); - if (-1 == ofd) { - fprintf (stderr, - _("%s: cannot create new defaults file\n"), - Prog); - goto setdef_err; - } - - ofp = fdopen (ofd, "w"); + ofp = fmkstemp(new_file); if (NULL == ofp) { fprintf (stderr, _("%s: cannot open new defaults file\n"), Prog); - goto setdef_err; + goto err_free_def; } /* @@ -608,7 +603,7 @@ static int set_defaults (void) goto skip; } - while (fgets (buf, (int) sizeof buf, ifp) == buf) { + while (fgets (buf, sizeof buf, ifp) == buf) { cp = strrchr (buf, '\n'); if (NULL != cp) { *cp = '\0'; @@ -620,14 +615,18 @@ static int set_defaults (void) fprintf (stderr, _("%s: line too long in %s: %s..."), Prog, default_file, buf); - (void) fclose (ifp); - goto setdef_err; + fclose(ifp); + fclose(ofp); + goto err_free_def; } } if (!out_group && MATCH (buf, DGROUP)) { fprintf (ofp, DGROUP "%u\n", (unsigned int) def_group); out_group = true; + } else if (!out_groups && MATCH (buf, DGROUPS)) { + fprintf (ofp, DGROUPS "%s\n", def_groups); + out_groups = true; } else if (!out_home && MATCH (buf, DHOME)) { fprintf (ofp, DHOME "%s\n", def_home); out_home = true; @@ -643,6 +642,9 @@ static int set_defaults (void) } else if (!out_skel && MATCH (buf, DSKEL)) { fprintf (ofp, DSKEL "%s\n", def_template); out_skel = true; + } else if (!out_usrskel && MATCH (buf, DUSRSKEL)) { + fprintf (ofp, DUSRSKEL "%s\n", def_usrtemplate); + out_usrskel = true; } else if (!out_create_mail_spool && MATCH (buf, DCREATE_MAIL_SPOOL)) { fprintf (ofp, @@ -668,6 +670,8 @@ static int set_defaults (void) */ if (!out_group) fprintf (ofp, DGROUP "%u\n", (unsigned int) def_group); + if (!out_groups) + fprintf (ofp, DGROUPS "%s\n", def_groups); if (!out_home) fprintf (ofp, DHOME "%s\n", def_home); if (!out_inactive) @@ -678,6 +682,8 @@ static int set_defaults (void) fprintf (ofp, DSHELL "%s\n", def_shell); if (!out_skel) fprintf (ofp, DSKEL "%s\n", def_template); + if (!out_usrskel) + fprintf (ofp, DUSRSKEL "%s\n", def_usrtemplate); if (!out_create_mail_spool) fprintf (ofp, DCREATE_MAIL_SPOOL "%s\n", def_create_mail_spool); @@ -690,16 +696,16 @@ static int set_defaults (void) (void) fflush (ofp); if ( (ferror (ofp) != 0) || (fsync (fileno (ofp)) != 0) - || (fclose (ofp) != 0)) { + || (fclose (ofp) != 0)) + { unlink (new_file); - goto setdef_err; + goto err_free_def; } /* * Rename the current default file to its backup name. */ - wlen = snprintf (buf, sizeof buf, "%s-", default_file); - assert (wlen < (int) sizeof buf); + assert(SNPRINTF(buf, "%s-", default_file) != -1); unlink (buf); if ((link (default_file, buf) != 0) && (ENOENT != errno)) { int err = errno; @@ -707,7 +713,7 @@ static int set_defaults (void) _("%s: Cannot create backup file (%s): %s\n"), Prog, buf, strerror (err)); unlink (new_file); - goto setdef_err; + goto err_free_def; } /* @@ -718,7 +724,7 @@ static int set_defaults (void) fprintf (stderr, _("%s: rename: %s: %s\n"), Prog, new_file, strerror (err)); - goto setdef_err; + goto err_free_def; } #ifdef WITH_AUDIT audit_logger (AUDIT_USYS_CONFIG, Prog, @@ -733,11 +739,12 @@ static int set_defaults (void) def_inactive, def_expire, def_template, def_create_mail_spool, def_log_init)); ret = 0; - setdef_err: - free(new_file); - if (prefix[0]) { + +err_free_def: + if (prefix[0]) free(default_file); - } +err_free_new: + free(new_file); return ret; } @@ -807,20 +814,6 @@ static int get_groups (char *list) continue; } -#ifdef USE_NIS - /* - * Don't add this group if they are an NIS group. Tell - * the user to go to the server for this group. - */ - if (__isgrNIS ()) { - fprintf (stderr, - _("%s: group '%s' is a NIS group.\n"), - Prog, grp->gr_name); - gr_free(grp); - continue; - } -#endif - if (ngroups == sys_ngroups) { fprintf (stderr, _("%s: too many groups specified (max %d).\n"), @@ -839,7 +832,7 @@ static int get_groups (char *list) close_group_files (); unlock_group_files (); - user_groups[ngroups] = (char *) 0; + user_groups[ngroups] = NULL; /* * Any errors in finding group names are fatal @@ -860,17 +853,17 @@ static int get_groups (char *list) */ static struct group * get_local_group(char * grp_name) { + char *end; const struct group *grp; struct group *result_grp = NULL; - long long int gid; - char *endptr; + long long gid; - gid = strtoll (grp_name, &endptr, 10); + gid = strtoll(grp_name, &end, 10); if ( ('\0' != *grp_name) - && ('\0' == *endptr) + && ('\0' == *end) && (ERANGE != errno) && (gid == (gid_t)gid)) { - grp = gr_locate_gid ((gid_t) gid); + grp = gr_locate_gid (gid); } else { grp = gr_locate(grp_name); @@ -923,8 +916,10 @@ static void usage (int status) (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); (void) fputs (_(" -k, --skel SKEL_DIR use this alternative skeleton directory\n"), usageout); (void) fputs (_(" -K, --key KEY=VALUE override /etc/login.defs defaults\n"), usageout); +#ifdef ENABLE_LASTLOG (void) fputs (_(" -l, --no-log-init do not add the user to the lastlog and\n" " faillog databases\n"), usageout); +#endif /* ENABLE_LASTLOG */ (void) fputs (_(" -m, --create-home create the user's home directory\n"), usageout); (void) fputs (_(" -M, --no-create-home do not create the user's home directory\n"), usageout); (void) fputs (_(" -N, --no-user-group do not create a group with the same name as\n" @@ -940,6 +935,7 @@ static void usage (int status) (void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), usageout); #ifdef WITH_SELINUX (void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), usageout); + (void) fputs (_(" --selinux-range SERANGE use a specific MLS range for the SELinux user mapping\n"), usageout); #endif /* WITH_SELINUX */ (void) fputs ("\n", usageout); exit (status); @@ -968,15 +964,6 @@ static void new_pwent (struct passwd *pwent) pwent->pw_shell = (char *) user_shell; } -static long scale_age (long x) -{ - if (x <= 0) { - return x; - } - - return x * (DAY / SCALE); -} - /* * new_spent - initialize the values in a shadow password file entry * @@ -988,17 +975,17 @@ static void new_spent (struct spwd *spent) memzero (spent, sizeof *spent); spent->sp_namp = (char *) user_name; spent->sp_pwdp = (char *) user_pass; - spent->sp_lstchg = (long) gettime () / SCALE; + spent->sp_lstchg = gettime () / DAY; if (0 == spent->sp_lstchg) { /* Better disable aging than requiring a password change */ spent->sp_lstchg = -1; } if (!rflg) { - spent->sp_min = scale_age (getdef_num ("PASS_MIN_DAYS", -1)); - spent->sp_max = scale_age (getdef_num ("PASS_MAX_DAYS", -1)); - spent->sp_warn = scale_age (getdef_num ("PASS_WARN_AGE", -1)); - spent->sp_inact = scale_age (def_inactive); - spent->sp_expire = scale_age (user_expire); + 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 = def_inactive; + spent->sp_expire = user_expire; } else { spent->sp_min = -1; spent->sp_max = -1; @@ -1223,6 +1210,7 @@ static void process_flags (int argc, char **argv) {"user-group", no_argument, NULL, 'U'}, #ifdef WITH_SELINUX {"selinux-user", required_argument, NULL, 'Z'}, + {"selinux-range", required_argument, NULL, 202}, #endif /* WITH_SELINUX */ {NULL, 0, NULL, '\0'} }; @@ -1310,7 +1298,7 @@ static void process_flags (int argc, char **argv) eflg = true; break; case 'f': - if ( (getlong (optarg, &def_inactive) == 0) + if ( (str2sl(&def_inactive, optarg) == -1) || (def_inactive < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -1382,7 +1370,7 @@ static void process_flags (int argc, char **argv) /* terminate name, point to value */ *cp = '\0'; cp++; - if (putdef_str (optarg, cp) < 0) { + if (putdef_str (optarg, cp, NULL) < 0) { exit (E_BAD_ARG); } break; @@ -1442,7 +1430,7 @@ static void process_flags (int argc, char **argv) sflg = true; break; case 'u': - if ( (get_uid (optarg, &user_id) == 0) + if ( (get_uid(optarg, &user_id) == -1) || (user_id == (gid_t)-1)) { fprintf (stderr, _("%s: invalid user ID '%s'\n"), @@ -1472,6 +1460,9 @@ static void process_flags (int argc, char **argv) exit (E_BAD_ARG); } break; + case 202: + user_selinux_range = optarg; + break; #endif /* WITH_SELINUX */ default: usage (E_USAGE); @@ -1519,6 +1510,14 @@ static void process_flags (int argc, char **argv) Prog, "-m", "-M"); usage (E_USAGE); } +#ifdef WITH_SELINUX + if (user_selinux_range && !Zflg) { + fprintf (stderr, + _("%s: %s flag is only allowed with the %s flag\n"), + Prog, "--selinux-range", "--selinux-user"); + usage (E_USAGE); + } +#endif /* WITH_SELINUX */ /* * Either -D or username is required. Defaults can be set with -D @@ -1551,26 +1550,17 @@ static void process_flags (int argc, char **argv) exit (E_BAD_ARG); } if (!dflg) { - char *uh; - size_t len = strlen (def_home) + strlen (user_name) + 2; - int wlen; - - uh = xmalloc (len); - wlen = snprintf (uh, len, "%s/%s", def_home, user_name); - assert (wlen == (int) len -1); + char *uh; + xasprintf(&uh, "%s/%s", def_home, user_name); user_home = uh; } if (prefix[0]) { - size_t len = strlen(prefix) + strlen(user_home) + 2; - int wlen; - char* _prefix_user_home; /* to avoid const warning */ - _prefix_user_home = xmalloc(len); - wlen = snprintf(_prefix_user_home, len, "%s/%s", prefix, user_home); - assert (wlen == (int) len -1); - prefix_user_home = _prefix_user_home; - } - else { + char *puh; /* to avoid const warning */ + + xasprintf(&puh, "%s/%s", prefix, user_home); + prefix_user_home = puh; + } else { prefix_user_home = user_home; } } @@ -1716,23 +1706,25 @@ static void close_files (void) */ static void close_group_files (void) { - if (do_grp_update) { - if (gr_close () == 0) { - fprintf (stderr, - _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); - SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); - fail_exit (E_GRP_UPDATE); - } + if (!do_grp_update) + return; + + if (gr_close() == 0) { + fprintf(stderr, + _("%s: failure while writing changes to %s\n"), + Prog, gr_dbname()); + SYSLOG((LOG_ERR, "failure while writing changes to %s", gr_dbname())); + fail_exit(E_GRP_UPDATE); + } #ifdef SHADOWGRP - if (is_shadow_grp && (sgr_close () == 0)) { - fprintf (stderr, - _("%s: failure while writing changes to %s\n"), - Prog, sgr_dbname ()); - SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); - fail_exit (E_GRP_UPDATE); - } -#endif /* SHADOWGRP */ + if (is_shadow_grp && sgr_close() == 0) { + fprintf(stderr, + _("%s: failure while writing changes to %s\n"), + Prog, sgr_dbname()); + SYSLOG((LOG_ERR, "failure while writing changes to %s", sgr_dbname())); + fail_exit(E_GRP_UPDATE); } +#endif /* SHADOWGRP */ } /* @@ -2013,14 +2005,14 @@ static void faillog_reset (uid_t uid) return; } if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl)) + || (write_full(fd, &fl, sizeof (fl)) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to reset the faillog entry of UID %lu: %s\n"), Prog, (unsigned long) uid, strerror (errno)); SYSLOG ((LOG_WARN, "failed to reset the faillog entry of UID %lu", (unsigned long) uid)); } - if (close (fd) != 0) { + if (close (fd) != 0 && errno != EINTR) { fprintf (stderr, _("%s: failed to close the faillog file for UID %lu: %s\n"), Prog, (unsigned long) uid, strerror (errno)); @@ -2028,6 +2020,7 @@ static void faillog_reset (uid_t uid) } } +#ifdef ENABLE_LASTLOG static void lastlog_reset (uid_t uid) { struct lastlog ll; @@ -2040,7 +2033,7 @@ static void lastlog_reset (uid_t uid) return; } - max_uid = (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL); + max_uid = getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL); if (uid > max_uid) { /* do not touch lastlog for large uids */ return; @@ -2057,7 +2050,7 @@ static void lastlog_reset (uid_t uid) return; } if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid) - || (write (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll)) + || (write_full (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll)) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to reset the lastlog entry of UID %lu: %s\n"), @@ -2065,7 +2058,7 @@ static void lastlog_reset (uid_t uid) SYSLOG ((LOG_WARN, "failed to reset the lastlog entry of UID %lu", (unsigned long) uid)); /* continue */ } - if (close (fd) != 0) { + if (close (fd) != 0 && errno != EINTR) { fprintf (stderr, _("%s: failed to close the lastlog file for UID %lu: %s\n"), Prog, (unsigned long) uid, strerror (errno)); @@ -2073,6 +2066,7 @@ static void lastlog_reset (uid_t uid) /* continue */ } } +#endif /* ENABLE_LASTLOG */ static void tallylog_reset (const char *user_name) { @@ -2085,6 +2079,9 @@ static void tallylog_reset (const char *user_name) if (access(pam_tally2, X_OK) == -1) return; + /* set SIGCHLD to default for waitpid */ + signal(SIGCHLD, SIG_DFL); + failed = 0; switch (childpid = fork()) { @@ -2159,7 +2156,9 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count) /* local, no need for xgetpwuid */ if ((!lflg) && (prefix_getpwuid (user_id) == NULL)) { faillog_reset (user_id); +#ifdef ENABLE_LASTLOG lastlog_reset (user_id); +#endif /* ENABLE_LASTLOG */ } /* @@ -2182,20 +2181,19 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count) #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_USER, Prog, "adding shadow password", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif fail_exit (E_PW_UPDATE); } #ifdef ENABLE_SUBIDS - if (is_sub_uid && + if (is_sub_uid && !local_sub_uid_assigned(user_name) && (sub_uid_add(user_name, sub_uid_start, subuid_count) == 0)) { fprintf (stderr, _("%s: failed to prepare the new %s entry\n"), Prog, sub_uid_dbname ()); fail_exit (E_SUB_UID_UPDATE); } - if (is_sub_gid && + if (is_sub_gid && !local_sub_gid_assigned(user_name) && (sub_gid_add(user_name, sub_gid_start, subgid_count) == 0)) { fprintf (stderr, _("%s: failed to prepare the new %s entry\n"), @@ -2205,9 +2203,14 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count) #endif /* ENABLE_SUBIDS */ #ifdef WITH_AUDIT + /* + * Even though we have the ID of the user, we won't send it now + * because its not written to disk yet. After close_files it is + * and we can use the real ID thereafter. + */ audit_logger (AUDIT_ADD_USER, Prog, "adding user", - user_name, (unsigned int) user_id, + user_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif /* @@ -2227,123 +2230,120 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count) */ static void create_home (void) { - if (access (prefix_user_home, F_OK) != 0) { - char path[strlen (prefix_user_home) + 2]; - char *bhome, *cp; + char path[strlen(prefix_user_home) + 2]; + char *bhome, *cp; + mode_t mode; - path[0] = '\0'; - bhome = strdup (prefix_user_home); - if (!bhome) { - fprintf (stderr, - _("%s: error while duplicating string %s\n"), - Prog, user_home); - fail_exit (E_HOMEDIR); - } + if (access (prefix_user_home, F_OK) == 0) + return; + + path[0] = '\0'; + bhome = strdup(prefix_user_home); + if (!bhome) { + fprintf(stderr, + _("%s: error while duplicating string %s\n"), + Prog, user_home); + fail_exit(E_HOMEDIR); + } #ifdef WITH_SELINUX - if (set_selinux_file_context (prefix_user_home, S_IFDIR) != 0) { - fprintf (stderr, - _("%s: cannot set SELinux context for home directory %s\n"), - Prog, user_home); - fail_exit (E_HOMEDIR); - } + if (set_selinux_file_context(prefix_user_home, S_IFDIR) != 0) { + fprintf(stderr, + _("%s: cannot set SELinux context for home directory %s\n"), + Prog, user_home); + fail_exit(E_HOMEDIR); + } #endif - /* Check for every part of the path, if the directory - exists. If not, create it with permissions 755 and - owner root:root. + /* Check for every part of the path, if the directory + exists. If not, create it with permissions 755 and + owner root:root. + */ + for (cp = strtok(bhome, "/"); cp != NULL; cp = strtok(NULL, "/")) { + /* Avoid turning a relative path into an absolute path. */ + if (bhome[0] == '/' || strlen(path) != 0) { + strcat(path, "/"); + } + strcat(path, cp); + if (access(path, F_OK) == 0) { + continue; + } + + /* Check if parent directory is BTRFS, fail if requesting + subvolume but no BTRFS. The paths could be different by the + trailing slash */ - cp = strtok (bhome, "/"); - while (cp) { - /* Avoid turning a relative path into an absolute path. - */ - if (bhome[0] == '/' || strlen (path) != 0) { - strcat (path, "/"); - } - strcat (path, cp); - if (access (path, F_OK) != 0) { - /* Check if parent directory is BTRFS, fail if requesting - subvolume but no BTRFS. The paths cound be different by the - trailing slash - */ #if WITH_BTRFS - if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { - char *btrfs_check = strdup(path); - - if (!btrfs_check) { - fprintf (stderr, - _("%s: error while duplicating string in BTRFS check %s\n"), - Prog, path); - fail_exit (E_HOMEDIR); - } - btrfs_check[strlen(path) - strlen(cp) - 1] = '\0'; - if (is_btrfs(btrfs_check) <= 0) { - fprintf (stderr, - _("%s: home directory \"%s\" must be mounted on BTRFS\n"), - Prog, path); - fail_exit (E_HOMEDIR); - } - // make subvolume to mount for user instead of directory - if (btrfs_create_subvolume(path)) { - fprintf (stderr, - _("%s: failed to create BTRFS subvolume: %s\n"), - Prog, path); - fail_exit (E_HOMEDIR); - } - } - else + if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { + char *btrfs_check = strdup(path); + + if (!btrfs_check) { + fprintf(stderr, + _("%s: error while duplicating string in BTRFS check %s\n"), + Prog, path); + fail_exit(E_HOMEDIR); + } + btrfs_check[strlen(path) - strlen(cp) - 1] = '\0'; + if (is_btrfs(btrfs_check) <= 0) { + fprintf(stderr, + _("%s: home directory \"%s\" must be mounted on BTRFS\n"), + Prog, path); + fail_exit(E_HOMEDIR); + } + free(btrfs_check); + // make subvolume to mount for user instead of directory + if (btrfs_create_subvolume(path)) { + fprintf(stderr, + _("%s: failed to create BTRFS subvolume: %s\n"), + Prog, path); + fail_exit(E_HOMEDIR); + } + } + else #endif - if (mkdir (path, 0) != 0) { - fprintf (stderr, - _("%s: cannot create directory %s\n"), - Prog, path); + if (mkdir(path, 0) != 0) { + fprintf(stderr, _("%s: cannot create directory %s\n"), + Prog, path); #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "adding home directory", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + audit_logger(AUDIT_ADD_USER, Prog, "adding home directory", + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif - fail_exit (E_HOMEDIR); + fail_exit(E_HOMEDIR); } - if (chown (path, 0, 0) < 0) { - fprintf (stderr, - _("%s: warning: chown on `%s' failed: %m\n"), - Prog, path); - } - if (chmod (path, 0755) < 0) { - fprintf (stderr, - _("%s: warning: chmod on `%s' failed: %m\n"), - Prog, path); - } - } - cp = strtok (NULL, "/"); + if (chown(path, 0, 0) < 0) { + fprintf(stderr, + _("%s: warning: chown on `%s' failed: %m\n"), + Prog, path); } - free (bhome); - - (void) chown (prefix_user_home, user_id, user_gid); - mode_t mode = getdef_num ("HOME_MODE", - 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); - if (chmod (prefix_user_home, mode)) { - fprintf (stderr, _("%s: warning: chown on '%s' failed: %m\n"), - Prog, path); + if (chmod(path, 0755) < 0) { + fprintf(stderr, + _("%s: warning: chmod on `%s' failed: %m\n"), + Prog, path); } - home_added = true; + } + free(bhome); + + (void) chown(prefix_user_home, user_id, user_gid); + mode = getdef_num("HOME_MODE", + 0777 & ~getdef_num("UMASK", GETDEF_DEFAULT_UMASK)); + if (chmod(prefix_user_home, mode)) { + fprintf(stderr, _("%s: warning: chown on '%s' failed: %m\n"), + Prog, path); + } + home_added = true; #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "adding home directory", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + audit_logger(AUDIT_ADD_USER, Prog, "adding home directory", + user_name, user_id, SHADOW_AUDIT_SUCCESS); #endif #ifdef WITH_SELINUX - /* Reset SELinux to create files with default contexts */ - if (reset_selinux_file_context () != 0) { - fprintf (stderr, - _("%s: cannot reset SELinux file creation context\n"), - Prog); - fail_exit (E_HOMEDIR); - } -#endif + /* Reset SELinux to create files with default contexts */ + if (reset_selinux_file_context() != 0) { + fprintf(stderr, + _("%s: cannot reset SELinux file creation context\n"), + Prog); + fail_exit(E_HOMEDIR); } +#endif } /* @@ -2355,72 +2355,79 @@ static void create_home (void) */ static void create_mail (void) { - if (strcasecmp (create_mail_spool, "yes") == 0) { - const char *spool; - char *file; - int fd; - struct group *gr; - gid_t gid; - mode_t mode; - - spool = getdef_str ("MAIL_DIR"); + int fd; + char *file; + gid_t gid; + mode_t mode; + const char *spool; + struct group *gr; + + if (strcasecmp(create_mail_spool, "yes") != 0) + return; + + spool = getdef_str("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR - if ((NULL == spool) && (getdef_str ("MAIL_FILE") == NULL)) { - spool = MAIL_SPOOL_DIR; - } + if ((NULL == spool) && (getdef_str("MAIL_FILE") == NULL)) { + spool = MAIL_SPOOL_DIR; + } #endif /* MAIL_SPOOL_DIR */ - if (NULL == spool) { - return; - } - file = alloca (strlen (prefix) + strlen (spool) + strlen (user_name) + 3); - if (prefix[0]) - sprintf (file, "%s/%s/%s", prefix, spool, user_name); - else - sprintf (file, "%s/%s", spool, user_name); + if (NULL == spool) { + return; + } + if (prefix[0]) + xasprintf(&file, "%s/%s/%s", prefix, spool, user_name); + else + xasprintf(&file, "%s/%s", spool, user_name); #ifdef WITH_SELINUX - if (set_selinux_file_context (file, S_IFREG) != 0) { - fprintf (stderr, - _("%s: cannot set SELinux context for mailbox file %s\n"), - Prog, file); - fail_exit (E_MAILBOXFILE); - } + if (set_selinux_file_context(file, S_IFREG) != 0) { + fprintf(stderr, + _("%s: cannot set SELinux context for mailbox file %s\n"), + Prog, file); + fail_exit(E_MAILBOXFILE); + } #endif - fd = open (file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0); - if (fd < 0) { - perror (_("Creating mailbox file")); - return; - } + fd = open(file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0); + free(file); - gr = prefix_getgrnam ("mail"); /* local, no need for xgetgrnam */ - if (NULL == gr) { - fputs (_("Group 'mail' not found. Creating the user mailbox file with 0600 mode.\n"), - stderr); - gid = user_gid; - mode = 0600; - } else { - gid = gr->gr_gid; - mode = 0660; - } + if (fd < 0) { + perror(_("Creating mailbox file")); + return; + } - if ( (fchown (fd, user_id, gid) != 0) - || (fchmod (fd, mode) != 0)) { - perror (_("Setting mailbox file permissions")); - } + gr = prefix_getgrnam("mail"); /* local, no need for xgetgrnam */ + if (NULL == gr) { + fputs(_("Group 'mail' not found. Creating the user mailbox file with 0600 mode.\n"), + stderr); + gid = user_gid; + mode = 0600; + } else { + gid = gr->gr_gid; + mode = 0660; + } + + if (fchown(fd, user_id, gid) != 0 + || fchmod(fd, mode) != 0) + { + perror(_("Setting mailbox file permissions")); + } - fsync (fd); - close (fd); + if (fsync(fd) != 0) { + perror (_("Synchronize mailbox file")); + } + if (close(fd) != 0 && errno != EINTR) { + perror (_("Closing mailbox file")); + } #ifdef WITH_SELINUX - /* Reset SELinux to create files with default contexts */ - if (reset_selinux_file_context () != 0) { - fprintf (stderr, - _("%s: cannot reset SELinux file creation context\n"), - Prog); - fail_exit (E_MAILBOXFILE); - } -#endif + /* Reset SELinux to create files with default contexts */ + if (reset_selinux_file_context() != 0) { + fprintf(stderr, + _("%s: cannot reset SELinux file creation context\n"), + Prog); + fail_exit(E_MAILBOXFILE); } +#endif } static void check_uid_range(int rflg, uid_t user_id) @@ -2428,13 +2435,13 @@ static void check_uid_range(int rflg, uid_t user_id) uid_t uid_min ; uid_t uid_max ; if (rflg) { - uid_max = (uid_t)getdef_ulong("SYS_UID_MAX",getdef_ulong("UID_MIN",1000UL)-1); + uid_max = getdef_ulong("SYS_UID_MAX",getdef_ulong("UID_MIN",1000UL)-1); if (user_id > uid_max) { fprintf(stderr, _("%s warning: %s's uid %d is greater than SYS_UID_MAX %d\n"), Prog, user_name, user_id, uid_max); } }else{ - uid_min = (uid_t)getdef_ulong("UID_MIN", 1000UL); - uid_max = (uid_t)getdef_ulong("UID_MAX", 6000UL); + uid_min = getdef_ulong("UID_MIN", 1000UL); + uid_max = getdef_ulong("UID_MAX", 6000UL); if (uid_min <= uid_max) { if (user_id < uid_min || user_id >uid_max) fprintf(stderr, _("%s warning: %s's uid %d outside of the UID_MIN %d and UID_MAX %d range.\n"), Prog, user_name, user_id, uid_min, uid_max); @@ -2461,10 +2468,6 @@ int main (int argc, char **argv) unsigned long subuid_count = 0; unsigned long subgid_count = 0; - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -2476,17 +2479,17 @@ int main (int argc, char **argv) prefix = process_prefix_flag("-P", argc, argv); - OPENLOG ("useradd"); + OPENLOG (Prog); #ifdef WITH_AUDIT audit_help_open (); #endif sys_ngroups = sysconf (_SC_NGROUPS_MAX); - user_groups = (char **) xmalloc ((1 + sys_ngroups) * sizeof (char *)); + user_groups = XMALLOC(1 + sys_ngroups, char *); /* * Initialize the list to be empty */ - user_groups[0] = (char *) 0; + user_groups[0] = NULL; is_shadow_pwd = spw_file_present (); @@ -2499,8 +2502,8 @@ int main (int argc, char **argv) process_flags (argc, argv); #ifdef ENABLE_SUBIDS - uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL); - uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL); + uid_min = getdef_ulong ("UID_MIN", 1000UL); + uid_max = getdef_ulong ("UID_MAX", 60000UL); subuid_count = getdef_ulong ("SUB_UID_COUNT", 65536); subgid_count = getdef_ulong ("SUB_GID_COUNT", 65536); is_sub_uid = subuid_count > 0 && sub_uid_file_present () && @@ -2528,7 +2531,7 @@ int main (int argc, char **argv) fail_exit (1); } - retval = pam_start ("useradd", pampw?pampw->pw_name:"root", &conv, &pamh); + retval = pam_start (Prog, pampw?pampw->pw_name:"root", &conv, &pamh); } if (PAM_SUCCESS == retval) { @@ -2629,7 +2632,7 @@ int main (int argc, char **argv) #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_USER, Prog, "adding user", - user_name, (unsigned int) user_id, + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif fail_exit (E_UID_IN_USE); @@ -2701,14 +2704,14 @@ int main (int argc, char **argv) #ifdef WITH_SELINUX if (Zflg) { - if (set_seuser (user_name, user_selinux) != 0) { + if (set_seuser (user_name, user_selinux, user_selinux_range) != 0) { fprintf (stderr, _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), Prog, user_name, user_selinux); #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_USER, Prog, "adding SELinux user mapping", - user_name, (unsigned int) user_id, 0); + user_name, user_id, 0); #endif /* WITH_AUDIT */ fail_exit (E_SE_UPDATE); } @@ -2720,6 +2723,8 @@ int main (int argc, char **argv) if (home_added) { copy_tree (def_template, prefix_user_home, false, true, (uid_t)-1, user_id, (gid_t)-1, user_gid); + copy_tree (def_usrtemplate, prefix_user_home, false, true, + (uid_t)-1, user_id, (gid_t)-1, user_gid); } else { fprintf (stderr, _("%s: warning: the home directory %s already exists.\n" @@ -2742,3 +2747,23 @@ int main (int argc, char **argv) return E_SUCCESS; } + +static FILE * +fmkstemp(char *template) +{ + int fd; + FILE *fp; + + fd = mkstemp(template); + if (fd == -1) + return NULL; + + fp = fdopen(fd, "w"); + if (fp == NULL) { + close(fd); + unlink(template); + return NULL; + } + + return fp; +} diff --git a/src/userdel.c b/src/userdel.c index 7012b0e..ff1f7dd 100644 --- a/src/userdel.c +++ b/src/userdel.c @@ -19,6 +19,8 @@ #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> + +#include "alloc.h" #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM #include "pam_defs.h" @@ -50,6 +52,8 @@ #include "subordinateio.h" #endif /* ENABLE_SUBIDS */ #include "shadowlog.h" +#include "string/sprintf.h" + /* * exit status values @@ -68,7 +72,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "userdel"; static char *user_name; static uid_t user_id; @@ -204,8 +208,7 @@ static void update_groups (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from group", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + user_name, user_id, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", user_name, ngrp->gr_name)); @@ -266,8 +269,7 @@ static void update_groups (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from shadow group", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + user_name, user_id, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", user_name, nsgrp->sg_name)); @@ -526,8 +528,7 @@ static void fail_exit (int code) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ exit (code); @@ -548,8 +549,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking password file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } @@ -560,8 +560,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening password file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } @@ -573,8 +572,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking shadow password file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } @@ -586,8 +584,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening shadow password file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } @@ -599,8 +596,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking group file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } @@ -610,8 +606,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening group file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } @@ -624,8 +619,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking shadow group file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } @@ -636,8 +630,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening shadow group file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } @@ -652,8 +645,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking subordinate user file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_UID_UPDATE); } @@ -664,8 +656,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening subordinate user file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_UID_UPDATE); } @@ -678,8 +669,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking subordinate group file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_GID_UPDATE); } @@ -690,8 +680,7 @@ static void open_files (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening subordinate group file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_GID_UPDATE); } @@ -738,8 +727,7 @@ static void update_user (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user entries", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + user_name, user_id, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete user '%s'\n", user_name)); } @@ -763,7 +751,7 @@ static void user_cancel (const char *user) } argv[0] = cmd; argv[1] = user; - argv[2] = (char *)0; + argv[2] = NULL; (void) run_command (cmd, argv, NULL, &status); } @@ -802,11 +790,9 @@ static int is_owner (uid_t uid, const char *path) static int remove_mailbox (void) { - const char *maildir; - char* mailfile; - int i; - int errors = 0; - size_t len; + int i, errors = 0; + char *mailfile; + const char *maildir; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR @@ -818,18 +804,11 @@ static int remove_mailbox (void) return 0; } - len = strlen (prefix) + strlen (maildir) + strlen (user_name) + 2; - mailfile = xmalloc (len); - if (prefix[0]) { - (void) snprintf (mailfile, len, "%s/%s/%s", - prefix, maildir, user_name); - } - else { - (void) snprintf (mailfile, len, "%s/%s", - maildir, user_name); + xasprintf(&mailfile, "%s/%s/%s", prefix, maildir, user_name); + } else { + xasprintf(&mailfile, "%s/%s", maildir, user_name); } - mailfile[len-1] = '\0'; if (access (mailfile, F_OK) != 0) { if (ENOENT == errno) { @@ -846,8 +825,7 @@ static int remove_mailbox (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ free(mailfile); return -1; @@ -863,8 +841,7 @@ static int remove_mailbox (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ errors = 1; /* continue */ @@ -874,8 +851,7 @@ static int remove_mailbox (void) { audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + user_name, user_id, SHADOW_AUDIT_SUCCESS); } #endif /* WITH_AUDIT */ free(mailfile); @@ -892,8 +868,7 @@ static int remove_mailbox (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ free(mailfile); return 1; @@ -909,8 +884,7 @@ static int remove_mailbox (void) #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ errors = 1; /* continue */ @@ -920,8 +894,7 @@ static int remove_mailbox (void) { audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + user_name, user_id, SHADOW_AUDIT_SUCCESS); } #endif /* WITH_AUDIT */ free(mailfile); @@ -931,22 +904,19 @@ static int remove_mailbox (void) #ifdef WITH_TCB static int remove_tcbdir (const char *user_name, uid_t user_id) { - char *buf; - int ret = 0; - size_t buflen = (sizeof TCB_DIR) + strlen (user_name) + 2; + int ret = 0; + char *buf; if (!getdef_bool ("USE_TCB")) { return 0; } - buf = malloc (buflen); - if (NULL == buf) { - fprintf (stderr, _("%s: Can't allocate memory, " - "tcb entry for %s not removed.\n"), - Prog, user_name); + if (asprintf(&buf, TCB_DIR "/%s", user_name) == -1) { + fprintf(stderr, + _("%s: Can't allocate memory, tcb entry for %s not removed.\n"), + Prog, user_name); return 1; } - snprintf (buf, buflen, TCB_DIR "/%s", user_name); if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) { fprintf (stderr, _("%s: Cannot drop privileges: %s\n"), Prog, strerror (errno)); @@ -989,10 +959,6 @@ int main (int argc, char **argv) #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); (void) setlocale (LC_ALL, ""); @@ -1002,7 +968,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); prefix = process_prefix_flag ("-P", argc, argv); - OPENLOG ("userdel"); + OPENLOG (Prog); #ifdef WITH_AUDIT audit_help_open (); #endif /* WITH_AUDIT */ @@ -1086,7 +1052,7 @@ int main (int argc, char **argv) exit (E_PW_UPDATE); } - retval = pam_start ("userdel", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); } if (PAM_SUCCESS == retval) { @@ -1148,15 +1114,9 @@ int main (int argc, char **argv) user_gid = pwd->pw_gid; if (prefix[0]) { - - size_t len = strlen(prefix) + strlen(pwd->pw_dir) + 2; - int wlen; - user_home = xmalloc(len); - wlen = snprintf(user_home, len, "%s/%s", prefix, pwd->pw_dir); - assert (wlen == (int) len -1); - } - else { - user_home = xstrdup (pwd->pw_dir); + xasprintf(&user_home, "%s/%s", prefix, pwd->pw_dir); + } else { + user_home = xstrdup(pwd->pw_dir); } pw_close(); } @@ -1165,26 +1125,6 @@ int main (int argc, char **argv) exit (E_NOTFOUND); } #endif /* WITH_TCB */ -#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 /* USE_NIS */ /* * Check to make certain the user isn't logged in. * Note: This is a best effort basis. The user may log in between, @@ -1290,8 +1230,7 @@ int main (int argc, char **argv) { audit_logger (AUDIT_DEL_USER, Prog, "deleting home directory", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_SUCCESS); + user_name, user_id, SHADOW_AUDIT_SUCCESS); } #endif /* WITH_AUDIT */ } @@ -1313,8 +1252,7 @@ int main (int argc, char **argv) #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_USER, Prog, "removing SELinux user mapping", - user_name, (unsigned int) user_id, - SHADOW_AUDIT_FAILURE); + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SE_UPDATE); } diff --git a/src/usermod.c b/src/usermod.c index c1a5b2c..f889698 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -17,7 +17,9 @@ #include <fcntl.h> #include <getopt.h> #include <grp.h> +#ifdef ENABLE_LASTLOG #include <lastlog.h> +#endif /* ENABLE_LASTLOG */ #include <pwd.h> #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM @@ -25,14 +27,19 @@ #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ #include <stdio.h> +#include <strings.h> #include <sys/stat.h> #include <sys/types.h> #include <time.h> + +#include "alloc.h" +#include "atoi/str2i.h" #include "chkname.h" #include "defines.h" #include "faillog.h" #include "getdef.h" #include "groupio.h" +#include "memzero.h" #include "nscd.h" #include "sssd.h" #include "prototypes.h" @@ -52,6 +59,9 @@ #include "tcbfuncs.h" #endif #include "shadowlog.h" +#include "string/sprintf.h" +#include "time/day_to_str.h" + /* * exit status values @@ -82,7 +92,7 @@ /* * Global variables */ -const char *Prog; +static const char Prog[] = "usermod"; static char *user_name; static char *user_newname; @@ -98,6 +108,7 @@ static char *user_newhome; static char *user_shell; #ifdef WITH_SELINUX static const char *user_selinux = ""; +static const char *user_selinux_range = NULL; #endif /* WITH_SELINUX */ static char *user_newshell; static long user_expire; @@ -163,14 +174,16 @@ static bool sub_gid_locked = false; /* local function prototypes */ static int get_groups (char *); -static /*@noreturn@*/void usage (int status); +NORETURN static void usage (int status); static void new_pwent (struct passwd *); static void new_spent (struct spwd *); -static /*@noreturn@*/void fail_exit (int); -static void update_group (void); +NORETURN static void fail_exit (int); +static void update_group_file(void); +static void update_group(const struct group *grp); #ifdef SHADOWGRP -static void update_gshadow (void); +static void update_gshadow_file(void); +static void update_gshadow(const struct sgrp *sgrp); #endif static void grp_update (void); @@ -179,7 +192,9 @@ static void close_files (void); static void open_files (void); static void usr_update (void); static void move_home (void); +#ifdef ENABLE_LASTLOG static void update_lastlog (void); +#endif /* ENABLE_LASTLOG */ static void update_faillog (void); #ifndef NO_MOVE_MAILBOX @@ -198,14 +213,14 @@ extern int allow_bad_names; static int get_groups (char *list) { char *cp; - const struct group *grp; + struct group *grp; int errors = 0; int ngroups = 0; /* * Initialize the list to be empty */ - user_groups[0] = (char *) 0; + user_groups[0] = NULL; if ('\0' == *list) { return 0; @@ -251,25 +266,11 @@ static int get_groups (char *list) continue; } -#ifdef USE_NIS - /* - * Don't add this group if they are an NIS group. Tell the - * user to go to the server for this group. - */ - if (__isgrNIS ()) { - fprintf (stderr, - _("%s: group '%s' is a NIS group.\n"), - Prog, grp->gr_name); - gr_free ((struct group *)grp); - continue; - } -#endif - if (ngroups == sys_ngroups) { fprintf (stderr, _("%s: too many groups specified (max %d).\n"), Prog, ngroups); - gr_free ((struct group *)grp); + gr_free (grp); break; } @@ -277,10 +278,10 @@ static int get_groups (char *list) * Add the group name to the user's list of groups. */ user_groups[ngroups++] = xstrdup (grp->gr_name); - gr_free ((struct group *)grp); + gr_free (grp); } while (NULL != list); - user_groups[ngroups] = (char *) 0; + user_groups[ngroups] = NULL; /* * Any errors in finding group names are fatal @@ -307,21 +308,28 @@ static struct ulong_range getulong_range(const char *str) errno = 0; first = strtoll(str, &pos, 10); - if (('\0' == *str) || ('-' != *pos ) || (ERANGE == errno) || - (first != (unsigned long int)first)) + if (('\0' == *str) || ('-' != *pos ) || (0 != errno) || + (first != (unsigned long)first)) goto out; errno = 0; last = strtoll(pos + 1, &pos, 10); - if (('\0' != *pos ) || (ERANGE == errno) || - (last != (unsigned long int)last)) + if (('\0' != *pos ) || (0 != errno) || + (last != (unsigned long)last)) goto out; if (first > last) goto out; - result.first = (unsigned long int)first; - result.last = (unsigned long int)last; + /* + * uid_t in linux is an unsigned int, anything over this is an invalid + * range will be later refused anyway by get_map_ranges(). + */ + if (first > UINT_MAX || last > UINT_MAX) + goto out; + + result.first = (unsigned long)first; + result.last = (unsigned long)last; out: return result; } @@ -342,7 +350,7 @@ static int prepend_range(const char *str, struct ulong_range_list_entry **head) if (range.first > range.last) return 0; - entry = malloc(sizeof(*entry)); + entry = MALLOC(1, struct ulong_range_list_entry); if (!entry) { fprintf (stderr, _("%s: failed to allocate memory: %s\n"), @@ -359,7 +367,9 @@ static int prepend_range(const char *str, struct ulong_range_list_entry **head) /* * usage - display usage message and exit */ -static /*@noreturn@*/void usage (int status) +NORETURN +static void +usage (int status) { FILE *usageout = (E_SUCCESS != status) ? stderr : stdout; (void) fprintf (usageout, @@ -401,6 +411,7 @@ static /*@noreturn@*/void usage (int status) #endif /* ENABLE_SUBIDS */ #ifdef WITH_SELINUX (void) fputs (_(" -Z, --selinux-user SEUSER new SELinux user mapping for the user account\n"), usageout); + (void) fputs (_(" --selinux-range SERANGE new SELinux MLS range for the user account\n"), usageout); #endif /* WITH_SELINUX */ (void) fputs ("\n", usageout); exit (status); @@ -413,20 +424,17 @@ static /*@noreturn@*/void usage (int status) static char *new_pw_passwd (char *pw_pass) { if (Lflg && ('!' != pw_pass[0])) { - char *buf = xmalloc (strlen (pw_pass) + 2); + char *buf = XMALLOC(strlen(pw_pass) + 2, char); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "updating passwd", - user_newname, (unsigned int) user_newid, 0); + "updating passwd", user_newname, user_newid, 0); #endif SYSLOG ((LOG_INFO, "lock user '%s' password", user_newname)); strcpy (buf, "!"); strcat (buf, pw_pass); pw_pass = buf; } else if (Uflg && pw_pass[0] == '!') { - char *s; - if (pw_pass[1] == '\0') { fprintf (stderr, _("%s: unlocking the user's password would result in a passwordless account.\n" @@ -437,20 +445,14 @@ static char *new_pw_passwd (char *pw_pass) #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "updating password", - user_newname, (unsigned int) user_newid, 0); + "updating password", user_newname, user_newid, 0); #endif SYSLOG ((LOG_INFO, "unlock user '%s' password", user_newname)); - s = pw_pass; - while ('\0' != *s) { - *s = *(s + 1); - s++; - } + memmove(pw_pass, pw_pass + 1, strlen(pw_pass)); } else if (pflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing password", - user_newname, (unsigned int) user_newid, 1); + "changing password", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' password", user_newname)); pw_pass = xstrdup (user_pass); @@ -479,8 +481,7 @@ static void new_pwent (struct passwd *pwent) } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing name", - user_newname, (unsigned int) user_newid, 1); + "changing name", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user name '%s' to '%s'", @@ -500,8 +501,7 @@ static void new_pwent (struct passwd *pwent) if (uflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing uid", - user_newname, (unsigned int) user_newid, 1); + "changing uid", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' UID from '%d' to '%d'", @@ -512,7 +512,7 @@ static void new_pwent (struct passwd *pwent) #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing primary group", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' GID from '%d' to '%d'", @@ -522,8 +522,7 @@ static void new_pwent (struct passwd *pwent) if (cflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing comment", - user_newname, (unsigned int) user_newid, 1); + "changing comment", user_newname, user_newid, 1); #endif pwent->pw_gecos = user_newcomment; } @@ -532,7 +531,7 @@ static void new_pwent (struct passwd *pwent) #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' home from '%s' to '%s'", @@ -549,7 +548,7 @@ static void new_pwent (struct passwd *pwent) #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing user shell", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' shell from '%s' to '%s'", @@ -580,7 +579,7 @@ static void new_spent (struct spwd *spent) #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing inactive days", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' inactive from '%ld' to '%ld'", @@ -590,12 +589,13 @@ static void new_spent (struct spwd *spent) if (eflg) { /* log dates rather than numbers of days. */ char new_exp[16], old_exp[16]; - date_to_str (sizeof(new_exp), new_exp, user_newexpire * DAY); - date_to_str (sizeof(old_exp), old_exp, user_expire * DAY); + + DAY_TO_STR(new_exp, user_newexpire); + DAY_TO_STR(old_exp, user_expire); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing expiration date", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user '%s' expiration from '%s' to '%s'", @@ -615,7 +615,7 @@ static void new_spent (struct spwd *spent) spent->sp_pwdp = new_pw_passwd (spent->sp_pwdp); if (pflg) { - spent->sp_lstchg = (long) gettime () / SCALE; + spent->sp_lstchg = gettime () / DAY; if (0 == spent->sp_lstchg) { /* Better disable aging than requiring a password * change. */ @@ -627,7 +627,9 @@ static void new_spent (struct spwd *spent) /* * fail_exit - exit with an error code after unlocking files */ -static /*@noreturn@*/void fail_exit (int code) +NORETURN +static void +fail_exit (int code) { if (gr_locked) { if (gr_unlock () == 0) { @@ -685,263 +687,277 @@ static /*@noreturn@*/void fail_exit (int code) } -static void update_group (void) +static void +update_group_file(void) { - bool is_member; - bool was_member; - bool changed; - const struct group *grp; - struct group *ngrp; - - changed = false; + const struct group *grp; /* * Scan through the entire group file looking for the groups that * the user is a member of. */ - while ((grp = gr_next ()) != NULL) { - /* - * See if the user specified this group as one of their - * concurrent groups. - */ - was_member = is_on_list (grp->gr_mem, user_name); - is_member = Gflg && ( (was_member && aflg) - || is_on_list (user_groups, grp->gr_name)); + while ((grp = gr_next()) != NULL) + update_group(grp); +} - if (!was_member && !is_member) { - continue; - } - /* - * If rflg+Gflg is passed in AKA -rG invert is_member flag, which removes - * mentioned groups while leaving the others. - */ - if (Gflg && rflg) { - is_member = !is_member; - } +static void +update_group(const struct group *grp) +{ + bool changed; + bool is_member; + bool was_member; + struct group *ngrp; - ngrp = __gr_dup (grp); - if (NULL == ngrp) { - fprintf (stderr, - _("%s: Out of memory. Cannot update %s.\n"), - Prog, gr_dbname ()); - fail_exit (E_GRP_UPDATE); - } + changed = false; - if (was_member) { - if ((!Gflg) || is_member) { - /* User was a member and is still a member - * of this group. - * But the user might have been renamed. - */ - if (lflg) { - ngrp->gr_mem = del_list (ngrp->gr_mem, - user_name); - ngrp->gr_mem = add_list (ngrp->gr_mem, - user_newname); - changed = true; -#ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing group member", - user_newname, AUDIT_NO_ID, 1); -#endif - SYSLOG ((LOG_INFO, - "change '%s' to '%s' in group '%s'", - user_name, user_newname, - ngrp->gr_name)); - } - } else { - /* User was a member but is no more a - * member of this group. - */ - ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); + /* + * See if the user specified this group as one of their + * concurrent groups. + */ + was_member = is_on_list (grp->gr_mem, user_name); + is_member = Gflg && ( (was_member && aflg) + || is_on_list (user_groups, grp->gr_name)); + + if (!was_member && !is_member) + return; + + /* + * If rflg+Gflg is passed in AKA -rG invert is_member flag, which removes + * mentioned groups while leaving the others. + */ + if (Gflg && rflg) { + is_member = !is_member; + } + + ngrp = __gr_dup (grp); + if (NULL == ngrp) { + fprintf (stderr, + _("%s: Out of memory. Cannot update %s.\n"), + Prog, gr_dbname ()); + fail_exit (E_GRP_UPDATE); + } + + if (was_member) { + if ((!Gflg) || is_member) { + /* User was a member and is still a member + * of this group. + * But the user might have been renamed. + */ + if (lflg) { + ngrp->gr_mem = del_list (ngrp->gr_mem, + user_name); + ngrp->gr_mem = add_list (ngrp->gr_mem, + user_newname); changed = true; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "removing group member", - user_name, AUDIT_NO_ID, 1); + "changing group member", + user_newname, AUDIT_NO_ID, 1); #endif SYSLOG ((LOG_INFO, - "delete '%s' from group '%s'", - user_name, ngrp->gr_name)); + "change '%s' to '%s' in group '%s'", + user_name, user_newname, + ngrp->gr_name)); } - } else if (is_member) { - /* User was not a member but is now a member this - * group. + } else { + /* User was a member but is no more a + * member of this group. */ - ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname); + ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); changed = true; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "adding user to group", - user_name, AUDIT_NO_ID, 1); + "removing group member", + user_name, AUDIT_NO_ID, 1); #endif - SYSLOG ((LOG_INFO, "add '%s' to group '%s'", - user_newname, ngrp->gr_name)); - } - if (!changed) { - continue; - } - - changed = false; - if (gr_update (ngrp) == 0) { - fprintf (stderr, - _("%s: failed to prepare the new %s entry '%s'\n"), - Prog, gr_dbname (), ngrp->gr_name); - SYSLOG ((LOG_WARN, "failed to prepare the new %s entry '%s'", gr_dbname (), ngrp->gr_name)); - fail_exit (E_GRP_UPDATE); + SYSLOG ((LOG_INFO, + "delete '%s' from group '%s'", + user_name, ngrp->gr_name)); } + } else if (is_member) { + /* User was not a member but is now a member this + * group. + */ + ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname); + changed = true; +#ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "adding user to group", + user_name, AUDIT_NO_ID, 1); +#endif + SYSLOG ((LOG_INFO, "add '%s' to group '%s'", + user_newname, ngrp->gr_name)); + } + if (!changed) + goto free_ngrp; - gr_free(ngrp); + if (gr_update (ngrp) == 0) { + fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, gr_dbname (), ngrp->gr_name); + SYSLOG ((LOG_WARN, "failed to prepare the new %s entry '%s'", gr_dbname (), ngrp->gr_name)); + fail_exit (E_GRP_UPDATE); } + +free_ngrp: + gr_free(ngrp); } + #ifdef SHADOWGRP -static void update_gshadow (void) +static void +update_gshadow_file(void) { - bool is_member; - bool was_member; - bool was_admin; - bool changed; - const struct sgrp *sgrp; - struct sgrp *nsgrp; - - changed = false; + const struct sgrp *sgrp; /* * Scan through the entire shadow group file looking for the groups * that the user is a member of. */ - while ((sgrp = sgr_next ()) != NULL) { + while ((sgrp = sgr_next()) != NULL) + update_gshadow(sgrp); +} +#endif /* SHADOWGRP */ - /* - * See if the user was a member of this group - */ - was_member = is_on_list (sgrp->sg_mem, user_name); - /* - * See if the user was an administrator of this group - */ - was_admin = is_on_list (sgrp->sg_adm, user_name); +#ifdef SHADOWGRP +static void +update_gshadow(const struct sgrp *sgrp) +{ + bool changed; + bool is_member; + bool was_member; + bool was_admin; + struct sgrp *nsgrp; - /* - * See if the user specified this group as one of their - * concurrent groups. - */ - is_member = Gflg && ( (was_member && aflg) - || is_on_list (user_groups, sgrp->sg_name)); + changed = false; - if (!was_member && !was_admin && !is_member) { - continue; - } + /* + * See if the user was a member of this group + */ + was_member = is_on_list (sgrp->sg_mem, user_name); - /* - * If rflg+Gflg is passed in AKA -rG invert is_member, to remove targeted - * groups while leaving the user apart of groups not mentioned - */ - if (Gflg && rflg) { - is_member = !is_member; - } + /* + * See if the user was an administrator of this group + */ + was_admin = is_on_list (sgrp->sg_adm, user_name); - nsgrp = __sgr_dup (sgrp); - if (NULL == nsgrp) { - fprintf (stderr, - _("%s: Out of memory. Cannot update %s.\n"), - Prog, sgr_dbname ()); - fail_exit (E_GRP_UPDATE); - } + /* + * See if the user specified this group as one of their + * concurrent groups. + */ + is_member = Gflg && ( (was_member && aflg) + || is_on_list (user_groups, sgrp->sg_name)); - if (was_admin && lflg) { - /* User was an admin of this group but the user - * has been renamed. - */ - nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name); - nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname); - changed = true; -#ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing admin name in shadow group", - user_name, AUDIT_NO_ID, 1); -#endif - SYSLOG ((LOG_INFO, - "change admin '%s' to '%s' in shadow group '%s'", - user_name, user_newname, nsgrp->sg_name)); - } - - if (was_member) { - if ((!Gflg) || is_member) { - /* User was a member and is still a member - * of this group. - * But the user might have been renamed. - */ - if (lflg) { - nsgrp->sg_mem = del_list (nsgrp->sg_mem, - user_name); - nsgrp->sg_mem = add_list (nsgrp->sg_mem, - user_newname); - changed = true; + if (!was_member && !was_admin && !is_member) + return; + + /* + * If rflg+Gflg is passed in AKA -rG invert is_member, to remove targeted + * groups while leaving the user apart of groups not mentioned + */ + if (Gflg && rflg) { + is_member = !is_member; + } + + nsgrp = __sgr_dup (sgrp); + if (NULL == nsgrp) { + fprintf (stderr, + _("%s: Out of memory. Cannot update %s.\n"), + Prog, sgr_dbname ()); + fail_exit (E_GRP_UPDATE); + } + + if (was_admin && lflg) { + /* User was an admin of this group but the user + * has been renamed. + */ + nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name); + nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname); + changed = true; #ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "changing member in shadow group", - user_name, AUDIT_NO_ID, 1); + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "changing admin name in shadow group", + user_name, AUDIT_NO_ID, 1); #endif - SYSLOG ((LOG_INFO, - "change '%s' to '%s' in shadow group '%s'", - user_name, user_newname, - nsgrp->sg_name)); - } - } else { - /* User was a member but is no more a - * member of this group. - */ - nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); + SYSLOG ((LOG_INFO, + "change admin '%s' to '%s' in shadow group '%s'", + user_name, user_newname, nsgrp->sg_name)); + } + + if (was_member) { + if ((!Gflg) || is_member) { + /* User was a member and is still a member + * of this group. + * But the user might have been renamed. + */ + if (lflg) { + nsgrp->sg_mem = del_list (nsgrp->sg_mem, + user_name); + nsgrp->sg_mem = add_list (nsgrp->sg_mem, + user_newname); changed = true; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "removing user from shadow group", - user_name, AUDIT_NO_ID, 1); + "changing member in shadow group", + user_name, AUDIT_NO_ID, 1); #endif SYSLOG ((LOG_INFO, - "delete '%s' from shadow group '%s'", - user_name, nsgrp->sg_name)); + "change '%s' to '%s' in shadow group '%s'", + user_name, user_newname, + nsgrp->sg_name)); } - } else if (is_member) { - /* User was not a member but is now a member this - * group. + } else { + /* User was a member but is no more a + * member of this group. */ - nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_newname); + nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); changed = true; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "adding user to shadow group", - user_newname, AUDIT_NO_ID, 1); + "removing user from shadow group", + user_name, AUDIT_NO_ID, 1); #endif - SYSLOG ((LOG_INFO, "add '%s' to shadow group '%s'", - user_newname, nsgrp->sg_name)); - } - if (!changed) { - continue; + SYSLOG ((LOG_INFO, + "delete '%s' from shadow group '%s'", + user_name, nsgrp->sg_name)); } - - changed = false; - - /* - * Update the group entry to reflect the changes. + } else if (is_member) { + /* User was not a member but is now a member this + * group. */ - if (sgr_update (nsgrp) == 0) { - fprintf (stderr, - _("%s: failed to prepare the new %s entry '%s'\n"), - Prog, sgr_dbname (), nsgrp->sg_name); - SYSLOG ((LOG_WARN, "failed to prepare the new %s entry '%s'", - sgr_dbname (), nsgrp->sg_name)); - fail_exit (E_GRP_UPDATE); - } + nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_newname); + changed = true; +#ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "adding user to shadow group", + user_newname, AUDIT_NO_ID, 1); +#endif + SYSLOG ((LOG_INFO, "add '%s' to shadow group '%s'", + user_newname, nsgrp->sg_name)); + } + if (!changed) + goto free_nsgrp; - free (nsgrp); + /* + * Update the group entry to reflect the changes. + */ + if (sgr_update (nsgrp) == 0) { + fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, sgr_dbname (), nsgrp->sg_name); + SYSLOG ((LOG_WARN, "failed to prepare the new %s entry '%s'", + sgr_dbname (), nsgrp->sg_name)); + fail_exit (E_GRP_UPDATE); } + +free_nsgrp: + free (nsgrp); } #endif /* SHADOWGRP */ + /* * grp_update - add user to secondary group set * @@ -950,10 +966,10 @@ static void update_gshadow (void) */ static void grp_update (void) { - update_group (); + update_group_file(); #ifdef SHADOWGRP if (is_shadow_grp) { - update_gshadow (); + update_gshadow_file(); } #endif } @@ -967,7 +983,6 @@ static void grp_update (void) */ static void process_flags (int argc, char **argv) { - const struct group *grp; struct stat st; bool anyflag = false; @@ -978,6 +993,7 @@ static void process_flags (int argc, char **argv) int c; static struct option long_options[] = { {"append", no_argument, NULL, 'a'}, + {"badname", no_argument, NULL, 'b'}, {"badnames", no_argument, NULL, 'b'}, {"comment", required_argument, NULL, 'c'}, {"home", required_argument, NULL, 'd'}, @@ -1000,11 +1016,12 @@ static void process_flags (int argc, char **argv) #ifdef ENABLE_SUBIDS {"add-subuids", required_argument, NULL, 'v'}, {"del-subuids", required_argument, NULL, 'V'}, - {"add-subgids", required_argument, NULL, 'w'}, - {"del-subgids", required_argument, NULL, 'W'}, + {"add-subgids", required_argument, NULL, 'w'}, + {"del-subgids", required_argument, NULL, 'W'}, #endif /* ENABLE_SUBIDS */ #ifdef WITH_SELINUX - {"selinux-user", required_argument, NULL, 'Z'}, + {"selinux-user", required_argument, NULL, 'Z'}, + {"selinux-range", required_argument, NULL, 202}, #endif /* WITH_SELINUX */ {NULL, 0, NULL, '\0'} }; @@ -1058,11 +1075,10 @@ static void process_flags (int argc, char **argv) Prog, optarg); exit (E_BAD_ARG); } - user_newexpire *= DAY / SCALE; eflg = true; break; case 'f': - if ( (getlong (optarg, &user_newinactive) == 0) + if ( (str2sl(&user_newinactive, optarg) == -1) || (user_newinactive < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), @@ -1072,7 +1088,10 @@ static void process_flags (int argc, char **argv) fflg = true; break; case 'g': - grp = getgr_nam_gid (optarg); + { + struct group *grp; + + grp = prefix_getgr_nam_gid (optarg); if (NULL == grp) { fprintf (stderr, _("%s: group '%s' does not exist\n"), @@ -1083,6 +1102,7 @@ static void process_flags (int argc, char **argv) gflg = true; gr_free (grp); break; + } case 'G': if (get_groups (optarg) != 0) { exit (E_NOTFOUND); @@ -1146,7 +1166,7 @@ static void process_flags (int argc, char **argv) sflg = true; break; case 'u': - if ( (get_uid (optarg, &user_newid) ==0) + if ( (get_uid(optarg, &user_newid) == -1) || (user_newid == (uid_t)-1)) { fprintf (stderr, _("%s: invalid user ID '%s'\n"), @@ -1214,6 +1234,9 @@ static void process_flags (int argc, char **argv) exit (E_BAD_ARG); } break; + case 202: + user_selinux_range = optarg; + break; #endif /* WITH_SELINUX */ default: usage (E_USAGE); @@ -1258,46 +1281,16 @@ static void process_flags (int argc, char **argv) user_newgid = user_gid; } if (prefix[0]) { - size_t len = strlen(prefix) + strlen(user_home) + 2; - int wlen; - prefix_user_home = xmalloc(len); - wlen = snprintf(prefix_user_home, len, "%s/%s", prefix, user_home); - assert (wlen == (int) len -1); + xasprintf(&prefix_user_home, "%s/%s", prefix, user_home); if (user_newhome) { - len = strlen(prefix) + strlen(user_newhome) + 2; - prefix_user_newhome = xmalloc(len); - wlen = snprintf(prefix_user_newhome, len, "%s/%s", prefix, user_newhome); - assert (wlen == (int) len -1); + xasprintf(&prefix_user_newhome, "%s/%s", + prefix, user_newhome); } - - } - else { + } else { prefix_user_home = user_home; prefix_user_newhome = user_newhome; } -#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 - { const struct spwd *spwd = NULL; /* local, no need for xgetspnam */ @@ -1354,6 +1347,15 @@ static void process_flags (int argc, char **argv) usage (E_USAGE); } +#ifdef WITH_SELINUX + if (user_selinux_range && !Zflg) { + fprintf (stderr, + _("%s: %s flag is only allowed with the %s flag\n"), + Prog, "--selinux-range", "--selinux-user"); + usage (E_USAGE); + } +#endif /* WITH_SELINUX */ + if (user_newid == user_id) { uflg = false; oflg = false; @@ -1723,7 +1725,7 @@ static void usr_update (void) * a shadowed password * + aging information is requested */ - memset (&spent, 0, sizeof spent); + bzero(&spent, sizeof spent); spent.sp_namp = user_name; /* The user explicitly asked for a shadow feature. @@ -1732,7 +1734,7 @@ static void usr_update (void) spent.sp_pwdp = xstrdup (pwent.pw_passwd); pwent.pw_passwd = xstrdup (SHADOW_PASSWD_STRING); - spent.sp_lstchg = (long) gettime () / SCALE; + spent.sp_lstchg = gettime () / DAY; if (0 == spent.sp_lstchg) { /* Better disable aging than * requiring a password change */ @@ -1819,7 +1821,7 @@ static void move_home (void) if (uflg || gflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory owner", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); } #endif @@ -1838,8 +1840,7 @@ static void move_home (void) #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", - user_newname, (unsigned int) user_newid, - 1); + user_newname, user_newid, 1); #endif return; } else { @@ -1869,7 +1870,7 @@ static void move_home (void) Prog, "moving home directory", user_newname, - (unsigned int) user_newid, + user_newid, 1); #endif return; @@ -1897,6 +1898,7 @@ static void move_home (void) * left alone in case the UID was shared. It doesn't hurt anything * to just leave it be. */ +#ifdef ENABLE_LASTLOG static void update_lastlog (void) { struct lastlog ll; @@ -1909,7 +1911,7 @@ static void update_lastlog (void) return; } - max_uid = (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL); + max_uid = getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL); if (user_newid > max_uid) { /* do not touch lastlog for large uids */ return; @@ -1928,7 +1930,7 @@ static void update_lastlog (void) && (read (fd, &ll, sizeof ll) == (ssize_t) sizeof ll)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) + || (write_full(fd, &ll, sizeof ll) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), @@ -1944,7 +1946,7 @@ static void update_lastlog (void) /* Reset the new uid's lastlog entry */ memzero (&ll, sizeof (ll)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) + || (write_full(fd, &ll, sizeof ll) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), @@ -1953,8 +1955,13 @@ static void update_lastlog (void) } } - (void) close (fd); + if (close (fd) != 0 && errno != EINTR) { + fprintf (stderr, + _("%s: failed to copy the lastlog entry of user %ju to user %ju: %s\n"), + Prog, (uintmax_t) user_id, (uintmax_t) user_newid, strerror (errno)); + } } +#endif /* ENABLE_LASTLOG */ /* * update_faillog - update the faillog file @@ -1984,10 +1991,10 @@ static void update_faillog (void) } if ( (lseek (fd, off_uid, SEEK_SET) == off_uid) - && (read (fd, (char *) &fl, sizeof fl) == (ssize_t) sizeof fl)) { + && (read (fd, &fl, sizeof fl) == (ssize_t) sizeof fl)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &fl, sizeof fl) != (ssize_t) sizeof fl) + || (write_full(fd, &fl, sizeof fl) == -1) || (fsync (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"), @@ -2003,7 +2010,8 @@ static void update_faillog (void) /* Reset the new uid's faillog entry */ memzero (&fl, sizeof (fl)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) - || (write (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)) { + || (write_full(fd, &fl, sizeof fl) == -1)) + { fprintf (stderr, _("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"), Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno)); @@ -2011,7 +2019,11 @@ static void update_faillog (void) } } - (void) close (fd); + if (close (fd) != 0 && errno != EINTR) { + fprintf (stderr, + _("%s: failed to copy the faillog entry of user %ju to user %ju: %s\n"), + Prog, (uintmax_t) user_id, (uintmax_t) user_newid, strerror (errno)); + } } #ifndef NO_MOVE_MAILBOX @@ -2024,12 +2036,10 @@ static void update_faillog (void) */ static void move_mailbox (void) { - const char *maildir; - char* mailfile; - char* newmailfile; - int fd; - struct stat st; - size_t len; + int fd; + char *mailfile; + const char *maildir; + struct stat st; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR @@ -2040,8 +2050,6 @@ static void move_mailbox (void) if (NULL == maildir) { return; } - len = strlen (prefix) + strlen (maildir) + strlen (user_name) + 2; - mailfile = alloca (len); /* * O_NONBLOCK is to make sure open won't hang on mandatory locks. @@ -2050,14 +2058,10 @@ static void move_mailbox (void) * between stat and chown). --marekm */ if (prefix[0]) { - (void) snprintf (mailfile, len, "%s/%s/%s", - prefix, maildir, user_name); - } - else { - (void) snprintf (mailfile, len, "%s/%s", - maildir, user_name); + xasprintf(&mailfile, "%s/%s/%s", prefix, maildir, user_name); + } else { + xasprintf(&mailfile, "%s/%s", maildir, user_name); } - mailfile[len-1] = '\0'; fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0); if (fd < 0) { @@ -2065,11 +2069,13 @@ static void move_mailbox (void) if (errno != ENOENT) { perror (mailfile); } + free(mailfile); return; } if (fstat (fd, &st) < 0) { perror ("fstat"); (void) close (fd); + free(mailfile); return; } if (st.st_uid != user_id) { @@ -2077,6 +2083,7 @@ static void move_mailbox (void) fprintf (stderr, _("%s: warning: %s not owned by %s\n"), Prog, mailfile, user_name); (void) close (fd); + free(mailfile); return; } if (uflg) { @@ -2087,7 +2094,7 @@ static void move_mailbox (void) else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file owner", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); } #endif } @@ -2095,17 +2102,14 @@ static void move_mailbox (void) (void) close (fd); if (lflg) { - len = strlen (prefix) + strlen (maildir) + strlen (user_newname) + 2; - newmailfile = alloca(len); + char *newmailfile; + if (prefix[0]) { - (void) snprintf (newmailfile, len, "%s/%s/%s", - prefix, maildir, user_newname); - } - else { - (void) snprintf (newmailfile, len, "%s/%s", - maildir, user_newname); + xasprintf(&newmailfile, "%s/%s/%s", + prefix, maildir, user_newname); + } else { + xasprintf(&newmailfile, "%s/%s", maildir, user_newname); } - newmailfile[len - 1] = '\0'; if ( (link (mailfile, newmailfile) != 0) || (unlink (mailfile) != 0)) { perror (_("failed to rename mailbox")); @@ -2114,10 +2118,14 @@ static void move_mailbox (void) else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file name", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); } + + free(newmailfile); #endif } + + free(mailfile); } #endif @@ -2133,10 +2141,6 @@ int main (int argc, char **argv) #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ - /* - * Get my name so that I can use it to report errors. - */ - Prog = Basename (argv[0]); log_set_progname(Prog); log_set_logfd(stderr); @@ -2147,14 +2151,14 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); prefix = process_prefix_flag ("-P", argc, argv); - OPENLOG ("usermod"); + OPENLOG (Prog); #ifdef WITH_AUDIT audit_help_open (); #endif sys_ngroups = sysconf (_SC_NGROUPS_MAX); - user_groups = (char **) malloc (sizeof (char *) * (1 + sys_ngroups)); - user_groups[0] = (char *) 0; + user_groups = XMALLOC(sys_ngroups + 1, char *); + user_groups[0] = NULL; is_shadow_pwd = spw_file_present (); #ifdef SHADOWGRP @@ -2193,7 +2197,7 @@ int main (int argc, char **argv) exit (1); } - retval = pam_start ("usermod", pampw->pw_name, &conv, &pamh); + retval = pam_start (Prog, pampw->pw_name, &conv, &pamh); } if (PAM_SUCCESS == retval) { @@ -2305,14 +2309,14 @@ int main (int argc, char **argv) #ifdef WITH_SELINUX if (Zflg) { if ('\0' != *user_selinux) { - if (set_seuser (user_name, user_selinux) != 0) { + if (set_seuser (user_name, user_selinux, user_selinux_range) != 0) { fprintf (stderr, _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), Prog, user_name, user_selinux); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying User mapping ", - user_name, (unsigned int) user_id, + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SE_UPDATE); @@ -2325,7 +2329,7 @@ int main (int argc, char **argv) #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_USER, Prog, "removing SELinux user mapping", - user_name, (unsigned int) user_id, + user_name, user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SE_UPDATE); @@ -2345,7 +2349,9 @@ int main (int argc, char **argv) #endif /* NO_MOVE_MAILBOX */ if (uflg) { +#ifdef ENABLE_LASTLOG update_lastlog (); +#endif /* ENABLE_LASTLOG */ update_faillog (); } @@ -2367,7 +2373,7 @@ int main (int argc, char **argv) if (uflg || gflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory owner", - user_newname, (unsigned int) user_newid, 1); + user_newname, user_newid, 1); } #endif if (chown_tree (dflg ? prefix_user_newhome : prefix_user_home, @@ -26,7 +26,10 @@ #include <sys/types.h> #include <unistd.h> #include <utime.h> + +#include "alloc.h" #include "defines.h" +#include "getdef.h" #include "groupio.h" #include "nscd.h" #include "sssd.h" @@ -41,6 +44,8 @@ #include "tcbfuncs.h" #endif /* WITH_TCB */ #include "shadowlog.h" +#include "string/sprintf.h" + #define MSG_WARN_EDIT_OTHER_FILE _( \ "You have modified %s.\n"\ @@ -50,7 +55,7 @@ /* * Global variables */ -const char *Prog; +static const char *Prog; static const char *filename, *fileeditname; static bool filelocked = false; @@ -190,18 +195,17 @@ static void vipwexit (const char *msg, int syserr, int ret) static void vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) { - const char *editor; - pid_t pid; - struct stat st1, st2; - int status; - FILE *f; - pid_t orig_pgrp, editor_pgrp = -1; - sigset_t mask, omask; + int status; + char *to_rename; + FILE *f; + pid_t pid, orig_pgrp, editor_pgrp = -1; + sigset_t mask, omask; + const char *editor; + struct stat st1, st2; /* FIXME: the following should have variable sizes */ - char filebackup[1024], fileedit[1024]; - char *to_rename; + char filebackup[1024], fileedit[1024]; - snprintf (filebackup, sizeof filebackup, "%s-", file); + SNPRINTF(filebackup, "%s-", file); #ifdef WITH_TCB if (tcb_mode) { if ( (mkdir (TCB_DIR "/" SHADOWTCB_SCRATCHDIR, 0700) != 0) @@ -211,12 +215,12 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) { vipwexit (_("failed to drop privileges"), errno, 1); } - snprintf (fileedit, sizeof fileedit, - TCB_DIR "/" SHADOWTCB_SCRATCHDIR "/.vipw.shadow.%s", - user); + SNPRINTF(fileedit, + TCB_DIR "/" SHADOWTCB_SCRATCHDIR "/.vipw.shadow.%s", + user); } else { #endif /* WITH_TCB */ - snprintf (fileedit, sizeof fileedit, "%s.edit", file); + SNPRINTF(fileedit, "%s.edit", file); #ifdef WITH_TCB } #endif /* WITH_TCB */ @@ -292,7 +296,7 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) } else if (0 == pid) { /* use the system() call to invoke the editor so that it accepts command line args in the EDITOR and VISUAL environment vars */ - char *buf; + char *buf; /* Wait for parent to make us the foreground pgrp. */ if (orig_pgrp != -1) { @@ -302,9 +306,8 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) continue; } - buf = (char *) malloc (strlen (editor) + strlen (fileedit) + 2); - snprintf (buf, strlen (editor) + strlen (fileedit) + 2, - "%s %s", editor, fileedit); + xasprintf(&buf, "%s %s", editor, fileedit); + status = system (buf); if (-1 == status) { fprintf (stderr, _("%s: %s: %s\n"), Prog, editor, @@ -418,13 +421,11 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) if (stat (file, &st1) != 0) { vipwexit (_("failed to stat edited file"), errno, 1); } - to_rename = malloc (strlen (file) + 2); - if (NULL == to_rename) { - vipwexit (_("failed to allocate memory"), errno, 1); - } - snprintf (to_rename, strlen (file) + 2, "%s+", file); + if (asprintf(&to_rename, "%s+", file) == -1) + vipwexit (_("asprintf(3) failed"), errno, 1); + if (create_backup_file (f, to_rename, &st1) != 0) { - free (to_rename); + free(to_rename); vipwexit (_("failed to create backup file"), errno, 1); } (void) fclose (f); @@ -442,7 +443,7 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) Prog, file, strerror (errno), to_rename); #ifdef WITH_TCB if (tcb_mode) { - free (to_rename); + free(to_rename); } #endif /* WITH_TCB */ vipwexit (0, 0, 1); @@ -450,7 +451,7 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) #ifdef WITH_TCB if (tcb_mode) { - free (to_rename); + free(to_rename); if (shadowtcb_gain_priv () == SHADOWTCB_FAILURE) { vipwexit (_("failed to gain privileges"), errno, 1); } @@ -467,10 +468,12 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void)) int main (int argc, char **argv) { - bool editshadow = false; - bool do_vipw; + bool editshadow = false; + bool do_vigr; + + do_vigr = (strcmp(Basename(argv[0]), "vigr") == 0); - Prog = Basename (argv[0]); + Prog = do_vigr ? "vigr" : "vipw"; log_set_progname(Prog); log_set_logfd(stderr); @@ -480,9 +483,7 @@ int main (int argc, char **argv) process_root_flag ("-R", argc, argv); - do_vipw = (strcmp (Prog, "vigr") != 0); - - OPENLOG (do_vipw ? "vipw" : "vigr"); + OPENLOG(Prog); { /* @@ -510,13 +511,13 @@ int main (int argc, char **argv) long_options, NULL)) != -1) { switch (c) { case 'g': - do_vipw = false; + do_vigr = true; break; case 'h': usage (E_SUCCESS); break; case 'p': - do_vipw = true; + do_vigr = false; break; case 'q': quiet = true; @@ -541,7 +542,27 @@ int main (int argc, char **argv) } } - if (do_vipw) { + if (do_vigr) { +#ifdef SHADOWGRP + if (editshadow) { + vipwedit (sgr_dbname (), sgr_lock, sgr_unlock); + printf (MSG_WARN_EDIT_OTHER_FILE, + sgr_dbname (), + gr_dbname (), + "vigr"); + } else { +#endif /* SHADOWGRP */ + vipwedit (gr_dbname (), gr_lock, gr_unlock); +#ifdef SHADOWGRP + if (sgr_file_present ()) { + printf (MSG_WARN_EDIT_OTHER_FILE, + gr_dbname (), + sgr_dbname (), + "vigr -s"); + } + } +#endif /* SHADOWGRP */ + } else { if (editshadow) { #ifdef WITH_TCB if (getdef_bool ("USE_TCB") && (NULL != user)) { @@ -568,26 +589,6 @@ int main (int argc, char **argv) "vipw -s"); } } - } else { -#ifdef SHADOWGRP - if (editshadow) { - vipwedit (sgr_dbname (), sgr_lock, sgr_unlock); - printf (MSG_WARN_EDIT_OTHER_FILE, - sgr_dbname (), - gr_dbname (), - "vigr"); - } else { -#endif /* SHADOWGRP */ - vipwedit (gr_dbname (), gr_lock, gr_unlock); -#ifdef SHADOWGRP - if (sgr_file_present ()) { - printf (MSG_WARN_EDIT_OTHER_FILE, - gr_dbname (), - sgr_dbname (), - "vigr -s"); - } - } -#endif /* SHADOWGRP */ } nscd_flush_cache ("passwd"); |