summaryrefslogtreecommitdiff
path: root/patches/source/shadow
diff options
context:
space:
mode:
Diffstat (limited to 'patches/source/shadow')
-rw-r--r--patches/source/shadow/adduser440
-rw-r--r--patches/source/shadow/doinst.sh17
-rw-r--r--patches/source/shadow/login.defs387
-rw-r--r--patches/source/shadow/patches/README_PATCHES9
-rw-r--r--patches/source/shadow/patches/r3054.diff27
-rw-r--r--patches/source/shadow/patches/r3055.diff1515
-rw-r--r--patches/source/shadow/patches/r3060.diff116
-rw-r--r--patches/source/shadow/patches/r3062.diff139
-rw-r--r--patches/source/shadow/patches/r3096.diff27
-rw-r--r--patches/source/shadow/patches/r3160.diff239
-rw-r--r--patches/source/shadow/patches/r3194.diff15
-rw-r--r--patches/source/shadow/patches/r3299.diff12
-rwxr-xr-xpatches/source/shadow/shadow.SlackBuild165
-rw-r--r--patches/source/shadow/shadow.url1
-rw-r--r--patches/source/shadow/slack-desc19
-rw-r--r--patches/source/shadow/useradd8
16 files changed, 3136 insertions, 0 deletions
diff --git a/patches/source/shadow/adduser b/patches/source/shadow/adduser
new file mode 100644
index 00000000..5b674a85
--- /dev/null
+++ b/patches/source/shadow/adduser
@@ -0,0 +1,440 @@
+#!/bin/bash
+#
+# Copyright 1995 Hrvoje Dogan, Croatia.
+# Copyright 2002-2004, 2008, 2009, 2010 Stuart Winter, Surrey, England, UK.
+# Copyright 2004, 2008-2010 Slackware Linux, Inc., Concord, CA, USA
+# All rights reserved.
+#
+# Redistribution and use of this script, with or without modification, is
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of this script must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+#
+#
+##########################################################################
+# Program: /usr/sbin/adduser
+# Purpose: Interactive front end to /usr/sbin/useradd for Slackware Linux
+# Author : Stuart Winter <mozes@slackware.com>
+# Based on the original Slackware adduser by Hrvoje Dogan
+# with modifications by Patrick Volkerding
+# Version: 1.13
+##########################################################################
+# Usage..: adduser [<new_user_name>]
+##########################################################################
+# History #
+###########
+# v1.13 - 13/01/10
+# * Fixed bug that removed underscore characters from UNIX group names.
+# Thanks to mRgOBLIN for the report and Jim Hawkins for the fix. <sw>
+# v1.12 - 21/07/09
+# * Adjusted the search of /etc/passwd to exclude the NIS inclusion
+# string. Thanks to Dominik L. Borkowski.
+# v1.11 - 04/06/09
+# * Add power and netdev to the suggested group list
+# v1.10 - 24/03/08
+# * To facilitate use of the automatic mounting features of HAL,
+# allow the admin to easily add users to the default groups:
+# audio,cdrom,video,plugdev,floppy.
+# The default is not to add new users to these groups.
+# And by the way, this script is "useradd from Slackware" not
+# "superadduser from Gentoo" ;-)
+# v1.09 - 07/06/04
+# * Added standard Slackware script licence to the head of this file.
+# v1.08 - 25/04/04
+# * Disallow user names that begin with a numeric because useradd
+# (from shadow v4.03) does not allow them. <sw>
+# v1.07 - 07/03/03
+# * When supplying a null string for the uid (meaning 'Choose next available'),
+# if there were file names in the range 'a-z' in the pwd then the
+# egrep command considered these files rather than the null string.
+# The egrep expression is now in quotes.
+# Reported & fixed by Vadim O. Ustiansky <sw>
+# v1.06 - 31/03/03
+# * Ask to chown user.group the home directory if it already exists.
+# This helps reduce later confusion when adding users whose home dir
+# already exists (mounted partition for example) and is owned
+# by a user other than the user to which the directory is being
+# assigned as home. Default is not to chown.
+# Brought to my attention by mRgOBLIN. <sw>
+# v1.05 - 04/01/03
+# * Advise & prevent users from creating logins with '.' characters
+# in the user name. <sw>
+# * Made pending account creation info look neater <sw>
+# v1.04 - 09/06/02
+# * Catered for shadow-4.0.3's 'useradd' binary that no longer
+# will let you create a user that has any uppercase chars in it
+# This was reported on the userlocal.org forums
+# by 'xcp' - thanks. <sw,pjv>
+# v1.03 - 20/05/02
+# * Support 'broken' (null lines in) /etc/passwd and
+# /etc/group files <sw>
+# * For recycling UIDs (default still 'off'), we now look in
+# /etc/login.defs for the UID_MIN value and use it
+# If not found then default to 1000 <sw>
+# v1.02 - 10/04/02
+# * Fix user-specified UID bug. <pjv>
+# v1.01 - 23/03/02
+# * Match Slackware indenting style, simplify. <pjv>
+# v1.00 - 22/03/02
+# * Created
+#######################################################################
+
+# Path to files
+pfile=/etc/passwd
+gfile=/etc/group
+sfile=/etc/shells
+
+# Paths to binaries
+useradd=/usr/sbin/useradd
+chfn=/usr/bin/chfn
+passwd=/usr/bin/passwd
+chmod=/bin/chmod
+
+# Defaults
+defhome=/home
+defshell=/bin/bash
+defchmod=711 # home dir permissions - may be preferable to use 701, however.
+defgroup=users
+AGID="audio cdrom floppy plugdev video power netdev" # additional groups for desktop users
+
+# Determine what the minimum UID is (for UID recycling)
+# (we ignore it if it's not at the beginning of the line (i.e. commented out with #))
+export recycleUIDMIN="$(grep ^UID_MIN /etc/login.defs | awk '{print $2}' 2>/dev/null)"
+# If we couldn't find it, set it to the default of 1000
+if [ -z "$recycleUIDMIN" ]; then
+ export recycleUIDMIN=1000 # this is the default from Slackware's /etc/login.defs
+fi
+
+
+# This setting enables the 'recycling' of older unused UIDs.
+# When you userdel a user, it removes it from passwd and shadow but it will
+# never get used again unless you specify it expliticly -- useradd (appears to) just
+# look at the last line in passwd and increment the uid. I like the idea of
+# recycling uids but you may have very good reasons not to (old forgotten
+# confidential files still on the system could then be owned by this new user).
+# We'll set this to no because this is what the original adduser shell script
+# did and it's what users expect.
+recycleuids=no
+
+# Function to read keyboard input.
+# bash1 is broken (even ash will take read -ep!), so we work around
+# it (even though bash1 is no longer supported on Slackware).
+function get_input() {
+ local output
+ if [ "`echo $BASH_VERSION | cut -b1`" = "1" ]; then
+ echo -n "${1} " >&2 # fudge for use with bash v1
+ read output
+ else # this should work with any other /bin/sh
+ read -ep "${1} " output
+ fi
+ echo $output
+}
+
+# Function to display the account info
+function display () {
+ local goose
+ goose="$(echo $2 | cut -d ' ' -f 2-)" # lop off the prefixed argument useradd needs
+ echo -n "$1 "
+ # If it's null then display the 'other' information
+ if [ -z "$goose" -a ! -z "$3" ]; then
+ echo "$3"
+ else
+ echo "$goose"
+ fi
+}
+
+# Function to check whether groups exist in the /etc/group file
+function check_group () {
+ local got_error group
+ if [ ! -z "$@" ]; then
+ for group in $@ ; do
+ local uid_not_named="" uid_not_num=""
+ grep -v "$^" $gfile | awk -F: '{print $1}' | grep "^${group}$" >/dev/null 2>&1 || uid_not_named=yes
+ grep -v "$^" $gfile | awk -F: '{print $3}' | grep "^${group}$" >/dev/null 2>&1 || uid_not_num=yes
+ if [ ! -z "$uid_not_named" -a ! -z "$uid_not_num" ]; then
+ echo "- Group '$group' does not exist"
+ got_error=yes
+ fi
+ done
+ fi
+ # Return exit code of 1 if at least one of the groups didn't exist
+ if [ ! -z "$got_error" ]; then
+ return 1
+ fi
+}
+
+#: Read the login name for the new user :#
+#
+# Remember that most Mail Transfer Agents are case independant, so having
+# 'uSer' and 'user' may cause confusion/things to break. Because of this,
+# useradd from shadow-4.0.3 no longer accepts usernames containing uppercase,
+# and we must reject them, too.
+
+# Set the login variable to the command line param
+echo
+LOGIN="$1"
+needinput=yes
+while [ ! -z $needinput ]; do
+ if [ -z "$LOGIN" ]; then
+ while [ -z "$LOGIN" ]; do LOGIN="$(get_input "Login name for new user []:")" ; done
+ fi
+ grep "^${LOGIN}:" $pfile >/dev/null 2>&1 # ensure it's not already used
+ if [ $? -eq 0 ]; then
+ echo "- User '$LOGIN' already exists; please choose another"
+ unset LOGIN
+ elif [ ! -z "$( echo $LOGIN | grep "^[0-9]" )" ]; then
+ echo "- User names cannot begin with a number; please choose another"
+ unset LOGIN
+ elif [ ! "$LOGIN" = "`echo $LOGIN | tr A-Z a-z`" ]; then # useradd does not allow uppercase
+ echo "- User '$LOGIN' contains illegal characters (uppercase); please choose another"
+ unset LOGIN
+ elif [ ! -z "$( echo $LOGIN | grep '\.' )" ]; then
+ echo "- User '$LOGIN' contains illegal characters (period/dot); please choose another"
+ unset LOGIN
+ else
+ unset needinput
+ fi
+done
+
+# Display the user name passed from the shell if it hasn't changed
+if [ "$1" = "$LOGIN" ]; then
+ echo "Login name for new user: $LOGIN"
+fi
+
+#: Get the UID for the user & ensure it's not already in use :#
+#
+# Whilst we _can_ allow users with identical UIDs, it's not a 'good thing' because
+# when you change password for the uid, it finds the first match in /etc/passwd
+# which isn't necessarily the correct user
+#
+echo
+needinput=yes
+while [ ! -z "$needinput" ]; do
+ _UID="$(get_input "User ID ('UID') [ defaults to next available ]:")"
+ egrep -v "^$|^\+" $pfile | awk -F: '{print $3}' | grep "^${_UID}$" >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "- That UID is already in use; please choose another"
+ elif [ ! -z "$(echo $_UID | egrep '[A-Za-z]')" ]; then
+ echo "- UIDs are numerics only"
+ else
+ unset needinput
+ fi
+done
+# If we were given a UID, then syntax up the variable to pass to useradd
+if [ ! -z "$_UID" ]; then
+ U_ID="-u ${_UID}"
+else
+ # Will we be recycling UIDs?
+ if [ "$recycleuids" = "yes" ]; then
+ U_ID="-u $(awk -F: '{uid[$3]=1} END { for (i=ENVIRON["recycleUIDMIN"];i in uid;i++);print i}' $pfile)"
+ fi
+fi
+
+#: Get the initial group for the user & ensure it exists :#
+#
+# We check /etc/group for both the text version and the group ID number
+echo
+needinput=yes
+while [ ! -z "$needinput" ]; do
+ GID="$(get_input "Initial group [ ${defgroup} ]:")"
+ check_group "$GID"
+ if [ $? -gt 0 ]; then
+ echo "- Please choose another"
+ else
+ unset needinput
+ fi
+done
+# Syntax the variable ready for useradd
+if [ -z "$GID" ]; then
+ GID="-g ${defgroup}"
+else
+ GID="-g ${GID}"
+fi
+
+#: Get additional groups for the user :#
+#
+echo "Additional UNIX groups:"
+echo
+echo "Users can belong to additional UNIX groups on the system."
+echo "For local users using graphical desktop login managers such"
+echo "as XDM/KDM, users may need to be members of additional groups"
+echo "to access the full functionality of removable media devices."
+echo
+echo "* Security implications *"
+echo "Please be aware that by adding users to additional groups may"
+echo "potentially give access to the removable media of other users."
+echo
+echo "If you are creating a new user for remote shell access only,"
+echo "users do not need to belong to any additional groups as standard,"
+echo "so you may press ENTER at the next prompt."
+echo
+needinput=yes
+while [ ! -z "$needinput" ]; do
+ history -c
+ history -s "$AGID"
+ echo "Press ENTER to continue without adding any additional groups"
+ echo "Or press the UP arrow key to add/select/edit additional groups"
+ AGID="$(get_input ": " | sed 's/[^A-Za-z0-9 _]//g;s/ */ /g;s/^ $//g' )"
+ if [ ! -z "$AGID" ]; then
+ check_group "$AGID" # check all groups at once (treated as N # of params)
+ if [ $? -gt 0 ]; then
+ echo "- Please re-enter the group(s)"
+ echo
+ else
+ unset needinput # we found all groups specified
+ AGID="-G $(echo $AGID | tr ' ' ,)" # useradd takes comma delimited groups
+ fi
+ else
+ unset needinput # we don't *have* to have additional groups
+ fi
+done
+
+#: Get the new user's home dir :#
+#
+echo
+needinput=yes
+while [ ! -z "$needinput" ]; do
+ HME="$(get_input "Home directory [ ${defhome}/${LOGIN} ]")"
+ if [ -z "$HME" ]; then
+ HME="${defhome}/${LOGIN}"
+ fi
+ # Warn the user if the home dir already exists
+ if [ -d "$HME" ]; then
+ echo "- Warning: '$HME' already exists !"
+ getyn="$(get_input " Do you wish to change the home directory path ? (Y/n) ")"
+ if [ "$(echo $getyn | grep -i "n")" ]; then
+ unset needinput
+ # You're most likely going to only do this if you have the dir *mounted* for this user's $HOME
+ getyn="$(get_input " Do you want to chown $LOGIN.$( echo $GID | awk '{print $2}') $HME ? (y/N) ")"
+ if [ "$(echo $getyn | grep -i "y")" ]; then
+ CHOWNHOMEDIR=$HME # set this to the home directory
+ fi
+ fi
+ else
+ unset needinput
+ fi
+done
+HME="-d ${HME}"
+
+#: Get the new user's shell :#
+echo
+needinput=yes
+while [ ! -z "$needinput" ]; do
+ unset got_error
+ SHL="$(get_input "Shell [ ${defshell} ]")"
+ if [ -z "$SHL" ]; then
+ SHL="${defshell}"
+ fi
+ # Warn the user if the shell doesn't exist in /etc/shells or as a file
+ if [ -z "$(grep "^${SHL}$" $sfile)" ]; then
+ echo "- Warning: ${SHL} is not in ${sfile} (potential problem using FTP)"
+ got_error=yes
+ fi
+ if [ ! -f "$SHL" ]; then
+ echo "- Warning: ${SHL} does not exist as a file"
+ got_error=yes
+ fi
+ if [ ! -z "$got_error" ]; then
+ getyn="$(get_input " Do you wish to change the shell ? (Y/n) ")"
+ if [ "$(echo $getyn | grep -i "n")" ]; then
+ unset needinput
+ fi
+ else
+ unset needinput
+ fi
+done
+SHL="-s ${SHL}"
+
+#: Get the expiry date :#
+echo
+needinput=yes
+while [ ! -z "$needinput" ]; do
+ EXP="$(get_input "Expiry date (YYYY-MM-DD) []:")"
+ if [ ! -z "$EXP" ]; then
+ # Check to see whether the expiry date is in the valid format
+ if [ -z "$(echo "$EXP" | grep "^[[:digit:]]\{4\}[-]\?[[:digit:]]\{2\}[-]\?[[:digit:]]\{2\}$")" ]; then
+ echo "- That is not a valid expiration date"
+ else
+ unset needinput
+ EXP="-e ${EXP}"
+ fi
+ else
+ unset needinput
+ fi
+done
+
+# Display the info about the new impending account
+echo
+echo "New account will be created as follows:"
+echo
+echo "---------------------------------------"
+display "Login name.......: " "$LOGIN"
+display "UID..............: " "$_UID" "[ Next available ]"
+display "Initial group....: " "$GID"
+display "Additional groups: " "$AGID" "[ None ]"
+display "Home directory...: " "$HME"
+display "Shell............: " "$SHL"
+display "Expiry date......: " "$EXP" "[ Never ]"
+echo
+
+echo "This is it... if you want to bail out, hit Control-C. Otherwise, press"
+echo "ENTER to go ahead and make the account."
+read junk
+
+echo
+echo "Creating new account..."
+echo
+echo
+
+# Add the account to the system
+CMD="$useradd "$HME" -m "$EXP" "$U_ID" "$GID" "$AGID" "$SHL" "$LOGIN""
+$CMD
+
+if [ $? -gt 0 ]; then
+ echo "- Error running useradd command -- account not created!"
+ echo "(cmd: $CMD)"
+ exit 1
+fi
+
+# chown the home dir ? We can only do this once the useradd has
+# completed otherwise the user name doesn't exist.
+if [ ! -z "${CHOWNHOMEDIR}" ]; then
+ chown "$LOGIN"."$( echo $GID | awk '{print $2}')" "${CHOWNHOMEDIR}"
+fi
+
+# Set the finger information
+$chfn "$LOGIN"
+if [ $? -gt 0 ]; then
+ echo "- Warning: an error occurred while setting finger information"
+fi
+
+# Set a password
+$passwd "$LOGIN"
+if [ $? -gt 0 ]; then
+ echo "* WARNING: An error occured while setting the password for"
+ echo " this account. Please manually investigate this *"
+ exit 1
+fi
+
+# If it was created (it should have been!), set the permissions for that user's dir
+HME="$(echo "$HME" | awk '{print $2}')" # We have to remove the -g prefix
+if [ -d "$HME" ]; then
+ $chmod $defchmod "$HME"
+fi
+
+echo
+echo
+echo "Account setup complete."
+exit 0
diff --git a/patches/source/shadow/doinst.sh b/patches/source/shadow/doinst.sh
new file mode 100644
index 00000000..88fefb3a
--- /dev/null
+++ b/patches/source/shadow/doinst.sh
@@ -0,0 +1,17 @@
+config() {
+ NEW="$1"
+ OLD="$(dirname $NEW)/$(basename $NEW .new)"
+ # If there's no config file by that name, mv it over:
+ if [ ! -r $OLD ]; then
+ mv $NEW $OLD
+ elif [ "$(cat $OLD | md5sum)" = "$(cat $NEW | md5sum)" ]; then # toss the redundant copy
+ rm $NEW
+ fi
+ # Otherwise, we leave the .new copy for the admin to consider...
+}
+
+config etc/login.access.new
+config etc/login.defs.new
+config var/log/faillog.new
+rm -f var/log/faillog.new
+
diff --git a/patches/source/shadow/login.defs b/patches/source/shadow/login.defs
new file mode 100644
index 00000000..dde37c97
--- /dev/null
+++ b/patches/source/shadow/login.defs
@@ -0,0 +1,387 @@
+#
+# /etc/login.defs - Configuration control definitions for the shadow package.
+#
+# $Id: login.defs 3038 2009-07-23 20:41:35Z nekral-guest $
+#
+
+#
+# Delay in seconds before being allowed another attempt after a login failure
+#
+FAIL_DELAY 3
+
+#
+# Enable logging and display of /var/log/faillog login failure info.
+#
+FAILLOG_ENAB yes
+
+#
+# Enable display of unknown usernames when login failures are recorded.
+#
+LOG_UNKFAIL_ENAB no
+
+#
+# Enable logging of successful logins
+#
+LOG_OK_LOGINS no
+
+#
+# Enable logging and display of /var/log/lastlog login time info.
+#
+LASTLOG_ENAB yes
+
+#
+# Enable checking and display of mailbox status upon login.
+#
+# Disable if the shell startup files already check for mail
+# ("mailx -e" or equivalent).
+#
+MAIL_CHECK_ENAB yes
+
+#
+# Enable additional checks upon password changes.
+#
+OBSCURE_CHECKS_ENAB yes
+
+#
+# Enable checking of time restrictions specified in /etc/porttime.
+#
+PORTTIME_CHECKS_ENAB yes
+
+#
+# Enable setting of ulimit, umask, and niceness from passwd gecos field.
+#
+QUOTAS_ENAB yes
+
+#
+# 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
+
+#
+# If defined, either full pathname of a file containing device names or
+# a ":" delimited list of device names. Root logins will be allowed only
+# upon these devices.
+#
+CONSOLE /etc/securetty
+#CONSOLE console:tty01:tty02:tty03:tty04
+
+#
+# If defined, all su activity is logged to this file.
+#
+#SULOG_FILE /var/log/sulog
+
+#
+# If defined, ":" delimited list of "message of the day" files to
+# be displayed upon login.
+#
+MOTD_FILE /etc/motd
+#MOTD_FILE /etc/motd:/usr/lib/news/news-motd
+
+#
+# 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 something like "vt100 tty01".
+#
+#TTYTYPE_FILE /etc/ttytype
+
+#
+# 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 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 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
+
+#
+# *REQUIRED*
+# Directory where mailboxes reside, _or_ name of file, relative to the
+# home directory. If you _do_ define both, MAIL_DIR takes precedence.
+#
+MAIL_DIR /var/spool/mail
+#MAIL_FILE .mail
+
+#
+# If defined, file which inhibits all the usual chatter during the login
+# sequence. If a full pathname, then hushed mode will be enabled if the
+# user's name or shell are found in the file. If not a full pathname, then
+# hushed mode will be enabled if the file exists in the user's home directory.
+#
+HUSHLOGIN_FILE .hushlogin
+#HUSHLOGIN_FILE /etc/hushlogins
+
+#
+# If defined, either a TZ environment parameter spec or the
+# fully-rooted pathname of a file containing such a spec.
+#
+#ENV_TZ TZ=CST6CDT
+#ENV_TZ /etc/tzname
+
+#
+# If defined, an HZ environment parameter spec.
+#
+# for Linux/x86
+ENV_HZ HZ=100
+# For Linux/Alpha...
+#ENV_HZ HZ=1024
+
+#
+# *REQUIRED* The default PATH settings, for superuser and normal users.
+#
+# (they are minimal, add the rest in the shell startup files)
+ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin
+ENV_PATH PATH=/usr/local/bin:/bin:/usr/bin
+
+#
+# Terminal permissions
+#
+# TTYGROUP Login tty will be assigned this group ownership.
+# TTYPERM Login tty will be set to this permission.
+#
+# 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 0620
+
+#
+# Login configuration initializations:
+#
+# ERASECHAR Terminal ERASE character ('\010' = backspace).
+# KILLCHAR Terminal KILL character ('\025' = CTRL/U).
+# ULIMIT Default "ulimit" value.
+#
+# The ERASECHAR and KILLCHAR are used only on System V machines.
+# The ULIMIT is used only if the system supports it.
+# (now it works with setrlimit too; ulimit is in 512-byte units)
+#
+# Prefix these values with "0" to get octal, "0x" to get hexadecimal.
+#
+ERASECHAR 0177
+KILLCHAR 025
+#ULIMIT 2097152
+
+# Default initial "umask" value.
+# 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
+# better for privacy. There is no One True Answer here: each sysadmin
+# must make up her mind.
+UMASK 022
+
+#
+# Password aging controls:
+#
+# PASS_MAX_DAYS Maximum number of days a password may be used.
+# PASS_MIN_DAYS Minimum number of days allowed between password changes.
+# PASS_MIN_LEN Minimum acceptable password length.
+# PASS_WARN_AGE Number of days warning given before a password expires.
+#
+PASS_MAX_DAYS 99999
+PASS_MIN_DAYS 0
+PASS_MIN_LEN 5
+PASS_WARN_AGE 7
+
+#
+# If "yes", the user must be listed as a member of the first gid 0 group
+# in /etc/group (called "root" on most Linux systems) to be able to "su"
+# to uid 0 accounts. If the group doesn't exist or is empty, no one
+# will be able to "su" to uid 0.
+#
+SU_WHEEL_ONLY no
+
+#
+# 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
+#
+UID_MIN 1000
+UID_MAX 60000
+# System accounts
+SYS_UID_MIN 101
+SYS_UID_MAX 999
+
+#
+# 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
+
+#
+# Max number of login retries if password is bad
+#
+LOGIN_RETRIES 5
+
+#
+# Max time in seconds for login
+#
+LOGIN_TIMEOUT 60
+
+#
+# Maximum number of attempts to change password if rejected (too easy)
+#
+PASS_CHANGE_TRIES 5
+
+#
+# Warn about weak passwords (but still allow them) if you are root.
+#
+PASS_ALWAYS_WARN yes
+
+#
+# Number of significant characters in the password for crypt().
+# Default is 8, don't change unless your crypt() is better.
+# Ignored if MD5_CRYPT_ENAB set to "yes".
+#
+#PASS_MAX_LEN 8
+
+#
+# Require password before chfn/chsh can make any changes.
+#
+CHFN_AUTH yes
+
+#
+# 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".
+#
+CHFN_RESTRICT frwh
+
+#
+# Password prompt (%s will be replaced by user name).
+#
+# XXX - it doesn't work correctly yet, for now leave it commented out
+# to use the default which is just "Password: ".
+#LOGIN_STRING "%s's Password: "
+
+#
+# Only works if compiled with MD5_CRYPT defined:
+# If set to "yes", new passwords will be encrypted using the MD5-based
+# algorithm compatible with the one used by recent releases of FreeBSD.
+# It supports passwords of unlimited length and longer salt strings.
+# Set to "no" if you need to copy encrypted passwords to other systems
+# which don't understand the new algorithm. Default is "no".
+#
+# 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 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)
+# Overrides the MD5_CRYPT_ENAB option
+#
+ENCRYPT_METHOD MD5
+
+#
+# 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 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 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.
+#
+# SHA_CRYPT_MIN_ROUNDS 5000
+# SHA_CRYPT_MAX_ROUNDS 5000
+
+#
+# List of groups to add to the user's supplementary group set
+# 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 on the console.
+# How to do it is left as an exercise for the reader...
+#
+# Most of these groups are self-explanatory.
+#
+# Note that users are added to these default groups only when
+# logging into a shell with /bin/login, not when using a login
+# manager such as kdm. In that case, users who should have
+# hardware access must be added to the appropriate groups
+# when the user is added with adduser or useradd, or by editing
+# /etc/group directly, preferably using "vigr"
+#
+CONSOLE_GROUPS floppy:audio:cdrom:video:scanner
+
+#
+# Should login be allowed if we can't cd to the home directory?
+# Default in no.
+#
+DEFAULT_HOME yes
+
+#
+# If this file exists and is readable, login environment will be
+# read from it. Every line should be in the form name=value.
+#
+ENVIRON_FILE /etc/environment
+
+#
+# If defined, this command is run when removing a user.
+# It should remove any at/cron/print jobs etc. owned by
+# the user to be removed (passed as the first argument).
+#
+#USERDEL_CMD /usr/sbin/userdel_local
+
+#
+# Enable setting of the umask group bits to be the same as owner bits
+# (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 to remove user groups if no members exist.
+#
+USERGROUPS_ENAB yes
+
+#
+# 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 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).
+#
+# 0 is the default value and disables this feature.
+#
+#MAX_MEMBERS_PER_GROUP 0
+
+#
+# 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
+
diff --git a/patches/source/shadow/patches/README_PATCHES b/patches/source/shadow/patches/README_PATCHES
new file mode 100644
index 00000000..0c639d1a
--- /dev/null
+++ b/patches/source/shadow/patches/README_PATCHES
@@ -0,0 +1,9 @@
+
+r3054.diff: Fixed wrong format string
+r3055.diff: Help output to stderr not stdout.
+r3060.diff: Fix memory leaks
+r3062.diff: Avoid memzero() on a possibly NULL pointer.
+r3096.diff: Fix parsing of gshadow entries.
+r3160.diff: Fixed limits support (non PAM enabled versions only)
+r3194.diff: shell's name must be -su when a su fakes a login.
+r3299.diff: man/ru/Makefile.am: Remove double inclusion of $(man_nopam)
diff --git a/patches/source/shadow/patches/r3054.diff b/patches/source/shadow/patches/r3054.diff
new file mode 100644
index 00000000..dc1eab13
--- /dev/null
+++ b/patches/source/shadow/patches/r3054.diff
@@ -0,0 +1,27 @@
+* src/useradd.c: Fixed wrong format string.
+* lib/gshadow.c: Removed declaration of unused variable.
+
+===================================================================
+--- src/useradd.c (revision 3052)
++++ src/useradd.c (revision 3054)
+@@ -684,7 +684,7 @@
+ static void usage (void)
+ {
+ (void) fprintf (stderr,
+- _("Usage: useradd [options] LOGIN\n"
++ _("Usage: %s [options] LOGIN\n"
+ "\n"
+ "Options:\n"),
+ Prog);
+
+===================================================================
+--- lib/gshadow.c (revision 3052)
++++ lib/gshadow.c (revision 3054)
+@@ -216,7 +216,6 @@
+ static char *buf = NULL;
+
+ char *cp;
+- struct sgrp *ret;
+
+ if (0 == buflen) {
+ buf = (char *) malloc (BUFSIZ);
diff --git a/patches/source/shadow/patches/r3055.diff b/patches/source/shadow/patches/r3055.diff
new file mode 100644
index 00000000..a2af6f39
--- /dev/null
+++ b/patches/source/shadow/patches/r3055.diff
@@ -0,0 +1,1515 @@
+===================================================================
+--- src/userdel.c (revision 3054)
++++ src/userdel.c (revision 3055)
+@@ -94,7 +94,7 @@
+ static bool spw_locked = false;
+
+ /* local function prototypes */
+-static void usage (void);
++static void usage (int status);
+ static void update_groups (void);
+ static void close_files (void);
+ static void fail_exit (int);
+@@ -111,7 +111,7 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+ fputs (_("Usage: userdel [options] LOGIN\n"
+ "\n"
+@@ -120,8 +120,8 @@
+ " even if not owned by user\n"
+ " -h, --help display this help message and exit\n"
+ " -r, --remove remove home directory and mail spool\n"
+- "\n"), stderr);
+- exit (E_USAGE);
++ "\n"), status ? stderr : stdout);
++ exit (status);
+ }
+
+ /*
+@@ -774,17 +774,19 @@
+ case 'f': /* force remove even if not owned by user */
+ fflg = true;
+ break;
++ case 'h':
++ usage (E_SUCCESS);
+ case 'r': /* remove home dir and mailbox */
+ rflg = true;
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+ }
+
+ if ((optind + 1) != argc) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ OPENLOG ("userdel");
+Index: src/lastlog.c
+===================================================================
+--- src/lastlog.c (revision 3054)
++++ src/lastlog.c (revision 3055)
+@@ -71,7 +71,7 @@
+
+ #define NOW (time ((time_t *) 0))
+
+-static void usage (void)
++static void usage (int status)
+ {
+ fputs (_("Usage: lastlog [options]\n"
+ "\n"
+@@ -80,8 +80,8 @@
+ " -h, --help display this help message and exit\n"
+ " -t, --time DAYS print only lastlog records more recent than DAYS\n"
+ " -u, --user LOGIN print lastlog record of the specified LOGIN\n"
+- "\n"), stderr);
+- exit (EXIT_FAILURE);
++ "\n"), status ? stderr : stdout);
++ exit (status);
+ }
+
+ static void print_one (/*@null@*/const struct passwd *pw)
+@@ -208,7 +208,7 @@
+ NULL)) != -1) {
+ switch (c) {
+ case 'h':
+- usage ();
++ usage (EXIT_SUCCESS);
+ break;
+ case 't':
+ {
+@@ -267,7 +267,7 @@
+ break;
+ }
+ default:
+- usage ();
++ usage (EXIT_FAILURE);
+ break;
+ }
+ }
+@@ -275,7 +275,7 @@
+ fprintf (stderr,
+ _("lastlog: unexpected argument: %s\n"),
+ argv[optind]);
+- usage();
++ usage (EXIT_FAILURE);
+ }
+ }
+
+Index: src/gpasswd.c
+===================================================================
+--- src/gpasswd.c (revision 3054)
++++ src/gpasswd.c (revision 3055)
+@@ -94,7 +94,7 @@
+ #endif
+
+ /* local function prototypes */
+-static void usage (void);
++static void usage (int status);
+ static RETSIGTYPE catch_signals (int killed);
+ static bool is_valid_user_list (const char *users);
+ static void process_flags (int argc, char **argv);
+@@ -128,14 +128,15 @@
+ /*
+ * usage - display usage message
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- fprintf (stderr,
++ fprintf (status ? stderr : stdout,
+ _("Usage: %s [option] GROUP\n"
+ "\n"
+ "Options:\n"
+ " -a, --add USER add USER to GROUP\n"
+ " -d, --delete USER remove USER from GROUP\n"
++ " -h, --help display this help message and exit\n"
+ " -r, --remove-password remove the GROUP's password\n"
+ " -R, --restrict restrict access to GROUP to its members\n"
+ " -M, --members USER,... set the list of members of GROUP\n"
+@@ -150,7 +151,7 @@
+ _("The options cannot be combined.\n")
+ #endif
+ );
+- exit (E_USAGE);
++ exit (status);
+ }
+
+ /*
+@@ -235,6 +236,7 @@
+ static struct option long_options[] = {
+ {"add", required_argument, NULL, 'a'},
+ {"delete", required_argument, NULL, 'd'},
++ {"help", no_argument, NULL, 'h'},
+ {"remove-password", no_argument, NULL, 'r'},
+ {"restrict", no_argument, NULL, 'R'},
+ {"administrators", required_argument, NULL, 'A'},
+@@ -242,7 +244,7 @@
+ {NULL, 0, NULL, '\0'}
+ };
+
+- while ((flag = getopt_long (argc, argv, "a:A:d:gM:rR", long_options, &option_index)) != -1) {
++ while ((flag = getopt_long (argc, argv, "a:A:d:ghM:rR", long_options, &option_index)) != -1) {
+ switch (flag) {
+ case 'a': /* add a user */
+ aflg = true;
+@@ -276,6 +278,8 @@
+ break;
+ case 'g': /* no-op from normal password */
+ break;
++ case 'h':
++ usage (E_SUCCESS);
+ case 'M': /* set the list of members */
+ members = optarg;
+ if (!is_valid_user_list (members)) {
+@@ -290,7 +294,7 @@
+ Rflg = true;
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+@@ -325,14 +329,14 @@
+ exclusive++;
+ }
+ if (exclusive > 1) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ /*
+ * Make sure one (and only one) group was provided
+ */
+ if ((argc != (opt_index+1)) || (NULL == group)) {
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+Index: src/newusers.c
+===================================================================
+--- src/newusers.c (revision 3054)
++++ src/newusers.c (revision 3055)
+@@ -92,7 +92,7 @@
+ static bool spw_locked = false;
+
+ /* local function prototypes */
+-static void usage (void);
++static void usage (int status);
+ static void fail_exit (int);
+ static int add_group (const char *, const char *, gid_t *, gid_t);
+ static int get_user_id (const char *, uid_t *);
+@@ -110,15 +110,16 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- (void) fprintf (stderr,
++ FILE *usageout = status ? stderr : stdout;
++ (void) fprintf (usageout,
+ _("Usage: %s [options]\n"
+ "\n"
+ "Options:\n"),
+ Prog);
+ #ifndef USE_PAM
+- (void) fprintf (stderr,
++ (void) fprintf (usageout,
+ _(" -c, --crypt-method the crypt method (one of %s)\n"),
+ #ifndef USE_SHA_CRYPT
+ "NONE DES MD5"
+@@ -127,18 +128,18 @@
+ #endif /* USE_SHA_CRYPT */
+ );
+ #endif /* !USE_PAM */
+- (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
+- (void) fputs (_(" -r, --system create system accounts\n"), stderr);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
++ (void) fputs (_(" -r, --system create system accounts\n"), usageout);
+ #ifndef USE_PAM
+ #ifdef USE_SHA_CRYPT
+ (void) fputs (_(" -s, --sha-rounds number of SHA rounds for the SHA*\n"
+ " crypt algorithms\n"),
+- stderr);
++ usageout);
+ #endif /* USE_SHA_CRYPT */
+ #endif /* !USE_PAM */
+- (void) fputs ("\n", stderr);
++ (void) fputs ("\n", usageout);
+
+- exit (EXIT_FAILURE);
++ exit (status);
+ }
+
+ /*
+@@ -548,7 +549,7 @@
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'h':
+- usage ();
++ usage (EXIT_SUCCESS);
+ break;
+ case 'r':
+ rflg = true;
+@@ -565,13 +566,13 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (EXIT_FAILURE);
+ }
+ break;
+ #endif /* USE_SHA_CRYPT */
+ #endif /* !USE_PAM */
+ default:
+- usage ();
++ usage (EXIT_FAILURE);
+ break;
+ }
+ }
+@@ -602,7 +603,7 @@
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-s", "-c");
+- usage ();
++ usage (EXIT_FAILURE);
+ }
+ #endif /* USE_SHA_CRYPT */
+
+@@ -618,7 +619,7 @@
+ fprintf (stderr,
+ _("%s: unsupported crypt method: %s\n"),
+ Prog, crypt_method);
+- usage ();
++ usage (EXIT_FAILURE);
+ }
+ }
+ #endif /* !USE_PAM */
+Index: src/chpasswd.c
+===================================================================
+--- src/chpasswd.c (revision 3054)
++++ src/chpasswd.c (revision 3055)
+@@ -74,7 +74,7 @@
+
+ /* local function prototypes */
+ static void fail_exit (int code);
+-static void usage (void);
++static void usage (int status);
+ static void process_flags (int argc, char **argv);
+ static void check_flags (void);
+ static void check_perms (void);
+@@ -112,15 +112,16 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- (void) fprintf (stderr,
++ FILE *usageout = status ? stderr : stdout;
++ (void) fprintf (usageout,
+ _("Usage: %s [options]\n"
+ "\n"
+ "Options:\n"),
+ Prog);
+ #ifndef USE_PAM
+- (void) fprintf (stderr,
++ (void) fprintf (usageout,
+ _(" -c, --crypt-method the crypt method (one of %s)\n"),
+ #ifndef USE_SHA_CRYPT
+ "NONE DES MD5"
+@@ -128,22 +129,22 @@
+ "NONE DES MD5 SHA256 SHA512"
+ #endif /* USE_SHA_CRYPT */
+ );
+- (void) fputs (_(" -e, --encrypted supplied passwords are encrypted\n"), stderr);
++ (void) fputs (_(" -e, --encrypted supplied passwords are encrypted\n"), usageout);
+ #endif /* !USE_PAM */
+- (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
+ #ifndef USE_PAM
+ (void) fputs (_(" -m, --md5 encrypt the clear text password using\n"
+ " the MD5 algorithm\n"),
+- stderr);
++ usageout);
+ #ifdef USE_SHA_CRYPT
+ (void) fputs (_(" -s, --sha-rounds number of SHA rounds for the SHA*\n"
+ " crypt algorithms\n"),
+- stderr);
++ usageout);
+ #endif /* USE_SHA_CRYPT */
+ #endif /* !USE_PAM */
+- (void) fputs ("\n", stderr);
++ (void) fputs ("\n", usageout);
+
+- exit (E_USAGE);
++ exit (status);
+ }
+
+ /*
+@@ -181,7 +182,7 @@
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ #ifndef USE_PAM
+ case 'c':
+@@ -201,13 +202,13 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ #endif /* USE_SHA_CRYPT */
+ #endif /* !USE_PAM */
+ default:
+- usage ();
++ usage (E_USAGE);
+ break;
+ }
+ }
+@@ -229,7 +230,7 @@
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-s", "-c");
+- usage ();
++ usage (E_USAGE);
+ }
+ #endif
+
+@@ -238,7 +239,7 @@
+ fprintf (stderr,
+ _("%s: the -c, -e, and -m flags are exclusive\n"),
+ Prog);
+- usage ();
++ usage (E_USAGE);
+ }
+
+ if (cflg) {
+@@ -253,7 +254,7 @@
+ fprintf (stderr,
+ _("%s: unsupported crypt method: %s\n"),
+ Prog, crypt_method);
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+ #endif /* USE_PAM */
+Index: src/groupmems.c
+===================================================================
+--- src/groupmems.c (revision 3054)
++++ src/groupmems.c (revision 3055)
+@@ -88,7 +88,7 @@
+ const struct group *grp);
+ static void purge_members (const struct group *grp);
+ static void display_members (const char *const *members);
+-static void usage (void);
++static void usage (int status);
+ static void process_flags (int argc, char **argv);
+ static void check_perms (void);
+ static void fail_exit (int code);
+@@ -361,7 +361,7 @@
+ }
+ }
+
+-static void usage (void)
++static void usage (int status)
+ {
+ (void) fputs (_("Usage: groupmems [options] [action]\n"
+ "\n"
+@@ -372,10 +372,11 @@
+ "Actions:\n"
+ " -a, --add username add username to the members of the group\n"
+ " -d, --delete username remove username from the members of the group\n"
++ " -h, --help display this help message and exit\n"
+ " -p, --purge purge all members from the group\n"
+ " -l, --list list the members of the group\n"
+- "\n"), stderr);
+- fail_exit (EXIT_USAGE);
++ "\n"), status ? stderr : stdout);
++ fail_exit (status);
+ }
+
+ /*
+@@ -389,12 +390,13 @@
+ {"add", required_argument, NULL, 'a'},
+ {"delete", required_argument, NULL, 'd'},
+ {"group", required_argument, NULL, 'g'},
++ {"help", no_argument, NULL, 'h'},
+ {"list", no_argument, NULL, 'l'},
+ {"purge", no_argument, NULL, 'p'},
+ {NULL, 0, NULL, '\0'}
+ };
+
+- while ((arg = getopt_long (argc, argv, "a:d:g:lp", long_options,
++ while ((arg = getopt_long (argc, argv, "a:d:g:hlp", long_options,
+ &option_index)) != EOF) {
+ switch (arg) {
+ case 'a':
+@@ -408,6 +410,8 @@
+ case 'g':
+ thisgroup = xstrdup (optarg);
+ break;
++ case 'h':
++ usage (EXIT_SUCCESS);
+ case 'l':
+ list = true;
+ ++exclusive;
+@@ -417,12 +421,12 @@
+ ++exclusive;
+ break;
+ default:
+- usage ();
++ usage (EXIT_USAGE);
+ }
+ }
+
+ if ((exclusive > 1) || (optind < argc)) {
+- usage ();
++ usage (EXIT_USAGE);
+ }
+
+ /* local, no need for xgetpwnam */
+Index: src/usermod.c
+===================================================================
+--- src/usermod.c (revision 3054)
++++ src/usermod.c (revision 3055)
+@@ -149,7 +149,7 @@
+ static void date_to_str (char *buf, size_t maxsize,
+ long int date, const char *negativ);
+ static int get_groups (char *);
+-static void usage (void);
++static void usage (int status);
+ static void new_pwent (struct passwd *);
+ #ifdef WITH_SELINUX
+ static void selinux_update_mapping (void);
+@@ -300,9 +300,9 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- fprintf (stderr,
++ fprintf (status ? stderr : stdout,
+ _("Usage: usermod [options] LOGIN\n"
+ "\n"
+ "Options:\n"
+@@ -334,7 +334,7 @@
+ ""
+ #endif
+ );
+- exit (E_USAGE);
++ exit (status);
+ }
+
+ /*
+@@ -815,7 +815,7 @@
+ bool anyflag = false;
+
+ if ((1 == argc) || ('-' == argv[argc - 1][0])) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ {
+@@ -955,7 +955,7 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ fflg = true;
+ break;
+@@ -976,6 +976,8 @@
+ }
+ Gflg = true;
+ break;
++ case 'h':
++ usage (E_SUCCESS);
+ case 'l':
+ if (!is_valid_user_name (optarg)) {
+ fprintf (stderr,
+@@ -1036,7 +1038,7 @@
+ break;
+ #endif
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ anyflag = true;
+ }
+@@ -1092,14 +1094,14 @@
+ }
+
+ if (optind != argc - 1) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ if (aflg && (!Gflg)) {
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-a", "-G");
+- usage ();
++ usage (E_USAGE);
+ exit (E_USAGE);
+ }
+
+@@ -1107,7 +1109,7 @@
+ fprintf (stderr,
+ _("%s: the -L, -p, and -U flags are exclusive\n"),
+ Prog);
+- usage ();
++ usage (E_USAGE);
+ exit (E_USAGE);
+ }
+
+@@ -1115,7 +1117,7 @@
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-o", "-u");
+- usage ();
++ usage (E_USAGE);
+ exit (E_USAGE);
+ }
+
+@@ -1123,7 +1125,7 @@
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-m", "-d");
+- usage ();
++ usage (E_USAGE);
+ exit (E_USAGE);
+ }
+
+Index: src/chgpasswd.c
+===================================================================
+--- src/chgpasswd.c (revision 3054)
++++ src/chgpasswd.c (revision 3055)
+@@ -78,7 +78,7 @@
+
+ /* local function prototypes */
+ static void fail_exit (int code);
+-static void usage (void);
++static void usage (int status);
+ static void process_flags (int argc, char **argv);
+ static void check_flags (void);
+ static void check_perms (void);
+@@ -114,9 +114,10 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- fprintf (stderr, _("Usage: %s [options]\n"
++ fprintf (status ? stderr : stdout,
++ _("Usage: %s [options]\n"
+ "\n"
+ "Options:\n"
+ " -c, --crypt-method the crypt method (one of %s)\n"
+@@ -135,7 +136,7 @@
+ " crypt algorithms\n")
+ #endif
+ );
+- exit (E_USAGE);
++ exit (status);
+ }
+
+ /*
+@@ -174,7 +175,7 @@
+ eflg = true;
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'm':
+ md5flg = true;
+@@ -186,12 +187,12 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ #endif
+ default:
+- usage ();
++ usage (E_USAGE);
+ break;
+ }
+ }
+@@ -212,7 +213,7 @@
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-s", "-c");
+- usage ();
++ usage (E_USAGE);
+ }
+ #endif
+
+@@ -221,7 +222,7 @@
+ fprintf (stderr,
+ _("%s: the -c, -e, and -m flags are exclusive\n"),
+ Prog);
+- usage ();
++ usage (E_USAGE);
+ }
+
+ if (cflg) {
+@@ -236,7 +237,7 @@
+ fprintf (stderr,
+ _("%s: unsupported crypt method: %s\n"),
+ Prog, crypt_method);
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+ }
+Index: src/vipw.c
+===================================================================
+--- src/vipw.c (revision 3054)
++++ src/vipw.c (revision 3055)
+@@ -1,7 +1,7 @@
+ /*
+ vipw, vigr edit the password or group file
+ with -s will edit shadow or gshadow file
+-
++
+ Copyright (c) 1997 , Guy Maor <maor@ece.utexas.edu>
+ Copyright (c) 1999 - 2000, Marek Michałkiewicz
+ Copyright (c) 2002 - 2006, Tomasz Kłoczko
+@@ -29,8 +29,8 @@
+
+ #include <errno.h>
+ #include <getopt.h>
+-#ifdef WITH_SELINUX
+-#include <selinux/selinux.h>
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
+ #endif
+ #include <signal.h>
+ #include <stdio.h>
+@@ -64,7 +64,7 @@
+ static bool quiet = false;
+
+ /* local function prototypes */
+-static void usage (void);
++static void usage (int status);
+ static int create_backup_file (FILE *, const char *, struct stat *);
+ static void vipwexit (const char *msg, int syserr, int ret);
+ static void vipwedit (const char *, int (*)(void), int (*)(void));
+@@ -72,9 +72,9 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- (void)
++ (void)
+ fputs (_("Usage: vipw [options]\n"
+ "\n"
+ "Options:\n"
+@@ -83,8 +83,8 @@
+ " -p, --passwd edit passwd database\n"
+ " -q, --quiet quiet mode\n"
+ " -s, --shadow edit shadow or gshadow database\n"
+- "\n"), stderr);
+- exit (E_USAGE);
++ "\n"), status ? stderr : stdout);
++ exit (status);
+ }
+
+ /*
+@@ -285,8 +285,8 @@
+ if (st1.st_mtime == st2.st_mtime) {
+ vipwexit (0, 0, 0);
+ }
+-#ifdef WITH_SELINUX
+- /* unset the fscreatecon */
++#ifdef WITH_SELINUX
++ /* unset the fscreatecon */
+ if (is_selinux_enabled ()) {
+ if (setfscreatecon (NULL)) {
+ vipwexit (_("setfscreatecon () failed"), errno, 1);
+@@ -353,7 +353,7 @@
+ do_vipw = false;
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'p':
+ do_vipw = true;
+@@ -365,7 +365,7 @@
+ editshadow = true;
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+ }
+Index: src/useradd.c
+===================================================================
+--- src/useradd.c (revision 3054)
++++ src/useradd.c (revision 3055)
+@@ -179,7 +179,7 @@
+ static void show_defaults (void);
+ static int set_defaults (void);
+ static int get_groups (char *);
+-static void usage (void);
++static void usage (int status);
+ static void new_pwent (struct passwd *);
+ #ifdef WITH_SELINUX
+ static void selinux_update_mapping (void);
+@@ -681,45 +681,46 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- (void) fprintf (stderr,
++ FILE *usageout = status ? stderr : stdout;
++ (void) fprintf (usageout,
+ _("Usage: %s [options] LOGIN\n"
+ "\n"
+ "Options:\n"),
+ Prog);
+ (void) fputs (_(" -b, --base-dir BASE_DIR base directory for the home directory of the\n"
+- " new account\n"), stderr);
+- (void) fputs (_(" -c, --comment COMMENT GECOS field of the new account\n"), stderr);
+- (void) fputs (_(" -d, --home-dir HOME_DIR home directory of the new account\n"), stderr);
+- (void) fputs (_(" -D, --defaults print or change default useradd configuration\n"), stderr);
+- (void) fputs (_(" -e, --expiredate EXPIRE_DATE expiration date of the new account\n"), stderr);
+- (void) fputs (_(" -f, --inactive INACTIVE password inactivity period of the new account\n"), stderr);
++ " new account\n"), usageout);
++ (void) fputs (_(" -c, --comment COMMENT GECOS field of the new account\n"), usageout);
++ (void) fputs (_(" -d, --home-dir HOME_DIR home directory of the new account\n"), usageout);
++ (void) fputs (_(" -D, --defaults print or change default useradd configuration\n"), usageout);
++ (void) fputs (_(" -e, --expiredate EXPIRE_DATE expiration date of the new account\n"), usageout);
++ (void) fputs (_(" -f, --inactive INACTIVE password inactivity period of the new account\n"), usageout);
+ (void) fputs (_(" -g, --gid GROUP name or ID of the primary group of the new\n"
+- " account\n"), stderr);
++ " account\n"), usageout);
+ (void) fputs (_(" -G, --groups GROUPS list of supplementary groups of the new\n"
+- " account\n"), stderr);
+- (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
+- (void) fputs (_(" -k, --skel SKEL_DIR use this alternative skeleton directory\n"), stderr);
+- (void) fputs (_(" -K, --key KEY=VALUE override /etc/login.defs defaults\n"), stderr);
++ " account\n"), usageout);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
++ (void) fputs (_(" -k, --skel SKEL_DIR use this alternative skeleton directory\n"), usageout);
++ (void) fputs (_(" -K, --key KEY=VALUE override /etc/login.defs defaults\n"), usageout);
+ (void) fputs (_(" -l, --no-log-init do not add the user to the lastlog and\n"
+- " faillog databases\n"), stderr);
+- (void) fputs (_(" -m, --create-home create the user's home directory\n"), stderr);
+- (void) fputs (_(" -M, --no-create-home do not create the user's home directory\n"), stderr);
++ " faillog databases\n"), usageout);
++ (void) fputs (_(" -m, --create-home create the user's home directory\n"), usageout);
++ (void) fputs (_(" -M, --no-create-home do not create the user's home directory\n"), usageout);
+ (void) fputs (_(" -N, --no-user-group do not create a group with the same name as\n"
+- " the user\n"), stderr);
++ " the user\n"), usageout);
+ (void) fputs (_(" -o, --non-unique allow to create users with duplicate\n"
+- " (non-unique) UID\n"), stderr);
+- (void) fputs (_(" -p, --password PASSWORD encrypted password of the new account\n"), stderr);
+- (void) fputs (_(" -r, --system create a system account\n"), stderr);
+- (void) fputs (_(" -s, --shell SHELL login shell of the new account\n"), stderr);
+- (void) fputs (_(" -u, --uid UID user ID of the new account\n"), stderr);
+- (void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), stderr);
++ " (non-unique) UID\n"), usageout);
++ (void) fputs (_(" -p, --password PASSWORD encrypted password of the new account\n"), usageout);
++ (void) fputs (_(" -r, --system create a system account\n"), usageout);
++ (void) fputs (_(" -s, --shell SHELL login shell of the new account\n"), usageout);
++ (void) fputs (_(" -u, --uid UID user ID of the new account\n"), usageout);
++ (void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), usageout);
+ #ifdef WITH_SELINUX
+- (void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), stderr);
++ (void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), usageout);
+ #endif
+- (void) fputs ("\n", stderr);
+- exit (E_USAGE);
++ (void) fputs ("\n", usageout);
++ exit (status);
+ }
+
+ /*
+@@ -989,9 +990,9 @@
+ };
+ while ((c = getopt_long (argc, argv,
+ #ifdef WITH_SELINUX
+- "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:UZ:",
++ "b:c:d:De:f:g:G:hk:K:lmMNop:rs:u:UZ:",
+ #else
+- "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:U",
++ "b:c:d:De:f:g:G:hk:K:lmMNop:rs:u:U",
+ #endif
+ long_options, NULL)) != -1) {
+ switch (c) {
+@@ -1029,7 +1030,7 @@
+ break;
+ case 'D':
+ if (anyflag) {
+- usage ();
++ usage (E_USAGE);
+ }
+ Dflg = true;
+ break;
+@@ -1066,7 +1067,7 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ /*
+ * -f -1 is allowed
+@@ -1106,7 +1107,7 @@
+ Gflg = true;
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'k':
+ def_template = optarg;
+@@ -1201,7 +1202,7 @@
+ break;
+ #endif
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ anyflag = true;
+ }
+@@ -1220,31 +1221,31 @@
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-o", "-u");
+- usage ();
++ usage (E_USAGE);
+ }
+ if (kflg && !mflg) {
+ fprintf (stderr,
+ _("%s: %s flag is only allowed with the %s flag\n"),
+ Prog, "-k", "-m");
+- usage ();
++ usage (E_USAGE);
+ }
+ if (Uflg && gflg) {
+ fprintf (stderr,
+ _("%s: options %s and %s conflict\n"),
+ Prog, "-U", "-g");
+- usage ();
++ usage (E_USAGE);
+ }
+ if (Uflg && Nflg) {
+ fprintf (stderr,
+ _("%s: options %s and %s conflict\n"),
+ Prog, "-U", "-N");
+- usage ();
++ usage (E_USAGE);
+ }
+ if (mflg && Mflg) {
+ fprintf (stderr,
+ _("%s: options %s and %s conflict\n"),
+ Prog, "-m", "-M");
+- usage ();
++ usage (E_USAGE);
+ }
+
+ /*
+@@ -1253,15 +1254,15 @@
+ */
+ if (Dflg) {
+ if (optind != argc) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ if (uflg || oflg || Gflg || dflg || cflg || mflg) {
+- usage ();
++ usage (E_USAGE);
+ }
+ } else {
+ if (optind != argc - 1) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ user_name = argv[optind];
+Index: src/su.c
+===================================================================
+--- src/su.c (revision 3054)
++++ src/su.c (revision 3055)
+@@ -323,7 +323,7 @@
+ /*
+ * usage - print command line syntax and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+ fputs (_("Usage: su [options] [LOGIN]\n"
+ "\n"
+@@ -335,8 +335,8 @@
+ " --preserve-environment do not reset environment variables, and\n"
+ " keep the same shell\n"
+ " -s, --shell SHELL use SHELL instead of the default in passwd\n"
+- "\n"), stderr);
+- exit (E_USAGE);
++ "\n"), status ? stderr : stdout);
++ exit (status);
+ }
+
+ /*
+@@ -421,7 +421,7 @@
+ command = optarg;
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'l':
+ fakelogin = true;
+@@ -438,7 +438,7 @@
+ shellstr = optarg;
+ break;
+ default:
+- usage (); /* NOT REACHED */
++ usage (E_USAGE); /* NOT REACHED */
+ }
+ }
+
+Index: src/groupmod.c
+===================================================================
+--- src/groupmod.c (revision 3054)
++++ src/groupmod.c (revision 3055)
+@@ -93,7 +93,7 @@
+ pflg = false; /* new encrypted password */
+
+ /* local function prototypes */
+-static void usage (void);
++static void usage (int status);
+ static void new_grent (struct group *);
+
+ #ifdef SHADOWGRP
+@@ -113,21 +113,22 @@
+ * usage - display usage message and exit
+ */
+
+-static void usage (void)
++static void usage (int status)
+ {
+- (void) fprintf (stderr,
++ FILE *usageout = status ? stderr : stdout;
++ (void) fprintf (usageout,
+ _("Usage: %s [options] GROUP\n"
+ "\n"
+ "Options:\n"),
+ Prog);
+- (void) fputs (_(" -g, --gid GID change the group ID to GID\n"), stderr);
+- (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
+- (void) fputs (_(" -n, --new-name NEW_GROUP change the name to NEW_GROUP\n"), stderr);
+- (void) fputs (_(" -o, --non-unique allow to use a duplicate (non-unique) GID\n"), stderr);
++ (void) fputs (_(" -g, --gid GID change the group ID to GID\n"), usageout);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
++ (void) fputs (_(" -n, --new-name NEW_GROUP change the name to NEW_GROUP\n"), usageout);
++ (void) fputs (_(" -o, --non-unique allow to use a duplicate (non-unique) GID\n"), usageout);
+ (void) fputs (_(" -p, --password PASSWORD change the password to this (encrypted)\n"
+- " PASSWORD\n"), stderr);
+- (void) fputs ("\n", stderr);
+- exit (E_USAGE);
++ " PASSWORD\n"), usageout);
++ (void) fputs ("\n", usageout);
++ exit (status);
+ }
+
+ /*
+@@ -362,6 +363,8 @@
+ exit (E_BAD_ARG);
+ }
+ break;
++ case 'h':
++ usage (E_SUCCESS);
+ case 'n':
+ nflg = true;
+ group_newname = optarg;
+@@ -374,16 +377,16 @@
+ pflg = true;
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+ if (oflg && !gflg) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ if (optind != (argc - 1)) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ group_name = argv[argc - 1];
+Index: src/passwd.c
+===================================================================
+--- src/passwd.c (revision 3054)
++++ src/passwd.c (revision 3055)
+@@ -180,7 +180,7 @@
+ " -w, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"
+ " -x, --maxdays MAX_DAYS set maximum number of days before password\n"
+ " change to MAX_DAYS\n"
+- "\n"), stderr);
++ "\n"), status ? stderr : stdout);
+ exit (status);
+ }
+
+@@ -811,7 +811,7 @@
+ {NULL, 0, NULL, '\0'}
+ };
+
+- while ((c = getopt_long (argc, argv, "adei:kln:qr:Suw:x:",
++ while ((c = getopt_long (argc, argv, "adehi:kln:qr:Suw:x:",
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'a':
+@@ -897,6 +897,8 @@
+ xflg = true;
+ anyflag = true;
+ break;
++ case 'h':
++ usage (E_SUCCESS);
+ default:
+ usage (E_BAD_ARG);
+ }
+Index: src/groupadd.c
+===================================================================
+--- src/groupadd.c (revision 3054)
++++ src/groupadd.c (revision 3055)
+@@ -88,7 +88,7 @@
+ #endif
+
+ /* local function prototypes */
+-static void usage (void);
++static void usage (int status);
+ static void new_grent (struct group *grent);
+
+ #ifdef SHADOWGRP
+@@ -105,24 +105,25 @@
+ /*
+ * usage - display usage message and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+- (void) fprintf (stderr,
++ FILE *usageout = status ? stderr : stdout;
++ (void) fprintf (usageout,
+ _("Usage: %s [options] GROUP\n"
+ "\n"
+ "Options:\n"),
+ Prog);
+ (void) fputs (_(" -f, --force exit successfully if the group already exists,\n"
+- " and cancel -g if the GID is already used\n"), stderr);
+- (void) fputs (_(" -g, --gid GID use GID for the new group\n"), stderr);
+- (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
+- (void) fputs (_(" -K, --key KEY=VALUE override /etc/login.defs defaults\n"), stderr);
++ " and cancel -g if the GID is already used\n"), usageout);
++ (void) fputs (_(" -g, --gid GID use GID for the new group\n"), usageout);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
++ (void) fputs (_(" -K, --key KEY=VALUE override /etc/login.defs defaults\n"), usageout);
+ (void) fputs (_(" -o, --non-unique allow to create groups with duplicate\n"
+- " (non-unique) GID\n"), stderr);
+- (void) fputs (_(" -p, --password PASSWORD use this encrypted password for the new group\n"), stderr);
+- (void) fputs (_(" -r, --system create a system account\n"), stderr);
+- (void) fputs ("\n", stderr);
+- exit (E_USAGE);
++ " (non-unique) GID\n"), usageout);
++ (void) fputs (_(" -p, --password PASSWORD use this encrypted password for the new group\n"), usageout);
++ (void) fputs (_(" -r, --system create a system account\n"), usageout);
++ (void) fputs ("\n", usageout);
++ exit (status);
+ }
+
+ /*
+@@ -412,7 +413,7 @@
+ }
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'K':
+ /*
+@@ -444,7 +445,7 @@
+ rflg = true;
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+@@ -452,7 +453,7 @@
+ * Check the flags consistency
+ */
+ if (optind != argc - 1) {
+- usage ();
++ usage (E_USAGE);
+ }
+ group_name = argv[optind];
+
+@@ -468,7 +469,7 @@
+ {
+ /* -o does not make sense without -g */
+ if (oflg && !gflg) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ check_new_name ();
+Index: src/chage.c
+===================================================================
+--- src/chage.c (revision 3054)
++++ src/chage.c (revision 3055)
+@@ -91,7 +91,7 @@
+
+ /* local function prototypes */
+ static bool isnum (const char *s);
+-static void usage (void);
++static void usage (int status);
+ static void date_to_str (char *buf, size_t maxsize, time_t date);
+ static int new_fields (void);
+ static void print_date (time_t date);
+@@ -152,7 +152,7 @@
+ /*
+ * usage - print command line syntax and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+ fputs (_("Usage: chage [options] [LOGIN]\n"
+ "\n"
+@@ -168,8 +168,8 @@
+ " -M, --maxdays MAX_DAYS set maximim number of days before password\n"
+ " change to MAX_DAYS\n"
+ " -W, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"
+- "\n"), stderr);
+- exit (E_USAGE);
++ "\n"), status ? stderr : stdout);
++ exit (status);
+ }
+
+ static void date_to_str (char *buf, size_t maxsize, time_t date)
+@@ -413,7 +413,7 @@
+ fprintf (stderr,
+ _("%s: invalid date '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ case 'E':
+@@ -425,11 +425,11 @@
+ fprintf (stderr,
+ _("%s: invalid date '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'I':
+ Iflg = true;
+@@ -438,7 +438,7 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ case 'l':
+@@ -451,7 +451,7 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ case 'M':
+@@ -461,7 +461,7 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ case 'W':
+@@ -471,11 +471,11 @@
+ fprintf (stderr,
+ _("%s: invalid numeric argument '%s'\n"),
+ Prog, optarg);
+- usage ();
++ usage (E_USAGE);
+ }
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+@@ -495,14 +495,14 @@
+ */
+
+ if (argc != opt_index + 1) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg)) {
+ fprintf (stderr,
+ _("%s: do not include \"l\" with other flags\n"),
+ Prog);
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+Index: src/faillog.c
+===================================================================
+--- src/faillog.c (revision 3054)
++++ src/faillog.c (revision 3055)
+@@ -47,6 +47,17 @@
+ /*@-exitarg@*/
+ #include "exitcodes.h"
+
++/* local function prototypes */
++static void usage (int status);
++static void print_one (/*@null@*/const struct passwd *pw, bool force);
++static void set_locktime (long locktime);
++static bool set_locktime_one (uid_t uid, long locktime);
++static void setmax (int max);
++static bool setmax_one (uid_t uid, int max);
++static void print (void);
++static bool reset_one (uid_t uid);
++static void reset (void);
++
+ /*
+ * Global variables
+ */
+@@ -69,24 +80,25 @@
+
+ #define NOW (time((time_t *) 0))
+
+-static void usage (void)
++static void usage (int status)
+ {
+- (void) fprintf (stderr,
++ FILE *usageout = status ? stderr : stdout;
++ (void) fprintf (usageout,
+ _("Usage: %s [options]\n"
+ "\n"
+ "Options:\n"),
+ "faillog");
+- (void) fputs (_(" -a, --all display faillog records for all users\n"), stderr);
+- (void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
+- (void) fputs (_(" -l, --lock-time SEC after failed login lock account for SEC seconds\n"), stderr);
+- (void) fputs (_(" -m, --maximum MAX set maximum failed login counters to MAX\n"), stderr);
+- (void) fputs (_(" -r, --reset reset the counters of login failures\n"), stderr);
+- (void) fputs (_(" -t, --time DAYS display faillog records more recent than DAYS\n"), stderr);
++ (void) fputs (_(" -a, --all display faillog records for all users\n"), usageout);
++ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
++ (void) fputs (_(" -l, --lock-time SEC after failed login lock account for SEC seconds\n"), usageout);
++ (void) fputs (_(" -m, --maximum MAX set maximum failed login counters to MAX\n"), usageout);
++ (void) fputs (_(" -r, --reset reset the counters of login failures\n"), usageout);
++ (void) fputs (_(" -t, --time DAYS display faillog records more recent than DAYS\n"), usageout);
+ (void) fputs (_(" -u, --user LOGIN/RANGE display faillog record or maintains failure\n"
+ " counters and limits (if used with -r, -m,\n"
+- " or -l) only for the specified LOGIN(s)\n"), stderr);
+- (void) fputs ("\n", stderr);
+- exit (E_USAGE);
++ " or -l) only for the specified LOGIN(s)\n"), usageout);
++ (void) fputs ("\n", usageout);
++ exit (status);
+ }
+
+ static void print_one (/*@null@*/const struct passwd *pw, bool force)
+@@ -495,7 +507,7 @@
+ aflg = true;
+ break;
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 'l':
+ if (getlong (optarg, &fail_locktime) == 0) {
+@@ -561,16 +573,16 @@
+ break;
+ }
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+ }
+
+ if (aflg && uflg) {
+- usage ();
++ usage (E_USAGE);
+ }
+ if (tflg && (lflg || mflg || rflg)) {
+- usage ();
++ usage (E_USAGE);
+ }
+
+ /* Open the faillog database */
+Index: src/chsh.c
+===================================================================
+--- src/chsh.c (revision 3054)
++++ src/chsh.c (revision 3055)
+@@ -72,7 +72,7 @@
+
+ /* local function prototypes */
+ static void fail_exit (int code);
+-static void usage (void);
++static void usage (int status);
+ static void new_fields (void);
+ static bool shell_is_listed (const char *);
+ static bool is_restricted_shell (const char *);
+@@ -101,15 +101,15 @@
+ /*
+ * usage - print command line syntax and exit
+ */
+-static void usage (void)
++static void usage (int status)
+ {
+ fputs (_("Usage: chsh [options] [LOGIN]\n"
+ "\n"
+ "Options:\n"
+ " -h, --help display this help message and exit\n"
+ " -s, --shell SHELL new login shell for the user account\n"
+- "\n"), stderr);
+- exit (E_USAGE);
++ "\n"), status ? stderr : stdout);
++ exit (status);
+ }
+
+ /*
+@@ -217,14 +217,14 @@
+ &option_index)) != -1) {
+ switch (c) {
+ case 'h':
+- usage ();
++ usage (E_SUCCESS);
+ break;
+ case 's':
+ sflg = true;
+ STRFCPY (loginsh, optarg);
+ break;
+ default:
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+@@ -233,7 +233,7 @@
+ * be the user's name.
+ */
+ if (argc > (optind + 1)) {
+- usage ();
++ usage (E_USAGE);
+ }
+ }
+
+Index: man/groupmems.8.xml
+===================================================================
+--- man/groupmems.8.xml (revision 3054)
++++ man/groupmems.8.xml (revision 3055)
+@@ -114,6 +114,12 @@
+ </listitem>
+ </varlistentry>
+ <varlistentry>
++ <term><option>-h</option>, <option>--help</option></term>
++ <listitem>
++ <para>Display help message and exit.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
+ <term><option>-l</option>, <option>--list</option></term>
+ <listitem>
+ <para>List the group membership list.</para>
+Index: man/gpasswd.1.xml
+===================================================================
+--- man/gpasswd.1.xml (revision 3054)
++++ man/gpasswd.1.xml (revision 3055)
+@@ -1,7 +1,7 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!--
+ Copyright (c) 1996 , Rafal Maszkowski
+- Copyright (c) 2007 - 2008, Nicolas François
++ Copyright (c) 2007 - 2009, Nicolas François
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+@@ -148,6 +148,14 @@
+ </variablelist>
+ <variablelist remap='IP'>
+ <varlistentry>
++ <term><option>-h</option>, <option>--help</option></term>
++ <listitem>
++ <para>Display help message and exit.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ <variablelist remap='IP'>
++ <varlistentry>
+ <term>
+ <option>-r</option>, <option>--remove-password</option>
+ </term>
+Index: NEWS
+===================================================================
+--- NEWS (revision 3054)
++++ NEWS (revision 3055)
+@@ -1,5 +1,11 @@
+ $Id$
+
++shadow-4.1.4.1 -> shadow-4.1.4.2 UNRELEASED
++
++- general
++ * report usage error to stderr, but report usage help to stdout (and return
++ zero) when explicitly requested (e.g. with --help).
++
+ shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
+
+ - general
diff --git a/patches/source/shadow/patches/r3060.diff b/patches/source/shadow/patches/r3060.diff
new file mode 100644
index 00000000..8ece6430
--- /dev/null
+++ b/patches/source/shadow/patches/r3060.diff
@@ -0,0 +1,116 @@
+* libmisc/copydir.c, lib/shadowmem.c, lib/groupmem.c, lib/pwmem.c:
+Fix some memory leaks.
+
+Index: libmisc/copydir.c
+===================================================================
+--- libmisc/copydir.c (revision 3059)
++++ libmisc/copydir.c (revision 3060)
+@@ -443,6 +443,7 @@
+ nchars = readlink (filename, buffer, size);
+
+ if (nchars < 0) {
++ free(buffer);
+ return NULL;
+ }
+
+
+Index: lib/shadowmem.c
+===================================================================
+--- lib/shadowmem.c (revision 3059)
++++ lib/shadowmem.c (revision 3060)
+@@ -52,10 +52,13 @@
+ *sp = *spent;
+ sp->sp_namp = strdup (spent->sp_namp);
+ if (NULL == sp->sp_namp) {
++ free(sp);
+ return NULL;
+ }
+ sp->sp_pwdp = strdup (spent->sp_pwdp);
+ if (NULL == sp->sp_pwdp) {
++ free(sp->sp_namp);
++ free(sp);
+ return NULL;
+ }
+
+Index: lib/groupmem.c
+===================================================================
+--- lib/groupmem.c (revision 3059)
++++ lib/groupmem.c (revision 3060)
+@@ -51,10 +51,13 @@
+ *gr = *grent;
+ gr->gr_name = strdup (grent->gr_name);
+ if (NULL == gr->gr_name) {
++ free(gr);
+ return NULL;
+ }
+ gr->gr_passwd = strdup (grent->gr_passwd);
+ if (NULL == gr->gr_passwd) {
++ free(gr->gr_name);
++ free(gr);
+ return NULL;
+ }
+
+@@ -62,11 +65,21 @@
+
+ gr->gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
+ if (NULL == gr->gr_mem) {
++ free(gr->gr_passwd);
++ free(gr->gr_name);
++ 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]) {
++ int j;
++ for (j=0; j<i; j++)
++ free(gr->gr_mem[j]);
++ free(gr->gr_mem);
++ free(gr->gr_passwd);
++ free(gr->gr_name);
++ free(gr);
+ return NULL;
+ }
+ }
+Index: lib/pwmem.c
+===================================================================
+--- lib/pwmem.c (revision 3059)
++++ lib/pwmem.c (revision 3060)
+@@ -51,22 +51,37 @@
+ *pw = *pwent;
+ pw->pw_name = strdup (pwent->pw_name);
+ if (NULL == pw->pw_name) {
++ free(pw);
+ return NULL;
+ }
+ pw->pw_passwd = strdup (pwent->pw_passwd);
+ if (NULL == pw->pw_passwd) {
++ free(pw->pw_name);
++ free(pw);
+ return NULL;
+ }
+ pw->pw_gecos = strdup (pwent->pw_gecos);
+ if (NULL == pw->pw_gecos) {
++ free(pw->pw_passwd);
++ free(pw->pw_name);
++ free(pw);
+ return NULL;
+ }
+ pw->pw_dir = strdup (pwent->pw_dir);
+ if (NULL == pw->pw_dir) {
++ free(pw->pw_gecos);
++ free(pw->pw_passwd);
++ free(pw->pw_name);
++ free(pw);
+ return NULL;
+ }
+ pw->pw_shell = strdup (pwent->pw_shell);
+ if (NULL == pw->pw_shell) {
++ free(pw->pw_dir);
++ free(pw->pw_gecos);
++ free(pw->pw_passwd);
++ free(pw->pw_name);
++ free(pw);
+ return NULL;
+ }
+
diff --git a/patches/source/shadow/patches/r3062.diff b/patches/source/shadow/patches/r3062.diff
new file mode 100644
index 00000000..00d9ba3a
--- /dev/null
+++ b/patches/source/shadow/patches/r3062.diff
@@ -0,0 +1,139 @@
+Index: lib/shadowmem.c
+===================================================================
+--- lib/shadowmem.c (revision 3061)
++++ lib/shadowmem.c (revision 3062)
+@@ -49,8 +49,14 @@
+ if (NULL == sp) {
+ return NULL;
+ }
+- *sp = *spent;
+- sp->sp_namp = strdup (spent->sp_namp);
++ 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;
++ sp->sp_namp = strdup (spent->sp_namp);
+ if (NULL == sp->sp_namp) {
+ free(sp);
+ return NULL;
+@@ -68,8 +74,10 @@
+ void spw_free (/*@out@*/ /*@only@*/struct spwd *spent)
+ {
+ free (spent->sp_namp);
+- memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
+- free (spent->sp_pwdp);
++ if (NULL != spent->sp_pwdp) {
++ memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
++ free (spent->sp_pwdp);
++ }
+ free (spent);
+ }
+
+Index: lib/groupmem.c
+===================================================================
+--- lib/groupmem.c (revision 3061)
++++ lib/groupmem.c (revision 3062)
+@@ -48,7 +48,7 @@
+ if (NULL == gr) {
+ return NULL;
+ }
+- *gr = *grent;
++ gr->gr_gid = grent->gr_gid;
+ gr->gr_name = strdup (grent->gr_name);
+ if (NULL == gr->gr_name) {
+ free(gr);
+@@ -90,13 +90,18 @@
+
+ void gr_free (/*@out@*/ /*@only@*/struct group *grent)
+ {
++ size_t i;
+ free (grent->gr_name);
+- memzero (grent->gr_passwd, strlen (grent->gr_passwd));
+- free (grent->gr_passwd);
+- while (*(grent->gr_mem)) {
+- free (*(grent->gr_mem));
+- grent->gr_mem++;
++ if (NULL != grent->gr_passwd) {
++ memzero (grent->gr_passwd, strlen (grent->gr_passwd));
++ free (grent->gr_passwd);
+ }
++ if (NULL != grent->gr_mem) {
++ for (i = 0; NULL != grent->gr_mem[i]; i++) {
++ free (grent->gr_mem[i]);
++ }
++ free (grent->gr_mem);
++ }
+ free (grent);
+ }
+
+Index: lib/sgroupio.c
+===================================================================
+--- lib/sgroupio.c (revision 3061)
++++ lib/sgroupio.c (revision 3062)
+@@ -51,7 +51,6 @@
+ if (NULL == sg) {
+ return NULL;
+ }
+- *sg = *sgent;
+ sg->sg_name = strdup (sgent->sg_name);
+ if (NULL == sg->sg_name) {
+ free (sg);
+@@ -137,17 +136,20 @@
+
+ void sgr_free (/*@out@*/ /*@only@*/struct sgrp *sgent)
+ {
++ size_t i;
+ free (sgent->sg_name);
+- memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
+- free (sgent->sg_passwd);
+- while (NULL != *(sgent->sg_adm)) {
+- free (*(sgent->sg_adm));
+- sgent->sg_adm++;
++ if (NULL != sgent->sg_passwd) {
++ memzero (sgent->sg_passwd, strlen (sgent->sg_passwd));
++ free (sgent->sg_passwd);
+ }
+- while (NULL != *(sgent->sg_mem)) {
+- free (*(sgent->sg_mem));
+- sgent->sg_mem++;
++ for (i = 0; NULL != sgent->sg_adm[i]; i++) {
++ free (sgent->sg_adm[i]);
+ }
++ free (sgent->sg_adm);
++ for (i = 0; NULL != sgent->sg_mem[i]; i++) {
++ free (sgent->sg_mem[i]);
++ }
++ free (sgent->sg_mem);
+ free (sgent);
+ }
+
+Index: lib/pwmem.c
+===================================================================
+--- lib/pwmem.c (revision 3061)
++++ lib/pwmem.c (revision 3062)
+@@ -48,7 +48,8 @@
+ if (NULL == pw) {
+ return NULL;
+ }
+- *pw = *pwent;
++ pw->pw_uid = pwent->pw_uid;
++ pw->pw_gid = pwent->pw_gid;
+ pw->pw_name = strdup (pwent->pw_name);
+ if (NULL == pw->pw_name) {
+ free(pw);
+@@ -91,8 +92,10 @@
+ void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent)
+ {
+ free (pwent->pw_name);
+- memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
+- free (pwent->pw_passwd);
++ if (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);
diff --git a/patches/source/shadow/patches/r3096.diff b/patches/source/shadow/patches/r3096.diff
new file mode 100644
index 00000000..0e77ce6f
--- /dev/null
+++ b/patches/source/shadow/patches/r3096.diff
@@ -0,0 +1,27 @@
+
+* lib/gshadow.c: Fix parsing of gshadow entries.
+
+Index: lib/gshadow.c
+===================================================================
+--- lib/gshadow.c (revision 3095)
++++ lib/gshadow.c (revision 3096)
+@@ -222,6 +222,7 @@
+ if (NULL == buf) {
+ return NULL;
+ }
++ buflen = BUFSIZ;
+ }
+
+ if (NULL == fp) {
+@@ -229,9 +230,9 @@
+ }
+
+ #ifdef USE_NIS
+- while (fgetsx (buf, (int) sizeof buf, fp) == buf)
++ while (fgetsx (buf, (int) buflen, fp) == buf)
+ #else
+- if (fgetsx (buf, (int) sizeof buf, fp) == buf)
++ if (fgetsx (buf, (int) buflen, fp) == buf)
+ #endif
+ {
+ while ( ((cp = strrchr (buf, '\n')) == NULL)
diff --git a/patches/source/shadow/patches/r3160.diff b/patches/source/shadow/patches/r3160.diff
new file mode 100644
index 00000000..5aabbaa9
--- /dev/null
+++ b/patches/source/shadow/patches/r3160.diff
@@ -0,0 +1,239 @@
+Index: libmisc/limits.c
+===================================================================
+--- libmisc/limits.c (revision 3159)
++++ libmisc/limits.c (revision 3160)
+@@ -33,6 +33,7 @@
+ /*
+ * Separated from setup.c. --marekm
+ * Resource limits thanks to Cristian Gafton.
++ * Enhancements of resource limit code by Thomas Orgis <thomas@orgis.org> ("thor").
+ */
+
+ #include <config.h>
+@@ -44,6 +45,7 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <stdio.h>
++#include <ctype.h>
+ #include "prototypes.h"
+ #include "defines.h"
+ #include <pwd.h>
+@@ -69,17 +71,37 @@
+ unsigned int multiplier)
+ {
+ struct rlimit rlim;
+- long limit;
++ rlim_t limit;
+
+- if (getlong (value, &limit) == 0) {
+- return 0;
++ /* The "-" is special, not belonging to a strange negative limit.
++ It is infinity, in a controlled way. --thor */
++ if(value[0] == '-') {
++ limit = RLIM_INFINITY;
+ }
+- limit *= multiplier;
+- if (limit != (rlim_t) limit) {
+- 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) --thor */
++ char *endptr;
++ long longlimit = strtol(value, &endptr, 10);
++ if ((0 == longlimit) && (value == endptr)) {
++ /* No argument at all. No-op.
++ We could instead throw an error, though. --thor */
++ return 0;
++ }
++ longlimit *= multiplier;
++ limit = (rlim_t)longlimit;
++ if(longlimit != limit)
++ {
++ /* Again, silent error handling... I left it that way.
++ Wouldn't screaming make more sense? --thor */
++ return 0;
++ }
+ }
+- rlim.rlim_cur = (rlim_t) limit;
+- rlim.rlim_max = (rlim_t) limit;
++
++ rlim.rlim_cur = limit;
++ rlim.rlim_max = limit;
+ if (setrlimit (resource, &rlim) != 0) {
+ return LOGIN_ERROR_RLIMIT;
+ }
+@@ -199,6 +221,9 @@
+ * [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)
+ *
++ * Remember to extend the "no-limits" string below when adding a new limit...
++ * --thor
++ *
+ * Return value:
+ * 0 = okay, of course
+ * LOGIN_ERROR_RLIMIT = error setting some RLIMIT
+@@ -214,7 +239,20 @@
+ bool reported = false;
+
+ pp = buf;
++ /* Skip leading whitespace. --thor */
++ while(*pp == ' ' || *pp == '\t') ++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. --thor */
++ 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?
++ --thor */
++ pp = "A- C- D- F- M- N- R- S- T- P- I- O-";
++ }
++
+ while ('\0' != *pp) {
+ switch (*pp++) {
+ #ifdef RLIMIT_AS
+@@ -316,6 +354,10 @@
+ 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
++ --thor */
+ if (!reported) {
+ SYSLOG ((LOG_WARN,
+ "Invalid limit string: '%s'",
+@@ -324,13 +366,51 @@
+ 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.
++ --thor */
++ while(isdigit(*pp) || *pp == '-' || *pp == ' ' || *pp == '\t') {
++ ++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. --thor
++ */
++static bool user_in_group (const char *uname, const char *gname)
++{
++ struct group *groupdata;
++ char **member;
++ 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(groupdata == NULL) {
++ SYSLOG ((LOG_WARN, "Nonexisting group `%s' in limits file.", gname));
++ return false;
++ }
++ /* Now look for our user in the list of members. */
++ member = groupdata->gr_mem;
++ while(*member != NULL) {
++ if(strcmp(*member, uname) == 0) {
++ return true;
++ }
++ ++member;
++ }
++ return false;
++}
++
+ static int setup_user_limits (const char *uname)
+ {
+- /* TODO: allow and use @group syntax --cristiang */
+ FILE *fil;
+ char buf[1024];
+ char name[1024];
+@@ -352,7 +432,7 @@
+ }
+ /* The limits file have the following format:
+ * - '#' (comment) chars only as first chars on a line;
+- * - username must start on first column
++ * - username must start on first column (or *, or @group --thor)
+ * A better (smarter) checking should be done --cristiang */
+ while (fgets (buf, 1024, fil) != NULL) {
+ if (('#' == buf[0]) || ('\n' == buf[0])) {
+@@ -367,6 +447,13 @@
+ * Imposing a limit should be done with care, so a wrong
+ * entry means no care anyway :-). A '-' as a limits
+ * strings means no limits --cristiang */
++ /* In addition to the handling of * as name which was alrady present,
++ I added handling of the @group syntax.
++ 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.
++ --thor. */
+ if (sscanf (buf, "%s%[ACDFMNRSTULPIOacdfmnrstulpio0-9 \t-]",
+ name, tempbuf) == 2) {
+ if (strcmp (name, uname) == 0) {
+@@ -374,6 +461,12 @@
+ 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. --thor */
++ if(user_in_group(uname, name+1)) {
++ strcpy (limits, tempbuf);
++ }
+ }
+ }
+ }
+Index: man/limits.5.xml
+===================================================================
+--- man/limits.5.xml (revision 3159)
++++ man/limits.5.xml (revision 3160)
+@@ -64,7 +64,13 @@
+ <emphasis remap='I'>user LIMITS_STRING</emphasis>
+ </para>
+
++ <para>or in the form:</para>
++
+ <para>
++ <emphasis remap='I'>@group LIMITS_STRING</emphasis>
++ </para>
++
++ <para>
+ The <emphasis>LIMITS_STRING</emphasis> is a string of a concatenated
+ list of resource limits. Each limit consists of a letter identifier
+ followed by a numerical limit.
+@@ -125,11 +131,23 @@
+ </para>
+
+ <para>
++ The limits specified in the form "<replaceable>@group</replaceable>"
++ apply to the members of the specified
++ <replaceable>group</replaceable>.
++ </para>
++
++ <para>
+ To completely disable limits for a user, a single dash
+ "<emphasis>-</emphasis>" will do.
+ </para>
+
+ <para>
++ To disable a limit for a user, a single dash
++ "<replaceable>-</replaceable>" can be used instead of the numerical
++ value for this limit.
++ </para>
++
++ <para>
+ Also, please note that all limit settings are set PER LOGIN. They are
+ not global, nor are they permanent. Perhaps global limits will come,
+ but for now this will have to do ;)
diff --git a/patches/source/shadow/patches/r3194.diff b/patches/source/shadow/patches/r3194.diff
new file mode 100644
index 00000000..0eff631b
--- /dev/null
+++ b/patches/source/shadow/patches/r3194.diff
@@ -0,0 +1,15 @@
+* src/su.c: shell's name must be -su when a su fakes a login.
+
+===================================================================
+--- src/su.c (revision 3193)
++++ src/su.c (revision 3194)
+@@ -1021,7 +1021,7 @@
+ * Use the shell and create an argv
+ * with the rest of the command line included.
+ */
+- argv[-1] = shellstr;
++ argv[-1] = cp;
+ #ifndef USE_PAM
+ execve_shell (shellstr, &argv[-1], environ);
+ err = errno;
+
diff --git a/patches/source/shadow/patches/r3299.diff b/patches/source/shadow/patches/r3299.diff
new file mode 100644
index 00000000..a46b18f0
--- /dev/null
+++ b/patches/source/shadow/patches/r3299.diff
@@ -0,0 +1,12 @@
+Index: man/ru/Makefile.am
+===================================================================
+--- man/ru/Makefile.am (revision 3298)
++++ man/ru/Makefile.am (revision 3299)
+@@ -1,7 +1,6 @@
+ mandir = @mandir@/ru
+
+ man_MANS = \
+- $(man_nopam) \
+ chage.1 \
+ chfn.1 \
+ chgpasswd.8 \
diff --git a/patches/source/shadow/shadow.SlackBuild b/patches/source/shadow/shadow.SlackBuild
new file mode 100755
index 00000000..84f790e2
--- /dev/null
+++ b/patches/source/shadow/shadow.SlackBuild
@@ -0,0 +1,165 @@
+#!/bin/sh
+
+# Copyright 2005-2011 Patrick J. Volkerding, Sebeka, Minnesota, USA
+# All rights reserved.
+#
+# Redistribution and use of this script, with or without modification, is
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of this script must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+
+PKGNAM=shadow
+VERSION=${VERSION:-$(echo $PKGNAM-*.tar.?z* | rev | cut -f 3- -d . | cut -f 1 -d - | rev)}
+BUILD=${BUILD:-2_slack13.1}
+
+# Automatically determine the architecture we're building on:
+if [ -z "$ARCH" ]; then
+ case "$( uname -m )" in
+ i?86) export ARCH=i486 ;;
+ arm*) export ARCH=arm ;;
+ # Unless $ARCH is already set, use uname -m for all other archs:
+ *) export ARCH=$( uname -m ) ;;
+ esac
+fi
+
+NUMJOBS=${NUMJOBS:--j6}
+
+CWD=$(pwd)
+TMP=${TMP:-/tmp}
+PKG=$TMP/package-shadow
+
+if [ "$ARCH" = "i486" ]; then
+ SLKCFLAGS="-O2 -march=i486 -mtune=i686"
+elif [ "$ARCH" = "s390" ]; then
+ SLKCFLAGS="-O2"
+elif [ "$ARCH" = "x86_64" ]; then
+ SLKCFLAGS="-O2 -fPIC"
+else
+ SLKCFLAGS="-O2"
+fi
+
+rm -rf $PKG
+mkdir -p $TMP $PKG
+cd $TMP
+rm -rf shadow-$VERSION
+tar xvf $CWD/shadow-$VERSION.tar.?z* || exit 1
+cd shadow-$VERSION
+
+# Apply some patches taken from the svn trunk that
+# fix some of the more serious bugs in 4.1.4.3:
+for patch in $CWD/patches/*.diff.gz ; do
+ zcat $patch | patch -p0 --verbose || exit 1
+done
+
+# Re-run automake because of r3299 patch to man/ru/Makefile.am:
+automake -f
+
+chown -R root:root .
+find . \
+ \( -perm 777 -o -perm 775 -o -perm 711 -o -perm 555 -o -perm 511 \) \
+ -exec chmod 755 {} \; -o \
+ \( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
+ -exec chmod 644 {} \;
+
+CFLAGS="$SLKCFLAGS" \
+./configure \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --mandir=/usr/man \
+ --docdir=/usr/doc/shadow-$VERSION \
+ --disable-shared \
+ --without-libcrack \
+ --build=$ARCH-slackware-linux
+
+# --enable-utmpx # defaults to 'no'
+
+make $NUMJOBS || make || exit 1
+make install DESTDIR=$PKG || exit 1
+
+# Fix user group = 100:
+zcat $CWD/useradd.gz > $PKG/etc/default/useradd
+
+# /bin/groups is provided by coreutils.
+rm -f $PKG/bin/groups
+find $PKG -name groups.1 -exec rm {} \;
+
+# Install a login.defs with unsurprising defaults:
+rm -f $PKG/etc/login.defs
+zcat $CWD/login.defs.gz > $PKG/etc/login.defs.new
+
+mv $PKG/etc/login.access $PKG/etc/login.access.new
+
+# I don't think this works well enough to recommend it.
+#mv $PKG/etc/limits $PKG/etc/limits.new
+rm -f $PKG/etc/limits
+
+# Add the friendly 'adduser' script:
+cat $CWD/adduser > $PKG/usr/sbin/adduser
+chmod 0755 $PKG/usr/sbin/adduser
+
+# Add sulogin to the package:
+cp -a src/sulogin $PKG/sbin
+( cd $PKG/bin ; ln -s ../sbin/sulogin )
+
+# Add the empty faillog log file:
+mkdir -p $PKG/var/log
+touch $PKG/var/log/faillog.new
+
+# Put some stuff back in "old" locations and make symlinks for compat
+( cd $PKG/usr/bin
+ mv faillog ../sbin
+ mv lastlog ../sbin
+ ln -s ../sbin/faillog
+ ln -s ../sbin/lastlog
+)
+
+# Use 4711 rather than 4755 permissions where setuid root is required:
+find $PKG -type f -perm 4755 -exec chmod 4711 "{}" \;
+
+# Compress and if needed symlink the man pages:
+if [ -d $PKG/usr/man ]; then
+ ( cd $PKG/usr/man
+ for manpagedir in $(find . -type d -name "man*") ; do
+ ( cd $manpagedir
+ for eachpage in $( find . -type l -maxdepth 1) ; do
+ ln -s $( readlink $eachpage ).gz $eachpage.gz
+ rm $eachpage
+ done
+ gzip -9 *.?
+ )
+ done
+ )
+fi
+
+mkdir -p $PKG/usr/doc/shadow-$VERSION
+cp -a \
+ COPYING* NEWS README* TODO doc/{README*,HOWTO,WISHLIST,*.txt} \
+ $PKG/usr/doc/shadow-$VERSION
+
+# If there's a ChangeLog, installing at least part of the recent history
+# is useful, but don't let it get totally out of control:
+if [ -r ChangeLog ]; then
+ DOCSDIR=$(echo $PKG/usr/doc/${PKGNAM}-$VERSION)
+ cat ChangeLog | head -n 1000 > $DOCSDIR/ChangeLog
+ touch -r ChangeLog $DOCSDIR/ChangeLog
+fi
+
+mkdir -p $PKG/install
+cat $CWD/slack-desc > $PKG/install/slack-desc
+zcat $CWD/doinst.sh.gz > $PKG/install/doinst.sh
+
+cd $PKG
+/sbin/makepkg -l y -c n $TMP/shadow-$VERSION-$ARCH-$BUILD.txz
+
diff --git a/patches/source/shadow/shadow.url b/patches/source/shadow/shadow.url
new file mode 100644
index 00000000..b18864a8
--- /dev/null
+++ b/patches/source/shadow/shadow.url
@@ -0,0 +1 @@
+ftp://pkg-shadow.alioth.debian.org/pub/pkg-shadow
diff --git a/patches/source/shadow/slack-desc b/patches/source/shadow/slack-desc
new file mode 100644
index 00000000..57749146
--- /dev/null
+++ b/patches/source/shadow/slack-desc
@@ -0,0 +1,19 @@
+# HOW TO EDIT THIS FILE:
+# The "handy ruler" below makes it easier to edit a package description. Line
+# up the first '|' above the ':' following the base package name, and the '|'
+# on the right side marks the last column you can put a character in. You must
+# make exactly 11 lines for the formatting to be correct. It's also
+# customary to leave one space after the ':'.
+
+ |-----handy-ruler------------------------------------------------------|
+shadow: shadow (shadow password suite)
+shadow:
+shadow: This set of login related programs utilizes an alternate, non-readable
+shadow: file to contain the actual encrypted passwords. This is presumed to
+shadow: increase system security by increasing the difficulty with which
+shadow: system crackers obtain encrypted passwords. It was written by
+shadow: Julianne Frances Haugh and the Linux port is maintained by Tomasz
+shadow: Kloczko.
+shadow:
+shadow: This package provides 'login', which is needed to log into the system.
+shadow:
diff --git a/patches/source/shadow/useradd b/patches/source/shadow/useradd
new file mode 100644
index 00000000..f3205e49
--- /dev/null
+++ b/patches/source/shadow/useradd
@@ -0,0 +1,8 @@
+# useradd defaults file
+GROUP=100
+HOME=/home
+INACTIVE=-1
+EXPIRE=
+SHELL=/bin/bash
+SKEL=/etc/skel
+CREATE_MAIL_SPOOL=yes