Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
499c6f7938 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,7 +17,6 @@ Makefile.in
|
||||
/ABOUT-NLS
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
/compile
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
|
||||
205
NEWS
205
NEWS
@@ -1,207 +1,6 @@
|
||||
$Id$
|
||||
|
||||
shadow-4.1.5.1 -> shadow-4.2 UNRELEASED
|
||||
|
||||
*** general
|
||||
* Handle libc whose crypt() returns NULL when passed a salt that
|
||||
violates specs or system requirements (e.g. FIPS140). This is needed
|
||||
with glibc/eglibc 2.17 for tools checking passwords (passwd (non PAM
|
||||
enabled) or newgrp), and for tools generating encrypted passwords
|
||||
(chgpasswd, chpasswd, or gpasswd when non PAM enabled or when a fixed
|
||||
crypt method is requested on the command line, and newusers, or passwd
|
||||
in their non PAM enabled versions)
|
||||
* Fix segfault when reading groups split on multiple lines. This impacts
|
||||
most user/group management tools when MAX_MEMBERS_PER_GROUP is set.
|
||||
|
||||
- su
|
||||
* When su receives a signal (SIGTERM, or SIGINT/SIGQUIT in non
|
||||
interactive mode), kill the child process group, rather than just the
|
||||
immediate child.
|
||||
* Fix segmentation faults for users without a proper home or shell in
|
||||
their passwd entries.
|
||||
|
||||
- login
|
||||
* Fix segmentation faults for users without a proper home or shell in
|
||||
their passwd entries.
|
||||
|
||||
*** documentation
|
||||
* Fixed useradd man page (--home-dir option, instead of --home).
|
||||
|
||||
*** translation
|
||||
* Updated Russian translation.
|
||||
* Updated German man pages translation.
|
||||
* Fixed gshadow Japanese man page translation.
|
||||
|
||||
shadow-4.1.5 -> shadow-4.1.5.1 2012-05-25
|
||||
|
||||
- login
|
||||
* Log into utmp(x) when PAM is enabled, but do not log into wtmp.
|
||||
This complete pam_lastlog which logs into wtmp and in into utmp(x).
|
||||
- su
|
||||
* non PAM enabled versions: do not fail if su is called without a
|
||||
controlling terminal.
|
||||
- userdel
|
||||
* Fix segfault when userdel removes the user's group.
|
||||
|
||||
*** documentation
|
||||
* .so links now point to paths relative to the top-level manual hierarchy
|
||||
|
||||
*** translation
|
||||
* Updated French man pages translation.
|
||||
* Updated German man pages translation.
|
||||
* Updated Polish man pages translation. (logoutd.8)
|
||||
|
||||
shadow-4.1.4.3 -> shadow-4.1.5 2012-02-12
|
||||
|
||||
*** security
|
||||
* su -c could be abused by the executed command to invoke commands with
|
||||
the caller privileges. See below. (CVE-2005-4890)
|
||||
|
||||
*** general
|
||||
* report usage error to stderr, but report usage help to stdout (and return
|
||||
zero) when explicitly requested (e.g. with --help).
|
||||
* initial support for tcb (http://openwall.com/tcb/) for useradd,
|
||||
userdel, usermod, chage, pwck, vipw.
|
||||
* Added support for ACLs and Extended Attributes in useradd and usermod.
|
||||
Support shall be enabled with the new --with-acl or --with-attr
|
||||
configure options.
|
||||
* Added diagnosis for lock failures.
|
||||
* use libsemanage instead of the semanage tool.
|
||||
|
||||
- chage
|
||||
* Add --root option.
|
||||
- chfn
|
||||
* Add --root option.
|
||||
- chgpasswd
|
||||
* When the gshadow file exists but there are no gshadow entries, an entry
|
||||
is created if the password is changed and group requires a
|
||||
shadow entry.
|
||||
* Add --root option.
|
||||
- chpasswd
|
||||
* PAM enabled versions: restore the -e option to allow restoring
|
||||
passwords without knowing those passwords. Restore together the -m
|
||||
and -c options. (These options were removed in shadow-4.1.4 on PAM
|
||||
enabled versions)
|
||||
* When the shadow file exists but there are no shadow entries, an entry
|
||||
is created if the password is changed and passwd requires a
|
||||
shadow entry.
|
||||
* Add --root option.
|
||||
- chsh
|
||||
* Add --root option.
|
||||
- faillog
|
||||
* The -l, -m, -r, -t options only act on the existing users, unless -a is
|
||||
specified.
|
||||
* Add --root option.
|
||||
- gpasswd
|
||||
* Add --root option.
|
||||
- groupadd
|
||||
* Add --root option.
|
||||
- groupdel
|
||||
* Add --root option.
|
||||
- groupmems
|
||||
* Fix parsing of gshadow entries.
|
||||
* Add --root option.
|
||||
- groupmod
|
||||
* Fixed groupmod when configured with --enable-account-tools-setuid.
|
||||
* When the gshadow file exists but there are no gshadow entries, an entry
|
||||
is created if the password is changed and group requires a
|
||||
shadow entry.
|
||||
* Add --root option.
|
||||
- grpck
|
||||
* Add --root option.
|
||||
* NIS entries were dropped by -s (sort).
|
||||
- grpconv
|
||||
* Add --root option.
|
||||
- grpunconv
|
||||
* Add --root option.
|
||||
- lastlog
|
||||
* Add --root option.
|
||||
- login
|
||||
* Fixed limits support (non PAM enabled versions only)
|
||||
* Added support for infinite limits and group based limits (non PAM
|
||||
enabled versions only)
|
||||
* Fixed infinite loop when CONSOLE is configured with a colon-separated
|
||||
list of TTYs.
|
||||
* Fixed warning and support for CONSOLE_GROUPS for users member of more
|
||||
than 16 groups.
|
||||
* Do not log into utmp(x) or wtmp when PAM is enabled. This is done by
|
||||
pam_lastlog.
|
||||
- newgrp, sg
|
||||
* Fix parsing of gshadow entries.
|
||||
- newusers
|
||||
* Add --root option.
|
||||
- passwd
|
||||
* Add --root option.
|
||||
- pwpck
|
||||
* NIS entries were dropped by -s (sort).
|
||||
* Add --root option.
|
||||
- pwconv
|
||||
* Add --root option.
|
||||
- pwunconv
|
||||
* Add --root option.
|
||||
- useradd
|
||||
* If the skeleton directory contained hardlinked files, copies of the
|
||||
hardlink were removed from the skeleton directory.
|
||||
* Add --root option.
|
||||
- userdel
|
||||
* Check the existence of the user's mail spool before trying to remove
|
||||
it. If it does not exist, a warning is issued, but no failure.
|
||||
* Do not remove a group with the same name as the user (usergroup) if
|
||||
this group isn't the user's primary group.
|
||||
* Add --root option.
|
||||
* Add --selinux-user option.
|
||||
- usermod
|
||||
* Accept options in any order (username not necessarily at the end)
|
||||
* When the shadow file exists but there are no shadow entries, an entry
|
||||
is created if the password is changed and passwd requires a
|
||||
shadow entry, or if aging features are used (-e or -f).
|
||||
* Add --root option.
|
||||
- su
|
||||
* Document the su exit values.
|
||||
* When su receives a signal, wait for the child to terminate (after
|
||||
sending a SIGTERM), and kill it only if it did not terminate by itself.
|
||||
No delay will be enforced if the child cooperates.
|
||||
* Default ENV_SUPATH is /sbin:/bin:/usr/sbin:/usr/bin
|
||||
* Fixed infinite loop when CONSOLE is configured with a colon-separated
|
||||
list of TTYs.
|
||||
* Fixed warning and support for CONSOLE_GROUPS for users member of more
|
||||
than 16 groups.
|
||||
* Do not forward the controlling terminal to commands executed with -c.
|
||||
This prevents tty hijacking which could lead to execution with the
|
||||
caller's privileges.
|
||||
* Close PAM sessions as root. This will be more friendly to PAM modules
|
||||
like pam_mount or pam_systemd.
|
||||
* Added support for PAM modules which change PAM_USER.
|
||||
|
||||
*** translation
|
||||
* Updated Brazilian Portuguese translation.
|
||||
* Updated Catalan translation.
|
||||
* Updated Czech translation.
|
||||
* Updated Danish translation.
|
||||
* New Danish man pages translation.
|
||||
* Updated French translation.
|
||||
* Updated French man pages translation.
|
||||
* Updated German translation.
|
||||
* Updated German man pages translation.
|
||||
* Updated Greek translation.
|
||||
* Updated Italian man pages translation.
|
||||
* Updated Japanese translation.
|
||||
* Updated Kazakh translation.
|
||||
* Updated Norwegian Bokmål translation.
|
||||
* Updated Portuguese translation.
|
||||
* Updated Russian translation.
|
||||
* Updated Simplified Chinese translation.
|
||||
* Updated Simplified Chinese man pages translation.
|
||||
* Updated Swedish translation.
|
||||
* Updated Vietnamese translation.
|
||||
|
||||
shadow-4.1.4.2 -> shadow-4.1.4.3 2011-02-15
|
||||
|
||||
*** security
|
||||
- CVE-2011-0721: An insufficient input sanitation in chfn can be exploited
|
||||
to create users or groups in a NIS environment.
|
||||
|
||||
shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
|
||||
shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
|
||||
|
||||
- general
|
||||
* Improved support for large groups (impacts most user/group management
|
||||
@@ -511,7 +310,7 @@ shadow-4.1.0 -> shadow-4.1.1 02-04-2008
|
||||
faillog faster.
|
||||
- gpasswd
|
||||
* Fix failures when the gshadow file is not present.
|
||||
* When a password is moved to the gshadow file, use "x" instead of "!"
|
||||
* When a password is moved to the gshadow file, use "x" instead of "x"
|
||||
to indicate that the password is shadowed (consistency with grpconv).
|
||||
* Make sure the group and gshadow files are unlocked on exit.
|
||||
- groupadd
|
||||
|
||||
6
README
6
README
@@ -37,7 +37,7 @@ S/Key support:
|
||||
Authors and contributors
|
||||
========================
|
||||
|
||||
Thanks to at least the following people for sending patches, bug
|
||||
Thanks to at least the following people for sending me patches, bug
|
||||
reports and various comments. This list may be incomplete, I received
|
||||
a lot of mail...
|
||||
|
||||
@@ -69,7 +69,6 @@ Greg Mortensen <loki@world.std.com>
|
||||
Guido van Rooij
|
||||
Guy Maor <maor@debian.org>
|
||||
Hrvoje Dogan <hdogan@bjesomar.srce.hr>
|
||||
Jakub Hrozek <jhrozek@redhat.com>
|
||||
Janos Farkas <chexum@bankinf.banki.hu>
|
||||
Jay Soffian <jay@lw.net>
|
||||
Jesse Thilo <Jesse.Thilo@pobox.com>
|
||||
@@ -81,7 +80,6 @@ Joshua Cowan <jcowan@hermit.reslife.okstate.edu>
|
||||
Judd Bourgeois <shagboy@bluesky.net>
|
||||
Juergen Heinzl <unicorn@noris.net>
|
||||
Juha Virtanen <jiivee@iki.fi>
|
||||
Julian Pidancet <julian.pidancet@gmail.com>
|
||||
Julianne Frances Haugh <jockgrrl@ix.netcom.com>
|
||||
Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
Luca Berra <bluca@www.polimi.it>
|
||||
@@ -97,12 +95,10 @@ Mike Pakovic <mpakovic@users.southeast.net>
|
||||
Nicolas François <nicolas.francois@centraliens.net>
|
||||
Nikos Mavroyanopoulos <nmav@i-net.paiko.gr>
|
||||
Pavel Machek <pavel@bug.ucw.cz>
|
||||
Peter Vrabec <pvrabec@redhat.com>
|
||||
Phillip Street
|
||||
Rafał Maszkowski <rzm@icm.edu.pl>
|
||||
Rani Chouha <ranibey@smartec.com>
|
||||
Sami Kerola <kerolasa@rocketmail.com>
|
||||
Scott Garman <scott.a.garman@intel.com>
|
||||
Sebastian Rick Rijkers <srrijkers@gmail.com>
|
||||
Seraphim Mellos <mellos@ceid.upatras.gr>
|
||||
Shane Watts <shane@nexus.mlckew.edu.au>
|
||||
|
||||
15
TODO
15
TODO
@@ -1,10 +1,3 @@
|
||||
* Create a common usage function that'd take the array of
|
||||
long options and an array of descriptions and output that so things would
|
||||
be standardized across the utils.
|
||||
Usage strings should be normalized and split first.
|
||||
Investigate optparse.
|
||||
|
||||
|
||||
/etc/default/useradd
|
||||
* GROUP=1000 should accept a group name.
|
||||
|
||||
@@ -115,13 +108,7 @@ ALL:
|
||||
entry (with a password).
|
||||
- Add check to move passwd passwords to shadow if there is a shadow
|
||||
file.
|
||||
- Support an alternative /etc/tcb directory as second parameter.
|
||||
- add options -g / -G to specify alternative group / gshadow files
|
||||
|
||||
- su
|
||||
- add a login.defs configuration parameter to add variables to keep in
|
||||
the environment with "su -l" (TERM/TERMCOLOR/...)
|
||||
|
||||
- vipw
|
||||
- set ACLs and XATTRs on the temporary file (and backups?)
|
||||
- vipw + selinux -> use lib/selinux.c
|
||||
the environment with "su -l" (TERM/TERMCOLOR/...
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#! /bin/sh
|
||||
|
||||
autoreconf -v -f --install || exit 1
|
||||
|
||||
./configure \
|
||||
CFLAGS="-O2 -Wall" \
|
||||
--enable-man \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT
|
||||
AM_INIT_AUTOMAKE(shadow, 4.3.1)
|
||||
AM_INIT_AUTOMAKE(shadow, 4.1.4.2)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
dnl Some hacks...
|
||||
@@ -19,6 +19,7 @@ AC_PROG_CC
|
||||
AC_ISC_POSIX
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_YACC
|
||||
AM_C_PROTOTYPES
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
dnl Checks for libraries.
|
||||
@@ -32,8 +33,7 @@ AC_HEADER_STDBOOL
|
||||
AC_CHECK_HEADERS(errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \
|
||||
utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \
|
||||
utime.h ulimit.h sys/resource.h gshadow.h lastlog.h \
|
||||
locale.h rpc/key_prot.h netdb.h acl/libacl.h attr/libattr.h \
|
||||
attr/error_context.h)
|
||||
locale.h rpc/key_prot.h netdb.h)
|
||||
|
||||
dnl shadow now uses the libc's shadow implementation
|
||||
AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
|
||||
@@ -41,8 +41,7 @@ AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
|
||||
AC_CHECK_FUNCS(l64a fchmod fchown fsync futimes getgroups gethostname getspnam \
|
||||
gettimeofday getusershell getutent initgroups lchown lckpwdf lstat \
|
||||
lutimes memcpy memset setgroups sigaction strchr updwtmp updwtmpx innetgr \
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo \
|
||||
ruserok)
|
||||
getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo)
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
@@ -113,6 +112,7 @@ AC_REPLACE_FUNCS(sgetgrent sgetpwent sgetspent)
|
||||
AC_REPLACE_FUNCS(snprintf strcasecmp strdup strerror strstr)
|
||||
|
||||
AC_CHECK_FUNC(setpgrp)
|
||||
AC_FUNC_SETPGRP
|
||||
|
||||
if test "$ac_cv_header_shadow_h" = "yes"; then
|
||||
AC_CACHE_CHECK(for working shadow group support,
|
||||
@@ -195,10 +195,8 @@ AC_DEFINE_UNQUOTED(PASSWD_PROGRAM, "$shadow_cv_passwd_dir/passwd",
|
||||
|
||||
dnl XXX - quick hack, should disappear before anyone notices :).
|
||||
AC_DEFINE(USE_SYSLOG, 1, [Define to use syslog().])
|
||||
if test "$ac_cv_func_ruserok" = "yes"; then
|
||||
AC_DEFINE(RLOGIN, 1, [Define if login should support the -r flag for rlogind.])
|
||||
AC_DEFINE(RUSEROK, 0, [Define to the ruserok() "success" return value (0 or 1).])
|
||||
fi
|
||||
AC_DEFINE(RLOGIN, 1, [Define if login should support the -r flag for rlogind.])
|
||||
AC_DEFINE(RUSEROK, 0, [Define to the ruserok() "success" return value (0 or 1).])
|
||||
|
||||
AC_ARG_ENABLE(shadowgrp,
|
||||
[AC_HELP_STRING([--enable-shadowgrp], [enable shadow group support @<:@default=yes@:>@])],
|
||||
@@ -240,13 +238,6 @@ AC_ARG_ENABLE(utmpx,
|
||||
[enable_utmpx="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(subordinate-ids,
|
||||
[AC_HELP_STRING([--enable-subordinate-ids],
|
||||
[support subordinate ids @<:@default=yes@:>@])],
|
||||
[enable_subids="${enableval}"],
|
||||
[enable_subids="maybe"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(audit,
|
||||
[AC_HELP_STRING([--with-audit], [use auditing support @<:@default=yes if found@:>@])],
|
||||
[with_audit=$withval], [with_audit=maybe])
|
||||
@@ -256,20 +247,11 @@ AC_ARG_WITH(libpam,
|
||||
AC_ARG_WITH(selinux,
|
||||
[AC_HELP_STRING([--with-selinux], [use SELinux support @<:@default=yes if found@:>@])],
|
||||
[with_selinux=$withval], [with_selinux=maybe])
|
||||
AC_ARG_WITH(acl,
|
||||
[AC_HELP_STRING([--with-acl], [use ACL support @<:@default=yes if found@:>@])],
|
||||
[with_acl=$withval], [with_acl=maybe])
|
||||
AC_ARG_WITH(attr,
|
||||
[AC_HELP_STRING([--with-attr], [use Extended Attribute support @<:@default=yes if found@:>@])],
|
||||
[with_attr=$withval], [with_attr=maybe])
|
||||
AC_ARG_WITH(skey,
|
||||
[AC_HELP_STRING([--with-skey], [use S/Key support @<:@default=no@:>@])],
|
||||
[with_skey=$withval], [with_skey=no])
|
||||
AC_ARG_WITH(tcb,
|
||||
[AC_HELP_STRING([--with-tcb], [use tcb support (incomplete) @<:@default=yes if found@:>@])],
|
||||
[with_tcb=$withval], [with_tcb=maybe])
|
||||
AC_ARG_WITH(libcrack,
|
||||
[AC_HELP_STRING([--with-libcrack], [use libcrack @<:@default=no@:>@])],
|
||||
[AC_HELP_STRING([--with-libcrack], [use libcrack @<:@default=yes if found and if PAM not enabled@:>@])],
|
||||
[with_libcrack=$withval], [with_libcrack=no])
|
||||
AC_ARG_WITH(sha-crypt,
|
||||
[AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])],
|
||||
@@ -331,81 +313,10 @@ if test "$enable_man" = "yes"; then
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_REGENERATE_MAN, test "x$enable_man" != "xno")
|
||||
|
||||
if test "$enable_subids" != "no"; then
|
||||
dnl
|
||||
dnl FIXME: check if 32 bit UIDs/GIDs are supported by libc
|
||||
dnl
|
||||
AC_CHECK_SIZEOF([uid_t],, [#include "sys/types.h"])
|
||||
AC_CHECK_SIZEOF([gid_t],, [#include "sys/types.h"])
|
||||
|
||||
if test "$ac_cv_sizeof_uid_t" -ge 4 && test "$ac_cv_sizeof_gid_t" -ge 4; then
|
||||
AC_DEFINE(ENABLE_SUBIDS, 1, [Define to support the subordinate IDs.])
|
||||
enable_subids="yes"
|
||||
else
|
||||
if test "x$enable_subids" = "xyes"; then
|
||||
AC_MSG_ERROR([Cannot enable support the subordinate IDs on systems where gid_t or uid_t has less than 32 bits])
|
||||
fi
|
||||
enable_subids="no"
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_SUBIDS, test "x$enable_subids" != "xno")
|
||||
|
||||
AC_SUBST(LIBCRYPT)
|
||||
AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
|
||||
[AC_MSG_ERROR([crypt() not found])])
|
||||
|
||||
AC_SUBST(LIBACL)
|
||||
if test "$with_acl" != "no"; then
|
||||
AC_CHECK_HEADERS(acl/libacl.h attr/error_context.h, [acl_header="yes"], [acl_header="no"])
|
||||
if test "$acl_header$with_acl" = "noyes" ; then
|
||||
AC_MSG_ERROR([acl/libacl.h or attr/error_context.h is missing])
|
||||
elif test "$acl_header" = "yes" ; then
|
||||
AC_CHECK_LIB(acl, perm_copy_file,
|
||||
[AC_CHECK_LIB(acl, perm_copy_fd,
|
||||
[acl_lib="yes"],
|
||||
[acl_lib="no"])],
|
||||
[acl_lib="no"])
|
||||
if test "$acl_lib$with_acl" = "noyes" ; then
|
||||
AC_MSG_ERROR([libacl not found])
|
||||
elif test "$acl_lib" = "no" ; then
|
||||
with_acl="no"
|
||||
else
|
||||
AC_DEFINE(WITH_ACL, 1,
|
||||
[Build shadow with ACL support])
|
||||
LIBACL="-lacl"
|
||||
with_acl="yes"
|
||||
fi
|
||||
else
|
||||
with_acl="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBATTR)
|
||||
if test "$with_attr" != "no"; then
|
||||
AC_CHECK_HEADERS(attr/libattr.h attr/error_context.h, [attr_header="yes"], [attr_header="no"])
|
||||
if test "$attr_header$with_attr" = "noyes" ; then
|
||||
AC_MSG_ERROR([attr/libattr.h or attr/error_context.h is missing])
|
||||
elif test "$attr_header" = "yes" ; then
|
||||
AC_CHECK_LIB(attr, attr_copy_file,
|
||||
[AC_CHECK_LIB(attr, attr_copy_fd,
|
||||
[attr_lib="yes"],
|
||||
[attr_lib="no"])],
|
||||
[attr_lib="no"])
|
||||
if test "$attr_lib$with_attr" = "noyes" ; then
|
||||
AC_MSG_ERROR([libattr not found])
|
||||
elif test "$attr_lib" = "no" ; then
|
||||
with_attr="no"
|
||||
else
|
||||
AC_DEFINE(WITH_ATTR, 1,
|
||||
[Build shadow with Extended Attributes support])
|
||||
LIBATTR="-lattr"
|
||||
with_attr="yes"
|
||||
fi
|
||||
else
|
||||
with_attr="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBAUDIT)
|
||||
if test "$with_audit" != "no"; then
|
||||
AC_CHECK_HEADER(libaudit.h, [audit_header="yes"], [audit_header="no"])
|
||||
@@ -450,65 +361,28 @@ if test "$with_libcrack" = "yes"; then
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBSELINUX)
|
||||
AC_SUBST(LIBSEMANAGE)
|
||||
if test "$with_selinux" != "no"; then
|
||||
AC_CHECK_HEADERS(selinux/selinux.h, [selinux_header="yes"], [selinux_header="no"])
|
||||
if test "$selinux_header$with_selinux" = "noyes" ; then
|
||||
AC_MSG_ERROR([selinux/selinux.h is missing])
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS(semanage/semanage.h, [semanage_header="yes"], [semanage_header="no"])
|
||||
if test "$semanage_header$with_selinux" = "noyes" ; then
|
||||
AC_MSG_ERROR([semanage/semanage.h is missing])
|
||||
fi
|
||||
|
||||
if test "$selinux_header$semanage_header" = "yesyes" ; then
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, [selinux_lib="yes"], [selinux_lib="no"])
|
||||
elif test "$selinux_header" = "yes" ; then
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled,
|
||||
[selinux_lib="yes"], [selinux_lib="no"])
|
||||
if test "$selinux_lib$with_selinux" = "noyes" ; then
|
||||
AC_MSG_ERROR([libselinux not found])
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB(semanage, semanage_connect, [semanage_lib="yes"], [semanage_lib="no"])
|
||||
if test "$semanage_lib$with_selinux" = "noyes" ; then
|
||||
AC_MSG_ERROR([libsemanage not found])
|
||||
fi
|
||||
|
||||
if test "$selinux_lib$semanage_lib" == "yesyes" ; then
|
||||
elif test "$selinux_lib" = "no" ; then
|
||||
with_selinux="no"
|
||||
else
|
||||
AC_DEFINE(WITH_SELINUX, 1,
|
||||
[Build shadow with SELinux support])
|
||||
LIBSELINUX="-lselinux"
|
||||
LIBSEMANAGE="-lsemanage"
|
||||
with_selinux="yes"
|
||||
else
|
||||
with_selinux="no"
|
||||
fi
|
||||
else
|
||||
with_selinux="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBTCB)
|
||||
if test "$with_tcb" != "no"; then
|
||||
AC_CHECK_HEADERS(tcb.h, [tcb_header="yes"], [tcb_header="no"])
|
||||
if test "$tcb_header$with_tcb" = "noyes" ; then
|
||||
AC_MSG_ERROR([tcb.h is missing])
|
||||
elif test "$tcb_header" = "yes" ; then
|
||||
AC_CHECK_LIB(tcb, tcb_is_suspect, [tcb_lib="yes"], [tcb_lib="no"])
|
||||
if test "$tcb_lib$with_tcb" = "noyes" ; then
|
||||
AC_MSG_ERROR([libtcb not found])
|
||||
elif test "$tcb_lib" = "no" ; then
|
||||
with_tcb="no"
|
||||
else
|
||||
AC_DEFINE(WITH_TCB, 1, [Build shadow with tcb support (incomplete)])
|
||||
LIBTCB="-ltcb"
|
||||
with_tcb="yes"
|
||||
fi
|
||||
else
|
||||
with_tcb="no"
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(WITH_TCB, test x$with_tcb = xyes)
|
||||
|
||||
AC_SUBST(LIBPAM)
|
||||
if test "$with_libpam" != "no"; then
|
||||
AC_CHECK_LIB(pam, pam_start,
|
||||
@@ -629,9 +503,8 @@ AC_CONFIG_FILES([
|
||||
doc/Makefile
|
||||
man/Makefile
|
||||
man/config.xml
|
||||
man/po/Makefile
|
||||
man/po/Makefile.in
|
||||
man/cs/Makefile
|
||||
man/da/Makefile
|
||||
man/de/Makefile
|
||||
man/es/Makefile
|
||||
man/fi/Makefile
|
||||
@@ -668,12 +541,8 @@ if test "$with_libpam" = "yes"; then
|
||||
echo " suid account management tools: $enable_acct_tools_setuid"
|
||||
fi
|
||||
echo " SELinux support: $with_selinux"
|
||||
echo " ACL support: $with_acl"
|
||||
echo " Extended Attributes support: $with_attr"
|
||||
echo " tcb support (incomplete): $with_tcb"
|
||||
echo " shadow group support: $enable_shadowgrp"
|
||||
echo " S/Key support: $with_skey"
|
||||
echo " SHA passwords encryption: $with_sha_crypt"
|
||||
echo " nscd support: $with_nscd"
|
||||
echo " subordinate IDs support: $enable_subids"
|
||||
echo
|
||||
114
etc/login.defs
114
etc/login.defs
@@ -6,18 +6,18 @@
|
||||
|
||||
#
|
||||
# Delay in seconds before being allowed another attempt after a login failure
|
||||
# Note: When PAM is used, some modules may enforce a minimum delay (e.g.
|
||||
# pam_unix(8) enforces a 2s delay)
|
||||
# Note: When PAM is used, some modules may enfore a minimal delay (e.g.
|
||||
# pam_unix enforces a 2s delay)
|
||||
#
|
||||
FAIL_DELAY 3
|
||||
|
||||
#
|
||||
# Enable logging and display of /var/log/faillog login(1) failure info.
|
||||
# Enable logging and display of /var/log/faillog login failure info.
|
||||
#
|
||||
FAILLOG_ENAB yes
|
||||
|
||||
#
|
||||
# Enable display of unknown usernames when login(1) failures are recorded.
|
||||
# Enable display of unknown usernames when login failures are recorded.
|
||||
#
|
||||
LOG_UNKFAIL_ENAB no
|
||||
|
||||
@@ -27,7 +27,7 @@ LOG_UNKFAIL_ENAB no
|
||||
LOG_OK_LOGINS no
|
||||
|
||||
#
|
||||
# Enable logging and display of /var/log/lastlog login(1) time info.
|
||||
# Enable logging and display of /var/log/lastlog login time info.
|
||||
#
|
||||
LASTLOG_ENAB yes
|
||||
|
||||
@@ -50,13 +50,13 @@ OBSCURE_CHECKS_ENAB yes
|
||||
PORTTIME_CHECKS_ENAB yes
|
||||
|
||||
#
|
||||
# Enable setting of ulimit, umask, and niceness from passwd(5) gecos field.
|
||||
# Enable setting of ulimit, umask, and niceness from passwd gecos field.
|
||||
#
|
||||
QUOTAS_ENAB yes
|
||||
|
||||
#
|
||||
# Enable "syslog" logging of su(1) activity - in addition to sulog file logging.
|
||||
# SYSLOG_SG_ENAB does the same for newgrp(1) and sg(1).
|
||||
# Enable "syslog" logging of su activity - in addition to sulog file logging.
|
||||
# SYSLOG_SG_ENAB does the same for newgrp and sg.
|
||||
#
|
||||
SYSLOG_SU_ENAB yes
|
||||
SYSLOG_SG_ENAB yes
|
||||
@@ -64,13 +64,13 @@ SYSLOG_SG_ENAB yes
|
||||
#
|
||||
# If defined, either full pathname of a file containing device names or
|
||||
# a ":" delimited list of device names. Root logins will be allowed only
|
||||
# from these devices.
|
||||
# upon these devices.
|
||||
#
|
||||
CONSOLE /etc/securetty
|
||||
#CONSOLE console:tty01:tty02:tty03:tty04
|
||||
|
||||
#
|
||||
# If defined, all su(1) activity is logged to this file.
|
||||
# If defined, all su activity is logged to this file.
|
||||
#
|
||||
#SULOG_FILE /var/log/sulog
|
||||
|
||||
@@ -82,33 +82,33 @@ MOTD_FILE /etc/motd
|
||||
#MOTD_FILE /etc/motd:/usr/lib/news/news-motd
|
||||
|
||||
#
|
||||
# If defined, this file will be output before each login(1) prompt.
|
||||
# If defined, this file will be output before each login prompt.
|
||||
#
|
||||
#ISSUE_FILE /etc/issue
|
||||
|
||||
#
|
||||
# If defined, file which maps tty line to TERM environment parameter.
|
||||
# Each line of the file is in a format similar to "vt100 tty01".
|
||||
# Each line of the file is in a format something like "vt100 tty01".
|
||||
#
|
||||
#TTYTYPE_FILE /etc/ttytype
|
||||
|
||||
#
|
||||
# If defined, login(1) failures will be logged here in a utmp format.
|
||||
# last(1), when invoked as lastb(1), will read /var/log/btmp, so...
|
||||
# If defined, login failures will be logged here in a utmp format.
|
||||
# last, when invoked as lastb, will read /var/log/btmp, so...
|
||||
#
|
||||
FTMP_FILE /var/log/btmp
|
||||
|
||||
#
|
||||
# If defined, name of file whose presence will inhibit non-root
|
||||
# logins. The content of this file should be a message indicating
|
||||
# If defined, name of file whose presence which will inhibit non-root
|
||||
# logins. The contents of this file should be a message indicating
|
||||
# why logins are inhibited.
|
||||
#
|
||||
NOLOGINS_FILE /etc/nologin
|
||||
|
||||
#
|
||||
# If defined, the command name to display when running "su -". For
|
||||
# example, if this is defined as "su" then ps(1) will display the
|
||||
# command as "-su". If not defined, then ps(1) will display the
|
||||
# example, if this is defined as "su" then a "ps" will display the
|
||||
# command is "-su". If not defined, then "ps" would display the
|
||||
# name of the shell actually being run, e.g. something like "-sh".
|
||||
#
|
||||
SU_NAME su
|
||||
@@ -158,10 +158,10 @@ ENV_PATH PATH=/bin:/usr/bin
|
||||
# TTYGROUP Login tty will be assigned this group ownership.
|
||||
# TTYPERM Login tty will be set to this permission.
|
||||
#
|
||||
# If you have a write(1) program which is "setgid" to a special group
|
||||
# which owns the terminals, define TTYGROUP as the number of such group
|
||||
# and TTYPERM as 0620. Otherwise leave TTYGROUP commented out and
|
||||
# set TTYPERM to either 622 or 600.
|
||||
# If you have a "write" program which is "setgid" to a special group
|
||||
# which owns the terminals, define TTYGROUP to the group number and
|
||||
# TTYPERM to 0620. Otherwise leave TTYGROUP commented out and assign
|
||||
# TTYPERM to either 622 or 600.
|
||||
#
|
||||
TTYGROUP tty
|
||||
TTYPERM 0600
|
||||
@@ -183,13 +183,12 @@ ERASECHAR 0177
|
||||
KILLCHAR 025
|
||||
#ULIMIT 2097152
|
||||
|
||||
# Default initial "umask" value used by login(1) on non-PAM enabled systems.
|
||||
# Default "umask" value for pam_umask(8) on PAM enabled systems.
|
||||
# UMASK is also used by useradd(8) and newusers(8) to set the mode for new
|
||||
# home directories.
|
||||
# Default initial "umask" value for non-PAM enabled systems.
|
||||
# UMASK is also used by useradd and newusers to set the mode of new home
|
||||
# directories.
|
||||
# 022 is the default value, but 027, or even 077, could be considered
|
||||
# for increased privacy. There is no One True Answer here: each sysadmin
|
||||
# must make up his/her mind.
|
||||
# better for privacy. There is no One True Answer here: each sysadmin
|
||||
# must make up her mind.
|
||||
UMASK 022
|
||||
|
||||
#
|
||||
@@ -214,43 +213,35 @@ PASS_WARN_AGE 7
|
||||
SU_WHEEL_ONLY no
|
||||
|
||||
#
|
||||
# If compiled with cracklib support, sets the path to the dictionaries
|
||||
# If compiled with cracklib support, where are the dictionaries
|
||||
#
|
||||
CRACKLIB_DICTPATH /var/cache/cracklib/cracklib_dict
|
||||
|
||||
#
|
||||
# Min/max values for automatic uid selection in useradd(8)
|
||||
# Min/max values for automatic uid selection in useradd
|
||||
#
|
||||
UID_MIN 1000
|
||||
UID_MAX 60000
|
||||
# System accounts
|
||||
SYS_UID_MIN 101
|
||||
SYS_UID_MAX 999
|
||||
# Extra per user uids
|
||||
SUB_UID_MIN 100000
|
||||
SUB_UID_MAX 600100000
|
||||
SUB_UID_COUNT 65536
|
||||
|
||||
#
|
||||
# Min/max values for automatic gid selection in groupadd(8)
|
||||
# Min/max values for automatic gid selection in groupadd
|
||||
#
|
||||
GID_MIN 1000
|
||||
GID_MAX 60000
|
||||
# System accounts
|
||||
SYS_GID_MIN 101
|
||||
SYS_GID_MAX 999
|
||||
# Extra per user group ids
|
||||
SUB_GID_MIN 100000
|
||||
SUB_GID_MAX 600100000
|
||||
SUB_GID_COUNT 65536
|
||||
|
||||
#
|
||||
# Max number of login(1) retries if password is bad
|
||||
# Max number of login retries if password is bad
|
||||
#
|
||||
LOGIN_RETRIES 5
|
||||
|
||||
#
|
||||
# Max time in seconds for login(1)
|
||||
# Max time in seconds for login
|
||||
#
|
||||
LOGIN_TIMEOUT 60
|
||||
|
||||
@@ -272,12 +263,12 @@ PASS_ALWAYS_WARN yes
|
||||
#PASS_MAX_LEN 8
|
||||
|
||||
#
|
||||
# Require password before chfn(1)/chsh(1) can make any changes.
|
||||
# Require password before chfn/chsh can make any changes.
|
||||
#
|
||||
CHFN_AUTH yes
|
||||
|
||||
#
|
||||
# Which fields may be changed by regular users using chfn(1) - use
|
||||
# Which fields may be changed by regular users using chfn - use
|
||||
# any combination of letters "frwh" (full name, room number, work
|
||||
# phone, home phone). If not defined, no changes are allowed.
|
||||
# For backward compatibility, "yes" = "rwh" and "no" = "frwh".
|
||||
@@ -302,13 +293,13 @@ CHFN_RESTRICT rwh
|
||||
# Note: If you use PAM, it is recommended to use a value consistent with
|
||||
# the PAM modules configuration.
|
||||
#
|
||||
# This variable is deprecated. You should use ENCRYPT_METHOD instead.
|
||||
# This variable is deprecated. You should use ENCRYPT_METHOD.
|
||||
#
|
||||
#MD5_CRYPT_ENAB no
|
||||
|
||||
#
|
||||
# Only works if compiled with ENCRYPTMETHOD_SELECT defined:
|
||||
# If set to MD5, MD5-based algorithm will be used for encrypting password
|
||||
# If set to MD5 , MD5-based algorithm will be used for encrypting password
|
||||
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
|
||||
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
|
||||
# If set to DES, DES-based algorithm will be used for encrypting password (default)
|
||||
@@ -323,12 +314,12 @@ CHFN_RESTRICT rwh
|
||||
# Only works if ENCRYPT_METHOD is set to SHA256 or SHA512.
|
||||
#
|
||||
# Define the number of SHA rounds.
|
||||
# With a lot of rounds, it is more difficult to brute-force the password.
|
||||
# However, more CPU resources will be needed to authenticate users if
|
||||
# this value is increased.
|
||||
# With a lot of rounds, it is more difficult to brute forcing the password.
|
||||
# But note also that it more CPU resources will be needed to authenticate
|
||||
# users.
|
||||
#
|
||||
# If not specified, the libc will choose the default number of rounds (5000).
|
||||
# The values must be within the 1000-999999999 range.
|
||||
# The values must be inside the 1000-999999999 range.
|
||||
# If only one of the MIN or MAX values is set, then this value will be used.
|
||||
# If MIN > MAX, the highest value will be used.
|
||||
#
|
||||
@@ -337,18 +328,18 @@ CHFN_RESTRICT rwh
|
||||
|
||||
#
|
||||
# List of groups to add to the user's supplementary group set
|
||||
# when logging in from the console (as determined by the CONSOLE
|
||||
# when logging in on the console (as determined by the CONSOLE
|
||||
# setting). Default is none.
|
||||
#
|
||||
# Use with caution - it is possible for users to gain permanent
|
||||
# access to these groups, even when not logged in from the console.
|
||||
# access to these groups, even when not logged in on the console.
|
||||
# How to do it is left as an exercise for the reader...
|
||||
#
|
||||
#CONSOLE_GROUPS floppy:audio:cdrom
|
||||
|
||||
#
|
||||
# Should login be allowed if we can't cd to the home directory?
|
||||
# Default is no.
|
||||
# Default in no.
|
||||
#
|
||||
DEFAULT_HOME yes
|
||||
|
||||
@@ -370,14 +361,14 @@ ENVIRON_FILE /etc/environment
|
||||
# (examples: 022 -> 002, 077 -> 007) for non-root users, if the uid is
|
||||
# the same as gid, and username is the same as the primary group name.
|
||||
#
|
||||
# This also enables userdel(8) to remove user groups if no members exist.
|
||||
# This also enables userdel to remove user groups if no members exist.
|
||||
#
|
||||
USERGROUPS_ENAB yes
|
||||
|
||||
#
|
||||
# If set to a non-zero number, the shadow utilities will make sure that
|
||||
# If set to a non-nul number, the shadow utilities will make sure that
|
||||
# groups never have more than this number of users on one line.
|
||||
# This permits to support split groups (groups split into multiple lines,
|
||||
# This permit to support split groups (groups split into multiple lines,
|
||||
# with the same group ID, to avoid limitation of the line length in the
|
||||
# group file).
|
||||
#
|
||||
@@ -386,15 +377,10 @@ USERGROUPS_ENAB yes
|
||||
#MAX_MEMBERS_PER_GROUP 0
|
||||
|
||||
#
|
||||
# If useradd(8) should create home directories for users by default (non
|
||||
# system users only).
|
||||
# This option is overridden with the -M or -m flags on the useradd(8)
|
||||
# command-line.
|
||||
# If useradd should create home directories for users by default (non
|
||||
# system users only)
|
||||
# This option is overridden with the -M or -m flags on the useradd command
|
||||
# line.
|
||||
#
|
||||
#CREATE_HOME yes
|
||||
|
||||
#
|
||||
# Force use shadow, even if shadow passwd & shadow group files are
|
||||
# missing.
|
||||
#
|
||||
#FORCE_SHADOW yes
|
||||
|
||||
@@ -14,7 +14,6 @@ libshadow_la_SOURCES = \
|
||||
encrypt.c \
|
||||
exitcodes.h \
|
||||
faillog.h \
|
||||
fields.c \
|
||||
fputsx.c \
|
||||
getdef.c \
|
||||
getdef.h \
|
||||
@@ -39,10 +38,6 @@ libshadow_la_SOURCES = \
|
||||
pwio.c \
|
||||
pwio.h \
|
||||
pwmem.c \
|
||||
subordinateio.h \
|
||||
subordinateio.c \
|
||||
selinux.c \
|
||||
semanage.c \
|
||||
sgetgrent.c \
|
||||
sgetpwent.c \
|
||||
sgetspent.c \
|
||||
@@ -52,13 +47,8 @@ libshadow_la_SOURCES = \
|
||||
shadowio.c \
|
||||
shadowio.h \
|
||||
shadowmem.c \
|
||||
spawn.c \
|
||||
utent.c
|
||||
|
||||
if WITH_TCB
|
||||
libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h
|
||||
endif
|
||||
|
||||
# These files are unneeded for some reason, listed in
|
||||
# order of appearance:
|
||||
#
|
||||
|
||||
297
lib/commonio.c
297
lib/commonio.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2011, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -45,16 +45,16 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include "nscd.h"
|
||||
#ifdef WITH_TCB
|
||||
#include <tcb.h>
|
||||
#endif /* WITH_TCB */
|
||||
#ifdef WITH_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
#include "prototypes.h"
|
||||
#include "commonio.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static int lrename (const char *, const char *);
|
||||
static int check_link_count (const char *file);
|
||||
static int do_lock_file (const char *file, const char *lock, bool log);
|
||||
static int do_lock_file (const char *file, const char *lock);
|
||||
static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
|
||||
const char *name,
|
||||
const char *mode,
|
||||
@@ -132,7 +132,7 @@ static int check_link_count (const char *file)
|
||||
}
|
||||
|
||||
|
||||
static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
static int do_lock_file (const char *file, const char *lock)
|
||||
{
|
||||
int fd;
|
||||
pid_t pid;
|
||||
@@ -142,11 +142,6 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
|
||||
fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600);
|
||||
if (-1 == fd) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: %s: %s\n",
|
||||
Prog, file, strerror (errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -154,11 +149,6 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
|
||||
len = (ssize_t) strlen (buf) + 1;
|
||||
if (write (fd, buf, (size_t) len) != len) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: %s: %s\n",
|
||||
Prog, file, strerror (errno));
|
||||
}
|
||||
(void) close (fd);
|
||||
unlink (file);
|
||||
return 0;
|
||||
@@ -167,22 +157,12 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
|
||||
if (link (file, lock) == 0) {
|
||||
retval = check_link_count (file);
|
||||
if ((0==retval) && log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: %s: lock file already used\n",
|
||||
Prog, file);
|
||||
}
|
||||
unlink (file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
fd = open (lock, O_RDWR);
|
||||
if (-1 == fd) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: %s: %s\n",
|
||||
Prog, lock, strerror (errno));
|
||||
}
|
||||
unlink (file);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
@@ -190,60 +170,29 @@ static int do_lock_file (const char *file, const char *lock, bool log)
|
||||
len = read (fd, buf, sizeof (buf) - 1);
|
||||
close (fd);
|
||||
if (len <= 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: existing lock file %s without a PID\n",
|
||||
Prog, lock);
|
||||
}
|
||||
unlink (file);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
if (get_pid (buf, &pid) == 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: existing lock file %s with an invalid PID '%s'\n",
|
||||
Prog, lock, buf);
|
||||
}
|
||||
unlink (file);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
if (kill (pid, 0) == 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: lock %s already used by PID %lu\n",
|
||||
Prog, lock, (unsigned long) pid);
|
||||
}
|
||||
unlink (file);
|
||||
errno = EEXIST;
|
||||
return 0;
|
||||
}
|
||||
if (unlink (lock) != 0) {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: cannot get lock %s: %s\n",
|
||||
Prog, lock, strerror (errno));
|
||||
}
|
||||
unlink (file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
if (link (file, lock) == 0) {
|
||||
retval = check_link_count (file);
|
||||
if ((0==retval) && log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: %s: lock file already used\n",
|
||||
Prog, file);
|
||||
}
|
||||
} else {
|
||||
if (log) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: cannot get lock %s: %s\n",
|
||||
Prog, lock, strerror (errno));
|
||||
}
|
||||
if ((link (file, lock) == 0) && (check_link_count (file) != 0)) {
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
unlink (file);
|
||||
@@ -270,21 +219,21 @@ static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
|
||||
if (fchown (fileno (fp), sb->st_uid, sb->st_gid) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
#else /* !HAVE_FCHOWN */
|
||||
#else
|
||||
if (chown (name, sb->st_mode) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
#endif /* !HAVE_FCHOWN */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FCHMOD
|
||||
if (fchmod (fileno (fp), sb->st_mode & 0664) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
#else /* !HAVE_FCHMOD */
|
||||
#else
|
||||
if (chmod (name, sb->st_mode & 0664) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
#endif /* !HAVE_FCHMOD */
|
||||
#endif
|
||||
return fp;
|
||||
|
||||
fail:
|
||||
@@ -376,7 +325,7 @@ bool commonio_present (const struct commonio_db *db)
|
||||
}
|
||||
|
||||
|
||||
int commonio_lock_nowait (struct commonio_db *db, bool log)
|
||||
int commonio_lock_nowait (struct commonio_db *db)
|
||||
{
|
||||
char file[1024];
|
||||
char lock[1024];
|
||||
@@ -388,7 +337,7 @@ int commonio_lock_nowait (struct commonio_db *db, bool log)
|
||||
snprintf (file, sizeof file, "%s.%lu",
|
||||
db->filename, (unsigned long) getpid ());
|
||||
snprintf (lock, sizeof lock, "%s.lock", db->filename);
|
||||
if (do_lock_file (file, lock, log) != 0) {
|
||||
if (do_lock_file (file, lock) != 0) {
|
||||
db->locked = true;
|
||||
lock_count++;
|
||||
return 1;
|
||||
@@ -412,22 +361,17 @@ int commonio_lock (struct commonio_db *db)
|
||||
*/
|
||||
if (0 == lock_count) {
|
||||
if (lckpwdf () == -1) {
|
||||
if (geteuid () != 0) {
|
||||
(void) fprintf (stderr,
|
||||
"%s: Permission denied.\n",
|
||||
Prog);
|
||||
}
|
||||
return 0; /* failure */
|
||||
}
|
||||
}
|
||||
|
||||
if (commonio_lock_nowait (db, true) != 0) {
|
||||
if (commonio_lock_nowait (db) != 0) {
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
ulckpwdf ();
|
||||
return 0; /* failure */
|
||||
#else /* !HAVE_LCKPWDF */
|
||||
#else
|
||||
int i;
|
||||
|
||||
/*
|
||||
@@ -444,18 +388,16 @@ int commonio_lock (struct commonio_db *db)
|
||||
if (i > 0) {
|
||||
sleep (LOCK_SLEEP); /* delay between retries */
|
||||
}
|
||||
if (commonio_lock_nowait (db, i==LOCK_TRIES-1) != 0) {
|
||||
if (commonio_lock_nowait (db) != 0) {
|
||||
return 1; /* success */
|
||||
}
|
||||
/* no unnecessary retries on "permission denied" errors */
|
||||
if (geteuid () != 0) {
|
||||
(void) fprintf (stderr, "%s: Permission denied.\n",
|
||||
Prog);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0; /* failure */
|
||||
#endif /* !HAVE_LCKPWDF */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dec_lock_count (void)
|
||||
@@ -472,7 +414,7 @@ static void dec_lock_count (void)
|
||||
}
|
||||
#ifdef HAVE_LCKPWDF
|
||||
ulckpwdf ();
|
||||
#endif /* HAVE_LCKPWDF */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,7 +533,6 @@ int commonio_open (struct commonio_db *db, int mode)
|
||||
void *eptr = NULL;
|
||||
int flags = mode;
|
||||
size_t buflen;
|
||||
int fd;
|
||||
int saved_errno;
|
||||
|
||||
mode &= ~O_CREAT;
|
||||
@@ -608,31 +549,11 @@ int commonio_open (struct commonio_db *db, int mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
db->head = NULL;
|
||||
db->tail = NULL;
|
||||
db->head = db->tail = NULL;
|
||||
db->cursor = NULL;
|
||||
db->changed = false;
|
||||
|
||||
fd = open (db->filename,
|
||||
(db->readonly ? O_RDONLY : O_RDWR)
|
||||
| O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
|
||||
saved_errno = errno;
|
||||
db->fp = NULL;
|
||||
if (fd >= 0) {
|
||||
#ifdef WITH_TCB
|
||||
if (tcb_is_suspect (fd) != 0) {
|
||||
(void) close (fd);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_TCB */
|
||||
db->fp = fdopen (fd, db->readonly ? "r" : "r+");
|
||||
saved_errno = errno;
|
||||
if (NULL == db->fp) {
|
||||
(void) close (fd);
|
||||
}
|
||||
}
|
||||
errno = saved_errno;
|
||||
db->fp = fopen (db->filename, db->readonly ? "r" : "r+");
|
||||
|
||||
/*
|
||||
* If O_CREAT was specified and the file didn't exist, it will be
|
||||
@@ -647,7 +568,16 @@ int commonio_open (struct commonio_db *db, int mode)
|
||||
}
|
||||
|
||||
/* Do not inherit fd in spawned processes (e.g. nscd) */
|
||||
fcntl (fileno (db->fp), F_SETFD, FD_CLOEXEC);
|
||||
fcntl(fileno(db->fp), F_SETFD, FD_CLOEXEC);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
db->scontext = NULL;
|
||||
if ((is_selinux_enabled () > 0) && (!db->readonly)) {
|
||||
if (fgetfilecon (fileno (db->fp), &db->scontext) < 0) {
|
||||
goto cleanup_errno;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buflen = BUFLEN;
|
||||
buf = (char *) malloc (buflen);
|
||||
@@ -733,6 +663,12 @@ int commonio_open (struct commonio_db *db, int mode)
|
||||
cleanup_errno:
|
||||
saved_errno = errno;
|
||||
free_linked_list (db);
|
||||
#ifdef WITH_SELINUX
|
||||
if (db->scontext != NULL) {
|
||||
freecon (db->scontext);
|
||||
db->scontext = NULL;
|
||||
}
|
||||
#endif
|
||||
fclose (db->fp);
|
||||
db->fp = NULL;
|
||||
errno = saved_errno;
|
||||
@@ -747,26 +683,10 @@ commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
|
||||
{
|
||||
struct commonio_entry **entries, *ptr;
|
||||
size_t n = 0, i;
|
||||
#if KEEP_NIS_AT_END
|
||||
struct commonio_entry *nis = NULL;
|
||||
#endif
|
||||
|
||||
for (ptr = db->head;
|
||||
(NULL != ptr)
|
||||
#if KEEP_NIS_AT_END
|
||||
&& (NULL != ptr->line)
|
||||
&& ( ('+' != ptr->line[0])
|
||||
&& ('-' != ptr->line[0]))
|
||||
#endif
|
||||
;
|
||||
ptr = ptr->next) {
|
||||
for (ptr = db->head; NULL != ptr; ptr = ptr->next) {
|
||||
n++;
|
||||
}
|
||||
#if KEEP_NIS_AT_END
|
||||
if ((NULL != ptr) && (NULL != ptr->line)) {
|
||||
nis = ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n <= 1) {
|
||||
return 0;
|
||||
@@ -778,40 +698,18 @@ commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (ptr = db->head;
|
||||
#if KEEP_NIS_AT_END
|
||||
nis != ptr;
|
||||
#else
|
||||
NULL != ptr;
|
||||
#endif
|
||||
/*@ -nullderef @*/
|
||||
ptr = ptr->next
|
||||
/*@ +nullderef @*/
|
||||
) {
|
||||
entries[n] = ptr;
|
||||
n++;
|
||||
for (ptr = db->head; NULL != ptr; ptr = ptr->next) {
|
||||
entries[n++] = ptr;
|
||||
}
|
||||
qsort (entries, n, sizeof (struct commonio_entry *), cmp);
|
||||
|
||||
/* Take care of the head and tail separately */
|
||||
db->head = entries[0];
|
||||
n--;
|
||||
#if KEEP_NIS_AT_END
|
||||
if (NULL == nis)
|
||||
#endif
|
||||
{
|
||||
db->tail = entries[n];
|
||||
}
|
||||
db->tail = entries[--n];
|
||||
db->head->prev = NULL;
|
||||
db->head->next = entries[1];
|
||||
entries[n]->prev = entries[n - 1];
|
||||
#if KEEP_NIS_AT_END
|
||||
entries[n]->next = nis;
|
||||
#else
|
||||
entries[n]->next = NULL;
|
||||
#endif
|
||||
db->tail->prev = entries[n - 1];
|
||||
db->tail->next = NULL;
|
||||
|
||||
/* Now other elements have prev and next entries */
|
||||
for (i = 1; i < n; i++) {
|
||||
entries[i]->prev = entries[i - 1];
|
||||
entries[i]->next = entries[i + 1];
|
||||
@@ -826,8 +724,7 @@ commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
|
||||
/*
|
||||
* Sort entries in db according to order in another.
|
||||
*/
|
||||
int commonio_sort_wrt (struct commonio_db *shadow,
|
||||
const struct commonio_db *passwd)
|
||||
int commonio_sort_wrt (struct commonio_db *shadow, struct commonio_db *passwd)
|
||||
{
|
||||
struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
|
||||
const char *name;
|
||||
@@ -914,6 +811,10 @@ int commonio_close (struct commonio_db *db)
|
||||
int errors = 0;
|
||||
struct stat sb;
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
/*@null@*/security_context_t old_context = NULL;
|
||||
#endif
|
||||
|
||||
if (!db->isopen) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
@@ -921,7 +822,7 @@ int commonio_close (struct commonio_db *db)
|
||||
db->isopen = false;
|
||||
|
||||
if (!db->changed || db->readonly) {
|
||||
(void) fclose (db->fp);
|
||||
fclose (db->fp);
|
||||
db->fp = NULL;
|
||||
goto success;
|
||||
}
|
||||
@@ -933,21 +834,27 @@ int commonio_close (struct commonio_db *db)
|
||||
memzero (&sb, sizeof sb);
|
||||
if (NULL != db->fp) {
|
||||
if (fstat (fileno (db->fp), &sb) != 0) {
|
||||
(void) fclose (db->fp);
|
||||
fclose (db->fp);
|
||||
db->fp = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (db->scontext != NULL) {
|
||||
if (getfscreatecon (&old_context) < 0) {
|
||||
errors++;
|
||||
goto fail;
|
||||
}
|
||||
if (setfscreatecon (db->scontext) < 0) {
|
||||
errors++;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Create backup file.
|
||||
*/
|
||||
snprintf (buf, sizeof buf, "%s-", db->filename);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (buf) != 0) {
|
||||
errors++;
|
||||
}
|
||||
#endif
|
||||
if (create_backup (buf, db->fp) != 0) {
|
||||
errors++;
|
||||
}
|
||||
@@ -956,11 +863,6 @@ int commonio_close (struct commonio_db *db)
|
||||
errors++;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (reset_selinux_file_context () != 0) {
|
||||
errors++;
|
||||
}
|
||||
#endif
|
||||
if (errors != 0) {
|
||||
db->fp = NULL;
|
||||
goto fail;
|
||||
@@ -968,20 +870,15 @@ int commonio_close (struct commonio_db *db)
|
||||
} else {
|
||||
/*
|
||||
* Default permissions for new [g]shadow files.
|
||||
* (passwd and group always exist...)
|
||||
*/
|
||||
sb.st_mode = db->st_mode;
|
||||
sb.st_uid = db->st_uid;
|
||||
sb.st_gid = db->st_gid;
|
||||
sb.st_mode = 0400;
|
||||
sb.st_uid = 0;
|
||||
sb.st_gid = 0;
|
||||
}
|
||||
|
||||
snprintf (buf, sizeof buf, "%s+", db->filename);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (buf) != 0) {
|
||||
errors++;
|
||||
}
|
||||
#endif
|
||||
|
||||
db->fp = fopen_set_perms (buf, "w", &sb);
|
||||
if (NULL == db->fp) {
|
||||
goto fail;
|
||||
@@ -998,9 +895,9 @@ int commonio_close (struct commonio_db *db)
|
||||
if (fsync (fileno (db->fp)) != 0) {
|
||||
errors++;
|
||||
}
|
||||
#else /* !HAVE_FSYNC */
|
||||
#else
|
||||
sync ();
|
||||
#endif /* !HAVE_FSYNC */
|
||||
#endif
|
||||
if (fclose (db->fp) != 0) {
|
||||
errors++;
|
||||
}
|
||||
@@ -1016,18 +913,25 @@ int commonio_close (struct commonio_db *db)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (reset_selinux_file_context () != 0) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
nscd_need_reload = true;
|
||||
goto success;
|
||||
fail:
|
||||
errors++;
|
||||
success:
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (db->scontext != NULL) {
|
||||
if (NULL != old_context) {
|
||||
if (setfscreatecon (old_context) < 0) {
|
||||
errors++;
|
||||
}
|
||||
freecon (old_context);
|
||||
old_context = NULL;
|
||||
}
|
||||
freecon (db->scontext);
|
||||
db->scontext = NULL;
|
||||
}
|
||||
#endif
|
||||
free_linked_list (db);
|
||||
return errors == 0;
|
||||
}
|
||||
@@ -1058,7 +962,7 @@ static /*@dependent@*/ /*@null@*/struct commonio_entry *find_entry_by_name (
|
||||
struct commonio_db *db,
|
||||
const char *name)
|
||||
{
|
||||
return next_entry_by_name (db, db->head, name);
|
||||
return next_entry_by_name(db, db->head, name);
|
||||
}
|
||||
|
||||
|
||||
@@ -1080,7 +984,6 @@ int commonio_update (struct commonio_db *db, const void *eptr)
|
||||
if (NULL != p) {
|
||||
if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) {
|
||||
fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
|
||||
db->ops->free (nentry);
|
||||
return 0;
|
||||
}
|
||||
db->ops->free (p->eptr);
|
||||
@@ -1105,46 +1008,14 @@ int commonio_update (struct commonio_db *db, const void *eptr)
|
||||
|
||||
#if KEEP_NIS_AT_END
|
||||
add_one_entry_nis (db, p);
|
||||
#else /* !KEEP_NIS_AT_END */
|
||||
#else
|
||||
add_one_entry (db, p);
|
||||
#endif /* !KEEP_NIS_AT_END */
|
||||
#endif
|
||||
|
||||
db->changed = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
int commonio_append (struct commonio_db *db, const void *eptr)
|
||||
{
|
||||
struct commonio_entry *p;
|
||||
void *nentry;
|
||||
|
||||
if (!db->isopen || db->readonly) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
nentry = db->ops->dup (eptr);
|
||||
if (NULL == nentry) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
/* new entry */
|
||||
p = (struct commonio_entry *) malloc (sizeof *p);
|
||||
if (NULL == p) {
|
||||
db->ops->free (nentry);
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->eptr = nentry;
|
||||
p->line = NULL;
|
||||
p->changed = true;
|
||||
add_one_entry (db, p);
|
||||
|
||||
db->changed = true;
|
||||
return 1;
|
||||
}
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -123,17 +123,10 @@ struct commonio_db {
|
||||
#ifdef WITH_SELINUX
|
||||
/*@null@*/security_context_t scontext;
|
||||
#endif
|
||||
/*
|
||||
* Default permissions and owner for newly created data file.
|
||||
*/
|
||||
mode_t st_mode;
|
||||
uid_t st_uid;
|
||||
gid_t st_gid;
|
||||
/*
|
||||
* Head, tail, current position in linked list.
|
||||
*/
|
||||
/*@owned@*/ /*@null@*/struct commonio_entry *head;
|
||||
/*@dependent@*/ /*@null@*/struct commonio_entry *tail;
|
||||
/*@owned@*/ /*@null@*/struct commonio_entry *head, *tail;
|
||||
/*@dependent@*/ /*@null@*/struct commonio_entry *cursor;
|
||||
|
||||
/*
|
||||
@@ -148,23 +141,20 @@ struct commonio_db {
|
||||
extern int commonio_setname (struct commonio_db *, const char *);
|
||||
extern bool commonio_present (const struct commonio_db *db);
|
||||
extern int commonio_lock (struct commonio_db *);
|
||||
extern int commonio_lock_nowait (struct commonio_db *, bool log);
|
||||
extern int commonio_lock_nowait (struct commonio_db *);
|
||||
extern int commonio_open (struct commonio_db *, int);
|
||||
extern /*@observer@*/ /*@null@*/const void *commonio_locate (struct commonio_db *, const char *);
|
||||
extern int commonio_update (struct commonio_db *, const void *);
|
||||
#ifdef ENABLE_SUBIDS
|
||||
extern int commonio_append (struct commonio_db *, const void *);
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
extern int commonio_remove (struct commonio_db *, const char *);
|
||||
extern int commonio_rewind (struct commonio_db *);
|
||||
extern /*@observer@*/ /*@null@*/const void *commonio_next (struct commonio_db *);
|
||||
extern int commonio_close (struct commonio_db *);
|
||||
extern int commonio_unlock (struct commonio_db *);
|
||||
extern void commonio_del_entry (struct commonio_db *,
|
||||
const struct commonio_entry *);
|
||||
const struct commonio_entry *);
|
||||
extern int commonio_sort_wrt (struct commonio_db *shadow,
|
||||
const struct commonio_db *passwd);
|
||||
struct commonio_db *passwd);
|
||||
extern int commonio_sort (struct commonio_db *db,
|
||||
int (*cmp) (const void *, const void *));
|
||||
int (*cmp) (const void *, const void *));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -177,7 +177,7 @@ char *strchr (), *strrchr (), *strtok ();
|
||||
* --Nekral */
|
||||
#define SYSLOG(x) \
|
||||
do { \
|
||||
char *old_locale = setlocale (LC_ALL, NULL); \
|
||||
char *old_locale = setlocale(LC_ALL, NULL); \
|
||||
char *saved_locale = NULL; \
|
||||
if (NULL != old_locale) { \
|
||||
saved_locale = strdup (old_locale); \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1990 - 1993, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -40,26 +40,27 @@
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
/*@exposed@*//*@null@*/char *pw_encrypt (const char *clear, const char *salt)
|
||||
char *pw_encrypt (const char *clear, const char *salt)
|
||||
{
|
||||
static char cipher[128];
|
||||
char *cp;
|
||||
|
||||
cp = crypt (clear, salt);
|
||||
if (NULL == cp) {
|
||||
if (!cp) {
|
||||
/*
|
||||
* Single Unix Spec: crypt() may return a null pointer,
|
||||
* and set errno to indicate an error. In this case return
|
||||
* the NULL so the caller can handle appropriately.
|
||||
* and set errno to indicate an error. The caller doesn't
|
||||
* expect us to return NULL, so...
|
||||
*/
|
||||
return NULL;
|
||||
perror ("crypt");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Some crypt() do not return NULL if the algorithm is not
|
||||
/* The GNU crypt does not return NULL if the algorithm is not
|
||||
* supported, and return a DES encrypted password. */
|
||||
if ((NULL != salt) && (salt[0] == '$') && (strlen (cp) <= 13))
|
||||
{
|
||||
/*@observer@*/const char *method;
|
||||
const char *method;
|
||||
switch (salt[1])
|
||||
{
|
||||
case '1':
|
||||
@@ -78,9 +79,9 @@
|
||||
method = &nummethod[0];
|
||||
}
|
||||
}
|
||||
(void) fprintf (stderr,
|
||||
_("crypt method not supported by libcrypt? (%s)\n"),
|
||||
method);
|
||||
fprintf (stderr,
|
||||
_("crypt method not supported by libcrypt? (%s)\n"),
|
||||
method);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
91
lib/getdef.c
91
lib/getdef.c
@@ -49,32 +49,6 @@ struct itemdef {
|
||||
/*@null@*/char *value; /* value given, or NULL if no value */
|
||||
};
|
||||
|
||||
#define PAMDEFS \
|
||||
{"CHFN_AUTH", NULL}, \
|
||||
{"CHSH_AUTH", NULL}, \
|
||||
{"CRACKLIB_DICTPATH", NULL}, \
|
||||
{"ENV_HZ", NULL}, \
|
||||
{"ENVIRON_FILE", NULL}, \
|
||||
{"ENV_TZ", NULL}, \
|
||||
{"FAILLOG_ENAB", NULL}, \
|
||||
{"FTMP_FILE", NULL}, \
|
||||
{"ISSUE_FILE", NULL}, \
|
||||
{"LASTLOG_ENAB", NULL}, \
|
||||
{"LOGIN_STRING", NULL}, \
|
||||
{"MAIL_CHECK_ENAB", NULL}, \
|
||||
{"MOTD_FILE", NULL}, \
|
||||
{"NOLOGINS_FILE", NULL}, \
|
||||
{"OBSCURE_CHECKS_ENAB", NULL}, \
|
||||
{"PASS_ALWAYS_WARN", NULL}, \
|
||||
{"PASS_CHANGE_TRIES", NULL}, \
|
||||
{"PASS_MAX_LEN", NULL}, \
|
||||
{"PASS_MIN_LEN", NULL}, \
|
||||
{"PORTTIME_CHECKS_ENAB", NULL}, \
|
||||
{"QUOTAS_ENAB", NULL}, \
|
||||
{"SU_WHEEL_ONLY", NULL}, \
|
||||
{"ULIMIT", NULL},
|
||||
|
||||
|
||||
#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
|
||||
static struct itemdef def_table[] = {
|
||||
{"CHFN_RESTRICT", NULL},
|
||||
@@ -107,12 +81,6 @@ static struct itemdef def_table[] = {
|
||||
{"SHA_CRYPT_MAX_ROUNDS", NULL},
|
||||
{"SHA_CRYPT_MIN_ROUNDS", NULL},
|
||||
#endif
|
||||
{"SUB_GID_COUNT", NULL},
|
||||
{"SUB_GID_MAX", NULL},
|
||||
{"SUB_GID_MIN", NULL},
|
||||
{"SUB_UID_COUNT", NULL},
|
||||
{"SUB_UID_MAX", NULL},
|
||||
{"SUB_UID_MIN", NULL},
|
||||
{"SULOG_FILE", NULL},
|
||||
{"SU_NAME", NULL},
|
||||
{"SYS_GID_MAX", NULL},
|
||||
@@ -128,28 +96,37 @@ static struct itemdef def_table[] = {
|
||||
{"USERDEL_CMD", NULL},
|
||||
{"USERGROUPS_ENAB", NULL},
|
||||
#ifndef USE_PAM
|
||||
PAMDEFS
|
||||
{"CHFN_AUTH", NULL},
|
||||
{"CHSH_AUTH", NULL},
|
||||
{"CRACKLIB_DICTPATH", NULL},
|
||||
{"ENV_HZ", NULL},
|
||||
{"ENVIRON_FILE", NULL},
|
||||
{"ENV_TZ", NULL},
|
||||
{"FAILLOG_ENAB", NULL},
|
||||
{"FTMP_FILE", NULL},
|
||||
{"ISSUE_FILE", NULL},
|
||||
{"LASTLOG_ENAB", NULL},
|
||||
{"LOGIN_STRING", NULL},
|
||||
{"MAIL_CHECK_ENAB", NULL},
|
||||
{"MOTD_FILE", NULL},
|
||||
{"NOLOGINS_FILE", NULL},
|
||||
{"OBSCURE_CHECKS_ENAB", NULL},
|
||||
{"PASS_ALWAYS_WARN", NULL},
|
||||
{"PASS_CHANGE_TRIES", NULL},
|
||||
{"PASS_MAX_LEN", NULL},
|
||||
{"PASS_MIN_LEN", NULL},
|
||||
{"PORTTIME_CHECKS_ENAB", NULL},
|
||||
{"QUOTAS_ENAB", NULL},
|
||||
{"SU_WHEEL_ONLY", NULL},
|
||||
{"ULIMIT", NULL},
|
||||
#endif
|
||||
#ifdef USE_SYSLOG
|
||||
{"SYSLOG_SG_ENAB", NULL},
|
||||
{"SYSLOG_SU_ENAB", NULL},
|
||||
#endif
|
||||
#ifdef WITH_TCB
|
||||
{"TCB_AUTH_GROUP", NULL},
|
||||
{"TCB_SYMLINKS", NULL},
|
||||
{"USE_TCB", NULL},
|
||||
#endif
|
||||
{"FORCE_SHADOW", NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
#define NUMKNOWNDEFS (sizeof(knowndef_table)/sizeof(knowndef_table[0]))
|
||||
static struct itemdef knowndef_table[] = {
|
||||
#ifdef USE_PAM
|
||||
PAMDEFS
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef LOGINDEFS
|
||||
#define LOGINDEFS "/etc/login.defs"
|
||||
#endif
|
||||
@@ -409,17 +386,10 @@ static /*@observer@*/ /*@null@*/struct itemdef *def_find (const char *name)
|
||||
* Item was never found.
|
||||
*/
|
||||
|
||||
for (ptr = knowndef_table; NULL != ptr->name; ptr++) {
|
||||
if (strcmp (ptr->name, name) == 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
fprintf (stderr,
|
||||
_("configuration error - unknown item '%s' (notify administrator)\n"),
|
||||
name);
|
||||
SYSLOG ((LOG_CRIT, "unknown configuration item `%s'", name));
|
||||
|
||||
out:
|
||||
return (struct itemdef *) NULL;
|
||||
}
|
||||
|
||||
@@ -435,26 +405,23 @@ static void def_load (void)
|
||||
FILE *fp;
|
||||
char buf[1024], *name, *value, *s;
|
||||
|
||||
/*
|
||||
* Set the initialized flag.
|
||||
* (do it early to prevent recursion in putdef_str())
|
||||
*/
|
||||
def_loaded = true;
|
||||
|
||||
/*
|
||||
* Open the configuration definitions file.
|
||||
*/
|
||||
fp = fopen (def_fname, "r");
|
||||
if (NULL == fp) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
|
||||
int err = errno;
|
||||
SYSLOG ((LOG_CRIT, "cannot open login definitions %s [%s]",
|
||||
def_fname, strerror (err)));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the initialized flag.
|
||||
* (do it early to prevent recursion in putdef_str())
|
||||
*/
|
||||
def_loaded = true;
|
||||
|
||||
/*
|
||||
* Go through all of the lines in the file.
|
||||
*/
|
||||
|
||||
@@ -44,19 +44,22 @@
|
||||
*/
|
||||
int getulong (const char *numstr, /*@out@*/unsigned long int *result)
|
||||
{
|
||||
unsigned long int val;
|
||||
long long int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoul (numstr, &endptr, 0);
|
||||
val = strtoll (numstr, &endptr, 0);
|
||||
if ( ('\0' == *numstr)
|
||||
|| ('\0' != *endptr)
|
||||
|| (ERANGE == errno)
|
||||
/*@+ignoresigns@*/
|
||||
|| (val != (unsigned long int)val)
|
||||
/*@=ignoresigns@*/
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*result = val;
|
||||
*result = (unsigned long int)val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -80,23 +80,6 @@ static int group_put (const void *ent, FILE * file)
|
||||
{
|
||||
const struct group *gr = ent;
|
||||
|
||||
if ( (NULL == gr)
|
||||
|| (valid_field (gr->gr_name, ":\n") == -1)
|
||||
|| (valid_field (gr->gr_passwd, ":\n") == -1)
|
||||
|| (gr->gr_gid == (gid_t)-1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: fail also if gr->gr_mem == NULL ?*/
|
||||
if (NULL != gr->gr_mem) {
|
||||
size_t i;
|
||||
for (i = 0; NULL != gr->gr_mem[i]; i++) {
|
||||
if (valid_field (gr->gr_mem[i], ",:\n") == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (putgrent (gr, file) == -1) ? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -130,9 +113,6 @@ static /*@owned@*/struct commonio_db group_db = {
|
||||
#ifdef WITH_SELINUX
|
||||
NULL, /* scontext */
|
||||
#endif
|
||||
0644, /* st_mode */
|
||||
0, /* st_uid */
|
||||
0, /* st_gid */
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
@@ -333,7 +313,7 @@ static /*@null@*/struct commonio_entry *merge_group_entries (
|
||||
|
||||
/* Concatenate the 2 lines */
|
||||
new_line_len = strlen (gr1->line) + strlen (gr2->line) +1;
|
||||
new_line = (char *)malloc (new_line_len + 1);
|
||||
new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*));
|
||||
if (NULL == new_line) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
@@ -356,7 +336,7 @@ static /*@null@*/struct commonio_entry *merge_group_entries (
|
||||
members++;
|
||||
}
|
||||
}
|
||||
new_members = (char **)calloc ( (members+1), sizeof(char*) );
|
||||
new_members = (char **)malloc ( (members+1) * sizeof(char*) );
|
||||
if (NULL == new_members) {
|
||||
free (new_line);
|
||||
errno = ENOMEM;
|
||||
@@ -365,8 +345,6 @@ static /*@null@*/struct commonio_entry *merge_group_entries (
|
||||
for (i=0; NULL != gptr1->gr_mem[i]; i++) {
|
||||
new_members[i] = gptr1->gr_mem[i];
|
||||
}
|
||||
/* NULL termination enforced by above calloc */
|
||||
|
||||
members = i;
|
||||
for (i=0; NULL != gptr2->gr_mem[i]; i++) {
|
||||
char **pmember = new_members;
|
||||
@@ -404,19 +382,15 @@ static int split_groups (unsigned int max_members)
|
||||
struct commonio_entry *new;
|
||||
struct group *new_gptr;
|
||||
unsigned int members = 0;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if this group must be split */
|
||||
if (!gr->changed) {
|
||||
if (!gr->changed)
|
||||
continue;
|
||||
}
|
||||
if (NULL == gptr) {
|
||||
if (NULL == gptr)
|
||||
continue;
|
||||
}
|
||||
for (members = 0; NULL != gptr->gr_mem[members]; members++);
|
||||
if (members <= max_members) {
|
||||
if (members <= max_members)
|
||||
continue;
|
||||
}
|
||||
|
||||
new = (struct commonio_entry *) malloc (sizeof *new);
|
||||
if (NULL == new) {
|
||||
@@ -434,23 +408,9 @@ static int split_groups (unsigned int max_members)
|
||||
new->changed = true;
|
||||
|
||||
/* Enforce the maximum number of members on gptr */
|
||||
for (i = max_members; NULL != gptr->gr_mem[i]; i++) {
|
||||
free (gptr->gr_mem[i]);
|
||||
gptr->gr_mem[i] = NULL;
|
||||
}
|
||||
/* Shift all the members */
|
||||
gptr->gr_mem[max_members] = NULL;
|
||||
/* The number of members in new_gptr will be check later */
|
||||
for (i = 0; NULL != new_gptr->gr_mem[i + max_members]; i++) {
|
||||
if (NULL != new_gptr->gr_mem[i]) {
|
||||
free (new_gptr->gr_mem[i]);
|
||||
}
|
||||
new_gptr->gr_mem[i] = new_gptr->gr_mem[i + max_members];
|
||||
new_gptr->gr_mem[i + max_members] = NULL;
|
||||
}
|
||||
for (; NULL != new_gptr->gr_mem[i]; i++) {
|
||||
free (new_gptr->gr_mem[i]);
|
||||
new_gptr->gr_mem[i] = NULL;
|
||||
}
|
||||
new_gptr->gr_mem = &new_gptr->gr_mem[max_members];
|
||||
|
||||
/* insert the new entry in the list */
|
||||
new->prev = gr;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2013, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -48,37 +48,25 @@
|
||||
if (NULL == gr) {
|
||||
return NULL;
|
||||
}
|
||||
/* The libc might define other fields. They won't be copied. */
|
||||
memset (gr, 0, sizeof *gr);
|
||||
gr->gr_gid = grent->gr_gid;
|
||||
/*@-mustfreeonly@*/
|
||||
*gr = *grent;
|
||||
gr->gr_name = strdup (grent->gr_name);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == gr->gr_name) {
|
||||
gr_free(gr);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
gr->gr_passwd = strdup (grent->gr_passwd);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == gr->gr_passwd) {
|
||||
gr_free(gr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; grent->gr_mem[i]; i++);
|
||||
|
||||
/*@-mustfreeonly@*/
|
||||
gr->gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == gr->gr_mem) {
|
||||
gr_free(gr);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; grent->gr_mem[i]; i++) {
|
||||
gr->gr_mem[i] = strdup (grent->gr_mem[i]);
|
||||
if (NULL == gr->gr_mem[i]) {
|
||||
gr_free(gr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -90,16 +78,11 @@
|
||||
void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
||||
{
|
||||
free (grent->gr_name);
|
||||
if (NULL != grent->gr_passwd) {
|
||||
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
||||
free (grent->gr_passwd);
|
||||
}
|
||||
if (NULL != grent->gr_mem) {
|
||||
size_t i;
|
||||
for (i = 0; NULL != grent->gr_mem[i]; i++) {
|
||||
free (grent->gr_mem[i]);
|
||||
}
|
||||
free (grent->gr_mem);
|
||||
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
||||
free (grent->gr_passwd);
|
||||
while (*(grent->gr_mem)) {
|
||||
free (*(grent->gr_mem));
|
||||
grent->gr_mem++;
|
||||
}
|
||||
free (grent);
|
||||
}
|
||||
|
||||
@@ -216,13 +216,13 @@ void endsgent (void)
|
||||
static char *buf = NULL;
|
||||
|
||||
char *cp;
|
||||
struct sgrp *ret;
|
||||
|
||||
if (0 == buflen) {
|
||||
buf = (char *) malloc (BUFSIZ);
|
||||
if (NULL == buf) {
|
||||
return NULL;
|
||||
}
|
||||
buflen = BUFSIZ;
|
||||
}
|
||||
|
||||
if (NULL == fp) {
|
||||
@@ -230,9 +230,9 @@ void endsgent (void)
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
while (fgetsx (buf, (int) buflen, fp) == buf)
|
||||
while (fgetsx (buf, (int) sizeof buf, fp) == buf)
|
||||
#else
|
||||
if (fgetsx (buf, (int) buflen, fp) == buf)
|
||||
if (fgetsx (buf, (int) sizeof buf, fp) == buf)
|
||||
#endif
|
||||
{
|
||||
while ( ((cp = strrchr (buf, '\n')) == NULL)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
struct sgrp {
|
||||
char *sg_name; /* group name */
|
||||
char *sg_passwd; /* group password */
|
||||
char **sg_adm; /* group administrator list */
|
||||
char **sg_adm; /* group administator list */
|
||||
char **sg_mem; /* group membership list */
|
||||
};
|
||||
|
||||
|
||||
60
lib/nscd.c
60
lib/nscd.c
@@ -3,49 +3,57 @@
|
||||
#include <config.h>
|
||||
#ifdef USE_NSCD
|
||||
|
||||
/* because of TEMP_FAILURE_RETRY */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <features.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <spawn.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include "exitcodes.h"
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#include "nscd.h"
|
||||
|
||||
#define MSG_NSCD_FLUSH_CACHE_FAILED "%s: Failed to flush the nscd cache.\n"
|
||||
#define MSG_NSCD_FLUSH_CACHE_FAILED "Failed to flush the nscd cache.\n"
|
||||
|
||||
/*
|
||||
* nscd_flush_cache - flush specified service buffer in nscd cache
|
||||
*/
|
||||
int nscd_flush_cache (const char *service)
|
||||
{
|
||||
int status, code;
|
||||
const char *cmd = "/usr/sbin/nscd";
|
||||
const char *spawnedArgs[] = {"nscd", "-i", service, NULL};
|
||||
const char *spawnedEnv[] = {NULL};
|
||||
pid_t pid, termpid;
|
||||
int err, status;
|
||||
char *spawnedArgs[] = {"/usr/sbin/nscd", "nscd", "-i", service, NULL};
|
||||
char *spawnedEnv[] = {NULL};
|
||||
|
||||
if (run_command (cmd, spawnedArgs, spawnedEnv, &status) != 0) {
|
||||
/* run_command writes its own more detailed message. */
|
||||
(void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||
/* spawn process */
|
||||
err = posix_spawn (&pid, spawnedArgs[0], NULL, NULL,
|
||||
spawnedArgs, spawnedEnv);
|
||||
if(0 != err)
|
||||
{
|
||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
||||
(void) fprintf (stderr, "posix_spawn() error=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
code = WEXITSTATUS (status);
|
||||
if (!WIFEXITED (status)) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: nscd did not terminate normally (signal %d)\n"),
|
||||
Prog, WTERMSIG (status));
|
||||
/* Wait for the spawned process to exit */
|
||||
termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
|
||||
if (-1 == termpid)
|
||||
{
|
||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
||||
perror("waitpid");
|
||||
return -1;
|
||||
} else if (code == E_CMD_NOTFOUND) {
|
||||
/* nscd is not installed, or it is installed but uses an
|
||||
interpreter that is missing. Probably the former. */
|
||||
return 0;
|
||||
} else if (code == 1) {
|
||||
/* nscd is installed, but it isn't active. */
|
||||
return 0;
|
||||
} else if (code != 0) {
|
||||
(void) fprintf (stderr, _("%s: nscd exited with status %d\n"),
|
||||
Prog, code);
|
||||
(void) fprintf (stderr, _(MSG_NSCD_FLUSH_CACHE_FAILED), Prog);
|
||||
}
|
||||
else if (termpid != pid)
|
||||
{
|
||||
(void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr);
|
||||
(void) fprintf (stderr, "waitpid returned %ld != %ld\n",
|
||||
(long int) termpid, (long int) pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -42,8 +42,6 @@
|
||||
#ifndef _PROTOTYPES_H
|
||||
#define _PROTOTYPES_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#ifdef USE_UTMPX
|
||||
#include <utmpx.h>
|
||||
@@ -59,7 +57,7 @@
|
||||
#include "defines.h"
|
||||
#include "commonio.h"
|
||||
|
||||
extern /*@observer@*/ const char *Prog;
|
||||
extern char *Prog;
|
||||
|
||||
/* addgrps.c */
|
||||
#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM)
|
||||
@@ -74,27 +72,25 @@ extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *);
|
||||
|
||||
/* basename() renamed to Basename() to avoid libc name space confusion */
|
||||
/* basename.c */
|
||||
extern /*@observer@*/const char *Basename (const char *str);
|
||||
extern char *Basename (char *str);
|
||||
|
||||
/* chowndir.c */
|
||||
extern int chown_tree (const char *root,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
extern int chown_tree (const char *, uid_t, uid_t, gid_t, gid_t);
|
||||
|
||||
/* chowntty.c */
|
||||
extern void chown_tty (const struct passwd *);
|
||||
|
||||
/* cleanup.c */
|
||||
typedef /*@null@*/void (*cleanup_function) (/*@null@*/void *arg);
|
||||
void add_cleanup (/*@notnull@*/cleanup_function pcf, /*@null@*/void *arg);
|
||||
void del_cleanup (/*@notnull@*/cleanup_function pcf);
|
||||
typedef void (*cleanup_function) (/*@null@*/void *arg);
|
||||
void add_cleanup (cleanup_function pcf, /*@null@*/void *arg);
|
||||
void del_cleanup (cleanup_function pcf);
|
||||
void do_cleanups (void);
|
||||
|
||||
/* cleanup_group.c */
|
||||
struct cleanup_info_mod {
|
||||
char *audit_msg;
|
||||
char *action;
|
||||
/*@observer@*/const char *name;
|
||||
char *name;
|
||||
};
|
||||
void cleanup_report_add_group (void *group_name);
|
||||
void cleanup_report_add_group_group (void *group_name);
|
||||
@@ -120,13 +116,15 @@ extern bool console (const char *);
|
||||
|
||||
/* copydir.c */
|
||||
extern int copy_tree (const char *src_root, const char *dst_root,
|
||||
bool copy_root,
|
||||
bool reset_selinux,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
long int uid, long int gid);
|
||||
extern int remove_tree (const char *root);
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
extern int selinux_file_context (const char *dst_name);
|
||||
#endif
|
||||
|
||||
/* encrypt.c */
|
||||
extern /*@exposed@*//*@null@*/char *pw_encrypt (const char *, const char *);
|
||||
extern char *pw_encrypt (const char *, const char *);
|
||||
|
||||
/* entry.c */
|
||||
extern void pw_entry (const char *, struct passwd *);
|
||||
@@ -151,22 +149,11 @@ extern int find_new_uid (bool sys_user,
|
||||
uid_t *uid,
|
||||
/*@null@*/uid_t const *preferred_uid);
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
/* find_new_sub_gids.c */
|
||||
extern int find_new_sub_gids (const char *owner,
|
||||
gid_t *range_start, unsigned long *range_count);
|
||||
|
||||
/* find_new_sub_uids.c */
|
||||
extern int find_new_sub_uids (const char *owner,
|
||||
uid_t *range_start, unsigned long *range_count);
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
|
||||
/* get_gid.c */
|
||||
extern int get_gid (const char *gidstr, gid_t *gid);
|
||||
|
||||
/* getgr_nam_gid.c */
|
||||
extern /*@only@*//*@null@*/struct group *getgr_nam_gid (/*@null@*/const char *grname);
|
||||
extern /*@null@*/struct group *getgr_nam_gid (const char *grname);
|
||||
|
||||
/* getlong.c */
|
||||
extern int getlong (const char *numstr, /*@out@*/long int *result);
|
||||
@@ -249,7 +236,7 @@ extern void mailcheck (void);
|
||||
extern void motd (void);
|
||||
|
||||
/* myname.c */
|
||||
extern /*@null@*//*@only@*/struct passwd *get_my_pwent (void);
|
||||
extern /*@null@*/struct passwd *get_my_pwent (void);
|
||||
|
||||
/* pam_pass_non_interractive.c */
|
||||
#ifdef USE_PAM
|
||||
@@ -260,7 +247,7 @@ extern int do_pam_passwd_non_interractive (const char *pam_service,
|
||||
|
||||
/* obscure.c */
|
||||
#ifndef USE_PAM
|
||||
extern bool obscure (const char *, const char *, const struct passwd *);
|
||||
extern int obscure (const char *, const char *, const struct passwd *);
|
||||
#endif
|
||||
|
||||
/* pam_pass.c */
|
||||
@@ -293,30 +280,12 @@ extern /*@dependent@*/ /*@null@*/struct commonio_entry *__pw_get_head (void);
|
||||
extern /*@null@*/ /*@only@*/struct passwd *__pw_dup (const struct passwd *pwent);
|
||||
extern void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent);
|
||||
|
||||
/* remove_tree.c */
|
||||
extern int remove_tree (const char *root, bool remove_root);
|
||||
|
||||
/* rlogin.c */
|
||||
extern int do_rlogin (const char *remote_host, char *name, size_t namelen,
|
||||
char *term, size_t termlen);
|
||||
|
||||
/* root_flag.c */
|
||||
extern void process_root_flag (const char* short_opt, int argc, char **argv);
|
||||
|
||||
/* salt.c */
|
||||
extern /*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const char *meth, /*@null@*/void *arg);
|
||||
|
||||
/* selinux.c */
|
||||
#ifdef WITH_SELINUX
|
||||
extern int set_selinux_file_context (const char *dst_name);
|
||||
extern int reset_selinux_file_context (void);
|
||||
#endif
|
||||
|
||||
/* semanage.c */
|
||||
#ifdef WITH_SELINUX
|
||||
extern int set_seuser(const char *login_name, const char *seuser_name);
|
||||
extern int del_seuser(const char *login_name);
|
||||
#endif
|
||||
extern /*@observer@*/const char *crypt_make_salt (/*@null@*/const char *meth, /*@null@*/void *arg);
|
||||
|
||||
/* setugid.c */
|
||||
extern int setup_groups (const struct passwd *info);
|
||||
@@ -362,17 +331,17 @@ extern void spw_free (/*@out@*/ /*@only@*/struct spwd *spent);
|
||||
/* shell.c */
|
||||
extern int shell (const char *file, /*@null@*/const char *arg, char *const envp[]);
|
||||
|
||||
/* spawn.c */
|
||||
extern int run_command (const char *cmd, const char *argv[],
|
||||
/*@null@*/const char *envp[], /*@out@*/int *status);
|
||||
/* system.c */
|
||||
extern int safe_system (const char *command,
|
||||
const char *argv[],
|
||||
const char *env[],
|
||||
int ignore_stderr);
|
||||
|
||||
/* strtoday.c */
|
||||
extern long strtoday (const char *);
|
||||
|
||||
/* suauth.c */
|
||||
extern int check_su_auth (const char *actual_id,
|
||||
const char *wanted_id,
|
||||
bool su_to_root);
|
||||
extern int check_su_auth (const char *actual_id, const char *wanted_id);
|
||||
|
||||
/* sulog.c */
|
||||
extern void sulog (const char *tty,
|
||||
@@ -388,7 +357,7 @@ extern void ttytype (const char *);
|
||||
|
||||
/* tz.c */
|
||||
#ifndef USE_PAM
|
||||
extern /*@observer@*/const char *tz (const char *);
|
||||
extern char *tz (const char *);
|
||||
#endif
|
||||
|
||||
/* ulimit.c */
|
||||
@@ -416,9 +385,9 @@ extern int setutmpx (struct utmpx *utx);
|
||||
extern bool valid (const char *, const struct passwd *);
|
||||
|
||||
/* xmalloc.c */
|
||||
extern /*@maynotreturn@*/ /*@only@*//*@out@*//*@notnull@*/char *xmalloc (size_t size)
|
||||
extern /*@maynotreturn@*/ /*@out@*//*@only@*/char *xmalloc (size_t size)
|
||||
/*@ensures MaxSet(result) == (size - 1); @*/;
|
||||
extern /*@maynotreturn@*/ /*@only@*//*@notnull@*/char *xstrdup (const char *);
|
||||
extern /*@maynotreturn@*/ /*@only@*/char *xstrdup (const char *);
|
||||
|
||||
/* xgetpwnam.c */
|
||||
extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *);
|
||||
|
||||
@@ -73,7 +73,6 @@ int pw_auth (const char *cipher,
|
||||
char prompt[1024];
|
||||
char *clear = NULL;
|
||||
const char *cp;
|
||||
const char *encrypted;
|
||||
int retval;
|
||||
|
||||
#ifdef SKEY
|
||||
@@ -178,12 +177,7 @@ int pw_auth (const char *cipher,
|
||||
* the results there as well.
|
||||
*/
|
||||
|
||||
encrypted = pw_encrypt (input, cipher);
|
||||
if (NULL != encrypted) {
|
||||
retval = strcmp (encrypted, cipher);
|
||||
} else {
|
||||
retval = -1;
|
||||
}
|
||||
retval = strcmp (pw_encrypt (input, cipher), cipher);
|
||||
|
||||
#ifdef SKEY
|
||||
/*
|
||||
|
||||
14
lib/pwio.c
14
lib/pwio.c
@@ -72,17 +72,6 @@ static int passwd_put (const void *ent, FILE * file)
|
||||
{
|
||||
const struct passwd *pw = ent;
|
||||
|
||||
if ( (NULL == pw)
|
||||
|| (valid_field (pw->pw_name, ":\n") == -1)
|
||||
|| (valid_field (pw->pw_passwd, ":\n") == -1)
|
||||
|| (pw->pw_uid == (uid_t)-1)
|
||||
|| (pw->pw_gid == (gid_t)-1)
|
||||
|| (valid_field (pw->pw_gecos, ":\n") == -1)
|
||||
|| (valid_field (pw->pw_dir, ":\n") == -1)
|
||||
|| (valid_field (pw->pw_shell, ":\n") == -1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (putpwent (pw, file) == -1) ? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -105,9 +94,6 @@ static struct commonio_db passwd_db = {
|
||||
#ifdef WITH_SELINUX
|
||||
NULL, /* scontext */
|
||||
#endif
|
||||
0644, /* st_mode */
|
||||
0, /* st_uid */
|
||||
0, /* st_gid */
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
|
||||
28
lib/pwmem.c
28
lib/pwmem.c
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2013, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -48,43 +48,25 @@
|
||||
if (NULL == pw) {
|
||||
return NULL;
|
||||
}
|
||||
/* The libc might define other fields. They won't be copied. */
|
||||
memset (pw, 0, sizeof *pw);
|
||||
pw->pw_uid = pwent->pw_uid;
|
||||
pw->pw_gid = pwent->pw_gid;
|
||||
/*@-mustfreeonly@*/
|
||||
*pw = *pwent;
|
||||
pw->pw_name = strdup (pwent->pw_name);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == pw->pw_name) {
|
||||
pw_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
pw->pw_passwd = strdup (pwent->pw_passwd);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == pw->pw_passwd) {
|
||||
pw_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
pw->pw_gecos = strdup (pwent->pw_gecos);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == pw->pw_gecos) {
|
||||
pw_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
pw->pw_dir = strdup (pwent->pw_dir);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == pw->pw_dir) {
|
||||
pw_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
pw->pw_shell = strdup (pwent->pw_shell);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == pw->pw_shell) {
|
||||
pw_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -94,10 +76,8 @@
|
||||
void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent)
|
||||
{
|
||||
free (pwent->pw_name);
|
||||
if (pwent->pw_passwd) {
|
||||
memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
|
||||
free (pwent->pw_passwd);
|
||||
}
|
||||
memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
|
||||
free (pwent->pw_passwd);
|
||||
free (pwent->pw_gecos);
|
||||
free (pwent->pw_dir);
|
||||
free (pwent->pw_shell);
|
||||
|
||||
103
lib/selinux.c
103
lib/selinux.c
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 , Peter Vrabec <pvrabec@redhat.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include <selinux/selinux.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
|
||||
static bool selinux_checked = false;
|
||||
static bool selinux_enabled;
|
||||
|
||||
/*
|
||||
* set_selinux_file_context - Set the security context before any file or
|
||||
* directory creation.
|
||||
*
|
||||
* set_selinux_file_context () should be called before any creation
|
||||
* of file, symlink, directory, ...
|
||||
*
|
||||
* Callers may have to Reset SELinux to create files with default
|
||||
* contexts with reset_selinux_file_context
|
||||
*/
|
||||
int set_selinux_file_context (const char *dst_name)
|
||||
{
|
||||
/*@null@*/security_context_t scontext = NULL;
|
||||
|
||||
if (!selinux_checked) {
|
||||
selinux_enabled = is_selinux_enabled () > 0;
|
||||
selinux_checked = true;
|
||||
}
|
||||
|
||||
if (selinux_enabled) {
|
||||
/* Get the default security context for this file */
|
||||
if (matchpathcon (dst_name, 0, &scontext) < 0) {
|
||||
if (security_getenforce () != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Set the security context for the next created file */
|
||||
if (setfscreatecon (scontext) < 0) {
|
||||
if (security_getenforce () != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
freecon (scontext);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* reset_selinux_file_context - Reset the security context to the default
|
||||
* policy behavior
|
||||
*
|
||||
* reset_selinux_file_context () should be called after the context
|
||||
* was changed with set_selinux_file_context ()
|
||||
*/
|
||||
int reset_selinux_file_context (void)
|
||||
{
|
||||
if (!selinux_checked) {
|
||||
selinux_enabled = is_selinux_enabled () > 0;
|
||||
selinux_checked = true;
|
||||
}
|
||||
if (selinux_enabled) {
|
||||
if (setfscreatecon (NULL) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !WITH_SELINUX */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !WITH_SELINUX */
|
||||
378
lib/semanage.c
378
lib/semanage.c
@@ -1,378 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 , Jakub Hrozek <jhrozek@redhat.com>
|
||||
* Copyright (c) 2011 , Peter Vrabec <pvrabec@redhat.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <semanage/semanage.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
|
||||
#ifndef DEFAULT_SERANGE
|
||||
#define DEFAULT_SERANGE "s0"
|
||||
#endif
|
||||
|
||||
|
||||
static void semanage_error_callback (unused void *varg,
|
||||
semanage_handle_t *handle,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
char * message = NULL;
|
||||
va_list ap;
|
||||
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = vasprintf (&message, fmt, ap);
|
||||
va_end (ap);
|
||||
if (ret < 0) {
|
||||
/* ENOMEM */
|
||||
return;
|
||||
}
|
||||
|
||||
switch (semanage_msg_get_level (handle)) {
|
||||
case SEMANAGE_MSG_ERR:
|
||||
case SEMANAGE_MSG_WARN:
|
||||
fprintf (stderr, _("[libsemanage]: %s\n"), message);
|
||||
break;
|
||||
case SEMANAGE_MSG_INFO:
|
||||
/* nop */
|
||||
break;
|
||||
}
|
||||
|
||||
free (message);
|
||||
}
|
||||
|
||||
|
||||
static semanage_handle_t *semanage_init (void)
|
||||
{
|
||||
int ret;
|
||||
semanage_handle_t *handle = NULL;
|
||||
|
||||
handle = semanage_handle_create ();
|
||||
if (NULL == handle) {
|
||||
fprintf (stderr,
|
||||
_("Cannot create SELinux management handle\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
semanage_msg_set_callback (handle, semanage_error_callback, NULL);
|
||||
|
||||
ret = semanage_is_managed (handle);
|
||||
if (ret != 1) {
|
||||
fprintf (stderr, _("SELinux policy not managed\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = semanage_access_check (handle);
|
||||
if (ret < SEMANAGE_CAN_READ) {
|
||||
fprintf (stderr, _("Cannot read SELinux policy store\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = semanage_connect (handle);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Cannot establish SELinux management connection\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = semanage_begin_transaction (handle);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Cannot begin SELinux transaction\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return handle;
|
||||
|
||||
fail:
|
||||
semanage_handle_destroy (handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int semanage_user_mod (semanage_handle_t *handle,
|
||||
semanage_seuser_key_t *key,
|
||||
const char *login_name,
|
||||
const char *seuser_name)
|
||||
{
|
||||
int ret;
|
||||
semanage_seuser_t *seuser = NULL;
|
||||
|
||||
semanage_seuser_query (handle, key, &seuser);
|
||||
if (NULL == seuser) {
|
||||
fprintf (stderr,
|
||||
_("Could not query seuser for %s\n"), login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not set serange for %s\n"), login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not set sename for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_modify_local (handle, key, seuser);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not modify login mapping for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
semanage_seuser_free (seuser);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int semanage_user_add (semanage_handle_t *handle,
|
||||
semanage_seuser_key_t *key,
|
||||
const char *login_name,
|
||||
const char *seuser_name)
|
||||
{
|
||||
int ret;
|
||||
semanage_seuser_t *seuser = NULL;
|
||||
|
||||
ret = semanage_seuser_create (handle, &seuser);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Cannot create SELinux login mapping for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_set_name (handle, seuser, login_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Could not set name for %s\n"), login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not set serange for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not set SELinux user for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_modify_local (handle, key, seuser);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not add login mapping for %s\n"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
semanage_seuser_free (seuser);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int set_seuser (const char *login_name, const char *seuser_name)
|
||||
{
|
||||
semanage_handle_t *handle = NULL;
|
||||
semanage_seuser_key_t *key = NULL;
|
||||
int ret;
|
||||
int seuser_exists = 0;
|
||||
|
||||
if (NULL == seuser_name) {
|
||||
/* don't care, just let system pick the defaults */
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle = semanage_init ();
|
||||
if (NULL == handle) {
|
||||
fprintf (stderr, _("Cannot init SELinux management\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_key_create (handle, login_name, &key);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Cannot create SELinux user key\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_exists (handle, key, &seuser_exists);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot verify the SELinux user\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 != seuser_exists) {
|
||||
ret = semanage_user_mod (handle, key, login_name, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Cannot modify SELinux user mapping\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
ret = semanage_user_add (handle, key, login_name, seuser_name);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Cannot add SELinux user mapping\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = semanage_commit (handle);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot commit SELinux transaction\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
semanage_seuser_key_free (key);
|
||||
semanage_handle_destroy (handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int del_seuser (const char *login_name)
|
||||
{
|
||||
semanage_handle_t *handle = NULL;
|
||||
semanage_seuser_key_t *key = NULL;
|
||||
int ret;
|
||||
int exists = 0;
|
||||
|
||||
handle = semanage_init ();
|
||||
if (NULL == handle) {
|
||||
fprintf (stderr, _("Cannot init SELinux management\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_key_create (handle, login_name, &key);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, _("Cannot create SELinux user key\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_exists (handle, key, &exists);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot verify the SELinux user\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 == exists) {
|
||||
fprintf (stderr,
|
||||
_("Login mapping for %s is not defined, OK if default mapping was used\n"),
|
||||
login_name);
|
||||
ret = 0; /* probably default mapping */
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_exists_local (handle, key, &exists);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot verify the SELinux user\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 == exists) {
|
||||
fprintf (stderr,
|
||||
_("Login mapping for %s is defined in policy, cannot be deleted\n"),
|
||||
login_name);
|
||||
ret = 0; /* Login mapping defined in policy can't be deleted */
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_seuser_del_local (handle, key);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr,
|
||||
_("Could not delete login mapping for %s"),
|
||||
login_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = semanage_commit (handle);
|
||||
if (ret < 0) {
|
||||
fprintf (stderr, _("Cannot commit SELinux transaction\n"));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
semanage_handle_destroy (handle);
|
||||
return ret;
|
||||
}
|
||||
#else /* !WITH_SELINUX */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !WITH_SELINUX */
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2013, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -51,19 +51,13 @@
|
||||
if (NULL == sg) {
|
||||
return NULL;
|
||||
}
|
||||
/* Do the same as the other _dup function, even if we know the
|
||||
* structure. */
|
||||
memset (sg, 0, sizeof *sg);
|
||||
/*@-mustfreeonly@*/
|
||||
*sg = *sgent;
|
||||
sg->sg_name = strdup (sgent->sg_name);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == sg->sg_name) {
|
||||
free (sg);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
sg->sg_passwd = strdup (sgent->sg_passwd);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == sg->sg_passwd) {
|
||||
free (sg->sg_name);
|
||||
free (sg);
|
||||
@@ -71,9 +65,7 @@
|
||||
}
|
||||
|
||||
for (i = 0; NULL != sgent->sg_adm[i]; i++);
|
||||
/*@-mustfreeonly@*/
|
||||
sg->sg_adm = (char **) malloc ((i + 1) * sizeof (char *));
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == sg->sg_adm) {
|
||||
free (sg->sg_passwd);
|
||||
free (sg->sg_name);
|
||||
@@ -96,9 +88,7 @@
|
||||
sg->sg_adm[i] = NULL;
|
||||
|
||||
for (i = 0; NULL != sgent->sg_mem[i]; i++);
|
||||
/*@-mustfreeonly@*/
|
||||
sg->sg_mem = (char **) malloc ((i + 1) * sizeof (char *));
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == sg->sg_mem) {
|
||||
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||
free (sg->sg_adm[i]);
|
||||
@@ -147,20 +137,17 @@ static void gshadow_free (/*@out@*/ /*@only@*/void *ent)
|
||||
|
||||
void sgr_free (/*@out@*/ /*@only@*/struct sgrp *sgent)
|
||||
{
|
||||
size_t i;
|
||||
free (sgent->sg_name);
|
||||
if (NULL != sgent->sg_passwd) {
|
||||
memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
|
||||
free (sgent->sg_passwd);
|
||||
memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
|
||||
free (sgent->sg_passwd);
|
||||
while (NULL != *(sgent->sg_adm)) {
|
||||
free (*(sgent->sg_adm));
|
||||
sgent->sg_adm++;
|
||||
}
|
||||
for (i = 0; NULL != sgent->sg_adm[i]; i++) {
|
||||
free (sgent->sg_adm[i]);
|
||||
while (NULL != *(sgent->sg_mem)) {
|
||||
free (*(sgent->sg_mem));
|
||||
sgent->sg_mem++;
|
||||
}
|
||||
free (sgent->sg_adm);
|
||||
for (i = 0; NULL != sgent->sg_mem[i]; i++) {
|
||||
free (sgent->sg_mem[i]);
|
||||
}
|
||||
free (sgent->sg_mem);
|
||||
free (sgent);
|
||||
}
|
||||
|
||||
@@ -180,32 +167,6 @@ static int gshadow_put (const void *ent, FILE * file)
|
||||
{
|
||||
const struct sgrp *sg = ent;
|
||||
|
||||
if ( (NULL == sg)
|
||||
|| (valid_field (sg->sg_name, ":\n") == -1)
|
||||
|| (valid_field (sg->sg_passwd, ":\n") == -1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: fail also if sg->sg_adm == NULL ?*/
|
||||
if (NULL != sg->sg_adm) {
|
||||
size_t i;
|
||||
for (i = 0; NULL != sg->sg_adm[i]; i++) {
|
||||
if (valid_field (sg->sg_adm[i], ",:\n") == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: fail also if sg->sg_mem == NULL ?*/
|
||||
if (NULL != sg->sg_mem) {
|
||||
size_t i;
|
||||
for (i = 0; NULL != sg->sg_mem[i]; i++) {
|
||||
if (valid_field (sg->sg_mem[i], ",:\n") == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (putsgent (sg, file) == -1) ? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -228,9 +189,6 @@ static struct commonio_db gshadow_db = {
|
||||
#ifdef WITH_SELINUX
|
||||
NULL, /* scontext */
|
||||
#endif
|
||||
0400, /* st_mode */
|
||||
0, /* st_uid */
|
||||
0, /* st_gid */
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
@@ -252,8 +210,6 @@ int sgr_setdbname (const char *filename)
|
||||
|
||||
bool sgr_file_present (void)
|
||||
{
|
||||
if (getdef_bool ("FORCE_SHADOW"))
|
||||
return true;
|
||||
return commonio_present (&gshadow_db);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
extern int sgr_close (void);
|
||||
extern bool sgr_file_present (void);
|
||||
extern /*@observer@*/ /*@null@*/const struct sgrp *sgr_locate (const char *name);
|
||||
extern /*@null@*/const struct sgrp *sgr_locate (const char *name);
|
||||
extern int sgr_lock (void);
|
||||
extern int sgr_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *sgr_dbname (void);
|
||||
|
||||
74
lib/shadow.c
74
lib/shadow.c
@@ -42,10 +42,10 @@
|
||||
#include "defines.h"
|
||||
#include <stdio.h>
|
||||
#ifdef USE_NIS
|
||||
static bool nis_used;
|
||||
static bool nis_ignore;
|
||||
static int nis_used;
|
||||
static int nis_ignore;
|
||||
static enum { native, start, middle, native2 } nis_state;
|
||||
static bool nis_bound;
|
||||
static int nis_bound;
|
||||
static char *nis_domain;
|
||||
static char *nis_key;
|
||||
static int nis_keylen;
|
||||
@@ -66,12 +66,12 @@ static FILE *shadow;
|
||||
* __setspNIS - turn on or off NIS searches
|
||||
*/
|
||||
|
||||
void __setspNIS (bool flag)
|
||||
void __setspNIS (int flag)
|
||||
{
|
||||
nis_ignore = !flag;
|
||||
|
||||
if (nis_ignore) {
|
||||
nis_used = false;
|
||||
nis_used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +81,10 @@ void __setspNIS (bool flag)
|
||||
|
||||
static int bind_nis (void)
|
||||
{
|
||||
if (yp_get_default_domain (&nis_domain)) {
|
||||
if (yp_get_default_domain (&nis_domain))
|
||||
return -1;
|
||||
}
|
||||
|
||||
nis_bound = true;
|
||||
nis_bound = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -96,11 +95,10 @@ static int bind_nis (void)
|
||||
|
||||
void setspent (void)
|
||||
{
|
||||
if (NULL != shadow) {
|
||||
if (shadow)
|
||||
rewind (shadow);
|
||||
}else {
|
||||
else
|
||||
shadow = fopen (SHADOW_FILE, "r");
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
nis_state = native;
|
||||
@@ -113,9 +111,8 @@ void setspent (void)
|
||||
|
||||
void endspent (void)
|
||||
{
|
||||
if (NULL != shadow) {
|
||||
if (shadow)
|
||||
(void) fclose (shadow);
|
||||
}
|
||||
|
||||
shadow = (FILE *) 0;
|
||||
}
|
||||
@@ -175,9 +172,8 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
|
||||
spwd.sp_namp = fields[0];
|
||||
#ifdef USE_NIS
|
||||
if (IS_NISCHAR (fields[0][0])) {
|
||||
nis_used = true;
|
||||
}
|
||||
if (IS_NISCHAR (fields[0][0]))
|
||||
nis_used = 1;
|
||||
#endif
|
||||
spwd.sp_pwdp = fields[1];
|
||||
|
||||
@@ -215,9 +211,7 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
spwd.sp_min = -1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} else if (spwd.sp_min < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -269,9 +263,7 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
spwd.sp_warn = -1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} else if (spwd.sp_warn < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -291,9 +283,7 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
spwd.sp_inact = -1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} else if (spwd.sp_inact < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -313,9 +303,7 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
spwd.sp_expire = -1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} else if (spwd.sp_expire < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -336,9 +324,7 @@ static struct spwd *my_sgetspent (const char *string)
|
||||
spwd.sp_flag = SHADOW_SP_FLAG_UNSET;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} else if (spwd.sp_flag < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -391,9 +377,8 @@ struct spwd *getspent (void)
|
||||
struct spwd *val;
|
||||
char buf[BUFSIZ];
|
||||
#endif
|
||||
if (NULL == shadow) {
|
||||
if (!shadow)
|
||||
setspent ();
|
||||
}
|
||||
|
||||
#ifdef USE_NIS
|
||||
again:
|
||||
@@ -447,7 +432,7 @@ struct spwd *getspent (void)
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (!nis_bound) {
|
||||
if (nis_bound == 0) {
|
||||
if (bind_nis ()) {
|
||||
nis_state = native2;
|
||||
goto again;
|
||||
@@ -455,15 +440,15 @@ struct spwd *getspent (void)
|
||||
}
|
||||
if (nis_state == start) {
|
||||
if (yp_first (nis_domain, "shadow.bynam", &nis_key,
|
||||
&nis_keylen, &nis_val, &nis_vallen)) {
|
||||
&nis_keylen, &nis_val, &nis_vallen)) {
|
||||
nis_state = native2;
|
||||
goto again;
|
||||
}
|
||||
nis_state = middle;
|
||||
} else if (nis_state == middle) {
|
||||
if (yp_next (nis_domain, "shadow.bynam", nis_key,
|
||||
nis_keylen, &nis_key, &nis_keylen,
|
||||
&nis_val, &nis_vallen)) {
|
||||
nis_keylen, &nis_key, &nis_keylen,
|
||||
&nis_val, &nis_vallen)) {
|
||||
nis_state = native2;
|
||||
goto again;
|
||||
}
|
||||
@@ -486,7 +471,7 @@ struct spwd *getspnam (const char *name)
|
||||
#ifdef USE_NIS
|
||||
char buf[BUFSIZ];
|
||||
static char save_name[16];
|
||||
bool nis_disabled = false;
|
||||
int nis_disabled = 0;
|
||||
#endif
|
||||
|
||||
setspent ();
|
||||
@@ -496,20 +481,18 @@ struct spwd *getspnam (const char *name)
|
||||
* Search the shadow.byname map for this user.
|
||||
*/
|
||||
|
||||
if (!nis_ignore && !nis_bound) {
|
||||
if (!nis_ignore && !nis_bound)
|
||||
bind_nis ();
|
||||
}
|
||||
|
||||
if (!nis_ignore && nis_bound) {
|
||||
char *cp;
|
||||
|
||||
if (yp_match (nis_domain, "shadow.byname", name,
|
||||
strlen (name), &nis_val, &nis_vallen) == 0) {
|
||||
strlen (name), &nis_val, &nis_vallen) == 0) {
|
||||
|
||||
cp = strchr (nis_val, '\n');
|
||||
if (NULL != cp) {
|
||||
if (NULL != cp)
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
nis_state = middle;
|
||||
sp = my_sgetspent (nis_val);
|
||||
@@ -520,9 +503,8 @@ struct spwd *getspnam (const char *name)
|
||||
}
|
||||
endspent ();
|
||||
return sp;
|
||||
} else {
|
||||
} else
|
||||
nis_state = native2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_NIS
|
||||
@@ -534,19 +516,17 @@ struct spwd *getspnam (const char *name)
|
||||
*/
|
||||
|
||||
if (nis_used) {
|
||||
nis_ignore = true;
|
||||
nis_disabled = true;
|
||||
nis_ignore++;
|
||||
nis_disabled++;
|
||||
}
|
||||
#endif
|
||||
while ((sp = getspent ()) != (struct spwd *) 0) {
|
||||
if (strcmp (name, sp->sp_namp) == 0) {
|
||||
if (strcmp (name, sp->sp_namp) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef USE_NIS
|
||||
if (nis_disabled) {
|
||||
nis_ignore = false;
|
||||
}
|
||||
if (nis_disabled)
|
||||
nis_ignore--;
|
||||
#endif
|
||||
endspent ();
|
||||
return (sp);
|
||||
|
||||
@@ -41,10 +41,6 @@
|
||||
#include <stdio.h>
|
||||
#include "commonio.h"
|
||||
#include "shadowio.h"
|
||||
#ifdef WITH_TCB
|
||||
#include <tcb.h>
|
||||
#include "tcbfuncs.h"
|
||||
#endif /* WITH_TCB */
|
||||
|
||||
static /*@null@*/ /*@only@*/void *shadow_dup (const void *ent)
|
||||
{
|
||||
@@ -76,12 +72,6 @@ static int shadow_put (const void *ent, FILE * file)
|
||||
{
|
||||
const struct spwd *sp = ent;
|
||||
|
||||
if ( (NULL == sp)
|
||||
|| (valid_field (sp->sp_namp, ":\n") == -1)
|
||||
|| (valid_field (sp->sp_pwdp, ":\n") == -1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (putspent (sp, file) == -1) ? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -103,10 +93,7 @@ static struct commonio_db shadow_db = {
|
||||
NULL, /* fp */
|
||||
#ifdef WITH_SELINUX
|
||||
NULL, /* scontext */
|
||||
#endif /* WITH_SELINUX */
|
||||
0400, /* st_mode */
|
||||
0, /* st_uid */
|
||||
0, /* st_gid */
|
||||
#endif
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
@@ -128,52 +115,17 @@ int spw_setdbname (const char *filename)
|
||||
|
||||
bool spw_file_present (void)
|
||||
{
|
||||
if (getdef_bool ("FORCE_SHADOW"))
|
||||
return true;
|
||||
return commonio_present (&shadow_db);
|
||||
}
|
||||
|
||||
int spw_lock (void)
|
||||
{
|
||||
#ifdef WITH_TCB
|
||||
int retval = 0;
|
||||
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
#endif /* WITH_TCB */
|
||||
return commonio_lock (&shadow_db);
|
||||
#ifdef WITH_TCB
|
||||
}
|
||||
if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
if (lckpwdf_tcb (shadow_db.filename) == 0) {
|
||||
shadow_db.locked = 1;
|
||||
retval = 1;
|
||||
}
|
||||
if (shadowtcb_gain_priv () == SHADOWTCB_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
return retval;
|
||||
#endif /* WITH_TCB */
|
||||
return commonio_lock (&shadow_db);
|
||||
}
|
||||
|
||||
int spw_open (int mode)
|
||||
{
|
||||
int retval = 0;
|
||||
#ifdef WITH_TCB
|
||||
bool use_tcb = getdef_bool ("USE_TCB");
|
||||
|
||||
if (use_tcb && (shadowtcb_drop_priv () == SHADOWTCB_FAILURE)) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_TCB */
|
||||
retval = commonio_open (&shadow_db, mode);
|
||||
#ifdef WITH_TCB
|
||||
if (use_tcb && (shadowtcb_gain_priv () == SHADOWTCB_FAILURE)) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_TCB */
|
||||
return retval;
|
||||
return commonio_open (&shadow_db, mode);
|
||||
}
|
||||
|
||||
/*@observer@*/ /*@null@*/const struct spwd *spw_locate (const char *name)
|
||||
@@ -203,45 +155,12 @@ int spw_rewind (void)
|
||||
|
||||
int spw_close (void)
|
||||
{
|
||||
int retval = 0;
|
||||
#ifdef WITH_TCB
|
||||
bool use_tcb = getdef_bool ("USE_TCB");
|
||||
|
||||
if (use_tcb && (shadowtcb_drop_priv () == SHADOWTCB_FAILURE)) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_TCB */
|
||||
retval = commonio_close (&shadow_db);
|
||||
#ifdef WITH_TCB
|
||||
if (use_tcb && (shadowtcb_gain_priv () == SHADOWTCB_FAILURE)) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_TCB */
|
||||
return retval;
|
||||
return commonio_close (&shadow_db);
|
||||
}
|
||||
|
||||
int spw_unlock (void)
|
||||
{
|
||||
#ifdef WITH_TCB
|
||||
int retval = 0;
|
||||
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
#endif /* WITH_TCB */
|
||||
return commonio_unlock (&shadow_db);
|
||||
#ifdef WITH_TCB
|
||||
}
|
||||
if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
if (ulckpwdf_tcb () == 0) {
|
||||
shadow_db.locked = 0;
|
||||
retval = 1;
|
||||
}
|
||||
if (shadowtcb_gain_priv () == SHADOWTCB_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
return retval;
|
||||
#endif /* WITH_TCB */
|
||||
return commonio_unlock (&shadow_db);
|
||||
}
|
||||
|
||||
struct commonio_entry *__spw_get_head (void)
|
||||
@@ -257,10 +176,5 @@ void __spw_del_entry (const struct commonio_entry *ent)
|
||||
/* Sort with respect to passwd ordering. */
|
||||
int spw_sort ()
|
||||
{
|
||||
#ifdef WITH_TCB
|
||||
if (getdef_bool ("USE_TCB")) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_TCB */
|
||||
return commonio_sort_wrt (&shadow_db, __pw_get_db ());
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 , Michał Moskal
|
||||
* Copyright (c) 2005 , Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2013, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,28 +49,13 @@
|
||||
if (NULL == sp) {
|
||||
return NULL;
|
||||
}
|
||||
/* The libc might define other fields. They won't be copied. */
|
||||
memset (sp, 0, sizeof *sp);
|
||||
sp->sp_lstchg = spent->sp_lstchg;
|
||||
sp->sp_min = spent->sp_min;
|
||||
sp->sp_max = spent->sp_max;
|
||||
sp->sp_warn = spent->sp_warn;
|
||||
sp->sp_inact = spent->sp_inact;
|
||||
sp->sp_expire = spent->sp_expire;
|
||||
sp->sp_flag = spent->sp_flag;
|
||||
/*@-mustfreeonly@*/
|
||||
sp->sp_namp = strdup (spent->sp_namp);
|
||||
/*@=mustfreeonly@*/
|
||||
*sp = *spent;
|
||||
sp->sp_namp = strdup (spent->sp_namp);
|
||||
if (NULL == sp->sp_namp) {
|
||||
free(sp);
|
||||
return NULL;
|
||||
}
|
||||
/*@-mustfreeonly@*/
|
||||
sp->sp_pwdp = strdup (spent->sp_pwdp);
|
||||
/*@=mustfreeonly@*/
|
||||
if (NULL == sp->sp_pwdp) {
|
||||
free(sp->sp_namp);
|
||||
free(sp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -80,10 +65,8 @@
|
||||
void spw_free (/*@out@*/ /*@only@*/struct spwd *spent)
|
||||
{
|
||||
free (spent->sp_namp);
|
||||
if (NULL != spent->sp_pwdp) {
|
||||
memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
|
||||
free (spent->sp_pwdp);
|
||||
}
|
||||
memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
|
||||
free (spent->sp_pwdp);
|
||||
free (spent);
|
||||
}
|
||||
|
||||
|
||||
82
lib/spawn.c
82
lib/spawn.c
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 , Jonathan Nieder
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "exitcodes.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
int run_command (const char *cmd, const char *argv[],
|
||||
/*@null@*/const char *envp[], /*@out@*/int *status)
|
||||
{
|
||||
pid_t pid, wpid;
|
||||
|
||||
if (NULL == envp) {
|
||||
envp = (const char **)environ;
|
||||
}
|
||||
|
||||
(void) fflush (stdout);
|
||||
(void) fflush (stderr);
|
||||
|
||||
pid = fork ();
|
||||
if (0 == pid) {
|
||||
(void) execve (cmd, (char * const *) argv,
|
||||
(char * const *) envp);
|
||||
if (ENOENT == errno) {
|
||||
exit (E_CMD_NOTFOUND);
|
||||
}
|
||||
fprintf (stderr, "%s: cannot execute %s: %s\n",
|
||||
Prog, cmd, strerror (errno));
|
||||
exit (E_CMD_NOEXEC);
|
||||
} else if ((pid_t)-1 == pid) {
|
||||
fprintf (stderr, "%s: cannot execute %s: %s\n",
|
||||
Prog, cmd, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
wpid = waitpid (pid, status, 0);
|
||||
} while ( ((pid_t)-1 == wpid && errno == EINTR)
|
||||
|| (wpid != pid));
|
||||
|
||||
if ((pid_t)-1 == wpid) {
|
||||
fprintf (stderr, "%s: waitpid (status: %d): %s\n",
|
||||
Prog, *status, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,701 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 - Eric Biederman
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <stdio.h>
|
||||
#include "commonio.h"
|
||||
#include "subordinateio.h"
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
struct subordinate_range {
|
||||
const char *owner;
|
||||
unsigned long start;
|
||||
unsigned long count;
|
||||
};
|
||||
|
||||
#define NFIELDS 3
|
||||
|
||||
/*
|
||||
* subordinate_dup: create a duplicate range
|
||||
*
|
||||
* @ent: a pointer to a subordinate_range struct
|
||||
*
|
||||
* Returns a pointer to a newly allocated duplicate subordinate_range struct
|
||||
* or NULL on failure
|
||||
*/
|
||||
static /*@null@*/ /*@only@*/void *subordinate_dup (const void *ent)
|
||||
{
|
||||
const struct subordinate_range *rangeent = ent;
|
||||
struct subordinate_range *range;
|
||||
|
||||
range = (struct subordinate_range *) malloc (sizeof *range);
|
||||
if (NULL == range) {
|
||||
return NULL;
|
||||
}
|
||||
range->owner = strdup (rangeent->owner);
|
||||
if (NULL == range->owner) {
|
||||
free(range);
|
||||
return NULL;
|
||||
}
|
||||
range->start = rangeent->start;
|
||||
range->count = rangeent->count;
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
/*
|
||||
* subordinate_free: free a subordinate_range struct
|
||||
*
|
||||
* @ent: pointer to a subordinate_range struct to free.
|
||||
*/
|
||||
static void subordinate_free (/*@out@*/ /*@only@*/void *ent)
|
||||
{
|
||||
struct subordinate_range *rangeent = ent;
|
||||
|
||||
free ((void *)(rangeent->owner));
|
||||
free (rangeent);
|
||||
}
|
||||
|
||||
/*
|
||||
* subordinate_parse:
|
||||
*
|
||||
* @line: a line to parse
|
||||
*
|
||||
* Returns a pointer to a subordinate_range struct representing the values
|
||||
* in @line, or NULL on failure. Note that the returned value should not
|
||||
* be freed by the caller.
|
||||
*/
|
||||
static void *subordinate_parse (const char *line)
|
||||
{
|
||||
static struct subordinate_range range;
|
||||
static char rangebuf[1024];
|
||||
int i;
|
||||
char *cp;
|
||||
char *fields[NFIELDS];
|
||||
|
||||
/*
|
||||
* Copy the string to a temporary buffer so the substrings can
|
||||
* be modified to be NULL terminated.
|
||||
*/
|
||||
if (strlen (line) >= sizeof rangebuf)
|
||||
return NULL; /* fail if too long */
|
||||
strcpy (rangebuf, line);
|
||||
|
||||
/*
|
||||
* Save a pointer to the start of each colon separated
|
||||
* field. The fields are converted into NUL terminated strings.
|
||||
*/
|
||||
|
||||
for (cp = rangebuf, i = 0; (i < NFIELDS) && (NULL != cp); i++) {
|
||||
fields[i] = cp;
|
||||
while (('\0' != *cp) && (':' != *cp)) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if ('\0' != *cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
} else {
|
||||
cp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There must be exactly NFIELDS colon separated fields or
|
||||
* the entry is invalid. Also, fields must be non-blank.
|
||||
*/
|
||||
if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
|
||||
return NULL;
|
||||
range.owner = fields[0];
|
||||
if (getulong (fields[1], &range.start) == 0)
|
||||
return NULL;
|
||||
if (getulong (fields[2], &range.count) == 0)
|
||||
return NULL;
|
||||
|
||||
return ⦥
|
||||
}
|
||||
|
||||
/*
|
||||
* subordinate_put: print a subordinate_range value to a file
|
||||
*
|
||||
* @ent: a pointer to a subordinate_range struct to print out.
|
||||
* @file: file to which to print.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
static int subordinate_put (const void *ent, FILE * file)
|
||||
{
|
||||
const struct subordinate_range *range = ent;
|
||||
|
||||
return fprintf(file, "%s:%lu:%lu\n",
|
||||
range->owner,
|
||||
range->start,
|
||||
range->count) < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static struct commonio_ops subordinate_ops = {
|
||||
subordinate_dup, /* dup */
|
||||
subordinate_free, /* free */
|
||||
NULL, /* getname */
|
||||
subordinate_parse, /* parse */
|
||||
subordinate_put, /* put */
|
||||
fgets, /* fgets */
|
||||
fputs, /* fputs */
|
||||
NULL, /* open_hook */
|
||||
NULL, /* close_hook */
|
||||
};
|
||||
|
||||
static /*@observer@*/ /*@null*/const struct subordinate_range *subordinate_next(struct commonio_db *db)
|
||||
{
|
||||
return (const struct subordinate_range *)commonio_next (db);
|
||||
}
|
||||
|
||||
/*
|
||||
* range_exists: Check whether @owner owns any ranges
|
||||
*
|
||||
* @db: database to query
|
||||
* @owner: owner being queried
|
||||
*
|
||||
* Returns true if @owner owns any subuid ranges, false otherwise.
|
||||
*/
|
||||
static const bool range_exists(struct commonio_db *db, const char *owner)
|
||||
{
|
||||
const struct subordinate_range *range;
|
||||
commonio_rewind(db);
|
||||
while ((range = commonio_next(db)) != NULL) {
|
||||
if (0 == strcmp(range->owner, owner))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_range: find a range which @owner is authorized to use which includes
|
||||
* subuid @val.
|
||||
*
|
||||
* @db: database to query
|
||||
* @owner: owning uid being queuried
|
||||
* @val: subuid being searched for.
|
||||
*
|
||||
* Returns a range of subuids belonging to @owner and including the subuid
|
||||
* @val, or NULL if no such range exists.
|
||||
*/
|
||||
static const struct subordinate_range *find_range(struct commonio_db *db,
|
||||
const char *owner, unsigned long val)
|
||||
{
|
||||
const struct subordinate_range *range;
|
||||
|
||||
/*
|
||||
* Search for exact username/group specification
|
||||
*
|
||||
* This is the original method - go fast through the db, doing only
|
||||
* exact username/group string comparison. Therefore we leave it as-is
|
||||
* for the time being, in order to keep it equally fast as it was
|
||||
* before.
|
||||
*/
|
||||
commonio_rewind(db);
|
||||
while ((range = commonio_next(db)) != NULL) {
|
||||
unsigned long first = range->start;
|
||||
unsigned long last = first + range->count - 1;
|
||||
|
||||
if (0 != strcmp(range->owner, owner))
|
||||
continue;
|
||||
|
||||
if ((val >= first) && (val <= last))
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We only do special handling for these two files
|
||||
*/
|
||||
if ((0 != strcmp(db->filename, "/etc/subuid")) && (0 != strcmp(db->filename, "/etc/subgid")))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Search loop above did not produce any result. Let's rerun it,
|
||||
* but this time try to matcha actual UIDs. The first entry that
|
||||
* matches is considered a success.
|
||||
* (It may be specified as literal UID or as another username which
|
||||
* has the same UID as the username we are looking for.)
|
||||
*/
|
||||
struct passwd *pwd;
|
||||
uid_t owner_uid;
|
||||
char owner_uid_string[33] = "";
|
||||
|
||||
|
||||
/* Get UID of the username we are looking for */
|
||||
pwd = getpwnam(owner);
|
||||
if (NULL == pwd) {
|
||||
/* Username not defined in /etc/passwd, or error occured during lookup */
|
||||
return NULL;
|
||||
}
|
||||
owner_uid = pwd->pw_uid;
|
||||
sprintf(owner_uid_string, "%lu", (unsigned long int)owner_uid);
|
||||
|
||||
commonio_rewind(db);
|
||||
while ((range = commonio_next(db)) != NULL) {
|
||||
unsigned long first = range->start;
|
||||
unsigned long last = first + range->count - 1;
|
||||
|
||||
/* For performance reasons check range before using getpwnam() */
|
||||
if ((val < first) || (val > last)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Range matches. Check if range owner is specified
|
||||
* as numeric UID and if it matches.
|
||||
*/
|
||||
if (0 == strcmp(range->owner, owner_uid_string)) {
|
||||
return range;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, this range owner is not specified as numeric UID
|
||||
* we are looking for. It may be specified as another
|
||||
* UID or as a literal username.
|
||||
*
|
||||
* If specified as another UID, the call to getpwnam()
|
||||
* will return NULL.
|
||||
*
|
||||
* If specified as literal username, we will get its
|
||||
* UID and compare that to UID we are looking for.
|
||||
*/
|
||||
const struct passwd *range_owner_pwd;
|
||||
|
||||
range_owner_pwd = getpwnam(range->owner);
|
||||
if (NULL == range_owner_pwd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (owner_uid == range_owner_pwd->pw_uid) {
|
||||
return range;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* have_range: check whether @owner is authorized to use the range
|
||||
* (@start .. @start+@count-1).
|
||||
* @db: database to check
|
||||
* @owner: owning uid being queried
|
||||
* @start: start of range
|
||||
* @count: number of uids in range
|
||||
*
|
||||
* Returns true if @owner is authorized to use the range, false otherwise.
|
||||
*/
|
||||
static bool have_range(struct commonio_db *db,
|
||||
const char *owner, unsigned long start, unsigned long count)
|
||||
{
|
||||
const struct subordinate_range *range;
|
||||
unsigned long end;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
end = start + count - 1;
|
||||
range = find_range (db, owner, start);
|
||||
while (range) {
|
||||
unsigned long last;
|
||||
|
||||
last = range->start + range->count - 1;
|
||||
if (last >= (start + count - 1))
|
||||
return true;
|
||||
|
||||
count = end - last;
|
||||
start = last + 1;
|
||||
range = find_range(db, owner, start);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* subordinate_range_cmp: compare uid ranges
|
||||
*
|
||||
* @p1: pointer to a commonio_entry struct to compare
|
||||
* @p2: pointer to second commonio_entry struct to compare
|
||||
*
|
||||
* Returns 0 if the entries are the same. Otherwise return -1
|
||||
* if the range in p1 is lower than that in p2, or (if the ranges are
|
||||
* equal) if the owning uid in p1 is lower than p2's. Return 1 if p1's
|
||||
* range or owning uid is great than p2's.
|
||||
*/
|
||||
static int subordinate_range_cmp (const void *p1, const void *p2)
|
||||
{
|
||||
struct subordinate_range *range1, *range2;
|
||||
|
||||
if ((*(struct commonio_entry **) p1)->eptr == NULL)
|
||||
return 1;
|
||||
if ((*(struct commonio_entry **) p2)->eptr == NULL)
|
||||
return -1;
|
||||
|
||||
range1 = ((struct subordinate_range *) (*(struct commonio_entry **) p1)->eptr);
|
||||
range2 = ((struct subordinate_range *) (*(struct commonio_entry **) p2)->eptr);
|
||||
|
||||
if (range1->start < range2->start)
|
||||
return -1;
|
||||
else if (range1->start > range2->start)
|
||||
return 1;
|
||||
else if (range1->count < range2->count)
|
||||
return -1;
|
||||
else if (range1->count > range2->count)
|
||||
return 1;
|
||||
else
|
||||
return strcmp(range1->owner, range2->owner);
|
||||
}
|
||||
|
||||
/*
|
||||
* find_free_range: find an unused consecutive sequence of ids to allocate
|
||||
* to a user.
|
||||
* @db: database to search
|
||||
* @min: the first uid in the range to find
|
||||
* @max: the highest uid to find
|
||||
* @count: the number of uids needed
|
||||
*
|
||||
* Return the lowest new uid, or ULONG_MAX on failure.
|
||||
*/
|
||||
static unsigned long find_free_range(struct commonio_db *db,
|
||||
unsigned long min, unsigned long max,
|
||||
unsigned long count)
|
||||
{
|
||||
const struct subordinate_range *range;
|
||||
unsigned long low, high;
|
||||
|
||||
/* When given invalid parameters fail */
|
||||
if ((count == 0) || (max < min))
|
||||
goto fail;
|
||||
|
||||
/* Sort by range then by owner */
|
||||
commonio_sort (db, subordinate_range_cmp);
|
||||
commonio_rewind(db);
|
||||
|
||||
low = min;
|
||||
while ((range = commonio_next(db)) != NULL) {
|
||||
unsigned long first = range->start;
|
||||
unsigned long last = first + range->count - 1;
|
||||
|
||||
/* Find the top end of the hole before this range */
|
||||
high = first;
|
||||
|
||||
/* Don't allocate IDs after max (included) */
|
||||
if (high > max + 1) {
|
||||
high = max + 1;
|
||||
}
|
||||
|
||||
/* Is the hole before this range large enough? */
|
||||
if ((high > low) && ((high - low) >= count))
|
||||
return low;
|
||||
|
||||
/* Compute the low end of the next hole */
|
||||
if (low < (last + 1))
|
||||
low = last + 1;
|
||||
if (low > max)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Is the remaining unclaimed area large enough? */
|
||||
if (((max - low) + 1) >= count)
|
||||
return low;
|
||||
fail:
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_range: add a subuid range to an owning uid's list of authorized
|
||||
* subuids.
|
||||
* @db: database to which to add
|
||||
* @owner: uid which owns the subuid
|
||||
* @start: the first uid in the owned range
|
||||
* @count: the number of uids in the range
|
||||
*
|
||||
* Return 1 if the range is already present or on succcess. On error
|
||||
* return 0 and set errno appropriately.
|
||||
*/
|
||||
static int add_range(struct commonio_db *db,
|
||||
const char *owner, unsigned long start, unsigned long count)
|
||||
{
|
||||
struct subordinate_range range;
|
||||
range.owner = owner;
|
||||
range.start = start;
|
||||
range.count = count;
|
||||
|
||||
/* See if the range is already present */
|
||||
if (have_range(db, owner, start, count))
|
||||
return 1;
|
||||
|
||||
/* Otherwise append the range */
|
||||
return commonio_append(db, &range);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove_range: remove a range of subuids from an owning uid's list
|
||||
* of authorized subuids.
|
||||
* @db: database to work on
|
||||
* @owner: owning uid whose range is being removed
|
||||
* @start: start of the range to be removed
|
||||
* @count: number of uids in the range.
|
||||
*
|
||||
* Returns 0 on failure, 1 on success. Failure means that we needed to
|
||||
* create a new range to represent the new limits, and failed doing so.
|
||||
*/
|
||||
static int remove_range (struct commonio_db *db,
|
||||
const char *owner,
|
||||
unsigned long start, unsigned long count)
|
||||
{
|
||||
struct commonio_entry *ent;
|
||||
unsigned long end;
|
||||
|
||||
if (count == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
end = start + count - 1;
|
||||
for (ent = db->head; NULL != ent; ent = ent->next) {
|
||||
struct subordinate_range *range = ent->eptr;
|
||||
unsigned long first;
|
||||
unsigned long last;
|
||||
|
||||
/* Skip unparsed entries */
|
||||
if (NULL == range) {
|
||||
continue;
|
||||
}
|
||||
|
||||
first = range->start;
|
||||
last = first + range->count - 1;
|
||||
|
||||
/* Skip entries with a different owner */
|
||||
if (0 != strcmp (range->owner, owner)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip entries outside of the range to remove */
|
||||
if ((end < first) || (start > last)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start <= first) {
|
||||
if (end >= last) {
|
||||
/* to be removed: [start, end]
|
||||
* range: [first, last] */
|
||||
/* entry completely contained in the
|
||||
* range to remove */
|
||||
commonio_del_entry (db, ent);
|
||||
} else {
|
||||
/* to be removed: [start, end]
|
||||
* range: [first, last] */
|
||||
/* Remove only the start of the entry */
|
||||
range->start = end + 1;
|
||||
range->count = (last - range->start) + 1;
|
||||
|
||||
ent->changed = true;
|
||||
db->changed = true;
|
||||
}
|
||||
} else {
|
||||
if (end >= last) {
|
||||
/* to be removed: [start, end]
|
||||
* range: [first, last] */
|
||||
/* Remove only the end of the entry */
|
||||
range->count = start - range->start;
|
||||
|
||||
ent->changed = true;
|
||||
db->changed = true;
|
||||
} else {
|
||||
/* to be removed: [start, end]
|
||||
* range: [first, last] */
|
||||
/* Remove the middle of the range
|
||||
* This requires to create a new range */
|
||||
struct subordinate_range tail;
|
||||
tail.owner = range->owner;
|
||||
tail.start = end + 1;
|
||||
tail.count = (last - tail.start) + 1;
|
||||
|
||||
if (commonio_append (db, &tail) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
range->count = start - range->start;
|
||||
|
||||
ent->changed = true;
|
||||
db->changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct commonio_db subordinate_uid_db = {
|
||||
"/etc/subuid", /* filename */
|
||||
&subordinate_ops, /* ops */
|
||||
NULL, /* fp */
|
||||
#ifdef WITH_SELINUX
|
||||
NULL, /* scontext */
|
||||
#endif
|
||||
0644, /* st_mode */
|
||||
0, /* st_uid */
|
||||
0, /* st_gid */
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
false, /* changed */
|
||||
false, /* isopen */
|
||||
false, /* locked */
|
||||
false /* readonly */
|
||||
};
|
||||
|
||||
int sub_uid_setdbname (const char *filename)
|
||||
{
|
||||
return commonio_setname (&subordinate_uid_db, filename);
|
||||
}
|
||||
|
||||
/*@observer@*/const char *sub_uid_dbname (void)
|
||||
{
|
||||
return subordinate_uid_db.filename;
|
||||
}
|
||||
|
||||
bool sub_uid_file_present (void)
|
||||
{
|
||||
return commonio_present (&subordinate_uid_db);
|
||||
}
|
||||
|
||||
int sub_uid_lock (void)
|
||||
{
|
||||
return commonio_lock (&subordinate_uid_db);
|
||||
}
|
||||
|
||||
int sub_uid_open (int mode)
|
||||
{
|
||||
return commonio_open (&subordinate_uid_db, mode);
|
||||
}
|
||||
|
||||
bool sub_uid_assigned(const char *owner)
|
||||
{
|
||||
return range_exists (&subordinate_uid_db, owner);
|
||||
}
|
||||
|
||||
bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
|
||||
{
|
||||
return have_range (&subordinate_uid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_uid_add (const char *owner, uid_t start, unsigned long count)
|
||||
{
|
||||
return add_range (&subordinate_uid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_uid_remove (const char *owner, uid_t start, unsigned long count)
|
||||
{
|
||||
return remove_range (&subordinate_uid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_uid_close (void)
|
||||
{
|
||||
return commonio_close (&subordinate_uid_db);
|
||||
}
|
||||
|
||||
int sub_uid_unlock (void)
|
||||
{
|
||||
return commonio_unlock (&subordinate_uid_db);
|
||||
}
|
||||
|
||||
uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count)
|
||||
{
|
||||
unsigned long start;
|
||||
start = find_free_range (&subordinate_uid_db, min, max, count);
|
||||
return start == ULONG_MAX ? (uid_t) -1 : start;
|
||||
}
|
||||
|
||||
static struct commonio_db subordinate_gid_db = {
|
||||
"/etc/subgid", /* filename */
|
||||
&subordinate_ops, /* ops */
|
||||
NULL, /* fp */
|
||||
#ifdef WITH_SELINUX
|
||||
NULL, /* scontext */
|
||||
#endif
|
||||
0644, /* st_mode */
|
||||
0, /* st_uid */
|
||||
0, /* st_gid */
|
||||
NULL, /* head */
|
||||
NULL, /* tail */
|
||||
NULL, /* cursor */
|
||||
false, /* changed */
|
||||
false, /* isopen */
|
||||
false, /* locked */
|
||||
false /* readonly */
|
||||
};
|
||||
|
||||
int sub_gid_setdbname (const char *filename)
|
||||
{
|
||||
return commonio_setname (&subordinate_gid_db, filename);
|
||||
}
|
||||
|
||||
/*@observer@*/const char *sub_gid_dbname (void)
|
||||
{
|
||||
return subordinate_gid_db.filename;
|
||||
}
|
||||
|
||||
bool sub_gid_file_present (void)
|
||||
{
|
||||
return commonio_present (&subordinate_gid_db);
|
||||
}
|
||||
|
||||
int sub_gid_lock (void)
|
||||
{
|
||||
return commonio_lock (&subordinate_gid_db);
|
||||
}
|
||||
|
||||
int sub_gid_open (int mode)
|
||||
{
|
||||
return commonio_open (&subordinate_gid_db, mode);
|
||||
}
|
||||
|
||||
bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
|
||||
{
|
||||
return have_range(&subordinate_gid_db, owner, start, count);
|
||||
}
|
||||
|
||||
bool sub_gid_assigned(const char *owner)
|
||||
{
|
||||
return range_exists (&subordinate_gid_db, owner);
|
||||
}
|
||||
|
||||
int sub_gid_add (const char *owner, gid_t start, unsigned long count)
|
||||
{
|
||||
return add_range (&subordinate_gid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_gid_remove (const char *owner, gid_t start, unsigned long count)
|
||||
{
|
||||
return remove_range (&subordinate_gid_db, owner, start, count);
|
||||
}
|
||||
|
||||
int sub_gid_close (void)
|
||||
{
|
||||
return commonio_close (&subordinate_gid_db);
|
||||
}
|
||||
|
||||
int sub_gid_unlock (void)
|
||||
{
|
||||
return commonio_unlock (&subordinate_gid_db);
|
||||
}
|
||||
|
||||
gid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count)
|
||||
{
|
||||
unsigned long start;
|
||||
start = find_free_range (&subordinate_gid_db, min, max, count);
|
||||
return start == ULONG_MAX ? (gid_t) -1 : start;
|
||||
}
|
||||
#else /* !ENABLE_SUBIDS */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !ENABLE_SUBIDS */
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012- Eric W. Biederman
|
||||
*/
|
||||
|
||||
#ifndef _SUBORDINATEIO_H
|
||||
#define _SUBORDINATEIO_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
extern int sub_uid_close(void);
|
||||
extern bool have_sub_uids(const char *owner, uid_t start, unsigned long count);
|
||||
extern bool sub_uid_file_present (void);
|
||||
extern bool sub_uid_assigned(const char *owner);
|
||||
extern int sub_uid_lock (void);
|
||||
extern int sub_uid_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *sub_uid_dbname (void);
|
||||
extern int sub_uid_open (int mode);
|
||||
extern int sub_uid_unlock (void);
|
||||
extern int sub_uid_add (const char *owner, uid_t start, unsigned long count);
|
||||
extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
|
||||
extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
|
||||
|
||||
extern int sub_gid_close(void);
|
||||
extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
|
||||
extern bool sub_gid_file_present (void);
|
||||
extern bool sub_gid_assigned(const char *owner);
|
||||
extern int sub_gid_lock (void);
|
||||
extern int sub_gid_setdbname (const char *filename);
|
||||
extern /*@observer@*/const char *sub_gid_dbname (void);
|
||||
extern int sub_gid_open (int mode);
|
||||
extern int sub_gid_unlock (void);
|
||||
extern int sub_gid_add (const char *owner, gid_t start, unsigned long count);
|
||||
extern int sub_gid_remove (const char *owner, gid_t start, unsigned long count);
|
||||
extern uid_t sub_gid_find_free_range(gid_t min, gid_t max, unsigned long count);
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
#endif
|
||||
613
lib/tcbfuncs.c
613
lib/tcbfuncs.c
@@ -1,613 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001 Rafal Wojtczuk, Solar Designer
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <tcb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#include "getdef.h"
|
||||
#include "shadowio.h"
|
||||
#include "tcbfuncs.h"
|
||||
|
||||
#define SHADOWTCB_HASH_BY 1000
|
||||
#define SHADOWTCB_LOCK_SUFFIX ".lock"
|
||||
|
||||
static /*@null@*//*@only@*/char *stored_tcb_user = NULL;
|
||||
|
||||
shadowtcb_status shadowtcb_drop_priv (void)
|
||||
{
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
|
||||
if (NULL != stored_tcb_user) {
|
||||
if (tcb_drop_priv (stored_tcb_user) == 0) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
|
||||
shadowtcb_status shadowtcb_gain_priv (void)
|
||||
{
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
|
||||
return (tcb_gain_priv () == 0) ? SHADOWTCB_SUCCESS : SHADOWTCB_FAILURE;
|
||||
}
|
||||
|
||||
/* In case something goes wrong, we return immediately, not polluting the
|
||||
* code with free(). All errors are fatal, so the application is expected
|
||||
* to exit soon.
|
||||
*/
|
||||
#define OUT_OF_MEMORY do { \
|
||||
fprintf (stderr, _("%s: out of memory\n"), Prog); \
|
||||
(void) fflush (stderr); \
|
||||
} while (false)
|
||||
|
||||
/* Returns user's tcb directory path relative to TCB_DIR. */
|
||||
static /*@null@*/ char *shadowtcb_path_rel (const char *name, uid_t uid)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!getdef_bool ("TCB_SYMLINKS") || uid < SHADOWTCB_HASH_BY) {
|
||||
if (asprintf (&ret, "%s", name) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
} else if (uid < SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY) {
|
||||
if (asprintf (&ret, ":%dK/%s",
|
||||
uid / SHADOWTCB_HASH_BY, name) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (asprintf (&ret, ":%dM/:%dK/%s",
|
||||
uid / (SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY),
|
||||
(uid % (SHADOWTCB_HASH_BY * SHADOWTCB_HASH_BY)) / SHADOWTCB_HASH_BY,
|
||||
name) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static /*@null@*/ char *shadowtcb_path_rel_existing (const char *name)
|
||||
{
|
||||
char *path, *rval;
|
||||
struct stat st;
|
||||
char link[8192];
|
||||
ssize_t ret;
|
||||
|
||||
if (asprintf (&path, TCB_DIR "/%s", name) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
if (lstat (path, &st) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, path, strerror (errno));
|
||||
free (path);
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISDIR (st.st_mode)) {
|
||||
free (path);
|
||||
rval = strdup (name);
|
||||
if (NULL == rval) {
|
||||
OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
if (!S_ISLNK (st.st_mode)) {
|
||||
fprintf (stderr,
|
||||
_("%s: %s is neither a directory, nor a symlink.\n"),
|
||||
Prog, path);
|
||||
free (path);
|
||||
return NULL;
|
||||
}
|
||||
ret = readlink (path, link, sizeof (link) - 1);
|
||||
if (-1 == ret) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot read symbolic link %s: %s\n"),
|
||||
Prog, path, strerror (errno));
|
||||
free (path);
|
||||
return NULL;
|
||||
}
|
||||
free (path);
|
||||
if ((size_t)ret >= sizeof(link) - 1) {
|
||||
link[sizeof(link) - 1] = '\0';
|
||||
fprintf (stderr,
|
||||
_("%s: Suspiciously long symlink: %s\n"),
|
||||
Prog, link);
|
||||
return NULL;
|
||||
}
|
||||
link[(size_t)ret] = '\0';
|
||||
rval = strdup (link);
|
||||
if (NULL == rval) {
|
||||
OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
static /*@null@*/ char *shadowtcb_path (const char *name, uid_t uid)
|
||||
{
|
||||
char *ret, *rel;
|
||||
|
||||
rel = shadowtcb_path_rel (name, uid);
|
||||
if (NULL == rel) {
|
||||
return NULL;
|
||||
}
|
||||
if (asprintf (&ret, TCB_DIR "/%s", rel) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
free (rel);
|
||||
return NULL;
|
||||
}
|
||||
free (rel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static /*@null@*/ char *shadowtcb_path_existing (const char *name)
|
||||
{
|
||||
char *ret, *rel;
|
||||
|
||||
rel = shadowtcb_path_rel_existing (name);
|
||||
if (NULL == rel) {
|
||||
return NULL;
|
||||
}
|
||||
if (asprintf (&ret, TCB_DIR "/%s", rel) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
free (rel);
|
||||
return NULL;
|
||||
}
|
||||
free (rel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static shadowtcb_status mkdir_leading (const char *name, uid_t uid)
|
||||
{
|
||||
char *ind, *dir, *ptr, *path = shadowtcb_path_rel (name, uid);
|
||||
struct stat st;
|
||||
|
||||
if (NULL == path) {
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
ptr = path;
|
||||
if (stat (TCB_DIR, &st) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, TCB_DIR, strerror (errno));
|
||||
goto out_free_path;
|
||||
}
|
||||
while ((ind = strchr (ptr, '/'))) {
|
||||
*ind = '\0';
|
||||
if (asprintf (&dir, TCB_DIR "/%s", path) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if ((mkdir (dir, 0700) != 0) && (errno != EEXIST)) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot create directory %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free_dir;
|
||||
}
|
||||
if (chown (dir, 0, st.st_gid) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free_dir;
|
||||
}
|
||||
if (chmod (dir, 0711) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free_dir;
|
||||
}
|
||||
free (dir);
|
||||
*ind = '/';
|
||||
ptr = ind + 1;
|
||||
}
|
||||
free (path);
|
||||
return SHADOWTCB_SUCCESS;
|
||||
out_free_dir:
|
||||
free (dir);
|
||||
out_free_path:
|
||||
free (path);
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
|
||||
static shadowtcb_status unlink_suffs (const char *user)
|
||||
{
|
||||
static char *suffs[] = { "+", "-", SHADOWTCB_LOCK_SUFFIX };
|
||||
char *tmp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (asprintf (&tmp, TCB_FMT "%s", user, suffs[i]) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if ((unlink (tmp) != 0) && (errno != ENOENT)) {
|
||||
fprintf (stderr,
|
||||
_("%s: unlink: %s: %s\n"),
|
||||
Prog, tmp, strerror (errno));
|
||||
free (tmp);
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
free (tmp);
|
||||
}
|
||||
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
|
||||
/* path should be a relative existing tcb directory */
|
||||
static shadowtcb_status rmdir_leading (char *path)
|
||||
{
|
||||
char *ind, *dir;
|
||||
shadowtcb_status ret = SHADOWTCB_SUCCESS;
|
||||
while ((ind = strrchr (path, '/'))) {
|
||||
*ind = '\0';
|
||||
if (asprintf (&dir, TCB_DIR "/%s", path) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (rmdir (dir) != 0) {
|
||||
if (errno != ENOTEMPTY) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot remove directory %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
ret = SHADOWTCB_FAILURE;
|
||||
}
|
||||
free (dir);
|
||||
break;
|
||||
}
|
||||
free (dir);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static shadowtcb_status move_dir (const char *user_newname, uid_t user_newid)
|
||||
{
|
||||
char *olddir = NULL, *newdir = NULL;
|
||||
char *real_old_dir = NULL, *real_new_dir = NULL;
|
||||
char *real_old_dir_rel = NULL, *real_new_dir_rel = NULL;
|
||||
uid_t old_uid, the_newid;
|
||||
struct stat oldmode;
|
||||
shadowtcb_status ret = SHADOWTCB_FAILURE;
|
||||
|
||||
if (NULL == stored_tcb_user) {
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (asprintf (&olddir, TCB_DIR "/%s", stored_tcb_user) == -1) {
|
||||
goto out_free_nomem;
|
||||
}
|
||||
if (stat (olddir, &oldmode) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, olddir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
old_uid = oldmode.st_uid;
|
||||
the_newid = (user_newid == -1) ? old_uid : user_newid;
|
||||
real_old_dir = shadowtcb_path_existing (stored_tcb_user);
|
||||
if (NULL == real_old_dir) {
|
||||
goto out_free;
|
||||
}
|
||||
real_new_dir = shadowtcb_path (user_newname, the_newid);
|
||||
if (NULL == real_new_dir) {
|
||||
goto out_free;
|
||||
}
|
||||
if (strcmp (real_old_dir, real_new_dir) == 0) {
|
||||
ret = SHADOWTCB_SUCCESS;
|
||||
goto out_free;
|
||||
}
|
||||
real_old_dir_rel = shadowtcb_path_rel_existing (stored_tcb_user);
|
||||
if (NULL == real_old_dir_rel) {
|
||||
goto out_free;
|
||||
}
|
||||
if (mkdir_leading (user_newname, the_newid) == SHADOWTCB_FAILURE) {
|
||||
goto out_free;
|
||||
}
|
||||
if (rename (real_old_dir, real_new_dir) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot rename %s to %s: %s\n"),
|
||||
Prog, real_old_dir, real_new_dir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (rmdir_leading (real_old_dir_rel) == SHADOWTCB_FAILURE) {
|
||||
goto out_free;
|
||||
}
|
||||
if ((unlink (olddir) != 0) && (errno != ENOENT)) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot remove %s: %s\n"),
|
||||
Prog, olddir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (asprintf (&newdir, TCB_DIR "/%s", user_newname) == -1) {
|
||||
goto out_free_nomem;
|
||||
}
|
||||
real_new_dir_rel = shadowtcb_path_rel (user_newname, the_newid);
|
||||
if (NULL == real_new_dir_rel) {
|
||||
goto out_free;
|
||||
}
|
||||
if ( (strcmp (real_new_dir, newdir) != 0)
|
||||
&& (symlink (real_new_dir_rel, newdir) != 0)) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot create symbolic link %s: %s\n"),
|
||||
Prog, real_new_dir_rel, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
ret = SHADOWTCB_SUCCESS;
|
||||
goto out_free;
|
||||
out_free_nomem:
|
||||
OUT_OF_MEMORY;
|
||||
out_free:
|
||||
free (olddir);
|
||||
free (newdir);
|
||||
free (real_old_dir);
|
||||
free (real_new_dir);
|
||||
free (real_old_dir_rel);
|
||||
free (real_new_dir_rel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
shadowtcb_status shadowtcb_set_user (const char* name)
|
||||
{
|
||||
char *buf;
|
||||
shadowtcb_status retval;
|
||||
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
|
||||
if (NULL != stored_tcb_user) {
|
||||
free (stored_tcb_user);
|
||||
}
|
||||
|
||||
stored_tcb_user = strdup (name);
|
||||
if (NULL == stored_tcb_user) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (asprintf (&buf, TCB_FMT, name) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
|
||||
retval = (spw_setdbname (buf) != 0) ? SHADOWTCB_SUCCESS : SHADOWTCB_FAILURE;
|
||||
free (buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* tcb directory must be empty before shadowtcb_remove is called. */
|
||||
shadowtcb_status shadowtcb_remove (const char *name)
|
||||
{
|
||||
shadowtcb_status ret = SHADOWTCB_SUCCESS;
|
||||
char *path = shadowtcb_path_existing (name);
|
||||
char *rel = shadowtcb_path_rel_existing (name);
|
||||
if ((NULL == path) || (NULL == rel) || (rmdir (path) != 0)) {
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (rmdir_leading (rel) == SHADOWTCB_FAILURE) {
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
free (path);
|
||||
free (rel);
|
||||
if (asprintf (&path, TCB_DIR "/%s", name) == -1) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if ((unlink (path) != 0) && (errno != ENOENT)) {
|
||||
ret = SHADOWTCB_FAILURE;
|
||||
}
|
||||
free (path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
shadowtcb_status shadowtcb_move (/*@NULL@*/const char *user_newname, uid_t user_newid)
|
||||
{
|
||||
struct stat dirmode, filemode;
|
||||
char *tcbdir, *shadow;
|
||||
shadowtcb_status ret = SHADOWTCB_FAILURE;
|
||||
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
if (NULL == stored_tcb_user) {
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (NULL == user_newname) {
|
||||
user_newname = stored_tcb_user;
|
||||
}
|
||||
if (move_dir (user_newname, user_newid) == SHADOWTCB_FAILURE) {
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (-1 == user_newid) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
if ( (asprintf (&tcbdir, TCB_DIR "/%s", user_newname) == -1)
|
||||
|| (asprintf (&shadow, TCB_FMT, user_newname) == -1)) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (stat (tcbdir, &dirmode) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (tcbdir, 0, 0) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change owners of %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (tcbdir, 0700) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (lstat (shadow, &filemode) != 0) {
|
||||
if (errno != ENOENT) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot lstat %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
fprintf (stderr,
|
||||
_("%s: Warning, user %s has no tcb shadow file.\n"),
|
||||
Prog, user_newname);
|
||||
} else {
|
||||
if (!S_ISREG (filemode.st_mode) ||
|
||||
filemode.st_nlink != 1) {
|
||||
fprintf (stderr,
|
||||
_("%s: Emergency: %s's tcb shadow is not a "
|
||||
"regular file with st_nlink=1.\n"
|
||||
"The account is left locked.\n"),
|
||||
Prog, user_newname);
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (shadow, user_newid, filemode.st_gid) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (shadow, filemode.st_mode & 07777) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
if (unlink_suffs (user_newname) == SHADOWTCB_FAILURE) {
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (tcbdir, user_newid, dirmode.st_gid) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, tcbdir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
ret = SHADOWTCB_SUCCESS;
|
||||
out_free:
|
||||
free (tcbdir);
|
||||
free (shadow);
|
||||
return ret;
|
||||
}
|
||||
|
||||
shadowtcb_status shadowtcb_create (const char *name, uid_t uid)
|
||||
{
|
||||
char *dir, *shadow;
|
||||
struct stat tcbdir_stat;
|
||||
gid_t shadowgid, authgid;
|
||||
struct group *gr;
|
||||
int fd;
|
||||
shadowtcb_status ret = SHADOWTCB_FAILURE;
|
||||
|
||||
if (!getdef_bool ("USE_TCB")) {
|
||||
return SHADOWTCB_SUCCESS;
|
||||
}
|
||||
if (stat (TCB_DIR, &tcbdir_stat) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot stat %s: %s\n"),
|
||||
Prog, TCB_DIR, strerror (errno));
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
shadowgid = tcbdir_stat.st_gid;
|
||||
authgid = shadowgid;
|
||||
if (getdef_bool ("TCB_AUTH_GROUP")) {
|
||||
gr = getgrnam ("auth");
|
||||
if (NULL != gr) {
|
||||
authgid = gr->gr_gid;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (asprintf (&dir, TCB_DIR "/%s", name) == -1)
|
||||
|| (asprintf (&shadow, TCB_FMT, name) == -1)) {
|
||||
OUT_OF_MEMORY;
|
||||
return SHADOWTCB_FAILURE;
|
||||
}
|
||||
if (mkdir (dir, 0700) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: mkdir: %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
fd = open (shadow, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot open %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
close (fd);
|
||||
if (chown (shadow, 0, authgid) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (shadow, (mode_t) ((authgid == shadowgid) ? 0600 : 0640)) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, shadow, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chown (dir, 0, authgid) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change owner of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if (chmod (dir, (mode_t) ((authgid == shadowgid) ? 02700 : 02710)) != 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: Cannot change mode of %s: %s\n"),
|
||||
Prog, dir, strerror (errno));
|
||||
goto out_free;
|
||||
}
|
||||
if ( (shadowtcb_set_user (name) == SHADOWTCB_FAILURE)
|
||||
|| (shadowtcb_move (NULL, uid) == SHADOWTCB_FAILURE)) {
|
||||
goto out_free;
|
||||
}
|
||||
ret = SHADOWTCB_SUCCESS;
|
||||
out_free:
|
||||
free (dir);
|
||||
free (shadow);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef _TCBFUNCS_H
|
||||
#define _TCBFUNCS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum {
|
||||
SHADOWTCB_FAILURE = 0,
|
||||
SHADOWTCB_SUCCESS = 1
|
||||
} shadowtcb_status;
|
||||
|
||||
extern shadowtcb_status shadowtcb_drop_priv (void);
|
||||
extern shadowtcb_status shadowtcb_gain_priv (void);
|
||||
extern shadowtcb_status shadowtcb_set_user (const char *name);
|
||||
extern shadowtcb_status shadowtcb_remove (const char *name);
|
||||
extern shadowtcb_status shadowtcb_move (/*@null@*/const char *user_newname,
|
||||
uid_t user_newid);
|
||||
extern shadowtcb_status shadowtcb_create (const char *name, uid_t uid);
|
||||
|
||||
#endif
|
||||
19
lib/utent.c
19
lib/utent.c
@@ -88,6 +88,25 @@ struct utmp *getutent (void)
|
||||
|
||||
return &utmp_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* getutline - get the utmp entry matching ut_line
|
||||
*/
|
||||
|
||||
struct utmp *getutline (const struct utmp *utent)
|
||||
{
|
||||
struct utmp save;
|
||||
struct utmp *new;
|
||||
|
||||
save = *utent;
|
||||
while (new = getutent ())
|
||||
if (strncmp (new->ut_line, save.ut_line, sizeof new->ut_line))
|
||||
continue;
|
||||
else
|
||||
return new;
|
||||
|
||||
return (struct utmp *) 0;
|
||||
}
|
||||
#else
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif
|
||||
|
||||
@@ -23,17 +23,14 @@ libmisc_a_SOURCES = \
|
||||
env.c \
|
||||
failure.c \
|
||||
failure.h \
|
||||
fields.c \
|
||||
find_new_gid.c \
|
||||
find_new_uid.c \
|
||||
find_new_sub_gids.c \
|
||||
find_new_sub_uids.c \
|
||||
getdate.h \
|
||||
getdate.y \
|
||||
getgr_nam_gid.c \
|
||||
getrange.c \
|
||||
hushed.c \
|
||||
idmapping.h \
|
||||
idmapping.c \
|
||||
isexpired.c \
|
||||
limits.c \
|
||||
list.c log.c \
|
||||
@@ -47,13 +44,12 @@ libmisc_a_SOURCES = \
|
||||
pwd2spwd.c \
|
||||
pwdcheck.c \
|
||||
pwd_init.c \
|
||||
remove_tree.c \
|
||||
rlogin.c \
|
||||
root_flag.c \
|
||||
salt.c \
|
||||
setugid.c \
|
||||
setupenv.c \
|
||||
shell.c \
|
||||
system.c \
|
||||
strtoday.c \
|
||||
sub.c \
|
||||
sulog.c \
|
||||
|
||||
@@ -71,11 +71,7 @@ int add_groups (const char *list)
|
||||
return -1;
|
||||
}
|
||||
ngroups = getgroups (i, grouplist);
|
||||
if ( ( (-1 == ngroups)
|
||||
&& (EINVAL != errno))
|
||||
|| (i > (size_t)ngroups)) {
|
||||
/* Unexpected failure of getgroups or successful
|
||||
* reception of the groups */
|
||||
if ((-1 == ngroups) || (i > (size_t)ngroups)) {
|
||||
break;
|
||||
}
|
||||
/* not enough room, so try allocating a larger buffer */
|
||||
|
||||
@@ -76,7 +76,7 @@ void audit_help_open (void)
|
||||
* id - uid or gid that the operation is being performed on. This is used
|
||||
* only when user is NULL.
|
||||
*/
|
||||
void audit_logger (int type, unused const char *pgname, const char *op,
|
||||
void audit_logger (int type, const char *pgname, const char *op,
|
||||
const char *name, unsigned int id,
|
||||
shadow_audit_result result)
|
||||
{
|
||||
@@ -84,7 +84,7 @@ void audit_logger (int type, unused const char *pgname, const char *op,
|
||||
return;
|
||||
} else {
|
||||
audit_log_acct_message (audit_fd, type, NULL, op, name, id,
|
||||
NULL, NULL, NULL, (int) result);
|
||||
NULL, NULL, NULL, (int) result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
/*@observer@*/const char *Basename (const char *str)
|
||||
char *Basename (char *str)
|
||||
{
|
||||
char *cp = strrchr (str, '/');
|
||||
|
||||
return (NULL != cp) ? cp + 1 : str;
|
||||
return cp ? cp + 1 : str;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) 1992 - 1993, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2010 - , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -45,92 +44,59 @@
|
||||
*
|
||||
* chown_dir() walks a directory tree and changes the ownership
|
||||
* of all files owned by the provided user ID.
|
||||
*
|
||||
* Only files owned (resp. group-owned) by old_uid (resp. by old_gid)
|
||||
* will have their ownership (resp. group-ownership) modified, unless
|
||||
* old_uid (resp. old_gid) is set to -1.
|
||||
*
|
||||
* new_uid and new_gid can be set to -1 to indicate that no owner or
|
||||
* group-owner shall be changed.
|
||||
*/
|
||||
int chown_tree (const char *root,
|
||||
uid_t old_uid,
|
||||
uid_t new_uid,
|
||||
gid_t old_gid,
|
||||
gid_t new_gid)
|
||||
int
|
||||
chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid,
|
||||
gid_t new_gid)
|
||||
{
|
||||
char *new_name;
|
||||
size_t new_name_len;
|
||||
char new_name[1024];
|
||||
int rc = 0;
|
||||
struct DIRECT *ent;
|
||||
struct stat sb;
|
||||
DIR *dir;
|
||||
|
||||
new_name = malloc (1024);
|
||||
if (NULL == new_name) {
|
||||
return -1;
|
||||
}
|
||||
new_name_len = 1024;
|
||||
|
||||
/*
|
||||
* Make certain the directory exists. This routine is called
|
||||
* directly by the invoker, or recursively.
|
||||
* directory by the invoker, or recursively.
|
||||
*/
|
||||
|
||||
if (access (root, F_OK) != 0) {
|
||||
free (new_name);
|
||||
if (access (root, F_OK) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the directory and read each entry. Every entry is tested
|
||||
* to see if it is a directory, and if so this routine is called
|
||||
* recursively. If not, it is checked to see if an ownership
|
||||
* shall be changed.
|
||||
* recursively. If not, it is checked to see if it is owned by
|
||||
* old user ID.
|
||||
*/
|
||||
|
||||
dir = opendir (root);
|
||||
if (NULL == dir) {
|
||||
free (new_name);
|
||||
if (!(dir = opendir (root)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((ent = readdir (dir))) {
|
||||
size_t ent_name_len;
|
||||
uid_t tmpuid = (uid_t) -1;
|
||||
gid_t tmpgid = (gid_t) -1;
|
||||
|
||||
/*
|
||||
* Skip the "." and ".." entries
|
||||
*/
|
||||
|
||||
if ( (strcmp (ent->d_name, ".") == 0)
|
||||
|| (strcmp (ent->d_name, "..") == 0)) {
|
||||
if (strcmp (ent->d_name, ".") == 0 ||
|
||||
strcmp (ent->d_name, "..") == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the filename for both the source and the
|
||||
* destination files.
|
||||
*/
|
||||
|
||||
ent_name_len = strlen (root) + strlen (ent->d_name) + 2;
|
||||
if (ent_name_len > new_name_len) {
|
||||
/*@only@*/char *tmp = realloc (new_name, ent_name_len);
|
||||
if (NULL == tmp) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
new_name = tmp;
|
||||
new_name_len = ent_name_len;
|
||||
}
|
||||
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name)
|
||||
break;
|
||||
|
||||
(void) snprintf (new_name, new_name_len, "%s/%s", root, ent->d_name);
|
||||
snprintf (new_name, sizeof new_name, "%s/%s", root,
|
||||
ent->d_name);
|
||||
|
||||
/* Don't follow symbolic links! */
|
||||
if (LSTAT (new_name, &sb) == -1) {
|
||||
if (LSTAT (new_name, &sb) == -1)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR (sb.st_mode) && !S_ISLNK (sb.st_mode)) {
|
||||
|
||||
@@ -146,56 +112,25 @@ int chown_tree (const char *root,
|
||||
}
|
||||
#ifndef HAVE_LCHOWN
|
||||
/* don't use chown (follows symbolic links!) */
|
||||
if (S_ISLNK (sb.st_mode)) {
|
||||
if (S_ISLNK (sb.st_mode))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* By default, the IDs are not changed (-1).
|
||||
*
|
||||
* If the file is not owned by the user, the owner is not
|
||||
* changed.
|
||||
*
|
||||
* If the file is not group-owned by the group, the
|
||||
* group-owner is not changed.
|
||||
*/
|
||||
if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
|
||||
tmpuid = new_uid;
|
||||
}
|
||||
if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
|
||||
tmpgid = new_gid;
|
||||
}
|
||||
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
|
||||
rc = LCHOWN (new_name, tmpuid, tmpgid);
|
||||
if (0 != rc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sb.st_uid == old_uid)
|
||||
LCHOWN (new_name, new_uid,
|
||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
||||
}
|
||||
|
||||
free (new_name);
|
||||
(void) closedir (dir);
|
||||
|
||||
/*
|
||||
* Now do the root of the tree
|
||||
*/
|
||||
|
||||
if ((0 == rc) && (stat (root, &sb) == 0)) {
|
||||
uid_t tmpuid = (uid_t) -1;
|
||||
gid_t tmpgid = (gid_t) -1;
|
||||
if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
|
||||
tmpuid = new_uid;
|
||||
if (stat (root, &sb) == 0) {
|
||||
if (sb.st_uid == old_uid) {
|
||||
LCHOWN (root, new_uid,
|
||||
sb.st_gid == old_gid ? new_gid : sb.st_gid);
|
||||
}
|
||||
if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
|
||||
tmpgid = new_gid;
|
||||
}
|
||||
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
|
||||
rc = LCHOWN (root, tmpuid, tmpgid);
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ void chown_tty (const struct passwd *info)
|
||||
*/
|
||||
|
||||
if ( (fchown (STDIN_FILENO, info->pw_uid, gid) != 0)
|
||||
|| (fchmod (STDIN_FILENO, (mode_t)getdef_num ("TTYPERM", 0600)) != 0)) {
|
||||
|| (fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600)) != 0)) {
|
||||
int err = errno;
|
||||
|
||||
fprintf (stderr,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008 - 2011, Nicolas François
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -38,12 +38,8 @@
|
||||
* The cleanup_functions stack.
|
||||
*/
|
||||
#define CLEANUP_FUNCTIONS 10
|
||||
|
||||
typedef /*@null@*/void * parg_t;
|
||||
|
||||
static cleanup_function cleanup_functions[CLEANUP_FUNCTIONS];
|
||||
static parg_t cleanup_function_args[CLEANUP_FUNCTIONS];
|
||||
static pid_t cleanup_pid = 0;
|
||||
static void * cleanup_function_args[CLEANUP_FUNCTIONS];
|
||||
|
||||
/*
|
||||
* - Cleanup functions shall not fail.
|
||||
@@ -57,9 +53,6 @@ static pid_t cleanup_pid = 0;
|
||||
/*
|
||||
* do_cleanups - perform the actions stored in the cleanup_functions stack.
|
||||
*
|
||||
* Cleanup action are not executed on exit of the processes started by the
|
||||
* parent (first caller of add_cleanup).
|
||||
*
|
||||
* It is intended to be used as:
|
||||
* atexit (do_cleanups);
|
||||
*/
|
||||
@@ -70,10 +63,6 @@ void do_cleanups (void)
|
||||
/* Make sure there were no overflow */
|
||||
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-1]);
|
||||
|
||||
if (getpid () != cleanup_pid) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = CLEANUP_FUNCTIONS;
|
||||
do {
|
||||
i--;
|
||||
@@ -86,17 +75,13 @@ void do_cleanups (void)
|
||||
/*
|
||||
* add_cleanup - Add a cleanup_function to the cleanup_functions stack.
|
||||
*/
|
||||
void add_cleanup (/*@notnull@*/cleanup_function pcf, /*@null@*/void *arg)
|
||||
void add_cleanup (cleanup_function pcf, /*@null@*/void *arg)
|
||||
{
|
||||
unsigned int i;
|
||||
assert (NULL != pcf);
|
||||
|
||||
assert (NULL == cleanup_functions[CLEANUP_FUNCTIONS-2]);
|
||||
|
||||
if (0 == cleanup_pid) {
|
||||
cleanup_pid = getpid ();
|
||||
}
|
||||
|
||||
/* Add the cleanup_function at the end of the stack */
|
||||
for (i=0; NULL != cleanup_functions[i]; i++);
|
||||
cleanup_functions[i] = pcf;
|
||||
@@ -106,7 +91,7 @@ void add_cleanup (/*@notnull@*/cleanup_function pcf, /*@null@*/void *arg)
|
||||
/*
|
||||
* del_cleanup - Remove a cleanup_function from the cleanup_functions stack.
|
||||
*/
|
||||
void del_cleanup (/*@notnull@*/cleanup_function pcf)
|
||||
void del_cleanup (cleanup_function pcf)
|
||||
{
|
||||
unsigned int i;
|
||||
assert (NULL != pcf);
|
||||
@@ -124,8 +109,7 @@ void del_cleanup (/*@notnull@*/cleanup_function pcf)
|
||||
/* Move the rest of the cleanup functions */
|
||||
for (; i<CLEANUP_FUNCTIONS; i++) {
|
||||
/* Make sure the cleanup function was specified only once */
|
||||
assert ( (i == (CLEANUP_FUNCTIONS -1))
|
||||
|| (cleanup_functions[i+1] != pcf));
|
||||
assert (cleanup_functions[i+1] != pcf);
|
||||
|
||||
if (i == (CLEANUP_FUNCTIONS -1)) {
|
||||
cleanup_functions[i] = NULL;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1991 , Chip Rosenthal
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -50,8 +50,7 @@ static bool is_listed (const char *cfgin, const char *tty, bool def);
|
||||
static bool is_listed (const char *cfgin, const char *tty, bool def)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[200], *s;
|
||||
const char *cons;
|
||||
char buf[200], *cons, *s;
|
||||
|
||||
/*
|
||||
* If the CONSOLE configuration definition isn't given,
|
||||
@@ -69,15 +68,13 @@ static bool is_listed (const char *cfgin, const char *tty, bool def)
|
||||
*/
|
||||
|
||||
if (*cons != '/') {
|
||||
char *pbuf;
|
||||
strcpy (buf, cons);
|
||||
pbuf = &buf[0];
|
||||
while ((s = strtok (pbuf, ":")) != NULL) {
|
||||
while ((s = strtok (buf, ":")) != NULL) {
|
||||
if (strcmp (s, tty) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
pbuf = NULL;
|
||||
cons = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -44,19 +44,7 @@
|
||||
#include "defines.h"
|
||||
#ifdef WITH_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif /* WITH_SELINUX */
|
||||
#if defined(WITH_ACL) || defined(WITH_ATTR)
|
||||
#include <stdarg.h>
|
||||
#include <attr/error_context.h>
|
||||
#endif /* WITH_ACL || WITH_ATTR */
|
||||
#ifdef WITH_ACL
|
||||
#include <acl/libacl.h>
|
||||
#endif /* WITH_ACL */
|
||||
#ifdef WITH_ATTR
|
||||
#include <attr/libattr.h>
|
||||
#endif /* WITH_ATTR */
|
||||
|
||||
|
||||
#endif
|
||||
static /*@null@*/const char *src_orig;
|
||||
static /*@null@*/const char *dst_orig;
|
||||
|
||||
@@ -70,73 +58,66 @@ struct link_name {
|
||||
static /*@exposed@*/struct link_name *links;
|
||||
|
||||
static int copy_entry (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
long int uid, long int gid);
|
||||
static int copy_dir (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
long int uid, long int gid);
|
||||
#ifdef S_IFLNK
|
||||
static /*@null@*/char *readlink_malloc (const char *filename);
|
||||
static char *readlink_malloc (const char *filename);
|
||||
static int copy_symlink (const char *src, const char *dst,
|
||||
unused bool reset_selinux,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
#endif /* S_IFLNK */
|
||||
static int copy_hardlink (const char *dst,
|
||||
unused bool reset_selinux,
|
||||
long int uid, long int gid);
|
||||
#endif
|
||||
static int copy_hardlink (const char *src, const char *dst,
|
||||
struct link_name *lp);
|
||||
static int copy_special (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
static int copy_special (const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
long int uid, long int gid);
|
||||
static int copy_file (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
static int chown_if_needed (const char *dst, const struct stat *statp,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
static int lchown_if_needed (const char *dst, const struct stat *statp,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
static int fchown_if_needed (int fdst, const struct stat *statp,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid);
|
||||
long int uid, long int gid);
|
||||
|
||||
#if defined(WITH_ACL) || defined(WITH_ATTR)
|
||||
#ifdef WITH_SELINUX
|
||||
/*
|
||||
* error_acl - format the error messages for the ACL and EQ libraries.
|
||||
* selinux_file_context - Set the security context before any file or
|
||||
* directory creation.
|
||||
*
|
||||
* selinux_file_context () should be called before any creation of file,
|
||||
* symlink, directory, ...
|
||||
*
|
||||
* Callers may have to Reset SELinux to create files with default
|
||||
* contexts:
|
||||
* setfscreatecon (NULL);
|
||||
*/
|
||||
static void error_acl (struct error_context *ctx, const char *fmt, ...)
|
||||
int selinux_file_context (const char *dst_name)
|
||||
{
|
||||
va_list ap;
|
||||
static bool selinux_checked = false;
|
||||
static bool selinux_enabled;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
/* ignore the case when destination does not support ACLs
|
||||
* or extended attributes */
|
||||
if (ENOTSUP == errno) {
|
||||
errno = 0;
|
||||
return;
|
||||
if (!selinux_checked) {
|
||||
selinux_enabled = is_selinux_enabled () > 0;
|
||||
selinux_checked = true;
|
||||
}
|
||||
|
||||
va_start (ap, fmt);
|
||||
(void) fprintf (stderr, _("%s: "), Prog);
|
||||
if (vfprintf (stderr, fmt, ap) != 0) {
|
||||
(void) fputs (_(": "), stderr);
|
||||
if (selinux_enabled) {
|
||||
/* Get the default security context for this file */
|
||||
if (matchpathcon (dst_name, 0, &scontext) < 0) {
|
||||
if (security_getenforce () != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Set the security context for the next created file */
|
||||
if (setfscreatecon (scontext) < 0) {
|
||||
if (security_getenforce () != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
freecon (scontext);
|
||||
}
|
||||
(void) fprintf (stderr, "%s\n", strerror (errno));
|
||||
va_end (ap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct error_context ctx = {
|
||||
error_acl
|
||||
};
|
||||
#endif /* WITH_ACL || WITH_ATTR */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* remove_link - delete a link from the linked list
|
||||
@@ -203,7 +184,7 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
|
||||
lp->ln_count = sb->st_nlink;
|
||||
len = name_len - src_len + dst_len + 1;
|
||||
lp->ln_name = (char *) xmalloc (len);
|
||||
(void) snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
|
||||
snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
|
||||
lp->ln_next = links;
|
||||
links = lp;
|
||||
|
||||
@@ -215,49 +196,15 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
|
||||
*
|
||||
* copy_tree() walks a directory tree and copies ordinary files
|
||||
* as it goes.
|
||||
*
|
||||
* When reset_selinux is enabled, extended attributes (and thus
|
||||
* SELinux attributes) are not copied.
|
||||
*
|
||||
* old_uid and new_uid are used to set the ownership of the copied
|
||||
* files. Unless old_uid is set to -1, only the files owned by
|
||||
* old_uid have their ownership changed to new_uid. In addition, if
|
||||
* new_uid is set to -1, no ownership will be changed.
|
||||
*
|
||||
* The same logic applies for the group-ownership and
|
||||
* old_gid/new_gid.
|
||||
*/
|
||||
int copy_tree (const char *src_root, const char *dst_root,
|
||||
bool copy_root, bool reset_selinux,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid)
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
bool set_orig = false;
|
||||
struct DIRECT *ent;
|
||||
DIR *dir;
|
||||
|
||||
if (copy_root) {
|
||||
struct stat sb;
|
||||
if (access (dst_root, F_OK) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (LSTAT (src_root, &sb) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISDIR (sb.st_mode)) {
|
||||
fprintf (stderr,
|
||||
"%s: %s is not a directory",
|
||||
Prog, src_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return copy_entry (src_root, dst_root, reset_selinux,
|
||||
old_uid, new_uid, old_gid, new_gid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make certain both directories exist. This routine is called
|
||||
* after the home directory is created, or recursively after the
|
||||
@@ -309,15 +256,12 @@ int copy_tree (const char *src_root, const char *dst_root,
|
||||
* Build the filename for both the source and
|
||||
* the destination files.
|
||||
*/
|
||||
(void) snprintf (src_name, src_len, "%s/%s",
|
||||
src_root, ent->d_name);
|
||||
(void) snprintf (dst_name, dst_len, "%s/%s",
|
||||
dst_root, ent->d_name);
|
||||
snprintf (src_name, src_len, "%s/%s",
|
||||
src_root, ent->d_name);
|
||||
snprintf (dst_name, dst_len, "%s/%s",
|
||||
dst_root, ent->d_name);
|
||||
|
||||
err = copy_entry (src_name, dst_name,
|
||||
reset_selinux,
|
||||
old_uid, new_uid,
|
||||
old_gid, new_gid);
|
||||
err = copy_entry (src_name, dst_name, uid, gid);
|
||||
}
|
||||
if (NULL != src_name) {
|
||||
free (src_name);
|
||||
@@ -332,25 +276,16 @@ int copy_tree (const char *src_root, const char *dst_root,
|
||||
if (set_orig) {
|
||||
src_orig = NULL;
|
||||
dst_orig = NULL;
|
||||
/* FIXME: clean links
|
||||
* Since there can be hardlinks elsewhere on the device,
|
||||
* we cannot check that all the hardlinks were found:
|
||||
assert (NULL == links);
|
||||
*/
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
/* Reset SELinux to create files with default contexts.
|
||||
* Note that the context is only reset on exit of copy_tree (it is
|
||||
* assumed that the program would quit without needing a restored
|
||||
* context if copy_tree failed previously), and that copy_tree can
|
||||
* be called recursively (hence the context is set on the
|
||||
* sub-functions of copy_entry).
|
||||
*/
|
||||
if (reset_selinux_file_context () != 0) {
|
||||
err = -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
/* Reset SELinux to create files with default contexts */
|
||||
setfscreatecon (NULL);
|
||||
#endif
|
||||
|
||||
/* FIXME: with the call to remove_link, we could also check that
|
||||
* no links remain in links.
|
||||
* assert (NULL == links); */
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -365,19 +300,13 @@ int copy_tree (const char *src_root, const char *dst_root,
|
||||
*
|
||||
* The access and modification time will not be modified.
|
||||
*
|
||||
* The permissions will be set to new_uid/new_gid.
|
||||
* The permissions will be set to uid/gid.
|
||||
*
|
||||
* If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will
|
||||
* If uid (resp. gid) is equal to -1, the user (resp. group) will
|
||||
* not be modified.
|
||||
*
|
||||
* Only the files owned (resp. group-owned) by old_uid (resp.
|
||||
* old_gid) will be modified, unless old_uid (resp. old_gid) is set
|
||||
* to -1.
|
||||
*/
|
||||
static int copy_entry (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid)
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
struct stat sb;
|
||||
@@ -390,30 +319,29 @@ static int copy_entry (const char *src, const char *dst,
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
||||
mt[0].tv_sec = sb.st_atim.tv_sec;
|
||||
mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||
#else /* !HAVE_STRUCT_STAT_ST_ATIM */
|
||||
#else
|
||||
mt[0].tv_sec = sb.st_atime;
|
||||
# ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
|
||||
mt[0].tv_usec = sb.st_atimensec / 1000;
|
||||
# else /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
|
||||
#else
|
||||
mt[0].tv_usec = 0;
|
||||
# endif /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
|
||||
#endif /* !HAVE_STRUCT_STAT_ST_ATIM */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
||||
mt[1].tv_sec = sb.st_mtim.tv_sec;
|
||||
mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
|
||||
#else /* !HAVE_STRUCT_STAT_ST_MTIM */
|
||||
#else
|
||||
mt[1].tv_sec = sb.st_mtime;
|
||||
# ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
mt[1].tv_usec = sb.st_mtimensec / 1000;
|
||||
# else /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
|
||||
#else
|
||||
mt[1].tv_usec = 0;
|
||||
# endif /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
|
||||
#endif /* !HAVE_STRUCT_STAT_ST_MTIM */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
err = copy_dir (src, dst, reset_selinux, &sb, mt,
|
||||
old_uid, new_uid, old_gid, new_gid);
|
||||
err = copy_dir (src, dst, &sb, mt, uid, gid);
|
||||
}
|
||||
|
||||
#ifdef S_IFLNK
|
||||
@@ -422,17 +350,16 @@ static int copy_entry (const char *src, const char *dst,
|
||||
*/
|
||||
|
||||
else if (S_ISLNK (sb.st_mode)) {
|
||||
err = copy_symlink (src, dst, reset_selinux, &sb, mt,
|
||||
old_uid, new_uid, old_gid, new_gid);
|
||||
err = copy_symlink (src, dst, &sb, mt, uid, gid);
|
||||
}
|
||||
#endif /* S_IFLNK */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* See if this is a previously copied link
|
||||
*/
|
||||
|
||||
else if ((lp = check_link (src, &sb)) != NULL) {
|
||||
err = copy_hardlink (dst, reset_selinux, lp);
|
||||
err = copy_hardlink (src, dst, lp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -442,8 +369,7 @@ static int copy_entry (const char *src, const char *dst,
|
||||
*/
|
||||
|
||||
else if (!S_ISREG (sb.st_mode)) {
|
||||
err = copy_special (src, dst, reset_selinux, &sb, mt,
|
||||
old_uid, new_uid, old_gid, new_gid);
|
||||
err = copy_special (dst, &sb, mt, uid, gid);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -452,8 +378,7 @@ static int copy_entry (const char *src, const char *dst,
|
||||
*/
|
||||
|
||||
else {
|
||||
err = copy_file (src, dst, reset_selinux, &sb, mt,
|
||||
old_uid, new_uid, old_gid, new_gid);
|
||||
err = copy_file (src, dst, &sb, mt, uid, gid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,16 +390,14 @@ static int copy_entry (const char *src, const char *dst,
|
||||
*
|
||||
* Copy a directory (recursively) from src to dst.
|
||||
*
|
||||
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||
* the access and modification and the access rights.
|
||||
* statp, mt, uid, gid are used to set the access and modification and the
|
||||
* access rights.
|
||||
*
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_dir (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid)
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
@@ -484,33 +407,14 @@ static int copy_dir (const char *src, const char *dst,
|
||||
*/
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
selinux_file_context (dst);
|
||||
#endif
|
||||
if ( (mkdir (dst, statp->st_mode) != 0)
|
||||
|| (chown_if_needed (dst, statp,
|
||||
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||
#ifdef WITH_ACL
|
||||
|| ( (perm_copy_file (src, dst, &ctx) != 0)
|
||||
&& (errno != 0))
|
||||
#else /* !WITH_ACL */
|
||||
|| (chown (dst,
|
||||
(uid == - 1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == - 1) ? statp->st_gid : (gid_t) gid) != 0)
|
||||
|| (chmod (dst, statp->st_mode) != 0)
|
||||
#endif /* !WITH_ACL */
|
||||
#ifdef WITH_ATTR
|
||||
/*
|
||||
* If the third parameter is NULL, all extended attributes
|
||||
* except those that define Access Control Lists are copied.
|
||||
* ACLs are excluded by default because copying them between
|
||||
* file systems with and without ACL support needs some
|
||||
* additional logic so that no unexpected permissions result.
|
||||
*/
|
||||
|| ( !reset_selinux
|
||||
&& (attr_copy_file (src, dst, NULL, &ctx) != 0)
|
||||
&& (errno != 0))
|
||||
#endif /* WITH_ATTR */
|
||||
|| (copy_tree (src, dst, false, reset_selinux,
|
||||
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||
|| (copy_tree (src, dst, uid, gid) != 0)
|
||||
|| (utimes (dst, mt) != 0)) {
|
||||
err = -1;
|
||||
}
|
||||
@@ -525,11 +429,11 @@ static int copy_dir (const char *src, const char *dst,
|
||||
* return NULL on error.
|
||||
* The return string shall be freed by the caller.
|
||||
*/
|
||||
static /*@null@*/char *readlink_malloc (const char *filename)
|
||||
static char *readlink_malloc (const char *filename)
|
||||
{
|
||||
size_t size = 1024;
|
||||
|
||||
while (true) {
|
||||
while (1) {
|
||||
ssize_t nchars;
|
||||
char *buffer = (char *) malloc (size);
|
||||
if (NULL == buffer) {
|
||||
@@ -539,11 +443,10 @@ static /*@null@*/char *readlink_malloc (const char *filename)
|
||||
nchars = readlink (filename, buffer, size);
|
||||
|
||||
if (nchars < 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size_t) nchars < size) { /* The buffer was large enough */
|
||||
if ( (size_t) nchars < size) { /* The buffer was large enough */
|
||||
/* readlink does not nul-terminate */
|
||||
buffer[nchars] = '\0';
|
||||
return buffer;
|
||||
@@ -560,16 +463,14 @@ static /*@null@*/char *readlink_malloc (const char *filename)
|
||||
*
|
||||
* Copy a symlink from src to dst.
|
||||
*
|
||||
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||
* the access and modification and the access rights.
|
||||
* statp, mt, uid, gid are used to set the access and modification and the
|
||||
* access rights.
|
||||
*
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_symlink (const char *src, const char *dst,
|
||||
unused bool reset_selinux,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid)
|
||||
long int uid, long int gid)
|
||||
{
|
||||
char *oldlink;
|
||||
|
||||
@@ -593,33 +494,25 @@ static int copy_symlink (const char *src, const char *dst,
|
||||
/* If src was a link to an entry of the src_orig directory itself,
|
||||
* create a link to the corresponding entry in the dst_orig
|
||||
* directory.
|
||||
* FIXME: This may change a relative link to an absolute link
|
||||
*/
|
||||
if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
|
||||
size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
|
||||
char *dummy = (char *) xmalloc (len);
|
||||
(void) snprintf (dummy, len, "%s%s",
|
||||
dst_orig,
|
||||
oldlink + strlen (src_orig));
|
||||
char *dummy = (char *) malloc (len);
|
||||
snprintf (dummy, len, "%s%s",
|
||||
dst_orig,
|
||||
oldlink + strlen (src_orig));
|
||||
free (oldlink);
|
||||
oldlink = dummy;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
free (oldlink);
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
selinux_file_context (dst);
|
||||
#endif
|
||||
if ( (symlink (oldlink, dst) != 0)
|
||||
|| (lchown_if_needed (dst, statp,
|
||||
old_uid, new_uid, old_gid, new_gid) != 0)) {
|
||||
/* FIXME: there are no modes on symlinks, right?
|
||||
* ACL could be copied, but this would be much more
|
||||
* complex than calling perm_copy_file.
|
||||
* Ditto for Extended Attributes.
|
||||
* We currently only document that ACL and Extended
|
||||
* Attributes are not copied.
|
||||
*/
|
||||
|| (lchown (dst,
|
||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
|
||||
free (oldlink);
|
||||
return -1;
|
||||
}
|
||||
@@ -631,12 +524,12 @@ static int copy_symlink (const char *src, const char *dst,
|
||||
* it returns ENOSYS on many system
|
||||
* - not implemented
|
||||
*/
|
||||
(void) lutimes (dst, mt);
|
||||
#endif /* HAVE_LUTIMES */
|
||||
lutimes (dst, mt);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* S_IFLNK */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* copy_hardlink - copy a hardlink
|
||||
@@ -645,18 +538,23 @@ static int copy_symlink (const char *src, const char *dst,
|
||||
*
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_hardlink (const char *dst,
|
||||
unused bool reset_selinux,
|
||||
static int copy_hardlink (const char *src, const char *dst,
|
||||
struct link_name *lp)
|
||||
{
|
||||
/* FIXME: selinux, ACL, Extended Attributes needed? */
|
||||
/* TODO: selinux needed? */
|
||||
|
||||
if (link (lp->ln_name, dst) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: why is it unlinked? This is a copy, not a move */
|
||||
if (unlink (src) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: idem, although it may never be used again */
|
||||
/* If the file could be unlinked, decrement the links counter,
|
||||
* and forget about this link if it was the last reference */
|
||||
* and delete the file if it was the last reference */
|
||||
lp->ln_count--;
|
||||
if (lp->ln_count <= 0) {
|
||||
remove_link (lp);
|
||||
@@ -670,46 +568,26 @@ static int copy_hardlink (const char *dst,
|
||||
*
|
||||
* Copy a special file from src to dst.
|
||||
*
|
||||
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||
* the access and modification and the access rights.
|
||||
* statp, mt, uid, gid are used to set the access and modification and the
|
||||
* access rights.
|
||||
*
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_special (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
static int copy_special (const char *dst,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid)
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
selinux_file_context (dst);
|
||||
#endif
|
||||
|
||||
if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
|
||||
|| (chown_if_needed (dst, statp,
|
||||
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||
#ifdef WITH_ACL
|
||||
|| ( (perm_copy_file (src, dst, &ctx) != 0)
|
||||
&& (errno != 0))
|
||||
#else /* !WITH_ACL */
|
||||
|| (chown (dst,
|
||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
||||
|| (chmod (dst, statp->st_mode & 07777) != 0)
|
||||
#endif /* !WITH_ACL */
|
||||
#ifdef WITH_ATTR
|
||||
/*
|
||||
* If the third parameter is NULL, all extended attributes
|
||||
* except those that define Access Control Lists are copied.
|
||||
* ACLs are excluded by default because copying them between
|
||||
* file systems with and without ACL support needs some
|
||||
* additional logic so that no unexpected permissions result.
|
||||
*/
|
||||
|| ( !reset_selinux
|
||||
&& (attr_copy_file (src, dst, NULL, &ctx) != 0)
|
||||
&& (errno != 0))
|
||||
#endif /* WITH_ATTR */
|
||||
|| (utimes (dst, mt) != 0)) {
|
||||
err = -1;
|
||||
}
|
||||
@@ -722,16 +600,14 @@ static int copy_special (const char *src, const char *dst,
|
||||
*
|
||||
* Copy a file from src to dst.
|
||||
*
|
||||
* statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
|
||||
* the access and modification and the access rights.
|
||||
* statp, mt, uid, gid are used to set the access and modification and the
|
||||
* access rights.
|
||||
*
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int copy_file (const char *src, const char *dst,
|
||||
bool reset_selinux,
|
||||
const struct stat *statp, const struct timeval mt[],
|
||||
uid_t old_uid, uid_t new_uid,
|
||||
gid_t old_gid, gid_t new_gid)
|
||||
long int uid, long int gid)
|
||||
{
|
||||
int err = 0;
|
||||
int ifd;
|
||||
@@ -744,40 +620,20 @@ static int copy_file (const char *src, const char *dst,
|
||||
return -1;
|
||||
}
|
||||
#ifdef WITH_SELINUX
|
||||
if (set_selinux_file_context (dst) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* WITH_SELINUX */
|
||||
selinux_file_context (dst);
|
||||
#endif
|
||||
ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
|
||||
if ( (ofd < 0)
|
||||
|| (fchown_if_needed (ofd, statp,
|
||||
old_uid, new_uid, old_gid, new_gid) != 0)
|
||||
#ifdef WITH_ACL
|
||||
|| ( (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
|
||||
&& (errno != 0))
|
||||
#else /* !WITH_ACL */
|
||||
|| (fchmod (ofd, statp->st_mode & 07777) != 0)
|
||||
#endif /* !WITH_ACL */
|
||||
#ifdef WITH_ATTR
|
||||
/*
|
||||
* If the third parameter is NULL, all extended attributes
|
||||
* except those that define Access Control Lists are copied.
|
||||
* ACLs are excluded by default because copying them between
|
||||
* file systems with and without ACL support needs some
|
||||
* additional logic so that no unexpected permissions result.
|
||||
*/
|
||||
|| ( !reset_selinux
|
||||
&& (attr_copy_fd (src, ifd, dst, ofd, NULL, &ctx) != 0)
|
||||
&& (errno != 0))
|
||||
#endif /* WITH_ATTR */
|
||||
) {
|
||||
|| (fchown (ofd,
|
||||
(uid == -1) ? statp->st_uid : (uid_t) uid,
|
||||
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
|
||||
|| (fchmod (ofd, statp->st_mode & 07777) != 0)) {
|
||||
(void) close (ifd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
||||
if (write (ofd, buf, (size_t)cnt) != cnt) {
|
||||
(void) close (ifd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -788,7 +644,7 @@ static int copy_file (const char *src, const char *dst,
|
||||
if (futimes (ofd, mt) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* HAVE_FUTIMES */
|
||||
#endif
|
||||
|
||||
if (close (ofd) != 0) {
|
||||
return -1;
|
||||
@@ -798,42 +654,97 @@ static int copy_file (const char *src, const char *dst,
|
||||
if (utimes(dst, mt) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* !HAVE_FUTIMES */
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define def_chown_if_needed(chown_function, type_dst) \
|
||||
static int chown_function ## _if_needed (type_dst dst, \
|
||||
const struct stat *statp, \
|
||||
uid_t old_uid, uid_t new_uid, \
|
||||
gid_t old_gid, gid_t new_gid) \
|
||||
{ \
|
||||
uid_t tmpuid = (uid_t) -1; \
|
||||
gid_t tmpgid = (gid_t) -1; \
|
||||
\
|
||||
/* Use new_uid if old_uid is set to -1 or if the file was \
|
||||
* owned by the user. */ \
|
||||
if (((uid_t) -1 == old_uid) || (statp->st_uid == old_uid)) { \
|
||||
tmpuid = new_uid; \
|
||||
} \
|
||||
/* Otherwise, or if new_uid was set to -1, we keep the same \
|
||||
* owner. */ \
|
||||
if ((uid_t) -1 == tmpuid) { \
|
||||
tmpuid = statp->st_uid; \
|
||||
} \
|
||||
\
|
||||
if (((gid_t) -1 == old_gid) || (statp->st_gid == old_gid)) { \
|
||||
tmpgid = new_gid; \
|
||||
} \
|
||||
if ((gid_t) -1 == tmpgid) { \
|
||||
tmpgid = statp->st_gid; \
|
||||
} \
|
||||
\
|
||||
return chown_function (dst, tmpuid, tmpgid); \
|
||||
/*
|
||||
* remove_tree - delete a directory tree
|
||||
*
|
||||
* remove_tree() walks a directory tree and deletes all the files
|
||||
* and directories.
|
||||
* At the end, it deletes the root directory itself.
|
||||
*/
|
||||
|
||||
int remove_tree (const char *root)
|
||||
{
|
||||
char *new_name = NULL;
|
||||
int err = 0;
|
||||
struct DIRECT *ent;
|
||||
struct stat sb;
|
||||
DIR *dir;
|
||||
|
||||
/*
|
||||
* Open the source directory and read each entry. Every file
|
||||
* entry in the directory is copied with the UID and GID set
|
||||
* to the provided values. As an added security feature only
|
||||
* regular files (and directories ...) are copied, and no file
|
||||
* is made set-ID.
|
||||
*/
|
||||
dir = opendir (root);
|
||||
if (NULL == dir) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((ent = readdir (dir))) {
|
||||
size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
|
||||
|
||||
/*
|
||||
* Skip the "." and ".." entries
|
||||
*/
|
||||
|
||||
if (strcmp (ent->d_name, ".") == 0 ||
|
||||
strcmp (ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the filename for the current entry.
|
||||
*/
|
||||
|
||||
if (NULL != new_name) {
|
||||
free (new_name);
|
||||
}
|
||||
new_name = (char *) malloc (new_len);
|
||||
if (NULL == new_name) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
|
||||
if (LSTAT (new_name, &sb) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
/*
|
||||
* Recursively delete this directory.
|
||||
*/
|
||||
if (remove_tree (new_name) != 0) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Delete the file.
|
||||
*/
|
||||
if (unlink (new_name) != 0) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL != new_name) {
|
||||
free (new_name);
|
||||
}
|
||||
(void) closedir (dir);
|
||||
|
||||
if (0 == err) {
|
||||
if (rmdir (root) != 0) {
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
def_chown_if_needed (chown, const char *)
|
||||
def_chown_if_needed (lchown, const char *)
|
||||
def_chown_if_needed (fchown, int)
|
||||
|
||||
|
||||
@@ -115,9 +115,6 @@ void addenv (const char *string, /*@null@*/const char *value)
|
||||
|
||||
n = (size_t) (cp - newstring);
|
||||
|
||||
/*
|
||||
* If this environment variable is already set, change its value.
|
||||
*/
|
||||
for (i = 0; i < newenvc; i++) {
|
||||
if ( (strncmp (newstring, newenvp[i], n) == 0)
|
||||
&& (('=' == newenvp[i][n]) || ('\0' == newenvp[i][n]))) {
|
||||
@@ -131,15 +128,8 @@ void addenv (const char *string, /*@null@*/const char *value)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, save the new environment variable
|
||||
*/
|
||||
newenvp[newenvc++] = newstring;
|
||||
|
||||
/*
|
||||
* And extend the environment if needed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check whether newenvc is a multiple of NEWENVP_STEP.
|
||||
* If so we have to resize the vector.
|
||||
@@ -153,14 +143,14 @@ void addenv (const char *string, /*@null@*/const char *value)
|
||||
size_t newsize;
|
||||
|
||||
/*
|
||||
* If the resize operation succeeds we can
|
||||
* If the resize operation succeds we can
|
||||
* happily go on, else print a message.
|
||||
*/
|
||||
|
||||
newsize = (newenvc + NEWENVP_STEP) * sizeof (char *);
|
||||
__newenvp = (char **) realloc (newenvp, newsize);
|
||||
|
||||
if (NULL != __newenvp) {
|
||||
if (__newenvp) {
|
||||
/*
|
||||
* If this is our current environment, update
|
||||
* environ so that it doesn't point to some
|
||||
@@ -261,7 +251,7 @@ void sanitize_env (void)
|
||||
if (strncmp (*cur, *bad, strlen (*bad)) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (strchr (*cur, '/') == NULL) {
|
||||
if (strchr (*cur, '/') != NULL) {
|
||||
continue; /* OK */
|
||||
}
|
||||
for (move = cur; NULL != *move; move++) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2002 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2010, Nicolas François
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -273,14 +273,12 @@ void failprint (const struct faillog *fail)
|
||||
lasttime++;
|
||||
}
|
||||
#endif
|
||||
/*@-formatconst@*/
|
||||
(void) printf (ngettext ("%d failure since last login.\n"
|
||||
"Last was %s on %s.\n",
|
||||
"%d failures since last login.\n"
|
||||
"Last was %s on %s.\n",
|
||||
(unsigned long) fail->fail_cnt),
|
||||
fail->fail_cnt, lasttime, fail->fail_line);
|
||||
/*@=formatconst@*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -298,7 +296,7 @@ void failtmp (const char *username,
|
||||
#endif /* !USE_UTMPX */
|
||||
)
|
||||
{
|
||||
const char *ftmp;
|
||||
char *ftmp;
|
||||
int fd;
|
||||
|
||||
/*
|
||||
|
||||
@@ -54,10 +54,6 @@ int valid_field (const char *field, const char *illegal)
|
||||
const char *cp;
|
||||
int err = 0;
|
||||
|
||||
if (NULL == field) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* For each character of field, search if it appears in the list
|
||||
* of illegal characters. */
|
||||
for (cp = field; '\0' != *cp; cp++) {
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 2008 - 2011, Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "groupio.h"
|
||||
@@ -53,7 +52,7 @@ int find_new_gid (bool sys_group,
|
||||
/*@null@*/gid_t const *preferred_gid)
|
||||
{
|
||||
const struct group *grp;
|
||||
gid_t gid_min, gid_max, group_id;
|
||||
gid_t gid_min, gid_max, group_id, id;
|
||||
bool *used_gids;
|
||||
|
||||
assert (gid != NULL);
|
||||
@@ -61,30 +60,12 @@ int find_new_gid (bool sys_group,
|
||||
if (!sys_group) {
|
||||
gid_min = (gid_t) getdef_ulong ("GID_MIN", 1000UL);
|
||||
gid_max = (gid_t) getdef_ulong ("GID_MAX", 60000UL);
|
||||
if (gid_max < gid_min) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: Invalid configuration: GID_MIN (%lu), GID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) gid_min, (unsigned long) gid_max);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
gid_min = (gid_t) getdef_ulong ("SYS_GID_MIN", 101UL);
|
||||
gid_max = (gid_t) getdef_ulong ("GID_MIN", 1000UL) - 1;
|
||||
gid_max = (gid_t) getdef_ulong ("SYS_GID_MAX", (unsigned long) gid_max);
|
||||
if (gid_max < gid_min) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: Invalid configuration: SYS_GID_MIN (%lu), GID_MIN (%lu), SYS_GID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) gid_min, getdef_ulong ("GID_MIN", 1000UL), (unsigned long) gid_max);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
used_gids = malloc (sizeof (bool) * (gid_max +1));
|
||||
if (NULL == used_gids) {
|
||||
fprintf (stderr,
|
||||
_("%s: failed to allocate memory: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
used_gids = alloca (sizeof (bool) * (gid_max +1));
|
||||
memset (used_gids, false, sizeof (bool) * (gid_max + 1));
|
||||
|
||||
if ( (NULL != preferred_gid)
|
||||
@@ -96,7 +77,6 @@ int find_new_gid (bool sys_group,
|
||||
* changes */
|
||||
&& (gr_locate_gid (*preferred_gid) == NULL)) {
|
||||
*gid = *preferred_gid;
|
||||
free (used_gids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -110,7 +90,6 @@ int find_new_gid (bool sys_group,
|
||||
* some groups were created but the changes were not committed yet.
|
||||
*/
|
||||
if (sys_group) {
|
||||
gid_t id;
|
||||
/* setgrent / getgrent / endgrent can be very slow with
|
||||
* LDAP configurations (and many accounts).
|
||||
* Since there is a limited amount of IDs to be tested
|
||||
@@ -125,7 +104,7 @@ int find_new_gid (bool sys_group,
|
||||
}
|
||||
}
|
||||
|
||||
(void) gr_rewind ();
|
||||
gr_rewind ();
|
||||
while ((grp = gr_next ()) != NULL) {
|
||||
if ((grp->gr_gid <= group_id) && (grp->gr_gid >= gid_min)) {
|
||||
group_id = grp->gr_gid - 1;
|
||||
@@ -149,7 +128,7 @@ int find_new_gid (bool sys_group,
|
||||
}
|
||||
endgrent ();
|
||||
|
||||
(void) gr_rewind ();
|
||||
gr_rewind ();
|
||||
while ((grp = gr_next ()) != NULL) {
|
||||
if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
|
||||
group_id = grp->gr_gid + 1;
|
||||
@@ -162,47 +141,43 @@ int find_new_gid (bool sys_group,
|
||||
}
|
||||
|
||||
/*
|
||||
* If a group (resp. system group) with GID equal to GID_MAX (resp.
|
||||
* GID_MIN) exists, the above algorithm will give us GID_MAX+1
|
||||
* (resp. GID_MIN-1) even if not unique. Search for the first free
|
||||
* GID starting with GID_MIN (resp. GID_MAX).
|
||||
* If a group with GID equal to GID_MAX exists, the above algorithm
|
||||
* will give us GID_MAX+1 even if not unique. Search for the first
|
||||
* free GID starting with GID_MIN.
|
||||
*/
|
||||
if (sys_group) {
|
||||
if (group_id < gid_min) {
|
||||
if (group_id == gid_min - 1) {
|
||||
for (group_id = gid_max; group_id >= gid_min; group_id--) {
|
||||
if (false == used_gids[group_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group_id < gid_min) {
|
||||
if ( group_id < gid_min ) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique system GID (no more available GIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN,
|
||||
"no more available GID on the system"));
|
||||
free (used_gids);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (group_id > gid_max) {
|
||||
for (group_id = gid_min; group_id <= gid_max; group_id++) {
|
||||
if (group_id == gid_max + 1) {
|
||||
for (group_id = gid_min; group_id < gid_max; group_id++) {
|
||||
if (false == used_gids[group_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group_id > gid_max) {
|
||||
if (group_id == gid_max) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique GID (no more available GIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available GID on the system"));
|
||||
free (used_gids);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (used_gids);
|
||||
*gid = group_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Eric Biederman
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "subordinateio.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* find_new_sub_gids - Find a new unused range of GIDs.
|
||||
*
|
||||
* If successful, find_new_sub_gids provides a range of unused
|
||||
* user IDs in the [SUB_GID_MIN:SUB_GID_MAX] range.
|
||||
*
|
||||
* Return 0 on success, -1 if no unused GIDs are available.
|
||||
*/
|
||||
int find_new_sub_gids (const char *owner,
|
||||
gid_t *range_start, unsigned long *range_count)
|
||||
{
|
||||
unsigned long min, max;
|
||||
unsigned long count;
|
||||
gid_t start;
|
||||
|
||||
assert (range_start != NULL);
|
||||
assert (range_count != NULL);
|
||||
|
||||
min = getdef_ulong ("SUB_GID_MIN", 100000UL);
|
||||
max = getdef_ulong ("SUB_GID_MAX", 600100000UL);
|
||||
count = getdef_ulong ("SUB_GID_COUNT", 65536);
|
||||
|
||||
if (min > max || count >= max || (min + count - 1) > max) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: Invalid configuration: SUB_GID_MIN (%lu),"
|
||||
" SUB_GID_MAX (%lu), SUB_GID_COUNT (%lu)\n"),
|
||||
Prog, min, max, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
start = sub_gid_find_free_range(min, max, count);
|
||||
if (start == (gid_t)-1) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique subordinate GID range\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available subordinate GIDs on the system"));
|
||||
return -1;
|
||||
}
|
||||
*range_start = start;
|
||||
*range_count = count;
|
||||
return 0;
|
||||
}
|
||||
#else /* !ENABLE_SUBIDS */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !ENABLE_SUBIDS */
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Eric Biederman
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "subordinateio.h"
|
||||
#include "getdef.h"
|
||||
|
||||
/*
|
||||
* find_new_sub_uids - Find a new unused range of UIDs.
|
||||
*
|
||||
* If successful, find_new_sub_uids provides a range of unused
|
||||
* user IDs in the [SUB_UID_MIN:SUB_UID_MAX] range.
|
||||
*
|
||||
* Return 0 on success, -1 if no unused UIDs are available.
|
||||
*/
|
||||
int find_new_sub_uids (const char *owner,
|
||||
uid_t *range_start, unsigned long *range_count)
|
||||
{
|
||||
unsigned long min, max;
|
||||
unsigned long count;
|
||||
uid_t start;
|
||||
|
||||
assert (range_start != NULL);
|
||||
assert (range_count != NULL);
|
||||
|
||||
min = getdef_ulong ("SUB_UID_MIN", 100000UL);
|
||||
max = getdef_ulong ("SUB_UID_MAX", 600100000UL);
|
||||
count = getdef_ulong ("SUB_UID_COUNT", 65536);
|
||||
|
||||
if (min > max || count >= max || (min + count - 1) > max) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: Invalid configuration: SUB_UID_MIN (%lu),"
|
||||
" SUB_UID_MAX (%lu), SUB_UID_COUNT (%lu)\n"),
|
||||
Prog, min, max, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
start = sub_uid_find_free_range(min, max, count);
|
||||
if (start == (uid_t)-1) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique subordinate UID range\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available subordinate UIDs on the system"));
|
||||
return -1;
|
||||
}
|
||||
*range_start = start;
|
||||
*range_count = count;
|
||||
return 0;
|
||||
}
|
||||
#else /* !ENABLE_SUBIDS */
|
||||
extern int errno; /* warning: ANSI C forbids an empty source file */
|
||||
#endif /* !ENABLE_SUBIDS */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 2008 - 2011, Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "prototypes.h"
|
||||
#include "pwio.h"
|
||||
@@ -53,7 +52,7 @@ int find_new_uid (bool sys_user,
|
||||
/*@null@*/uid_t const *preferred_uid)
|
||||
{
|
||||
const struct passwd *pwd;
|
||||
uid_t uid_min, uid_max, user_id;
|
||||
uid_t uid_min, uid_max, user_id, id;
|
||||
bool *used_uids;
|
||||
|
||||
assert (uid != NULL);
|
||||
@@ -61,30 +60,12 @@ int find_new_uid (bool sys_user,
|
||||
if (!sys_user) {
|
||||
uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
|
||||
uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
|
||||
if (uid_max < uid_min) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: Invalid configuration: UID_MIN (%lu), UID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) uid_min, (unsigned long) uid_max);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
uid_min = (uid_t) getdef_ulong ("SYS_UID_MIN", 101UL);
|
||||
uid_max = (uid_t) getdef_ulong ("UID_MIN", 1000UL) - 1;
|
||||
uid_max = (uid_t) getdef_ulong ("SYS_UID_MAX", (unsigned long) uid_max);
|
||||
if (uid_max < uid_min) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: Invalid configuration: SYS_UID_MIN (%lu), UID_MIN (%lu), SYS_UID_MAX (%lu)\n"),
|
||||
Prog, (unsigned long) uid_min, getdef_ulong ("UID_MIN", 1000UL), (unsigned long) uid_max);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
used_uids = malloc (sizeof (bool) * (uid_max +1));
|
||||
if (NULL == used_uids) {
|
||||
fprintf (stderr,
|
||||
_("%s: failed to allocate memory: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
used_uids = alloca (sizeof (bool) * (uid_max +1));
|
||||
memset (used_uids, false, sizeof (bool) * (uid_max + 1));
|
||||
|
||||
if ( (NULL != preferred_uid)
|
||||
@@ -96,7 +77,6 @@ int find_new_uid (bool sys_user,
|
||||
* changes */
|
||||
&& (pw_locate_uid (*preferred_uid) == NULL)) {
|
||||
*uid = *preferred_uid;
|
||||
free (used_uids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -110,7 +90,6 @@ int find_new_uid (bool sys_user,
|
||||
* some users were created but the changes were not committed yet.
|
||||
*/
|
||||
if (sys_user) {
|
||||
uid_t id;
|
||||
/* setpwent / getpwent / endpwent can be very slow with
|
||||
* LDAP configurations (and many accounts).
|
||||
* Since there is a limited amount of IDs to be tested
|
||||
@@ -125,7 +104,7 @@ int find_new_uid (bool sys_user,
|
||||
}
|
||||
}
|
||||
|
||||
(void) pw_rewind ();
|
||||
pw_rewind ();
|
||||
while ((pwd = pw_next ()) != NULL) {
|
||||
if ((pwd->pw_uid <= user_id) && (pwd->pw_uid >= uid_min)) {
|
||||
user_id = pwd->pw_uid - 1;
|
||||
@@ -149,7 +128,7 @@ int find_new_uid (bool sys_user,
|
||||
}
|
||||
endpwent ();
|
||||
|
||||
(void) pw_rewind ();
|
||||
pw_rewind ();
|
||||
while ((pwd = pw_next ()) != NULL) {
|
||||
if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
|
||||
user_id = pwd->pw_uid + 1;
|
||||
@@ -162,13 +141,12 @@ int find_new_uid (bool sys_user,
|
||||
}
|
||||
|
||||
/*
|
||||
* If a user (resp. system user) with UID equal to UID_MAX (resp.
|
||||
* UID_MIN) exists, the above algorithm will give us UID_MAX+1
|
||||
* (resp. UID_MIN-1) even if not unique. Search for the first free
|
||||
* UID starting with UID_MIN (resp. UID_MAX).
|
||||
* If a user with UID equal to UID_MAX exists, the above algorithm
|
||||
* will give us UID_MAX+1 even if not unique. Search for the first
|
||||
* free UID starting with UID_MIN.
|
||||
*/
|
||||
if (sys_user) {
|
||||
if (user_id < uid_min) {
|
||||
if (user_id == uid_min - 1) {
|
||||
for (user_id = uid_max; user_id >= uid_min; user_id--) {
|
||||
if (false == used_uids[user_id]) {
|
||||
break;
|
||||
@@ -180,29 +158,26 @@ int find_new_uid (bool sys_user,
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN,
|
||||
"no more available UID on the system"));
|
||||
free (used_uids);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (user_id > uid_max) {
|
||||
for (user_id = uid_min; user_id <= uid_max; user_id++) {
|
||||
if (user_id == uid_max + 1) {
|
||||
for (user_id = uid_min; user_id < uid_max; user_id++) {
|
||||
if (false == used_uids[user_id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (user_id > uid_max) {
|
||||
if (user_id == uid_max) {
|
||||
fprintf (stderr,
|
||||
_("%s: Can't get unique UID (no more available UIDs)\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_WARN, "no more available UID on the system"));
|
||||
free (used_uids);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (used_uids);
|
||||
*uid = user_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,5 +35,5 @@
|
||||
#include <config.h>
|
||||
#include "defines.h"
|
||||
|
||||
time_t get_date (const char *p, /*@null@*/const time_t *now);
|
||||
time_t get_date (const char *, const time_t *);
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
* The string may be a valid GID or a valid groupname.
|
||||
* If the group does not exist on the system, NULL is returned.
|
||||
*/
|
||||
extern /*@only@*//*@null@*/struct group *getgr_nam_gid (/*@null@*/const char *grname)
|
||||
extern /*@null@*/struct group *getgr_nam_gid (const char *grname)
|
||||
{
|
||||
long long int gid;
|
||||
char *endptr;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1991 - 1993, Chip Rosenthal
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2010, Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -50,7 +50,7 @@
|
||||
bool hushed (const char *username)
|
||||
{
|
||||
struct passwd *pw;
|
||||
const char *hushfile;
|
||||
char *hushfile;
|
||||
char buf[BUFSIZ];
|
||||
bool found;
|
||||
FILE *fp;
|
||||
@@ -76,7 +76,7 @@ bool hushed (const char *username)
|
||||
*/
|
||||
|
||||
if (hushfile[0] != '/') {
|
||||
(void) snprintf (buf, sizeof (buf), "%s/%s", pw->pw_dir, hushfile);
|
||||
snprintf (buf, sizeof (buf), "%s/%s", pw->pw_dir, hushfile);
|
||||
return (access (buf, F_OK) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Eric Biederman
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "prototypes.h"
|
||||
#include "idmapping.h"
|
||||
|
||||
struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
||||
{
|
||||
struct map_range *mappings, *mapping;
|
||||
int idx, argidx;
|
||||
|
||||
if (ranges < 0 || argc < 0) {
|
||||
fprintf(stderr, "%s: error calculating number of arguments\n", Prog);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ranges != ((argc + 2) / 3)) {
|
||||
fprintf(stderr, "%s: ranges: %u is wrong for argc: %d\n", Prog, ranges, argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ranges * 3) > argc) {
|
||||
fprintf(stderr, "ranges: %u argc: %d\n",
|
||||
ranges, argc);
|
||||
fprintf(stderr,
|
||||
_( "%s: Not enough arguments to form %u mappings\n"),
|
||||
Prog, ranges);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mappings = calloc(ranges, sizeof(*mappings));
|
||||
if (!mappings) {
|
||||
fprintf(stderr, _( "%s: Memory allocation failure\n"),
|
||||
Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Gather up the ranges from the command line */
|
||||
mapping = mappings;
|
||||
for (idx = 0, argidx = 0; idx < ranges; idx++, argidx += 3, mapping++) {
|
||||
if (!getulong(argv[argidx + 0], &mapping->upper)) {
|
||||
free(mappings);
|
||||
return NULL;
|
||||
}
|
||||
if (!getulong(argv[argidx + 1], &mapping->lower)) {
|
||||
free(mappings);
|
||||
return NULL;
|
||||
}
|
||||
if (!getulong(argv[argidx + 2], &mapping->count)) {
|
||||
free(mappings);
|
||||
return NULL;
|
||||
}
|
||||
if (ULONG_MAX - mapping->upper <= mapping->count || ULONG_MAX - mapping->lower <= mapping->count) {
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mapping->upper > UINT_MAX ||
|
||||
mapping->lower > UINT_MAX ||
|
||||
mapping->count > UINT_MAX) {
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mapping->lower + mapping->count > UINT_MAX ||
|
||||
mapping->upper + mapping->count > UINT_MAX) {
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mapping->lower + mapping->count < mapping->lower ||
|
||||
mapping->upper + mapping->count < mapping->upper) {
|
||||
/* this one really shouldn't be possible given previous checks */
|
||||
fprintf(stderr, _( "%s: subuid overflow detected.\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/* Number of ascii digits needed to print any unsigned long in decimal.
|
||||
* There are approximately 10 bits for every 3 decimal digits.
|
||||
* So from bits to digits the formula is roundup((Number of bits)/10) * 3.
|
||||
* For common sizes of integers this works out to:
|
||||
* 2bytes --> 6 ascii estimate -> 65536 (5 real)
|
||||
* 4bytes --> 12 ascii estimated -> 4294967296 (10 real)
|
||||
* 8bytes --> 21 ascii estimated -> 18446744073709551616 (20 real)
|
||||
* 16bytes --> 39 ascii estimated -> 340282366920938463463374607431768211456 (39 real)
|
||||
*/
|
||||
#define ULONG_DIGITS ((((sizeof(unsigned long) * CHAR_BIT) + 9)/10)*3)
|
||||
|
||||
|
||||
void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
||||
const char *map_file)
|
||||
{
|
||||
int idx;
|
||||
struct map_range *mapping;
|
||||
size_t bufsize;
|
||||
char *buf, *pos;
|
||||
int fd;
|
||||
|
||||
bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
|
||||
pos = buf = xmalloc(bufsize);
|
||||
|
||||
/* Build the mapping command */
|
||||
mapping = mappings;
|
||||
for (idx = 0; idx < ranges; idx++, mapping++) {
|
||||
/* Append this range to the string that will be written */
|
||||
int written = snprintf(pos, bufsize - (pos - buf),
|
||||
"%lu %lu %lu\n",
|
||||
mapping->upper,
|
||||
mapping->lower,
|
||||
mapping->count);
|
||||
if ((written <= 0) || (written >= (bufsize - (pos - buf)))) {
|
||||
fprintf(stderr, _("%s: snprintf failed!\n"), Prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pos += written;
|
||||
}
|
||||
|
||||
/* Write the mapping to the maping file */
|
||||
fd = openat(proc_dir_fd, map_file, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, _("%s: open of %s failed: %s\n"),
|
||||
Prog, map_file, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (write(fd, buf, pos - buf) != (pos - buf)) {
|
||||
fprintf(stderr, _("%s: write to %s failed: %s\n"),
|
||||
Prog, map_file, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ int isexpired (const struct passwd *pw, /*@null@*/const struct spwd *sp)
|
||||
|
||||
if ( (-1 == sp->sp_lstchg)
|
||||
|| (-1 == sp->sp_max)
|
||||
|| (sp->sp_max >= ((10000L * DAY) / SCALE))) {
|
||||
|| (sp->sp_max >= (10000L * DAY / SCALE))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
254
libmisc/limits.c
254
libmisc/limits.c
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -33,7 +33,6 @@
|
||||
/*
|
||||
* Separated from setup.c. --marekm
|
||||
* Resource limits thanks to Cristian Gafton.
|
||||
* Enhancements of resource limit code by Thomas Orgis <thomas@orgis.org>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@@ -45,7 +44,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
#include <pwd.h>
|
||||
@@ -66,46 +64,22 @@
|
||||
* value - string value to be read
|
||||
* multiplier - value*multiplier is the actual limit
|
||||
*/
|
||||
static int setrlimit_value (unsigned int resource,
|
||||
const char *value,
|
||||
unsigned int multiplier)
|
||||
static int
|
||||
setrlimit_value (unsigned int resource, const char *value,
|
||||
unsigned int multiplier)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
rlim_t limit;
|
||||
long limit;
|
||||
|
||||
/* The "-" is special, not belonging to a strange negative limit.
|
||||
* It is infinity, in a controlled way.
|
||||
*/
|
||||
if ('-' == value[0]) {
|
||||
limit = RLIM_INFINITY;
|
||||
if (getlong (value, &limit) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* We cannot use getlong here because it fails when there
|
||||
* is more to the value than just this number!
|
||||
* Also, we are limited to base 10 here (hex numbers will not
|
||||
* work with the limit string parser as is anyway)
|
||||
*/
|
||||
char *endptr;
|
||||
long longlimit = strtol (value, &endptr, 10);
|
||||
if ((0 == longlimit) && (value == endptr)) {
|
||||
/* No argument at all. No-op.
|
||||
* FIXME: We could instead throw an error, though.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
longlimit *= multiplier;
|
||||
limit = (rlim_t)longlimit;
|
||||
if (longlimit != limit)
|
||||
{
|
||||
/* FIXME: Again, silent error handling...
|
||||
* Wouldn't screaming make more sense?
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
limit *= multiplier;
|
||||
if (limit != (rlim_t) limit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rlim.rlim_cur = limit;
|
||||
rlim.rlim_max = limit;
|
||||
rlim.rlim_cur = (rlim_t) limit;
|
||||
rlim.rlim_max = (rlim_t) limit;
|
||||
if (setrlimit (resource, &rlim) != 0) {
|
||||
return LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
@@ -164,12 +138,11 @@ static int check_logins (const char *name, const char *maxlogins)
|
||||
count = 0;
|
||||
#ifdef USE_UTMPX
|
||||
setutxent ();
|
||||
while ((ut = getutxent ()))
|
||||
while ((ut = getutxent ())) {
|
||||
#else /* !USE_UTMPX */
|
||||
setutent ();
|
||||
while ((ut = getutent ()))
|
||||
while ((ut = getutent ())) {
|
||||
#endif /* !USE_UTMPX */
|
||||
{
|
||||
if (USER_PROCESS != ut->ut_type) {
|
||||
continue;
|
||||
}
|
||||
@@ -194,9 +167,8 @@ static int check_logins (const char *name, const char *maxlogins)
|
||||
* includes the user who is currently trying to log in.
|
||||
*/
|
||||
if (count > limit) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Too many logins (max %lu) for %s\n",
|
||||
limit, name));
|
||||
SYSLOG ((LOG_WARN, "Too many logins (max %d) for %s\n",
|
||||
limit, name));
|
||||
return LOGIN_ERROR_LOGIN;
|
||||
}
|
||||
return 0;
|
||||
@@ -214,20 +186,17 @@ static int check_logins (const char *name, const char *maxlogins)
|
||||
* [Cc]: c = RLIMIT_CORE max core file size (KB)
|
||||
* [Dd]: d = RLIMIT_DATA max data size (KB)
|
||||
* [Ff]: f = RLIMIT_FSIZE max file size (KB)
|
||||
* [Ii]: i = RLIMIT_NICE max nice value (0..39 translates to 20..-19)
|
||||
* [Kk]: k = file creation masK (umask)
|
||||
* [Ll]: l = max number of logins for this user
|
||||
* [Mm]: m = RLIMIT_MEMLOCK max locked-in-memory address space (KB)
|
||||
* [Nn]: n = RLIMIT_NOFILE max number of open files
|
||||
* [Oo]: o = RLIMIT_RTPRIO max real time priority (linux/sched.h 0..MAX_RT_PRIO)
|
||||
* [Pp]: p = process priority -20..20 (negative = high, positive = low)
|
||||
* [Rr]: r = RLIMIT_RSS max resident set size (KB)
|
||||
* [Ss]: s = RLIMIT_STACK max stack size (KB)
|
||||
* [Tt]: t = RLIMIT_CPU max CPU time (MIN)
|
||||
* [Uu]: u = RLIMIT_NPROC max number of processes
|
||||
*
|
||||
* NOTE: Remember to extend the "no-limits" string below when adding a new
|
||||
* limit...
|
||||
* [Kk]: k = file creation masK (umask)
|
||||
* [Ll]: l = max number of logins for this user
|
||||
* [Pp]: p = process priority -20..20 (negative = high, positive = low)
|
||||
* [Ii]: i = RLIMIT_NICE max nice value (0..39 translates to 20..-19)
|
||||
* [Oo]: o = RLIMIT_RTPRIO max real time priority (linux/sched.h 0..MAX_RT_PRIO)
|
||||
*
|
||||
* Return value:
|
||||
* 0 = okay, of course
|
||||
@@ -244,24 +213,6 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
bool reported = false;
|
||||
|
||||
pp = buf;
|
||||
/* Skip leading whitespace. */
|
||||
while ((' ' == *pp) || ('\t' == *pp)) {
|
||||
pp++;
|
||||
}
|
||||
|
||||
/* The special limit string "-" results in no limit for all known
|
||||
* limits.
|
||||
* We achieve that by parsing a full limit string, parts of it
|
||||
* being ignored if a limit type is not known to the system.
|
||||
* Though, there will be complaining for unknown limit types.
|
||||
*/
|
||||
if (strcmp (pp, "-") == 0) {
|
||||
/* Remember to extend this, too, when adding new limits!
|
||||
* Oh... but "unlimited" does not make sense for umask,
|
||||
* or does it? (K-)
|
||||
*/
|
||||
pp = "A- C- D- F- I- L- M- N- O- P- R- S- T- U-";
|
||||
}
|
||||
|
||||
while ('\0' != *pp) {
|
||||
switch (*pp++) {
|
||||
@@ -272,11 +223,11 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
retval |= setrlimit_value (RLIMIT_AS, pp, 1024);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_CORE
|
||||
case 'c':
|
||||
case 'C':
|
||||
/* RLIMIT_CORE - max core file size (KB) */
|
||||
retval |= setrlimit_value (RLIMIT_CORE, pp, 1024);
|
||||
#ifdef RLIMIT_CPU
|
||||
case 't':
|
||||
case 'T':
|
||||
/* RLIMIT_CPU - max CPU time (MIN) */
|
||||
retval |= setrlimit_value (RLIMIT_CPU, pp, 60);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_DATA
|
||||
@@ -293,22 +244,20 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
retval |= setrlimit_value (RLIMIT_FSIZE, pp, 1024);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
case 'i':
|
||||
case 'I':
|
||||
/* RLIMIT_NICE - max scheduling priority (0..39) */
|
||||
retval |= setrlimit_value (RLIMIT_NICE, pp, 1);
|
||||
#ifdef RLIMIT_NPROC
|
||||
case 'u':
|
||||
case 'U':
|
||||
/* RLIMIT_NPROC - max number of processes */
|
||||
retval |= setrlimit_value (RLIMIT_NPROC, pp, 1);
|
||||
break;
|
||||
#endif
|
||||
case 'k':
|
||||
case 'K':
|
||||
retval |= set_umask (pp);
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
/* LIMIT the number of concurrent logins */
|
||||
retval |= check_logins (name, pp);
|
||||
#ifdef RLIMIT_CORE
|
||||
case 'c':
|
||||
case 'C':
|
||||
/* RLIMIT_CORE - max core file size (KB) */
|
||||
retval |= setrlimit_value (RLIMIT_CORE, pp, 1024);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
case 'm':
|
||||
case 'M':
|
||||
@@ -323,17 +272,6 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
retval |= setrlimit_value (RLIMIT_NOFILE, pp, 1);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
case 'o':
|
||||
case 'O':
|
||||
/* RLIMIT_RTPRIO - max real time priority (0..MAX_RT_PRIO) */
|
||||
retval |= setrlimit_value (RLIMIT_RTPRIO, pp, 1);
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
case 'P':
|
||||
retval |= set_prio (pp);
|
||||
break;
|
||||
#ifdef RLIMIT_RSS
|
||||
case 'r':
|
||||
case 'R':
|
||||
@@ -348,28 +286,35 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
retval |= setrlimit_value (RLIMIT_STACK, pp, 1024);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_CPU
|
||||
case 't':
|
||||
case 'T':
|
||||
/* RLIMIT_CPU - max CPU time (MIN) */
|
||||
retval |= setrlimit_value (RLIMIT_CPU, pp, 60);
|
||||
#ifdef RLIMIT_NICE
|
||||
case 'i':
|
||||
case 'I':
|
||||
/* RLIMIT_NICE - max scheduling priority (0..39) */
|
||||
retval |= setrlimit_value (RLIMIT_NICE, pp, 1);
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_NPROC
|
||||
case 'u':
|
||||
case 'U':
|
||||
/* RLIMIT_NPROC - max number of processes */
|
||||
retval |= setrlimit_value (RLIMIT_NPROC, pp, 1);
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
case 'o':
|
||||
case 'O':
|
||||
/* RLIMIT_RTPRIO - max real time priority (0..MAX_RT_PRIO) */
|
||||
retval |= setrlimit_value (RLIMIT_RTPRIO, pp, 1);
|
||||
break;
|
||||
#endif
|
||||
case 'k':
|
||||
case 'K':
|
||||
retval |= set_umask (pp);
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
/* LIMIT the number of concurrent logins */
|
||||
retval |= check_logins (name, pp);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
retval |= set_prio (pp);
|
||||
break;
|
||||
default:
|
||||
/* Only report invalid strings once */
|
||||
/* Note: A string can be invalid just because a
|
||||
* specific (theoretically valid) setting is not
|
||||
* supported by this build.
|
||||
* It is just a warning in syslog anyway. The line
|
||||
* is still processed
|
||||
*/
|
||||
if (!reported) {
|
||||
SYSLOG ((LOG_WARN,
|
||||
"Invalid limit string: '%s'",
|
||||
@@ -378,51 +323,13 @@ static int do_user_limits (const char *buf, const char *name)
|
||||
retval |= LOGIN_ERROR_RLIMIT;
|
||||
}
|
||||
}
|
||||
/* After parsing one limit setting (or just complaining
|
||||
* about it), one still needs to skip its argument to
|
||||
* prevent a bogus warning on trying to parse that as
|
||||
* limit specification.
|
||||
* So, let's skip all digits, "-" and our limited set of
|
||||
* whitespace.
|
||||
*/
|
||||
while ( isdigit (*pp)
|
||||
|| ('-' == *pp)
|
||||
|| (' ' == *pp)
|
||||
|| ('\t' ==*pp)) {
|
||||
pp++;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Check if user uname is in the group gname.
|
||||
* Can I be sure that gr_mem contains no UID as string?
|
||||
* Returns true when user is in the group, false when not.
|
||||
* Any error is treated as false.
|
||||
*/
|
||||
static bool user_in_group (const char *uname, const char *gname)
|
||||
{
|
||||
struct group *groupdata;
|
||||
|
||||
if (uname == NULL || gname == NULL){
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We are not claiming to be re-entrant!
|
||||
* In case of paranoia or a multithreaded login program,
|
||||
* one needs to add some mess for getgrnam_r. */
|
||||
groupdata = getgrnam (gname);
|
||||
if (NULL == groupdata) {
|
||||
SYSLOG ((LOG_WARN, "Nonexisting group `%s' in limits file.",
|
||||
gname));
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_on_list (groupdata->gr_mem, uname);
|
||||
}
|
||||
|
||||
static int setup_user_limits (const char *uname)
|
||||
{
|
||||
/* TODO: allow and use @group syntax --cristiang */
|
||||
FILE *fil;
|
||||
char buf[1024];
|
||||
char name[1024];
|
||||
@@ -444,10 +351,8 @@ static int setup_user_limits (const char *uname)
|
||||
}
|
||||
/* The limits file have the following format:
|
||||
* - '#' (comment) chars only as first chars on a line;
|
||||
* - username must start on first column (or *, or @group)
|
||||
*
|
||||
* FIXME: A better (smarter) checking should be done
|
||||
*/
|
||||
* - username must start on first column
|
||||
* A better (smarter) checking should be done --cristiang */
|
||||
while (fgets (buf, 1024, fil) != NULL) {
|
||||
if (('#' == buf[0]) || ('\n' == buf[0])) {
|
||||
continue;
|
||||
@@ -459,35 +364,15 @@ static int setup_user_limits (const char *uname)
|
||||
* username L2 D2048 R4096
|
||||
* where spaces={' ',\t}. Also, we reject invalid limits.
|
||||
* Imposing a limit should be done with care, so a wrong
|
||||
* entry means no care anyway :-).
|
||||
*
|
||||
* A '-' as a limits strings means no limits
|
||||
*
|
||||
* The username can also be:
|
||||
* '*': the default limits (only the last is taken into
|
||||
* account)
|
||||
* @group: the limit applies to the members of the group
|
||||
*
|
||||
* To clarify: The first entry with matching user name rules,
|
||||
* everything after it is ignored. If there is no user entry,
|
||||
* the last encountered entry for a matching group rules.
|
||||
* If there is no matching group entry, the default limits rule.
|
||||
*/
|
||||
if (sscanf (buf, "%s%[ACDFIKLMNOPRSTUacdfiklmnoprstu0-9 \t-]",
|
||||
name, tempbuf) == 2) {
|
||||
* entry means no care anyway :-). A '-' as a limits
|
||||
* strings means no limits --cristiang */
|
||||
if (sscanf (buf, "%s%[ACDFMNRSTULPIOacdfmnrstulpio0-9 \t-]",
|
||||
name, tempbuf) == 2) {
|
||||
if (strcmp (name, uname) == 0) {
|
||||
strcpy (limits, tempbuf);
|
||||
break;
|
||||
} else if (strcmp (name, "*") == 0) {
|
||||
strcpy (deflimits, tempbuf);
|
||||
} else if (name[0] == '@') {
|
||||
/* If the user is in the group, the group
|
||||
* limits apply unless later a line for
|
||||
* the specific user is found.
|
||||
*/
|
||||
if (user_in_group (uname, name+1)) {
|
||||
strcpy (limits, tempbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -507,6 +392,7 @@ static int setup_user_limits (const char *uname)
|
||||
static void setup_usergroups (const struct passwd *info)
|
||||
{
|
||||
const struct group *grp;
|
||||
mode_t tmpmask;
|
||||
|
||||
/*
|
||||
* if not root, and UID == GID, and username is the same as primary
|
||||
@@ -518,7 +404,6 @@ static void setup_usergroups (const struct passwd *info)
|
||||
grp = getgrgid (info->pw_gid);
|
||||
if ( (NULL != grp)
|
||||
&& (strcmp (info->pw_name, grp->gr_name) == 0)) {
|
||||
mode_t tmpmask;
|
||||
tmpmask = umask (0777);
|
||||
tmpmask = (tmpmask & ~070) | ((tmpmask >> 3) & 070);
|
||||
(void) umask (tmpmask);
|
||||
@@ -547,7 +432,8 @@ void setup_limits (const struct passwd *info)
|
||||
if (getdef_bool ("QUOTAS_ENAB")) {
|
||||
#ifdef LIMITS
|
||||
if (info->pw_uid != 0) {
|
||||
if ((setup_user_limits (info->pw_name) & LOGIN_ERROR_LOGIN) != 0) {
|
||||
if (setup_user_limits (info->pw_name) &
|
||||
LOGIN_ERROR_LOGIN) {
|
||||
(void) fputs (_("Too many logins.\n"), stderr);
|
||||
(void) sleep (2); /* XXX: Should be FAIL_DELAY */
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
@@ -141,12 +141,6 @@
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate a list.
|
||||
* The input list is not modified, but in order to allow the use of this
|
||||
* function with list of members, the list elements are not enforced to be
|
||||
* constant strings here.
|
||||
*/
|
||||
/*@only@*/ /*@out@*/char **dup_list (char *const *list)
|
||||
{
|
||||
int i;
|
||||
@@ -169,12 +163,6 @@
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if member is part of the input list
|
||||
* The input list is not modified, but in order to allow the use of this
|
||||
* function with list of members, the list elements are not enforced to be
|
||||
* constant strings here.
|
||||
*/
|
||||
bool is_on_list (char *const *list, const char *member)
|
||||
{
|
||||
assert (NULL != member);
|
||||
@@ -199,7 +187,7 @@ bool is_on_list (char *const *list, const char *member)
|
||||
char *members;
|
||||
char **array;
|
||||
int i;
|
||||
char *cp;
|
||||
const char *cp;
|
||||
char *cp2;
|
||||
|
||||
assert (NULL != comma);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1993, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2011, Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -60,6 +60,7 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
|
||||
#define MAX_ENV 32
|
||||
char *envp[MAX_ENV];
|
||||
int envc;
|
||||
char *cp;
|
||||
int i;
|
||||
FILE *fp;
|
||||
@@ -87,9 +88,9 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
*/
|
||||
|
||||
if (NULL != prompt) {
|
||||
const char *fname = getdef_str ("ISSUE_FILE");
|
||||
if (NULL != fname) {
|
||||
fp = fopen (fname, "r");
|
||||
cp = getdef_str ("ISSUE_FILE");
|
||||
if (NULL != cp) {
|
||||
fp = fopen (cp, "r");
|
||||
if (NULL != fp) {
|
||||
while ((i = getc (fp)) != EOF) {
|
||||
(void) putc (i, stdout);
|
||||
@@ -98,7 +99,7 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
(void) fclose (fp);
|
||||
}
|
||||
}
|
||||
(void) gethostname (buf, sizeof buf);
|
||||
gethostname (buf, sizeof buf);
|
||||
printf (prompt, buf);
|
||||
(void) fflush (stdout);
|
||||
}
|
||||
@@ -147,7 +148,6 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
if ('\0' != *cp) { /* process new variables */
|
||||
char *nvar;
|
||||
int count = 1;
|
||||
int envc;
|
||||
|
||||
for (envc = 0; envc < MAX_ENV; envc++) {
|
||||
nvar = strtok ((0 != envc) ? (char *) 0 : cp, " \t,");
|
||||
@@ -158,9 +158,10 @@ void login_prompt (const char *prompt, char *name, int namesize)
|
||||
envp[envc] = nvar;
|
||||
} else {
|
||||
size_t len = strlen (nvar) + 32;
|
||||
int wlen;
|
||||
envp[envc] = xmalloc (len);
|
||||
(void) snprintf (envp[envc], len,
|
||||
"L%d=%s", count++, nvar);
|
||||
wlen = snprintf (envp[envc], len, "L%d=%s", count++, nvar);
|
||||
assert (wlen == (int) len -1);
|
||||
}
|
||||
}
|
||||
set_env (envc, envp);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) 1989 - 1991, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2010 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -48,34 +47,21 @@
|
||||
void motd (void)
|
||||
{
|
||||
FILE *fp;
|
||||
char *motdlist;
|
||||
const char *motdfile;
|
||||
char *mb;
|
||||
char motdlist[BUFSIZ], *motdfile, *mb;
|
||||
register int c;
|
||||
|
||||
motdfile = getdef_str ("MOTD_FILE");
|
||||
if (NULL == motdfile) {
|
||||
if ((mb = getdef_str ("MOTD_FILE")) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
motdlist = xstrdup (motdfile);
|
||||
strncpy (motdlist, mb, sizeof (motdlist));
|
||||
motdlist[sizeof (motdlist) - 1] = '\0';
|
||||
|
||||
for (mb = motdlist; ;mb = NULL) {
|
||||
motdfile = strtok (mb, ":");
|
||||
if (NULL == motdfile) {
|
||||
break;
|
||||
}
|
||||
|
||||
fp = fopen (motdfile, "r");
|
||||
if (NULL != fp) {
|
||||
while ((c = getc (fp)) != EOF) {
|
||||
for (mb = motdlist; (motdfile = strtok (mb, ":")) != NULL; mb = NULL) {
|
||||
if ((fp = fopen (motdfile, "r")) != NULL) {
|
||||
while ((c = getc (fp)) != EOF)
|
||||
putchar (c);
|
||||
}
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
fflush (stdout);
|
||||
|
||||
free (motdlist);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1999, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -69,7 +69,7 @@ static bool palindrome (unused const char *old, const char *new)
|
||||
* more than half of the characters are different ones.
|
||||
*/
|
||||
|
||||
static bool similar (/*@notnull@*/const char *old, /*@notnull@*/const char *new)
|
||||
static bool similar (const char *old, const char *new)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
@@ -100,7 +100,7 @@ static bool similar (/*@notnull@*/const char *old, /*@notnull@*/const char *new)
|
||||
* a nice mix of characters.
|
||||
*/
|
||||
|
||||
static bool simple (unused const char *old, const char *new)
|
||||
static int simple (unused const char *old, const char *new)
|
||||
{
|
||||
bool digits = false;
|
||||
bool uppers = false;
|
||||
@@ -147,7 +147,7 @@ static bool simple (unused const char *old, const char *new)
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *str_lower (/*@returned@*/char *string)
|
||||
static char *str_lower (char *string)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
@@ -157,10 +157,8 @@ static char *str_lower (/*@returned@*/char *string)
|
||||
return string;
|
||||
}
|
||||
|
||||
static /*@observer@*//*@null@*/const char *password_check (
|
||||
/*@notnull@*/const char *old,
|
||||
/*@notnull@*/const char *new,
|
||||
/*@notnull@*/const struct passwd *pwdp)
|
||||
static const char *password_check (const char *old, const char *new,
|
||||
const struct passwd *pwdp)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
char *oldmono, *newmono, *wrapped;
|
||||
@@ -221,15 +219,14 @@ static /*@observer@*//*@null@*/const char *password_check (
|
||||
return msg;
|
||||
}
|
||||
|
||||
static /*@observer@*//*@null@*/const char *obscure_msg (
|
||||
/*@notnull@*/const char *old,
|
||||
/*@notnull@*/const char *new,
|
||||
/*@notnull@*/const struct passwd *pwdp)
|
||||
/*ARGSUSED*/
|
||||
static const char *obscure_msg (const char *old, const char *new,
|
||||
const struct passwd *pwdp)
|
||||
{
|
||||
size_t maxlen, oldlen, newlen;
|
||||
char *new1, *old1;
|
||||
const char *msg;
|
||||
const char *result;
|
||||
char *result;
|
||||
|
||||
oldlen = strlen (old);
|
||||
newlen = strlen (new);
|
||||
@@ -307,15 +304,15 @@ static /*@observer@*//*@null@*/const char *obscure_msg (
|
||||
* check passwords.
|
||||
*/
|
||||
|
||||
bool obscure (const char *old, const char *new, const struct passwd *pwdp)
|
||||
int obscure (const char *old, const char *new, const struct passwd *pwdp)
|
||||
{
|
||||
const char *msg = obscure_msg (old, new, pwdp);
|
||||
|
||||
if (NULL != msg) {
|
||||
printf (_("Bad password: %s. "), msg);
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* !USE_PAM */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009 - 2010, Nicolas François
|
||||
* Copyright (c) 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <security/pam_appl.h>
|
||||
#include "prototypes.h"
|
||||
|
||||
/*@null@*/ /*@only@*/static const char *non_interactive_password = NULL;
|
||||
/*@null@*/ /*@only@*/static char *non_interactive_password = NULL;
|
||||
static int ni_conv (int num_msg,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
/*
|
||||
* remove_tree - delete a directory tree
|
||||
*
|
||||
* remove_tree() walks a directory tree and deletes all the files
|
||||
* and directories.
|
||||
* At the end, it deletes the root directory itself.
|
||||
*/
|
||||
|
||||
int remove_tree (const char *root, bool remove_root)
|
||||
{
|
||||
char *new_name = NULL;
|
||||
int err = 0;
|
||||
struct DIRECT *ent;
|
||||
struct stat sb;
|
||||
DIR *dir;
|
||||
|
||||
/*
|
||||
* Open the source directory and read each entry. Every file
|
||||
* entry in the directory is copied with the UID and GID set
|
||||
* to the provided values. As an added security feature only
|
||||
* regular files (and directories ...) are copied, and no file
|
||||
* is made set-ID.
|
||||
*/
|
||||
dir = opendir (root);
|
||||
if (NULL == dir) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((ent = readdir (dir))) {
|
||||
size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
|
||||
|
||||
/*
|
||||
* Skip the "." and ".." entries
|
||||
*/
|
||||
|
||||
if (strcmp (ent->d_name, ".") == 0 ||
|
||||
strcmp (ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the filename for the current entry.
|
||||
*/
|
||||
|
||||
free (new_name);
|
||||
new_name = (char *) malloc (new_len);
|
||||
if (NULL == new_name) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
(void) snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
|
||||
if (LSTAT (new_name, &sb) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
/*
|
||||
* Recursively delete this directory.
|
||||
*/
|
||||
if (remove_tree (new_name, true) != 0) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Delete the file.
|
||||
*/
|
||||
if (unlink (new_name) != 0) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL != new_name) {
|
||||
free (new_name);
|
||||
}
|
||||
(void) closedir (dir);
|
||||
|
||||
if (remove_root && (0 == err)) {
|
||||
if (rmdir (root) != 0) {
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 , Julian Pidancet
|
||||
* Copyright (c) 2011 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the copyright holders or contributors may not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
/*@-exitarg@*/
|
||||
#include "exitcodes.h"
|
||||
|
||||
static void change_root (const char* newroot);
|
||||
|
||||
/*
|
||||
* process_root_flag - chroot if given the --root option
|
||||
*
|
||||
* This shall be called before accessing the passwd, group, shadow,
|
||||
* gshadow, useradd's default, login.defs files (non exhaustive list)
|
||||
* or authenticating the caller.
|
||||
*
|
||||
* The audit, syslog, or locale files shall be open before
|
||||
*/
|
||||
extern void process_root_flag (const char* short_opt, int argc, char **argv)
|
||||
{
|
||||
/*
|
||||
* Parse the command line options.
|
||||
*/
|
||||
int i;
|
||||
const char *newroot = NULL;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if ( (strcmp (argv[i], "--root") == 0)
|
||||
|| (strcmp (argv[i], short_opt) == 0)) {
|
||||
if (NULL != newroot) {
|
||||
fprintf (stderr,
|
||||
_("%s: multiple --root options\n"),
|
||||
Prog);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (i + 1 == argc) {
|
||||
fprintf (stderr,
|
||||
_("%s: option '%s' requires an argument\n"),
|
||||
Prog, argv[i]);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
newroot = argv[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != newroot) {
|
||||
change_root (newroot);
|
||||
}
|
||||
}
|
||||
|
||||
static void change_root (const char* newroot)
|
||||
{
|
||||
/* Drop privileges */
|
||||
if ( (setregid (getgid (), getgid ()) != 0)
|
||||
|| (setreuid (getuid (), getuid ()) != 0)) {
|
||||
fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
|
||||
Prog, strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ('/' != newroot[0]) {
|
||||
fprintf (stderr,
|
||||
_("%s: invalid chroot path '%s'\n"),
|
||||
Prog, newroot);
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (access (newroot, F_OK) != 0) {
|
||||
fprintf(stderr,
|
||||
_("%s: cannot access chroot directory %s: %s\n"),
|
||||
Prog, newroot, strerror (errno));
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (chdir (newroot) != 0) {
|
||||
fprintf(stderr,
|
||||
_("%s: cannot chdir to chroot directory %s: %s\n"),
|
||||
Prog, newroot, strerror (errno));
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
|
||||
if (chroot (newroot) != 0) {
|
||||
fprintf(stderr,
|
||||
_("%s: unable to chroot to directory %s: %s\n"),
|
||||
Prog, newroot, strerror (errno));
|
||||
exit (E_BAD_ARG);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
static void seedRNG (void);
|
||||
static /*@observer@*/const char *gensalt (size_t salt_size);
|
||||
#ifdef USE_SHA_CRYPT
|
||||
static long shadow_random (long min, long max);
|
||||
static size_t SHA_salt_size (void);
|
||||
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds);
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
|
||||
@@ -81,29 +81,17 @@ static void seedRNG (void)
|
||||
#define MAGNUM(array,ch) (array)[0]=(array)[2]='$',(array)[1]=(ch),(array)[3]='\0'
|
||||
|
||||
#ifdef USE_SHA_CRYPT
|
||||
/* It is not clear what is the maximum value of random().
|
||||
* We assume 2^31-1.*/
|
||||
#define RANDOM_MAX 0x7FFFFFFF
|
||||
|
||||
/*
|
||||
* Return a random number between min and max (both included).
|
||||
*
|
||||
* It favors slightly the higher numbers.
|
||||
* Return the salt size.
|
||||
* The size of the salt string is between 8 and 16 bytes for the SHA crypt
|
||||
* methods.
|
||||
*/
|
||||
static long shadow_random (long min, long max)
|
||||
static size_t SHA_salt_size (void)
|
||||
{
|
||||
double drand;
|
||||
long ret;
|
||||
double rand_size;
|
||||
seedRNG ();
|
||||
drand = (double) (max - min + 1) * random () / RANDOM_MAX;
|
||||
/* On systems were this is not random() range is lower, we favor
|
||||
* higher numbers of salt. */
|
||||
ret = (long) (max + 1 - drand);
|
||||
/* And we catch limits, and use the highest number */
|
||||
if ((ret < min) || (ret > max)) {
|
||||
ret = max;
|
||||
}
|
||||
return ret;
|
||||
rand_size = (double) 9.0 * random () / RAND_MAX;
|
||||
return (size_t) (8 + rand_size);
|
||||
}
|
||||
|
||||
/* Default number of rounds if not explicitly specified. */
|
||||
@@ -118,12 +106,13 @@ static long shadow_random (long min, long max)
|
||||
*/
|
||||
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds)
|
||||
{
|
||||
static char rounds_prefix[18]; /* Max size: rounds=999999999$ */
|
||||
static char rounds_prefix[18];
|
||||
long rounds;
|
||||
|
||||
if (NULL == prefered_rounds) {
|
||||
long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
|
||||
long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
|
||||
double rand_rounds;
|
||||
|
||||
if ((-1 == min_rounds) && (-1 == max_rounds)) {
|
||||
return "";
|
||||
@@ -141,7 +130,10 @@ static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds
|
||||
max_rounds = min_rounds;
|
||||
}
|
||||
|
||||
rounds = shadow_random (min_rounds, max_rounds);
|
||||
seedRNG ();
|
||||
rand_rounds = (double) (max_rounds-min_rounds+1.0) * random ();
|
||||
rand_rounds /= RAND_MAX;
|
||||
rounds = min_rounds + rand_rounds;
|
||||
} else if (0 == *prefered_rounds) {
|
||||
return "";
|
||||
} else {
|
||||
@@ -158,8 +150,13 @@ static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds
|
||||
rounds = ROUNDS_MAX;
|
||||
}
|
||||
|
||||
(void) snprintf (rounds_prefix, sizeof rounds_prefix,
|
||||
"rounds=%ld$", rounds);
|
||||
snprintf (rounds_prefix, 18, "rounds=%ld$", rounds);
|
||||
|
||||
/* Sanity checks. That should not be necessary. */
|
||||
rounds_prefix[17] = '\0';
|
||||
if ('$' != rounds_prefix[16]) {
|
||||
rounds_prefix[17] = '$';
|
||||
}
|
||||
|
||||
return rounds_prefix;
|
||||
}
|
||||
@@ -205,7 +202,7 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
|
||||
* * For the SHA256 and SHA512 method, this specifies the number of rounds
|
||||
* (if not NULL).
|
||||
*/
|
||||
/*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const char *meth, /*@null@*/void *arg)
|
||||
/*@observer@*/const char *crypt_make_salt (/*@null@*/const char *meth, /*@null@*/void *arg)
|
||||
{
|
||||
/* Max result size for the SHA methods:
|
||||
* +3 $5$
|
||||
@@ -234,11 +231,11 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
|
||||
} else if (0 == strcmp (method, "SHA256")) {
|
||||
MAGNUM(result, '5');
|
||||
strcat(result, SHA_salt_rounds((int *)arg));
|
||||
salt_len = (size_t) shadow_random (8, 16);
|
||||
salt_len = SHA_salt_size();
|
||||
} else if (0 == strcmp (method, "SHA512")) {
|
||||
MAGNUM(result, '6');
|
||||
strcat(result, SHA_salt_rounds((int *)arg));
|
||||
salt_len = (size_t) shadow_random (8, 16);
|
||||
salt_len = SHA_salt_size();
|
||||
#endif /* USE_SHA_CRYPT */
|
||||
} else if (0 != strcmp (method, "DES")) {
|
||||
fprintf (stderr,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2010, Nicolas François
|
||||
* Copyright (c) 2008 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -131,7 +131,7 @@ int setup_uid_gid (const struct passwd *info)
|
||||
|
||||
#if defined (HAVE_INITGROUPS) && ! defined (USE_PAM)
|
||||
if (is_console) {
|
||||
const char *cp = getdef_str ("CONSOLE_GROUPS");
|
||||
char *cp = getdef_str ("CONSOLE_GROUPS");
|
||||
|
||||
if ((NULL != cp) && (add_groups (cp) != 0)) {
|
||||
perror ("Warning: add_groups");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2009, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -74,7 +74,7 @@ static void read_env_file (const char *filename)
|
||||
if (NULL == fp) {
|
||||
return;
|
||||
}
|
||||
while (fgets (buf, (int)(sizeof buf), fp) == buf) {
|
||||
while (fgets (buf, sizeof buf, fp) == buf) {
|
||||
cp = strrchr (buf, '\n');
|
||||
if (NULL == cp) {
|
||||
break;
|
||||
@@ -200,9 +200,9 @@ static void read_env_file (const char *filename)
|
||||
void setup_env (struct passwd *info)
|
||||
{
|
||||
#ifndef USE_PAM
|
||||
const char *envf;
|
||||
char *envf;
|
||||
#endif
|
||||
const char *cp;
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* Change the current working directory to be the home directory
|
||||
@@ -228,8 +228,7 @@ void setup_env (struct passwd *info)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
(void) puts (_("No directory, logging in with HOME=/"));
|
||||
free (info->pw_dir);
|
||||
info->pw_dir = xstrdup (temp_pw_dir);
|
||||
info->pw_dir = temp_pw_dir;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -245,8 +244,7 @@ void setup_env (struct passwd *info)
|
||||
if ((NULL == info->pw_shell) || ('\0' == *info->pw_shell)) {
|
||||
static char temp_pw_shell[] = SHELL;
|
||||
|
||||
free (info->pw_shell);
|
||||
info->pw_shell = xstrdup (temp_pw_shell);
|
||||
info->pw_shell = temp_pw_shell;
|
||||
}
|
||||
|
||||
addenv ("SHELL", info->pw_shell);
|
||||
@@ -267,7 +265,7 @@ void setup_env (struct passwd *info)
|
||||
|
||||
if (NULL == cp) {
|
||||
/* not specified, use a minimal default */
|
||||
addenv ((info->pw_uid == 0) ? "PATH=/sbin:/bin:/usr/sbin:/usr/bin" : "PATH=/bin:/usr/bin", NULL);
|
||||
addenv ("PATH=/bin:/usr/bin", NULL);
|
||||
} else if (strchr (cp, '=')) {
|
||||
/* specified as name=value (PATH=...) */
|
||||
addenv (cp, NULL);
|
||||
|
||||
@@ -68,8 +68,7 @@ int shell (const char *file, /*@null@*/const char *arg, char *const envp[])
|
||||
* don't want to tell us what it is themselves.
|
||||
*/
|
||||
if (arg == (char *) 0) {
|
||||
(void) snprintf (arg0, sizeof arg0, "-%s", Basename ((char *) file));
|
||||
arg0[sizeof arg0 - 1] = '\0';
|
||||
snprintf (arg0, sizeof arg0, "-%s", Basename ((char *) file));
|
||||
arg = arg0;
|
||||
}
|
||||
|
||||
@@ -78,7 +77,7 @@ int shell (const char *file, /*@null@*/const char *arg, char *const envp[])
|
||||
* able to figure out what we are up to without too much
|
||||
* grief.
|
||||
*/
|
||||
(void) execle (file, arg, (char *) 0, envp);
|
||||
execle (file, arg, (char *) 0, envp);
|
||||
err = errno;
|
||||
|
||||
if (access (file, R_OK|X_OK) == 0) {
|
||||
@@ -86,7 +85,7 @@ int shell (const char *file, /*@null@*/const char *arg, char *const envp[])
|
||||
* Assume this is a shell script (with no shebang).
|
||||
* Interpret it with /bin/sh
|
||||
*/
|
||||
(void) execle (SHELL, "sh", "-", file, (char *)0, envp);
|
||||
execle (SHELL, "sh", "-", file, (char *)0, envp);
|
||||
err = errno;
|
||||
}
|
||||
|
||||
@@ -95,7 +94,7 @@ int shell (const char *file, /*@null@*/const char *arg, char *const envp[])
|
||||
* how to execute this stupid shell, so I might as well give
|
||||
* up in disgust ...
|
||||
*/
|
||||
(void) snprintf (arg0, sizeof arg0, _("Cannot execute %s"), file);
|
||||
snprintf (arg0, sizeof arg0, _("Cannot execute %s"), file);
|
||||
errno = err;
|
||||
perror (arg0);
|
||||
return err;
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ident "$Id$"
|
||||
|
||||
#include "defines.h"
|
||||
@@ -46,7 +44,6 @@
|
||||
#ifndef USE_GETDATE
|
||||
#define USE_GETDATE 1
|
||||
#endif
|
||||
|
||||
#if USE_GETDATE
|
||||
#include "getdate.h"
|
||||
/*
|
||||
@@ -66,8 +63,6 @@
|
||||
long strtoday (const char *str)
|
||||
{
|
||||
time_t t;
|
||||
bool isnum = true;
|
||||
const char *s = str;
|
||||
|
||||
/*
|
||||
* get_date() interprets an empty string as the current date,
|
||||
@@ -78,32 +73,9 @@ long strtoday (const char *str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If a numerical value is provided, this is already a number of
|
||||
* days since EPOCH.
|
||||
*/
|
||||
if ('-' == *s) {
|
||||
s++;
|
||||
}
|
||||
while (' ' == *s) {
|
||||
s++;
|
||||
}
|
||||
while (isnum && ('\0' != *s)) {
|
||||
if (!isdigit (*s)) {
|
||||
isnum = false;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (isnum) {
|
||||
long retdate;
|
||||
if (getlong (str, &retdate) == 0) {
|
||||
return -2;
|
||||
}
|
||||
return retdate;
|
||||
}
|
||||
|
||||
t = get_date (str, NULL);
|
||||
t = get_date (str, (time_t *) 0);
|
||||
if ((time_t) - 1 == t) {
|
||||
return -2;
|
||||
return -1;
|
||||
}
|
||||
/* convert seconds to days since 1970-01-01 */
|
||||
return (long) (t + DAY / 2) / DAY;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
/*
|
||||
* subsystem - change to subsystem root
|
||||
*
|
||||
* A subsystem login is indicated by the presence of a "*" as
|
||||
* A subsystem login is indicated by the presense of a "*" as
|
||||
* the first character of the login shell. The given home
|
||||
* directory will be used as the root of a new filesystem which
|
||||
* the user is actually logged into.
|
||||
@@ -66,13 +66,11 @@ void subsystem (const struct passwd *pw)
|
||||
* must be able to change into it.
|
||||
*/
|
||||
|
||||
if ( (chdir (pw->pw_dir) != 0)
|
||||
|| (chroot (pw->pw_dir) != 0)) {
|
||||
(void) printf (_("Can't change root directory to '%s'\n"),
|
||||
pw->pw_dir);
|
||||
if (chdir (pw->pw_dir) || chroot (pw->pw_dir)) {
|
||||
printf (_("Can't change root directory to '%s'\n"),
|
||||
pw->pw_dir);
|
||||
SYSLOG ((LOG_WARN, NO_SUBROOT2, pw->pw_dir, pw->pw_name));
|
||||
closelog ();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1992, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
||||
* Copyright (c) 2001 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2010, Nicolas François
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -47,7 +47,7 @@
|
||||
*/
|
||||
void sulog (const char *tty, bool success, const char *oldname, const char *name)
|
||||
{
|
||||
const char *sulog_file;
|
||||
char *sulog_file;
|
||||
time_t now;
|
||||
struct tm *tm;
|
||||
FILE *fp;
|
||||
@@ -62,10 +62,8 @@ void sulog (const char *tty, bool success, const char *oldname, const char *name
|
||||
"FAILED su for %s by %s",name,oldname));
|
||||
}
|
||||
|
||||
sulog_file = getdef_str ("SULOG_FILE");
|
||||
if (NULL == sulog_file) {
|
||||
if ((sulog_file = getdef_str ("SULOG_FILE")) == (char *) 0)
|
||||
return;
|
||||
}
|
||||
|
||||
oldgid = getgid ();
|
||||
oldmask = umask (077);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Eric Biederman
|
||||
* Copyright (c) 2009 , Dan Walsh <dwalsh@redhat.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,19 +26,47 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#ifndef _IDMAPPING_H_
|
||||
#define _IDMAPPING_H_
|
||||
#ident "$Id$"
|
||||
|
||||
struct map_range {
|
||||
unsigned long upper; /* first ID inside the namespace */
|
||||
unsigned long lower; /* first ID outside the namespace */
|
||||
unsigned long count; /* Length of the inside and outside ranges */
|
||||
};
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include "prototypes.h"
|
||||
#include "defines.h"
|
||||
|
||||
extern struct map_range *get_map_ranges(int ranges, int argc, char **argv);
|
||||
extern void write_mapping(int proc_dir_fd, int ranges,
|
||||
struct map_range *mappings, const char *map_file);
|
||||
int safe_system (const char *command,
|
||||
const char *argv[],
|
||||
const char *env[],
|
||||
int ignore_stderr)
|
||||
{
|
||||
int status = -1;
|
||||
int fd;
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* _ID_MAPPING_H_ */
|
||||
if (pid) { /* Parent */
|
||||
if (waitpid (pid, &status, 0) > 0) {
|
||||
return status;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open ("/dev/null", O_RDWR);
|
||||
/* Child */
|
||||
dup2 (fd, 0); // Close Stdin
|
||||
if (ignore_stderr) {
|
||||
dup2 (fd, 2); // Close Stderr
|
||||
}
|
||||
|
||||
execve (command, (char *const *) argv, (char *const *) env);
|
||||
fprintf (stderr, _("Failed to exec '%s'\n"), argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1989 - 1994, Julianne Frances Haugh
|
||||
* Copyright (c) 1996 - 1997, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2008 - 2010, Nicolas François
|
||||
* Copyright (c) 2008 , Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -45,10 +45,10 @@ void ttytype (const char *line)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[BUFSIZ];
|
||||
const char *typefile;
|
||||
char *typefile;
|
||||
char *cp;
|
||||
char type[1024] = "";
|
||||
char port[1024];
|
||||
char type[BUFSIZ];
|
||||
char port[BUFSIZ];
|
||||
|
||||
if (getenv ("TERM") != NULL) {
|
||||
return;
|
||||
@@ -76,12 +76,12 @@ void ttytype (const char *line)
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if ( (sscanf (buf, "%1023s %1023s", type, port) == 2)
|
||||
&& (strcmp (line, port) == 0)) {
|
||||
if ((sscanf (buf, "%s %s", type, port) == 2) &&
|
||||
(strcmp (line, port) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((feof (fp) == 0) && (ferror (fp) == 0) && (type[0] != '\0')) {
|
||||
if ((feof (fp) == 0) && (ferror (fp) == 0)) {
|
||||
addenv ("TERM", type);
|
||||
}
|
||||
|
||||
|
||||
21
libmisc/tz.c
21
libmisc/tz.c
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 1991 - 1994, Chip Rosenthal
|
||||
* Copyright (c) 1996 - 1998, Marek Michałkiewicz
|
||||
* Copyright (c) 2003 - 2005, Tomasz Kłoczko
|
||||
* Copyright (c) 2007 - 2010, Nicolas François
|
||||
* Copyright (c) 2007 - 2008, Nicolas François
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,28 +49,23 @@
|
||||
* tz() determines the name of the local timezone by reading the
|
||||
* contents of the file named by ``fname''.
|
||||
*/
|
||||
/*@observer@*/const char *tz (const char *fname)
|
||||
char *tz (const char *fname)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
FILE *fp = 0;
|
||||
static char tzbuf[BUFSIZ];
|
||||
const char *def_tz = "TZ=CST6CDT";
|
||||
|
||||
fp = fopen (fname, "r");
|
||||
if ( (NULL == fp)
|
||||
|| (fgets (tzbuf, (int) sizeof (tzbuf), fp) == NULL)) {
|
||||
def_tz = getdef_str ("ENV_TZ");
|
||||
if ((NULL == def_tz) || ('/' == def_tz[0])) {
|
||||
if ((fp = fopen (fname, "r")) == NULL ||
|
||||
fgets (tzbuf, (int) sizeof (tzbuf), fp) == NULL) {
|
||||
if (!(def_tz = getdef_str ("ENV_TZ")) || def_tz[0] == '/')
|
||||
def_tz = "TZ=CST6CDT";
|
||||
}
|
||||
|
||||
strcpy (tzbuf, def_tz);
|
||||
} else {
|
||||
} else
|
||||
tzbuf[strlen (tzbuf) - 1] = '\0';
|
||||
}
|
||||
|
||||
if (NULL != fp) {
|
||||
if (fp)
|
||||
(void) fclose (fp);
|
||||
}
|
||||
|
||||
return tzbuf;
|
||||
}
|
||||
|
||||
@@ -38,16 +38,12 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
#ifdef ENABLE_SUBIDS
|
||||
#include "subordinateio.h"
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
#ifdef __linux__
|
||||
static int check_status (const char *name, const char *sname, uid_t uid);
|
||||
static int user_busy_processes (const char *name, uid_t uid);
|
||||
static int check_status (const char *sname, uid_t uid);
|
||||
static int user_busy_processes (uid_t uid);
|
||||
#else /* !__linux__ */
|
||||
static int user_busy_utmp (const char *name);
|
||||
#endif /* !__linux__ */
|
||||
@@ -62,7 +58,7 @@ int user_busy (const char *name, uid_t uid)
|
||||
*/
|
||||
#ifdef __linux__
|
||||
/* On Linux, directly parse /proc */
|
||||
return user_busy_processes (name, uid);
|
||||
return user_busy_processes (uid);
|
||||
#else /* !__linux__ */
|
||||
/* If we cannot rely on /proc, check is there is a record in utmp
|
||||
* indicating that the user is still logged in */
|
||||
@@ -95,9 +91,6 @@ static int user_busy_utmp (const char *name)
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf (stderr,
|
||||
_("%s: user %s is currently logged in\n"),
|
||||
Prog, name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -106,7 +99,7 @@ static int user_busy_utmp (const char *name)
|
||||
#endif /* !__linux__ */
|
||||
|
||||
#ifdef __linux__
|
||||
static int check_status (const char *name, const char *sname, uid_t uid)
|
||||
static int check_status (const char *sname, uid_t uid)
|
||||
{
|
||||
/* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
|
||||
char status[40];
|
||||
@@ -129,13 +122,7 @@ static int check_status (const char *name, const char *sname, uid_t uid)
|
||||
&ruid, &euid, &suid) == 3) {
|
||||
if ( (ruid == (unsigned long) uid)
|
||||
|| (euid == (unsigned long) uid)
|
||||
|| (suid == (unsigned long) uid)
|
||||
#ifdef ENABLE_SUBIDS
|
||||
|| have_sub_uids(name, ruid, 1)
|
||||
|| have_sub_uids(name, euid, 1)
|
||||
|| have_sub_uids(name, suid, 1)
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
) {
|
||||
|| (suid == (unsigned long) uid)) {
|
||||
(void) fclose (sfile);
|
||||
return 1;
|
||||
}
|
||||
@@ -150,7 +137,7 @@ static int check_status (const char *name, const char *sname, uid_t uid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int user_busy_processes (const char *name, uid_t uid)
|
||||
static int user_busy_processes (uid_t uid)
|
||||
{
|
||||
DIR *proc;
|
||||
struct dirent *ent;
|
||||
@@ -163,10 +150,6 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
struct stat sbroot;
|
||||
struct stat sbroot_process;
|
||||
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_open (O_RDONLY);
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
|
||||
proc = opendir ("/proc");
|
||||
if (proc == NULL) {
|
||||
perror ("opendir /proc");
|
||||
@@ -175,9 +158,6 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
if (stat ("/", &sbroot) != 0) {
|
||||
perror ("stat (\"/\")");
|
||||
(void) closedir (proc);
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_close();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -213,14 +193,8 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check_status (name, tmp_d_name, uid) != 0) {
|
||||
if (check_status (tmp_d_name, uid) != 0) {
|
||||
(void) closedir (proc);
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_close();
|
||||
#endif
|
||||
fprintf (stderr,
|
||||
_("%s: user %s is currently used by process %d\n"),
|
||||
Prog, name, pid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -236,14 +210,8 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
if (tid == pid) {
|
||||
continue;
|
||||
}
|
||||
if (check_status (name, task_path+6, uid) != 0) {
|
||||
if (check_status (task_path+6, uid) != 0) {
|
||||
(void) closedir (proc);
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_close();
|
||||
#endif
|
||||
fprintf (stderr,
|
||||
_("%s: user %s is currently used by process %d\n"),
|
||||
Prog, name, pid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -254,9 +222,6 @@ static int user_busy_processes (const char *name, uid_t uid)
|
||||
}
|
||||
|
||||
(void) closedir (proc);
|
||||
#ifdef ENABLE_SUBIDS
|
||||
sub_uid_close();
|
||||
#endif /* ENABLE_SUBIDS */
|
||||
return 0;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
@@ -42,8 +42,6 @@
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -73,7 +71,7 @@ static bool is_my_tty (const char *tty)
|
||||
}
|
||||
}
|
||||
|
||||
if ('\0' == tmptty[0]) {
|
||||
if (NULL == tmptty) {
|
||||
(void) puts (_("Unable to determine your tty name."));
|
||||
exit (EXIT_FAILURE);
|
||||
} else if (strncmp (tty, tmptty, sizeof (tmptty)) != 0) {
|
||||
@@ -131,7 +129,6 @@ static bool is_my_tty (const char *tty)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef USE_PAM
|
||||
/*
|
||||
* Some systems already have updwtmp() and possibly updwtmpx(). Others
|
||||
* don't, so we re-implement these functions if necessary.
|
||||
@@ -163,7 +160,6 @@ static void updwtmpx (const char *filename, const struct utmpx *utx)
|
||||
}
|
||||
#endif /* ! HAVE_UPDWTMPX */
|
||||
#endif /* ! USE_UTMPX */
|
||||
#endif /* ! USE_PAM */
|
||||
|
||||
|
||||
/*
|
||||
@@ -204,6 +200,7 @@ static void updwtmpx (const char *filename, const struct utmpx *utx)
|
||||
strcpy (hostname, host);
|
||||
#ifdef HAVE_STRUCT_UTMP_UT_HOST
|
||||
} else if ( (NULL != ut)
|
||||
&& (NULL != ut->ut_host)
|
||||
&& ('\0' != ut->ut_host[0])) {
|
||||
hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
|
||||
strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
|
||||
@@ -317,10 +314,7 @@ int setutmp (struct utmp *ut)
|
||||
}
|
||||
endutent ();
|
||||
|
||||
#ifndef USE_PAM
|
||||
/* This is done by pam_lastlog */
|
||||
updwtmp (_WTMP_FILE, ut);
|
||||
#endif /* ! USE_PAM */
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -453,10 +447,7 @@ int setutmpx (struct utmpx *utx)
|
||||
}
|
||||
endutxent ();
|
||||
|
||||
#ifndef USE_PAM
|
||||
/* This is done by pam_lastlog */
|
||||
updwtmpx (_WTMP_FILE "x", utx);
|
||||
#endif /* ! USE_PAM */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
bool valid (const char *password, const struct passwd *ent)
|
||||
{
|
||||
const char *encrypted;
|
||||
/*@observer@*/const char *salt;
|
||||
const char *salt;
|
||||
|
||||
/*
|
||||
* Start with blank or empty password entries. Always encrypt
|
||||
@@ -95,7 +95,6 @@ bool valid (const char *password, const struct passwd *ent)
|
||||
*/
|
||||
|
||||
if ( (NULL != ent->pw_name)
|
||||
&& (NULL != encrypted)
|
||||
&& (strcmp (encrypted, ent->pw_passwd) == 0)) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
errno = 0;
|
||||
status = REENTRANT_NAME(ARG_NAME, result, buffer,
|
||||
length, &resbuf);
|
||||
if ((0 == status) && (resbuf == result)) {
|
||||
if ((0 ==status) && (resbuf == result)) {
|
||||
/* Build a result structure that can be freed by
|
||||
* the shadow *_free functions. */
|
||||
LOOKUP_TYPE *ret_result = DUP_FUNCTION(result);
|
||||
|
||||
@@ -44,25 +44,22 @@
|
||||
#ident "$Id$"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "defines.h"
|
||||
#include "prototypes.h"
|
||||
|
||||
/*@maynotreturn@*/ /*@only@*//*@out@*//*@notnull@*/char *xmalloc (size_t size)
|
||||
char *xmalloc (size_t size)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr = (char *) malloc (size);
|
||||
if (NULL == ptr) {
|
||||
(void) fprintf (stderr,
|
||||
_("%s: failed to allocate memory: %s\n"),
|
||||
Prog, strerror (errno));
|
||||
if ((NULL == ptr) && (0 != size)) {
|
||||
fprintf (stderr, _("malloc(%d) failed\n"), (int) size);
|
||||
exit (13);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*@maynotreturn@*/ /*@only@*//*@notnull@*/char *xstrdup (const char *str)
|
||||
char *xstrdup (const char *str)
|
||||
{
|
||||
return strcpy (xmalloc (strlen (str) + 1), str);
|
||||
}
|
||||
|
||||
1
man/.gitignore
vendored
1
man/.gitignore
vendored
@@ -1,6 +1,5 @@
|
||||
.xml2po.mo
|
||||
config.xml
|
||||
generate_mans.deps
|
||||
|
||||
*.[0-9]
|
||||
|
||||
|
||||
129
man/Makefile.am
129
man/Makefile.am
@@ -1,73 +1,63 @@
|
||||
|
||||
# subdirectories for translated manual pages
|
||||
if USE_NLS
|
||||
SUBDIRS = po cs da de es fi fr hu id it ja ko pl pt_BR ru sv tr zh_CN zh_TW
|
||||
SUBDIRS = po cs de es fi fr hu id it ja ko pl pt_BR ru sv tr zh_CN zh_TW
|
||||
else
|
||||
SUBDIRS =
|
||||
endif
|
||||
|
||||
man_MANS = \
|
||||
man1/chage.1 \
|
||||
man1/chfn.1 \
|
||||
man8/chgpasswd.8 \
|
||||
man8/chpasswd.8 \
|
||||
man1/chsh.1 \
|
||||
man1/expiry.1 \
|
||||
man5/faillog.5 \
|
||||
man8/faillog.8 \
|
||||
man3/getspnam.3 \
|
||||
man1/gpasswd.1 \
|
||||
man8/groupadd.8 \
|
||||
man8/groupdel.8 \
|
||||
man8/groupmems.8 \
|
||||
man8/groupmod.8 \
|
||||
man1/groups.1 \
|
||||
man8/grpck.8 \
|
||||
man8/grpconv.8 \
|
||||
man8/grpunconv.8 \
|
||||
man5/gshadow.5 \
|
||||
man8/lastlog.8 \
|
||||
man1/login.1 \
|
||||
man5/login.defs.5 \
|
||||
man8/logoutd.8 \
|
||||
man1/newgrp.1 \
|
||||
man8/newusers.8 \
|
||||
man8/nologin.8 \
|
||||
man1/passwd.1 \
|
||||
man5/passwd.5 \
|
||||
man8/pwck.8 \
|
||||
man8/pwconv.8 \
|
||||
man8/pwunconv.8 \
|
||||
man1/sg.1 \
|
||||
man3/shadow.3 \
|
||||
man5/shadow.5 \
|
||||
man1/su.1 \
|
||||
man5/suauth.5 \
|
||||
man8/useradd.8 \
|
||||
man8/userdel.8 \
|
||||
man8/usermod.8 \
|
||||
man8/vigr.8 \
|
||||
man8/vipw.8
|
||||
chage.1 \
|
||||
chfn.1 \
|
||||
chgpasswd.8 \
|
||||
chpasswd.8 \
|
||||
chsh.1 \
|
||||
expiry.1 \
|
||||
faillog.5 \
|
||||
faillog.8 \
|
||||
getspnam.3 \
|
||||
gpasswd.1 \
|
||||
groupadd.8 \
|
||||
groupdel.8 \
|
||||
groupmems.8 \
|
||||
groupmod.8 \
|
||||
groups.1 \
|
||||
grpck.8 \
|
||||
grpconv.8 \
|
||||
grpunconv.8 \
|
||||
gshadow.5 \
|
||||
lastlog.8 \
|
||||
login.1 \
|
||||
login.defs.5 \
|
||||
logoutd.8 \
|
||||
newgrp.1 \
|
||||
newusers.8 \
|
||||
nologin.8 \
|
||||
passwd.1 \
|
||||
passwd.5 \
|
||||
pwck.8 \
|
||||
pwconv.8 \
|
||||
pwunconv.8 \
|
||||
sg.1 \
|
||||
shadow.3 \
|
||||
shadow.5 \
|
||||
su.1 \
|
||||
suauth.5 \
|
||||
useradd.8 \
|
||||
userdel.8 \
|
||||
usermod.8 \
|
||||
vigr.8 \
|
||||
vipw.8
|
||||
|
||||
man_nopam = \
|
||||
man5/limits.5 \
|
||||
man5/login.access.5 \
|
||||
man5/porttime.5
|
||||
limits.5 \
|
||||
login.access.5 \
|
||||
porttime.5
|
||||
|
||||
if !USE_PAM
|
||||
man_MANS += $(man_nopam)
|
||||
endif
|
||||
|
||||
man_subids = \
|
||||
man1/newgidmap.1 \
|
||||
man1/newuidmap.1 \
|
||||
man5/subgid.5 \
|
||||
man5/subuid.5
|
||||
|
||||
if ENABLE_SUBIDS
|
||||
man_MANS += $(man_subids)
|
||||
endif
|
||||
|
||||
man_XMANS = \
|
||||
chage.1.xml \
|
||||
chfn.1.xml \
|
||||
@@ -91,9 +81,7 @@ man_XMANS = \
|
||||
login.access.5.xml \
|
||||
login.defs.5.xml \
|
||||
logoutd.8.xml \
|
||||
newgidmap.1.xml \
|
||||
newgrp.1.xml \
|
||||
newuidmap.1.xml \
|
||||
newusers.8.xml \
|
||||
nologin.8.xml \
|
||||
passwd.1.xml \
|
||||
@@ -106,8 +94,6 @@ man_XMANS = \
|
||||
sg.1.xml \
|
||||
su.1.xml \
|
||||
suauth.5.xml \
|
||||
subgid.5.xml \
|
||||
subuid.5.xml \
|
||||
useradd.8.xml \
|
||||
userdel.8.xml \
|
||||
usermod.8.xml \
|
||||
@@ -163,8 +149,6 @@ login_defs_v = \
|
||||
SU_WHEEL_ONLY.xml \
|
||||
SYSLOG_SG_ENAB.xml \
|
||||
SYSLOG_SU_ENAB.xml \
|
||||
TCB_AUTH_GROUP.xml \
|
||||
TCB_SYMLINKS.xml \
|
||||
TTYGROUP.xml \
|
||||
TTYTYPE_FILE.xml \
|
||||
UID_MAX.xml \
|
||||
@@ -172,9 +156,6 @@ login_defs_v = \
|
||||
UMASK.xml \
|
||||
USERDEL_CMD.xml \
|
||||
USERGROUPS_ENAB.xml \
|
||||
USE_TCB.xml \
|
||||
SUB_GID_COUNT.xml \
|
||||
SUB_UID_COUNT.xml \
|
||||
SYS_GID_MAX.xml \
|
||||
SYS_UID_MAX.xml
|
||||
|
||||
@@ -182,32 +163,24 @@ EXTRA_DIST = \
|
||||
$(man_MANS) \
|
||||
$(man_XMANS) \
|
||||
$(addprefix login.defs.d/,$(login_defs_v)) \
|
||||
man1/id.1 \
|
||||
$(man_nopam) \
|
||||
id.1 \
|
||||
id.1.xml \
|
||||
man8/sulogin.8 \
|
||||
sulogin.8 \
|
||||
sulogin.8.xml \
|
||||
generate_mans.mak \
|
||||
generate_translations.mak
|
||||
|
||||
if USE_PAM
|
||||
EXTRA_DIST += $(man_nopam)
|
||||
endif
|
||||
|
||||
if !ENABLE_SUBIDS
|
||||
EXTRA_DIST += $(man_subids)
|
||||
endif
|
||||
|
||||
generate_mans.deps: *.xml
|
||||
echo "# This file is generated" > $@
|
||||
awk 'BEGIN{FS="\"";} /^<!ENTITY .* * SYSTEM ".*">$$/{ f=FILENAME; sub(/.xml/,"",f); print "man" substr(f, length (f)) "/" f ": " $$2 }' $(man_XMANS) >> $@
|
||||
awk 'BEGIN{FS="\"";} /^<!ENTITY .* * SYSTEM ".*">$$/{ f=FILENAME; sub(/.xml/,"",f); print f ": " $$2 }' $(man_XMANS) > $@
|
||||
|
||||
if ENABLE_REGENERATE_MAN
|
||||
|
||||
@ENABLE_REGENERATE_MAN_TRUE@include generate_mans.deps
|
||||
include generate_mans.deps
|
||||
|
||||
include generate_mans.mak
|
||||
|
||||
CLEANFILES = $(man_MANS) man1/id.1 man8/sulogin.8
|
||||
CLEANFILES = $(man_MANS)
|
||||
|
||||
else
|
||||
$(man_MANS):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
Copyright (c) 2007 - 2011, Nicolas François
|
||||
Copyright (c) 2007 - 2008, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,38 +28,12 @@
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY USE_TCB SYSTEM "login.defs.d/USE_TCB.xml">
|
||||
<!-- SHADOW-CONFIG-HERE -->
|
||||
]>
|
||||
<refentry id='chage.1'>
|
||||
<!-- $Id$ -->
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Julianne Frances</firstname>
|
||||
<surname>Haugh</surname>
|
||||
<contrib>Creation, 1990</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Kłoczko</surname>
|
||||
<email>kloczek@pld.org.pl</email>
|
||||
<contrib>shadow-utils maintainer, 2000 - 2007</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Nicolas</firstname>
|
||||
<surname>François</surname>
|
||||
<email>nicolas.francois@centraliens.net</email>
|
||||
<contrib>shadow-utils maintainer, 2007 - now</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>chage</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="sectdesc">User Commands</refmiscinfo>
|
||||
<refmiscinfo class="source">shadow-utils</refmiscinfo>
|
||||
<refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv id='name'>
|
||||
<refname>chage</refname>
|
||||
@@ -71,8 +45,8 @@
|
||||
<arg choice='opt'>
|
||||
<replaceable>options</replaceable>
|
||||
</arg>
|
||||
<arg choice='plain'>
|
||||
<replaceable>LOGIN</replaceable>
|
||||
<arg choice='opt'>
|
||||
<replaceable>LOGIN</replaceable>
|
||||
</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
@@ -95,7 +69,7 @@
|
||||
<variablelist remap='IP'>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-d</option>, <option>--lastday</option> <replaceable>LAST_DAY</replaceable>
|
||||
<option>-d</option>, <option>--lastday</option> <replaceable>LAST_DAY</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -107,7 +81,7 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-E</option>, <option>--expiredate</option> <replaceable>EXPIRE_DATE</replaceable>
|
||||
<option>-E</option>, <option>--expiredate</option> <replaceable>EXPIRE_DATE</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -133,7 +107,7 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-I</option>, <option>--inactive</option> <replaceable>INACTIVE</replaceable>
|
||||
<option>-I</option>, <option>--inactive</option> <replaceable>INACTIVE</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -162,7 +136,7 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-m</option>, <option>--mindays</option> <replaceable>MIN_DAYS</replaceable>
|
||||
<option>-m</option>, <option>--mindays</option> <replaceable>MIN_DAYS</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -174,7 +148,7 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-M</option>, <option>--maxdays</option> <replaceable>MAX_DAYS</replaceable>
|
||||
<option>-M</option>, <option>--maxdays</option> <replaceable>MAX_DAYS</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -195,19 +169,7 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-R</option>, <option>--root</option> <replaceable>CHROOT_DIR</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Apply changes in the <replaceable>CHROOT_DIR</replaceable>
|
||||
directory and use the configuration files from the
|
||||
<replaceable>CHROOT_DIR</replaceable> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-W</option>, <option>--warndays</option> <replaceable>WARN_DAYS</replaceable>
|
||||
<option>-W</option>, <option>--warndays</option> <replaceable>WARN_DAYS</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -240,18 +202,6 @@
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='configuration'>
|
||||
<title>CONFIGURATION</title>
|
||||
<para>
|
||||
The following configuration variables in
|
||||
<filename>/etc/login.defs</filename> change the behavior of this
|
||||
tool:
|
||||
</para>
|
||||
<variablelist>
|
||||
&USE_TCB;
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='files'>
|
||||
<title>FILES</title>
|
||||
<variablelist>
|
||||
|
||||
112
man/chfn.1.xml
112
man/chfn.1.xml
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 1990 - 1994, Julianne Frances Haugh
|
||||
Copyright (c) 2007 - 2011, Nicolas François
|
||||
Copyright (c) 2007 - 2008, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -33,35 +33,14 @@
|
||||
<!ENTITY CHFN_AUTH SYSTEM "login.defs.d/CHFN_AUTH.xml">
|
||||
<!ENTITY CHFN_RESTRICT SYSTEM "login.defs.d/CHFN_RESTRICT.xml">
|
||||
<!ENTITY LOGIN_STRING SYSTEM "login.defs.d/LOGIN_STRING.xml">
|
||||
<!-- SHADOW-CONFIG-HERE -->
|
||||
]>
|
||||
|
||||
<refentry id='chfn.1'>
|
||||
<!-- $Id$ -->
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Julianne Frances</firstname>
|
||||
<surname>Haugh</surname>
|
||||
<contrib>Creation, 1990</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Kłoczko</surname>
|
||||
<email>kloczek@pld.org.pl</email>
|
||||
<contrib>shadow-utils maintainer, 2000 - 2007</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Nicolas</firstname>
|
||||
<surname>François</surname>
|
||||
<email>nicolas.francois@centraliens.net</email>
|
||||
<contrib>shadow-utils maintainer, 2007 - now</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>chfn</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="sectdesc">User Commands</refmiscinfo>
|
||||
<refmiscinfo class="source">shadow-utils</refmiscinfo>
|
||||
<refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv id='name'>
|
||||
<refname>chfn</refname>
|
||||
@@ -71,12 +50,12 @@
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis>
|
||||
<command>chfn</command>
|
||||
<arg choice='opt'>
|
||||
<replaceable>options</replaceable>
|
||||
</arg>
|
||||
<arg choice='opt'>
|
||||
<replaceable>LOGIN</replaceable>
|
||||
</arg>
|
||||
<arg choice='opt'>-f <replaceable>full_name</replaceable></arg>
|
||||
<arg choice='opt'>-r <replaceable>room_no</replaceable></arg>
|
||||
<arg choice='opt'>-w <replaceable>work_ph</replaceable></arg>
|
||||
<arg choice='opt'>-h <replaceable>home_ph</replaceable></arg>
|
||||
<arg choice='opt'>-o <replaceable>other</replaceable></arg>
|
||||
<arg choice='opt'><replaceable>user</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@@ -84,7 +63,7 @@
|
||||
<title>DESCRIPTION</title>
|
||||
<para>
|
||||
The <command>chfn</command> command changes user fullname,
|
||||
office room number, office phone number, and home phone number information
|
||||
office number, office extension, and home phone number information
|
||||
for a user's account. This information is typically printed by
|
||||
<citerefentry><refentrytitle>finger</refentrytitle><manvolnum>1</manvolnum>
|
||||
</citerefentry> and similar programs. A normal user may only change
|
||||
@@ -105,79 +84,6 @@
|
||||
store accounting information used by other applications.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='options'>
|
||||
<title>OPTIONS</title>
|
||||
<para>
|
||||
The options which apply to the <command>chfn</command> command are:
|
||||
</para>
|
||||
<variablelist remap='IP'>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-f</option>, <option>--full-name</option> <replaceable>FULL_NAME</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Change the user's full name.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-h</option>, <option>--home-phone</option> <replaceable>HOME_PHONE</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Change the user's home phone number.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-o</option>, <option>--other</option> <replaceable>OTHER</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Change the user's other GECOS information. This field is used to
|
||||
store accounting information used by other applications, and can
|
||||
be changed only by a superuser.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-r</option>, <option>--room</option> <replaceable>ROOM_NUMBER</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Change the user's room number.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-R</option>, <option>--root</option> <replaceable>CHROOT_DIR</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Apply changes in the <replaceable>CHROOT_DIR</replaceable>
|
||||
directory and use the configuration files from the
|
||||
<replaceable>CHROOT_DIR</replaceable> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-u</option>, <option>--help</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Display help message and exit.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-w</option>, <option>--work-phone</option> <replaceable>WORK_PHONE</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Change the user's office phone number.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
If none of the options are selected, <command>chfn</command>
|
||||
operates in an interactive fashion, prompting the user with the
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 2006 , Tomasz Kłoczko
|
||||
Copyright (c) 2007 - 2011, Nicolas François
|
||||
Copyright (c) 2007 - 2009, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,31 +34,14 @@
|
||||
<!ENTITY MAX_MEMBERS_PER_GROUP SYSTEM "login.defs.d/MAX_MEMBERS_PER_GROUP.xml">
|
||||
<!ENTITY MD5_CRYPT_ENAB SYSTEM "login.defs.d/MD5_CRYPT_ENAB.xml">
|
||||
<!ENTITY SHA_CRYPT_MIN_ROUNDS SYSTEM "login.defs.d/SHA_CRYPT_MIN_ROUNDS.xml">
|
||||
<!-- SHADOW-CONFIG-HERE -->
|
||||
]>
|
||||
|
||||
<refentry id='chgpasswd.8'>
|
||||
<!-- $Id$ -->
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Kłoczko</surname>
|
||||
<email>kloczek@pld.org.pl</email>
|
||||
<contrib>Creation, 2006</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Nicolas</firstname>
|
||||
<surname>François</surname>
|
||||
<email>nicolas.francois@centraliens.net</email>
|
||||
<contrib>shadow-utils maintainer, 2007 - now</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>chgpasswd</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="sectdesc">System Management Commands</refmiscinfo>
|
||||
<refmiscinfo class="source">shadow-utils</refmiscinfo>
|
||||
<refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv id='name'>
|
||||
<refname>chgpasswd</refname>
|
||||
@@ -91,8 +74,8 @@
|
||||
</para>
|
||||
<para>
|
||||
The default encryption algorithm can be defined for the system with
|
||||
the <option>ENCRYPT_METHOD</option> variable of <filename>/etc/login.defs</filename>,
|
||||
and can be overwritten with the <option>-e</option>,
|
||||
the ENCRYPT_METHOD variable of <filename>/etc/login.defs</filename>,
|
||||
and can be overwiten with the <option>-e</option>,
|
||||
<option>-m</option>, or <option>-c</option> options.
|
||||
</para>
|
||||
<para>
|
||||
@@ -142,18 +125,6 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-R</option>, <option>--root</option> <replaceable>CHROOT_DIR</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Apply changes in the <replaceable>CHROOT_DIR</replaceable>
|
||||
directory and use the configuration files from the
|
||||
<replaceable>CHROOT_DIR</replaceable> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry condition="sha_crypt">
|
||||
<term><option>-s</option>, <option>--sha-rounds</option></term>
|
||||
<listitem>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 1991 , Julianne Frances Haugh
|
||||
Copyright (c) 2007 - 2011, Nicolas François
|
||||
Copyright (c) 2007 - 2009, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -33,36 +33,14 @@
|
||||
<!ENTITY ENCRYPT_METHOD SYSTEM "login.defs.d/ENCRYPT_METHOD.xml">
|
||||
<!ENTITY MD5_CRYPT_ENAB SYSTEM "login.defs.d/MD5_CRYPT_ENAB.xml">
|
||||
<!ENTITY SHA_CRYPT_MIN_ROUNDS SYSTEM "login.defs.d/SHA_CRYPT_MIN_ROUNDS.xml">
|
||||
<!-- SHADOW-CONFIG-HERE -->
|
||||
]>
|
||||
|
||||
<refentry id='chpasswd.8'>
|
||||
<!-- $Id$ -->
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Julianne Frances</firstname>
|
||||
<surname>Haugh</surname>
|
||||
<contrib>Creation, 1991</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Kłoczko</surname>
|
||||
<email>kloczek@pld.org.pl</email>
|
||||
<contrib>shadow-utils maintainer, 2000 - 2007</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Nicolas</firstname>
|
||||
<surname>François</surname>
|
||||
<email>nicolas.francois@centraliens.net</email>
|
||||
<contrib>shadow-utils maintainer, 2007 - now</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>chpasswd</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="sectdesc">System Management Commands</refmiscinfo>
|
||||
<refmiscinfo class="source">shadow-utils</refmiscinfo>
|
||||
<refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv id='name'>
|
||||
<refname>chpasswd</refname>
|
||||
@@ -89,37 +67,38 @@
|
||||
<emphasis remap='I'>user_name</emphasis>:<emphasis
|
||||
remap='I'>password</emphasis>
|
||||
</para>
|
||||
<refsect2 condition="no_pam">
|
||||
<para>
|
||||
By default the passwords must be supplied in clear-text, and are
|
||||
By default the supplied password must be in clear-text, and is
|
||||
encrypted by <command>chpasswd</command>.
|
||||
Also the password age will be updated, if present.
|
||||
</para>
|
||||
<para condition="no_pam">
|
||||
The default encryption algorithm can be defined for the system with
|
||||
the <option>ENCRYPT_METHOD</option> or
|
||||
<option>MD5_CRYPT_ENAB</option> variables of
|
||||
<filename>/etc/login.defs</filename>, and can be overwritten with the
|
||||
<option>-e</option>, <option>-m</option>, or <option>-c</option>
|
||||
options.
|
||||
</para>
|
||||
<para condition="pam">
|
||||
By default, passwords are encrypted by PAM, but (even if not
|
||||
recommended) you can select a different encryption method with the
|
||||
<option>-e</option>, <option>-m</option>, or <option>-c</option>
|
||||
options.
|
||||
</para>
|
||||
<para>
|
||||
<phrase condition="pam">Except when PAM is used to encrypt the
|
||||
passwords,</phrase> <command>chpasswd</command> first updates all the
|
||||
passwords in memory, and then commits all the changes to disk if no
|
||||
errors occurred for any user.
|
||||
</para>
|
||||
<para condition="pam">
|
||||
When PAM is used to encrypt the passwords (and update the passwords in
|
||||
the system database) then if a password cannot be updated
|
||||
<command>chpasswd</command> continues updating the passwords of the
|
||||
next users, and will return an error code on exit.
|
||||
The default encryption algorithm can be defined for the system with
|
||||
the ENCRYPT_METHOD variable of <filename>/etc/login.defs</filename>,
|
||||
and can be overwiten with the <option>-e</option>,
|
||||
<option>-m</option>, or <option>-c</option> options.
|
||||
</para>
|
||||
<para>
|
||||
<command>chpasswd</command> first update the password in memory,
|
||||
and then commit all the changes to disk if no errors occured for
|
||||
any users.
|
||||
</para>
|
||||
</refsect2>
|
||||
<refsect2 condition="pam">
|
||||
<para>
|
||||
The supplied passwords must be in clear-text.
|
||||
</para>
|
||||
<para>
|
||||
PAM is used to update the password in the system database
|
||||
according to the PAM chpasswd configuration.
|
||||
</para>
|
||||
<para>
|
||||
When <command>chpasswd</command> fails to update a password, it
|
||||
continues updating the passwords of the next users, and will
|
||||
return an error code on exit.
|
||||
</para>
|
||||
</refsect2>
|
||||
<para>
|
||||
This command is intended to be used in a large system environment
|
||||
where many accounts are created at a single time.
|
||||
@@ -132,11 +111,9 @@
|
||||
The options which apply to the <command>chpasswd</command> command
|
||||
are:
|
||||
</para>
|
||||
<variablelist remap='IP'>
|
||||
<variablelist remap='IP' condition="no_pam">
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-c</option>, <option>--crypt-method</option> <replaceable>METHOD</replaceable>
|
||||
</term>
|
||||
<term><option>-c</option>, <option>--crypt-method</option></term>
|
||||
<listitem>
|
||||
<para>Use the specified method to encrypt the passwords.</para>
|
||||
<para condition="no_sha_crypt">
|
||||
@@ -146,17 +123,6 @@
|
||||
The available methods are DES, MD5, NONE, and SHA256 or SHA512
|
||||
if your libc support these methods.
|
||||
</para>
|
||||
<para condition="pam">
|
||||
By default, PAM is used to encrypt the passwords.
|
||||
</para>
|
||||
<para condition="no_pam">
|
||||
By default (if none of the <option>-c</option>,
|
||||
<option>-m</option>, or <option>-e</option> options are
|
||||
specified), the encryption method is defined by the
|
||||
<option>ENCRYPT_METHOD</option> or
|
||||
<option>MD5_CRYPT_ENAB</option> variables of
|
||||
<filename>/etc/login.defs</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@@ -174,7 +140,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<variablelist remap='IP'>
|
||||
<variablelist remap='IP' condition="no_pam">
|
||||
<varlistentry>
|
||||
<term><option>-m</option>, <option>--md5</option></term>
|
||||
<listitem>
|
||||
@@ -184,22 +150,8 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-R</option>, <option>--root</option> <replaceable>CHROOT_DIR</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Apply changes in the <replaceable>CHROOT_DIR</replaceable>
|
||||
directory and use the configuration files from the
|
||||
<replaceable>CHROOT_DIR</replaceable> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry condition="sha_crypt">
|
||||
<term>
|
||||
<option>-s</option>, <option>--sha-rounds</option> <replaceable>ROUNDS</replaceable>
|
||||
</term>
|
||||
<term><option>-s</option>, <option>--sha-rounds</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the specified number of rounds to encrypt the passwords.
|
||||
@@ -218,8 +170,7 @@
|
||||
</para>
|
||||
<para>
|
||||
By default, the number of rounds is defined by the
|
||||
<option>SHA_CRYPT_MIN_ROUNDS</option> and
|
||||
<option>SHA_CRYPT_MAX_ROUNDS</option> variables in
|
||||
SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS variables in
|
||||
<filename>/etc/login.defs</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -233,20 +184,22 @@
|
||||
Remember to set permissions or umask to prevent readability of
|
||||
unencrypted files by other users.
|
||||
</para>
|
||||
<para condition="no_pam">
|
||||
You should make sure the passwords and the encryption method respect
|
||||
the system's password policy.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id='configuration'>
|
||||
<refsect1 id='configuration' condition="no_pam">
|
||||
<title>CONFIGURATION</title>
|
||||
<para>
|
||||
The following configuration variables in
|
||||
<filename>/etc/login.defs</filename> change the behavior of this
|
||||
tool:
|
||||
</para>
|
||||
<variablelist condition="no_pam">
|
||||
<variablelist>
|
||||
&ENCRYPT_METHOD;
|
||||
&MD5_CRYPT_ENAB;
|
||||
</variablelist>
|
||||
<variablelist>
|
||||
&SHA_CRYPT_MIN_ROUNDS; <!--documents also SHA_CRYPT_MAX_ROUNDS-->
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
@@ -254,19 +207,19 @@
|
||||
<refsect1 id='files'>
|
||||
<title>FILES</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<varlistentry condition="no_pam">
|
||||
<term><filename>/etc/passwd</filename></term>
|
||||
<listitem>
|
||||
<para>User account information.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<varlistentry condition="no_pam">
|
||||
<term><filename>/etc/shadow</filename></term>
|
||||
<listitem>
|
||||
<para>Secure user account information.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<varlistentry condition="no_pam">
|
||||
<term><filename>/etc/login.defs</filename></term>
|
||||
<listitem>
|
||||
<para>Shadow password suite configuration.</para>
|
||||
@@ -290,7 +243,7 @@
|
||||
<citerefentry>
|
||||
<refentrytitle>newusers</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<phrase>
|
||||
<phrase condition="no_pam">
|
||||
<citerefentry>
|
||||
<refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
|
||||
</citerefentry>,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 1990 , Julianne Frances Haugh
|
||||
Copyright (c) 2007 - 2011, Nicolas François
|
||||
Copyright (c) 2007 - 2008, Nicolas François
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,36 +32,14 @@
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY CHSH_AUTH SYSTEM "login.defs.d/CHSH_AUTH.xml">
|
||||
<!ENTITY LOGIN_STRING SYSTEM "login.defs.d/LOGIN_STRING.xml">
|
||||
<!-- SHADOW-CONFIG-HERE -->
|
||||
]>
|
||||
|
||||
<refentry id='chsh.1'>
|
||||
<!-- $Id$ -->
|
||||
<refentryinfo>
|
||||
<author>
|
||||
<firstname>Julianne Frances</firstname>
|
||||
<surname>Haugh</surname>
|
||||
<contrib>Creation, 1990</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Kłoczko</surname>
|
||||
<email>kloczek@pld.org.pl</email>
|
||||
<contrib>shadow-utils maintainer, 2000 - 2007</contrib>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Nicolas</firstname>
|
||||
<surname>François</surname>
|
||||
<email>nicolas.francois@centraliens.net</email>
|
||||
<contrib>shadow-utils maintainer, 2007 - now</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>chsh</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="sectdesc">User Commands</refmiscinfo>
|
||||
<refmiscinfo class="source">shadow-utils</refmiscinfo>
|
||||
<refmiscinfo class="version">&SHADOW_UTILS_VERSION;</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv id='name'>
|
||||
<refname>chsh</refname>
|
||||
@@ -85,7 +63,7 @@
|
||||
<para>
|
||||
The <command>chsh</command> command changes the user login shell.
|
||||
This determines the name of the user's initial login command. A normal
|
||||
user may only change the login shell for her own account; the
|
||||
user may only change the login shell for her own account, the
|
||||
superuser may change the login shell for any account.
|
||||
</para>
|
||||
|
||||
@@ -105,19 +83,7 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-R</option>, <option>--root</option> <replaceable>CHROOT_DIR</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Apply changes in the <replaceable>CHROOT_DIR</replaceable>
|
||||
directory and use the configuration files from the
|
||||
<replaceable>CHROOT_DIR</replaceable> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-s</option>, <option>--shell</option> <replaceable>SHELL</replaceable>
|
||||
<option>-s</option>, <option>--shell</option> <replaceable>SHELL</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
<!ENTITY GROUP_NAME_MAX_LENGTH '@GROUP_NAME_MAX_LENGTH@'>
|
||||
<!ENTITY SHADOW_UTILS_VERSION '@VERSION@'>
|
||||
|
||||
@@ -2,25 +2,24 @@
|
||||
mandir = @mandir@/cs
|
||||
|
||||
man_MANS = \
|
||||
man1/expiry.1 \
|
||||
man5/faillog.5 \
|
||||
man8/faillog.8 \
|
||||
man1/gpasswd.1 \
|
||||
man8/groupadd.8 \
|
||||
man8/groupdel.8 \
|
||||
man8/groupmod.8 \
|
||||
man1/groups.1 \
|
||||
man8/grpck.8 \
|
||||
man5/gshadow.5 \
|
||||
man8/lastlog.8 \
|
||||
man8/nologin.8 \
|
||||
man5/passwd.5 \
|
||||
man5/shadow.5 \
|
||||
man1/su.1 \
|
||||
man8/vipw.8
|
||||
expiry.1 \
|
||||
faillog.5 \
|
||||
faillog.8 \
|
||||
gpasswd.1 \
|
||||
groupadd.8 \
|
||||
groupdel.8 \
|
||||
groupmod.8 \
|
||||
groups.1 \
|
||||
grpck.8 \
|
||||
gshadow.5 \
|
||||
lastlog.8 \
|
||||
nologin.8 \
|
||||
passwd.5 \
|
||||
shadow.5 \
|
||||
su.1 \
|
||||
vipw.8
|
||||
|
||||
EXTRA_DIST = $(man_MANS) \
|
||||
man1/id.1 \
|
||||
man8/groupmems.8 \
|
||||
man8/logoutd.8
|
||||
|
||||
id.1 \
|
||||
groupmems.8 \
|
||||
logoutd.8
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user