Port over the last of the tinylogin applets
authorEric Andersen <andersen@codepoet.org>
Sun, 23 Jun 2002 04:24:25 +0000 (04:24 -0000)
committerEric Andersen <andersen@codepoet.org>
Sun, 23 Jun 2002 04:24:25 +0000 (04:24 -0000)
 -Erik

27 files changed:
include/applets.h
include/libbb.h
include/shadow_.h [new file with mode: 0644]
include/usage.h
libbb/Makefile.in
libbb/change_identity.c [new file with mode: 0644]
libbb/correct_password.c [new file with mode: 0644]
libbb/libc5.c
libbb/messages.c
libbb/obscure.c [new file with mode: 0644]
libbb/pw_encrypt.c [new file with mode: 0644]
libbb/pwd2spwd.c [new file with mode: 0644]
libbb/restricted_shell.c [new file with mode: 0644]
libbb/run_shell.c [new file with mode: 0644]
libbb/setup_environment.c [new file with mode: 0644]
loginutils/Makefile.in
loginutils/addgroup.c
loginutils/adduser.c
loginutils/config.in
loginutils/deluser.c
loginutils/login.c
loginutils/passwd.c [new file with mode: 0644]
loginutils/su.c
loginutils/sulogin.c [new file with mode: 0644]
loginutils/tinylogin.c [deleted file]
loginutils/tinylogin.h [deleted file]
loginutils/vlock.c [new file with mode: 0644]

index 3a8c731a554624bb2361d3836f222752b4c235c8..c2d7acf4bae4ccdf58de83bc8456e08ee0e3aba3 100644 (file)
 #ifdef CONFIG_OD
        APPLET(od, od_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
 #endif
+#ifdef CONFIG_PASSWD
+       APPLET(passwd, passwd_main, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS)
+#endif
 #ifdef CONFIG_PIDOF
        APPLET(pidof, pidof_main, _BB_DIR_BIN, _BB_SUID_NEVER)
 #endif
 #ifdef CONFIG_SU
        APPLET(su, su_main, _BB_DIR_BIN, _BB_SUID_ALWAYS)
 #endif
+#ifdef CONFIG_SULOGIN
+       APPLET(sulogin, sulogin_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+#endif
 #ifdef CONFIG_SWAPONOFF
        APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
 #endif
 #ifdef CONFIG_VI
        APPLET(vi, vi_main, _BB_DIR_BIN, _BB_SUID_NEVER)
 #endif
+#ifdef CONFIG_VLOCK
+       APPLET(vlock, vlock_main, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS)
+#endif
 #ifdef CONFIG_WATCHDOG
        APPLET(watchdog, watchdog_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
 #endif
index 0b2411fcdcee200b698dc793af1d6fe5ff166507..2b9fd5fd6c96f6b1952f1110fa5ed75df1f25318 100644 (file)
 
 #include "config.h"
 
+#include "pwd.h"
+#include "grp.h"
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+#include "shadow_.h"
+#endif
+#ifdef CONFIG_FEATURE_SHA1_PASSWORDS
+# include "sha1.h"
+#endif
+
+
 #if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
 /* libc5 doesn't define socklen_t */
 typedef unsigned int socklen_t;
@@ -260,6 +270,15 @@ extern const char * const too_few_args;
 extern const char * const name_longer_than_foo;
 extern const char * const unknown;
 extern const char * const can_not_create_raw_socket;
+extern const char * const nologin_file;
+extern const char * const passwd_file;
+extern const char * const shadow_file;
+extern const char * const gshadow_file;
+extern const char * const group_file;
+extern const char * const securetty_file;
+extern const char * const motd_file;
+extern const char * const issue_file;
+extern const char * const _path_login;
 
 #ifdef CONFIG_FEATURE_DEVFS
 # define CURRENT_VC "/dev/vc/0"
@@ -299,4 +318,15 @@ void reset_ino_dev_hashtable(void);
 extern size_t xstrlen(const char *string);
 #define strlen(x)   xstrlen(x)
 
+
+#define FAIL_DELAY    3
+extern void change_identity ( const struct passwd *pw );
+extern void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args );
+extern int restricted_shell ( const char *shell );
+extern void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw );
+extern int correct_password ( const struct passwd *pw );
+extern char *pw_encrypt(const char *clear, const char *salt);
+extern struct spwd *pwd_to_spwd(const struct passwd *pw);
+extern int obscure(const char *old, const char *newval, const struct passwd *pwdp);
+
 #endif /* __LIBCONFIG_H__ */
diff --git a/include/shadow_.h b/include/shadow_.h
new file mode 100644 (file)
index 0000000..a677d52
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1988 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef        _H_SHADOW
+#define        _H_SHADOW
+
+
+#ifdef USE_SYSTEM_SHADOW
+#include <shadow.h>
+#else
+
+/*
+ * This information is not derived from AT&T licensed sources.  Posted
+ * to the USENET 11/88, and updated 11/90 with information from SVR4.
+ *
+ *     $Id: shadow_.h,v 1.1 2002/06/23 04:24:20 andersen Exp $
+ */
+
+typedef long sptime;
+
+/*
+ * Shadow password security file structure.
+ */
+
+struct spwd {
+       char *sp_namp;                          /* login name */
+       char *sp_pwdp;                          /* encrypted password */
+       sptime sp_lstchg;                       /* date of last change */
+       sptime sp_min;                          /* minimum number of days between changes */
+       sptime sp_max;                          /* maximum number of days between changes */
+       sptime sp_warn;                         /* number of days of warning before password
+                                                                  expires */
+       sptime sp_inact;                        /* number of days after password expires
+                                                                  until the account becomes unusable. */
+       sptime sp_expire;                       /* days since 1/1/70 until account expires */
+       unsigned long sp_flag;          /* reserved for future use */
+};
+
+/*
+ * Shadow password security file functions.
+ */
+
+#include <stdio.h>                             /* for FILE */
+
+extern struct spwd *getspent(void);
+extern struct spwd *sgetspent(const char *);
+extern struct spwd *fgetspent(FILE *);
+extern void setspent(void);
+extern void endspent(void);
+extern int putspent(const struct spwd *, FILE *);
+extern struct spwd *getspnam(const char *name);
+extern struct spwd *pwd_to_spwd(const struct passwd *pw);
+
+#endif                                                 /* USE_LOCAL_SHADOW */
+
+#endif                                                 /* _H_SHADOW */
index 08ee00d77a3f2f079a89666c5c18b9a64939786a..18593fb1d1499817e5d90270a51949ab056086af 100644 (file)
        "Write an unambiguous representation, octal bytes by default, of FILE\n"\
        "to standard output.  With no FILE, or when FILE is -, read standard input."
 
+#ifdef CONFIG_FEATURE_SHA1_PASSWORDS
+  #define PASSWORD_ALG_TYPES(a) a
+#else   
+  #define PASSWORD_ALG_TYPES(a)
+#endif
+#define passwd_trivial_usage \
+       "[OPTION] [name]"
+#define passwd_full_usage \
+       "CChange a user password. If no name is specified,\n" \
+       "changes the password for the current user.\n" \
+       "Options:\n" \
+       "\t-a\tDefine which algorithm shall be used for the password.\n" \
+       "\t\t\t(Choices: des, md5" \
+       CONFIG_FEATURE_SHA1_PASSWORDS(", sha1") \
+       ")\n\t-d\tDelete the password for the specified user account.\n" \
+       "\t-l\tLocks (disables) the specified user account.\n" \
+       "\t-u\tUnlocks (re-enables) the specified user account.";
+
 #define pidof_trivial_usage \
        "process-name [process-name ...]"
 #define pidof_full_usage \
        "Options:\n" \
        "\t-p\tPreserve environment"
 
+#define sulogin_trivial_usage \
+       "[OPTION]... [tty-device]"
+#define sulogin_full_usage \
+       "Single user login\n" \
+       "Options:\n" \
+       "\t-f\tDo not authenticate (user already authenticated)\n" \
+       "\t-h\tName of the remote host for this login.\n" \
+       "\t-p\tPreserve environment."
+
 #define swapoff_trivial_usage \
        "[OPTION] [DEVICE]"
 #define swapoff_full_usage \
        "Options:\n" \
        "\t-R\tRead-only- do not write to the file." 
 
+#define vlock_trivial_usage \
+       "[OPTIONS]"
+#define vlock_full_usage \
+       "Lock a virtual terminal.  A password is required to unlock\n" \
+       "Options:\n" \
+       "\t-a\tLock all VTs"
+
 #define watchdog_trivial_usage \
        "DEV"
 #define watchdog_full_usage \
index c6493bfa6dc7265b382996ed13c12baf0477760d..2af70f8c7504664ced4318e49658c4790198411a 100644 (file)
@@ -34,17 +34,21 @@ LIBBB_SRC:= \
        my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \
        print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \
        safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \
-       trim.c unzip.c uncompress.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \
+       trim.c unzip.c uncompress.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c \
        xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \
        copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
        dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \
-       simplify_path.c inet_common.c inode_hash.c
+       simplify_path.c inet_common.c inode_hash.c obscure.c pwd2spwd.c xfuncs.c \
+       correct_password.c change_identity.c setup_environment.c run_shell.c \
+       pw_encrypt.c restricted_shell.c
 LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC))
 
 LIBBB_MSRC:=$(LIBBB_DIR)messages.c
 LIBBB_MOBJ:=full_version.o name_too_long.o omitting_directory.o not_a_directory.o \
        memory_exhausted.o invalid_date.o invalid_option.o io_error.o dash_dash_help.o \
-       write_error.o too_few_args.o name_longer_than_foo.o unknown.o can_not_create_raw_socket.o
+       write_error.o too_few_args.o name_longer_than_foo.o unknown.o can_not_create_raw_socket.o \
+       shadow_file.o passwd_file.o group_file.o gshadow_file.o nologin_file.o securetty_file.o \
+       motd_file.o
 LIBBB_MOBJS=$(patsubst %,$(LIBBB_DIR)%, $(LIBBB_MOBJ))
 
 libraries-y+=$(LIBBB_DIR)$(LIBBB_AR)
diff --git a/libbb/change_identity.c b/libbb/change_identity.c
new file mode 100644 (file)
index 0000000..819b216
--- /dev/null
@@ -0,0 +1,54 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#include "libbb.h"
+
+
+/* Become the user and group(s) specified by PW.  */
+void change_identity ( const struct passwd *pw )
+{
+       if ( initgroups ( pw-> pw_name, pw-> pw_gid ) == -1 )
+               perror_msg_and_die ( "cannot set groups" );
+       endgrent ( );
+
+       if ( setgid ( pw-> pw_gid ))
+               perror_msg_and_die ( "cannot set group id" );
+       if ( setuid ( pw->pw_uid ))
+               perror_msg_and_die ( "cannot set user id" );
+}
+
diff --git a/libbb/correct_password.c b/libbb/correct_password.c
new file mode 100644 (file)
index 0000000..758b89e
--- /dev/null
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <crypt.h>
+
+#include "libbb.h"
+
+
+
+/* Ask the user for a password.
+   Return 1 if the user gives the correct password for entry PW,
+   0 if not.  Return 1 without asking for a password if run by UID 0
+   or if PW has an empty password.  */
+
+int correct_password ( const struct passwd *pw )
+{
+       char *unencrypted, *encrypted, *correct;
+       
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+       if (( strcmp ( pw-> pw_passwd, "x" ) == 0 ) || ( strcmp ( pw-> pw_passwd, "*" ) == 0 )) {
+               struct spwd *sp = getspnam ( pw-> pw_name );
+               
+               if ( !sp )
+                       error_msg_and_die ( "no valid shadow password" );
+               
+               correct = sp-> sp_pwdp;
+       }
+       else
+#endif
+       correct = pw-> pw_passwd;
+
+       if ( correct == 0 || correct[0] == '\0' )
+               return 1;
+
+       unencrypted = getpass ( "Password: " );
+       if ( !unencrypted )
+       {
+               fputs ( "getpass: cannot open /dev/tty\n", stderr );
+               return 0;
+       }
+       encrypted = crypt ( unencrypted, correct );
+       memset ( unencrypted, 0, xstrlen ( unencrypted ));
+       return ( strcmp ( encrypted, correct ) == 0 ) ? 1 : 0;
+}
index df622f65bb69cd6326fd407d9cef0fb7215b210b..af15d1ac7d689b557af950bd8cd0f28c3b856359 100644 (file)
 
 #if __GNU_LIBRARY__ < 5
 
+/*
+ * Some systems already have updwtmp().  Some don't...  This is
+ * the updwtmp() implementation from uClibc, Copyright 2002 by
+ * Erik Andersen <andersee@debian.org> 
+ */
+extern void updwtmp(const char *wtmp_file, const struct utmp *lutmp)
+{
+       int fd;
+
+       fd = open(wtmp_file, O_APPEND | O_WRONLY, 0);
+       if (fd >= 0) {
+               if (lockf(fd, F_LOCK, 0)==0) {
+                       write(fd, (const char *) lutmp, sizeof(struct utmp));
+                       lockf(fd, F_ULOCK, 0);
+                       close(fd);
+               }
+       }
+}
 
 /* Copyright (C) 1991 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
index 895cfdc2ba82627e568c71553571b135e539a922..185c1ee917a08199569946e51e363fb016e88f10 100644 (file)
 #ifdef L_can_not_create_raw_socket
        const char * const can_not_create_raw_socket = "can`t create raw socket";
 #endif
+
+#ifdef L_passwd_file
+#define PASSWD_FILE        "/etc/passwd"
+const char * const passwd_file = PASSWD_FILE;
+#endif
+
+#ifdef L_shadow_file
+#define SHADOW_FILE        "/etc/shadow"
+const char * const shadow_file = SHADOW_FILE;
+#endif
+
+#ifdef L_group_file
+#define GROUP_FILE         "/etc/group"
+const char * const group_file = GROUP_FILE;
+#endif
+
+#ifdef L_gshadow_file
+#define GSHADOW_FILE       "/etc/gshadow"
+const char * const gshadow_file = GSHADOW_FILE;
+#endif
+
+#ifdef L_nologin_file
+#define NOLOGIN_FILE       "/etc/nologin"
+const char * const nologin_file = NOLOGIN_FILE;
+#endif
+
+#ifdef L_securetty_file
+#define SECURETTY_FILE     "/etc/securetty"
+const char * const securetty_file = SECURETTY_FILE;
+#endif
+
+#ifdef L_motd_file
+#define MOTD_FILE          "/etc/motd"
+const char * const motd_file = MOTD_FILE;
+#endif
+
diff --git a/libbb/obscure.c b/libbb/obscure.c
new file mode 100644 (file)
index 0000000..dc7de75
--- /dev/null
@@ -0,0 +1,246 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This version of obscure.c contains modifications to support "cracklib"
+ * by Alec Muffet (alec.muffett@uk.sun.com).  You must obtain the Cracklib
+ * library source code for this function to operate.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "libbb.h"
+
+/*
+ * can't be a palindrome - like `R A D A R' or `M A D A M'
+ */
+
+static int palindrome(const char *old, const char *newval)
+{
+       int i, j;
+
+       i = strlen(newval);
+
+       for (j = 0; j < i; j++)
+               if (newval[i - j - 1] != newval[j])
+                       return 0;
+
+       return 1;
+}
+
+/*
+ * more than half of the characters are different ones.
+ */
+
+static int similiar(const char *old, const char *newval)
+{
+       int i, j;
+
+       for (i = j = 0; newval[i] && old[i]; i++)
+               if (strchr(newval, old[i]))
+                       j++;
+
+       if (i >= j * 2)
+               return 0;
+
+       return 1;
+}
+
+/*
+ * a nice mix of characters.
+ */
+
+static int simple(const char *old, const char *newval)
+{
+       int digits = 0;
+       int uppers = 0;
+       int lowers = 0;
+       int others = 0;
+       int size;
+       int i;
+
+       for (i = 0; newval[i]; i++) {
+               if (isdigit(newval[i]))
+                       digits++;
+               else if (isupper(newval[i]))
+                       uppers++;
+               else if (islower(newval[i]))
+                       lowers++;
+               else
+                       others++;
+       }
+
+       /*
+        * The scam is this - a password of only one character type
+        * must be 8 letters long.  Two types, 7, and so on.
+        */
+
+       size = 9;
+       if (digits)
+               size--;
+       if (uppers)
+               size--;
+       if (lowers)
+               size--;
+       if (others)
+               size--;
+
+       if (size <= i)
+               return 0;
+
+       return 1;
+}
+
+static char *str_lower(char *string)
+{
+       char *cp;
+
+       for (cp = string; *cp; cp++)
+               *cp = tolower(*cp);
+       return string;
+}
+
+static char *password_check(const char *old, const char *newval, const struct passwd *pwdp)
+{
+       char *msg = NULL;
+       char *oldmono, *newmono, *wrapped;
+
+       if (strcmp(newval, old) == 0)
+               return "no change";
+
+       newmono = str_lower(xstrdup(newval));
+       oldmono = str_lower(xstrdup(old));
+       wrapped = (char *) xmalloc(strlen(oldmono) * 2 + 1);
+       strcpy(wrapped, oldmono);
+       strcat(wrapped, oldmono);
+
+       if (palindrome(oldmono, newmono))
+               msg = "a palindrome";
+
+       if (!msg && strcmp(oldmono, newmono) == 0)
+               msg = "case changes only";
+
+       if (!msg && similiar(oldmono, newmono))
+               msg = "too similiar";
+
+       if (!msg && simple(old, newval))
+               msg = "too simple";
+
+       if (!msg && strstr(wrapped, newmono))
+               msg = "rotated";
+
+       bzero(newmono, strlen(newmono));
+       bzero(oldmono, strlen(oldmono));
+       bzero(wrapped, strlen(wrapped));
+       free(newmono);
+       free(oldmono);
+       free(wrapped);
+
+       return msg;
+}
+
+static char *obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
+{
+       int maxlen, oldlen, newlen;
+       char *new1, *old1, *msg;
+
+       oldlen = strlen(old);
+       newlen = strlen(newval);
+
+#if 0                                                  /* why not check the password when set for the first time?  --marekm */
+       if (old[0] == '\0')
+               /* return (1); */
+               return NULL;
+#endif
+
+       if (newlen < 5)
+               return "too short";
+
+       /*
+        * Remaining checks are optional.
+        */
+       /* Not for us -- Sean
+        *if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
+        *      return NULL;
+        */
+       msg = password_check(old, newval, pwdp);
+       if (msg)
+               return msg;
+
+       /* The traditional crypt() truncates passwords to 8 chars.  It is
+          possible to circumvent the above checks by choosing an easy
+          8-char password and adding some random characters to it...
+          Example: "password$%^&*123".  So check it again, this time
+          truncated to the maximum length.  Idea from npasswd.  --marekm */
+
+       maxlen = 8;
+       if (oldlen <= maxlen && newlen <= maxlen)
+               return NULL;
+
+       new1 = (char *) xstrdup(newval);
+       old1 = (char *) xstrdup(old);
+       if (newlen > maxlen)
+               new1[maxlen] = '\0';
+       if (oldlen > maxlen)
+               old1[maxlen] = '\0';
+
+       msg = password_check(old1, new1, pwdp);
+
+       bzero(new1, newlen);
+       bzero(old1, oldlen);
+       free(new1);
+       free(old1);
+
+       return msg;
+}
+
+/*
+ * Obscure - see if password is obscure enough.
+ *
+ *     The programmer is encouraged to add as much complexity to this
+ *     routine as desired.  Included are some of my favorite ways to
+ *     check passwords.
+ */
+
+extern int obscure(const char *old, const char *newval, const struct passwd *pwdp)
+{
+       char *msg = obscure_msg(old, newval, pwdp);
+
+       /*  if (msg) { */
+       if (msg != NULL) {
+               printf("Bad password: %s.\n", msg);
+               /* return 0; */
+               return 1;
+       }
+       /* return 1; */
+       return 0;
+}
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
new file mode 100644 (file)
index 0000000..0e4eb9f
--- /dev/null
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routine.
+ *
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <string.h>
+#include <crypt.h>
+#include "libbb.h"
+
+
+extern char *pw_encrypt(const char *clear, const char *salt)
+{
+       static char cipher[128];
+       char *cp;
+
+#ifdef CONFIG_FEATURE_SHA1_PASSWORDS
+       if (strncmp(salt, "$2$", 3) == 0) {
+               return sha1_crypt(clear);
+       }
+#endif
+       cp = (char *) crypt(clear, salt);
+       /* if crypt (a nonstandard crypt) returns a string too large,
+          truncate it so we don't overrun buffers and hope there is
+          enough security in what's left */
+       if (strlen(cp) > sizeof(cipher)-1) {
+               cp[sizeof(cipher)-1] = 0;
+       }
+       strcpy(cipher, cp);
+       return cipher;
+}
+
diff --git a/libbb/pwd2spwd.c b/libbb/pwd2spwd.c
new file mode 100644 (file)
index 0000000..95a2e46
--- /dev/null
@@ -0,0 +1,73 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <time.h>
+#include <sys/types.h>
+#include "libbb.h"
+
+/*
+ * pwd_to_spwd - create entries for new spwd structure
+ *
+ *     pwd_to_spwd() creates a new (struct spwd) containing the
+ *     information in the pointed-to (struct passwd).
+ */
+#define DAY (24L*3600L)
+#define WEEK (7*DAY)
+#define SCALE DAY
+struct spwd *pwd_to_spwd(const struct passwd *pw)
+{
+       static struct spwd sp;
+
+       /*
+        * Nice, easy parts first.  The name and passwd map directly
+        * from the old password structure to the new one.
+        */
+       sp.sp_namp = pw->pw_name;
+       sp.sp_pwdp = pw->pw_passwd;
+
+       /*
+        * Defaults used if there is no pw_age information.
+        */
+       sp.sp_min = 0;
+       sp.sp_max = (10000L * DAY) / SCALE;
+       sp.sp_lstchg = time((time_t *) 0) / SCALE;
+
+       /*
+        * These fields have no corresponding information in the password
+        * file.  They are set to uninitialized values.
+        */
+       sp.sp_warn = -1;
+       sp.sp_expire = -1;
+       sp.sp_inact = -1;
+       sp.sp_flag = -1;
+
+       return &sp;
+}
+
diff --git a/libbb/restricted_shell.c b/libbb/restricted_shell.c
new file mode 100644 (file)
index 0000000..74a6414
--- /dev/null
@@ -0,0 +1,57 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+
+/* Return 1 if SHELL is a restricted shell (one not returned by
+   getusershell), else 0, meaning it is a standard shell.  */
+
+int restricted_shell ( const char *shell )
+{
+       char *line;
+
+       setusershell ( );
+       while (( line = getusershell ( ))) {
+               if (( *line != '#' ) && ( strcmp ( line, shell ) == 0 ))
+                       break;
+       }
+       endusershell ( );
+       return line ? 0 : 1;
+}
+
diff --git a/libbb/run_shell.c b/libbb/run_shell.c
new file mode 100644 (file)
index 0000000..30050fe
--- /dev/null
@@ -0,0 +1,81 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
+   If COMMAND is nonzero, pass it to the shell with the -c option.
+   If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
+   arguments.  */
+
+void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args )
+{
+       const char **args;
+       int argno = 1;
+       int additional_args_cnt = 0;
+       
+       for ( args = additional_args; args && *args; args++ )
+               additional_args_cnt++;
+
+       if ( additional_args )
+               args = (const char **) xmalloc (sizeof (char *) * ( 4  + additional_args_cnt ));
+       else
+               args = (const char **) xmalloc (sizeof (char *) * 4 );
+               
+       args [0] = get_last_path_component ( xstrdup ( shell ));
+       
+       if ( loginshell ) {
+               char *args0 = xmalloc ( xstrlen ( args [0] ) + 2 );
+               args0 [0] = '-';
+               strcpy ( args0 + 1, args [0] );
+               args [0] = args0;
+       }
+    
+       if ( command ) {
+               args [argno++] = "-c";
+               args [argno++] = command;
+       }
+       if ( additional_args ) {
+               for ( ; *additional_args; ++additional_args )
+                       args [argno++] = *additional_args;
+       }
+       args [argno] = 0;
+       execv ( shell, (char **) args );
+       perror_msg_and_die ( "cannot run %s", shell );
+}
+
diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c
new file mode 100644 (file)
index 0000000..dc171fa
--- /dev/null
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+
+#define DEFAULT_LOGIN_PATH      "/bin:/usr/bin"
+#define DEFAULT_ROOT_LOGIN_PATH "/usr/sbin:/bin:/usr/bin:/sbin"
+
+static void xsetenv ( const char *key, const char *value )
+{
+           if ( setenv ( key, value, 1 ))
+                               error_msg_and_die ( "out of memory" );
+}
+
+void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw )
+{
+       if ( loginshell ) {
+               char *term;
+       
+               /* Change the current working directory to be the home directory
+                * of the user.  It is a fatal error for this process to be unable
+                * to change to that directory.  There is no "default" home
+                * directory.
+                * Some systems default to HOME=/
+                */              
+               if ( chdir ( pw-> pw_dir )) {
+                       if ( chdir ( "/" )) {
+                               syslog ( LOG_WARNING, "unable to cd to %s' for user %s'\n", pw-> pw_dir, pw-> pw_name );
+                               error_msg_and_die ( "cannot cd to home directory or /" );
+                       }
+                       fputs ( "warning: cannot change to home directory\n", stderr );
+               }
+
+               /* Leave TERM unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
+                  Unset all other environment variables.  */
+               term = getenv ("TERM");
+               clearenv ( );
+               if ( term )
+                       xsetenv ( "TERM", term );
+               xsetenv ( "HOME",    pw-> pw_dir );
+               xsetenv ( "SHELL",   shell );
+               xsetenv ( "USER",    pw-> pw_name );
+               xsetenv ( "LOGNAME", pw-> pw_name );
+               xsetenv ( "PATH",    ( pw-> pw_uid ? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH ));
+       }
+       else if ( changeenv ) {
+               /* Set HOME, SHELL, and if not becoming a super-user,
+                  USER and LOGNAME.  */
+               xsetenv ( "HOME",  pw-> pw_dir );
+               xsetenv ( "SHELL", shell );
+               if  ( pw-> pw_uid ) {
+                       xsetenv ( "USER",    pw-> pw_name );
+                       xsetenv ( "LOGNAME", pw-> pw_name );
+               }
+       }
+}
+
index adee35baa4d26351f695b3fdc2fe993bff58eb21..cb6452c39db5078a6a4c4c2432cde5598838afe7 100644 (file)
@@ -26,9 +26,12 @@ LOGINUTILS-y:=
 LOGINUTILS-$(CONFIG_ADDGROUP)  += addgroup.o
 LOGINUTILS-$(CONFIG_ADDUSER)   += adduser.o
 LOGINUTILS-$(CONFIG_DELUSER)   += deluser.o
-LOGINUTILS-$(CONFIG_GETTY)             += getty.o
-LOGINUTILS-$(CONFIG_LOGIN)             += login.o tinylogin.o
-LOGINUTILS-$(CONFIG_SU)                        += su.o tinylogin.o
+LOGINUTILS-$(CONFIG_GETTY)     += getty.o
+LOGINUTILS-$(CONFIG_LOGIN)     += login.o
+LOGINUTILS-$(CONFIG_PASSWD)    += passwd.o
+LOGINUTILS-$(CONFIG_SU)                += su.o
+LOGINUTILS-$(CONFIG_SULOGIN)   += sulogin.o
+LOGINUTILS-$(CONFIG_VLOCK)     += vlock.o
 
 libraries-y+=$(LOGINUTILS_DIR)$(LOGINUTILS_AR)
 
index e04a8d784087ff8e1363e13c98e98d78ae1bffd2..87e98fb185a207713250a5f7e0edeacff06ed575 100644 (file)
@@ -35,9 +35,6 @@
 #include "pwd.h"
 #include "grp.h"
 
-#define GROUP_FILE      "/etc/group"
-#define SHADOW_FILE            "/etc/gshadow"
-
 
 /* structs __________________________ */
 
@@ -92,7 +89,7 @@ static int addgroup(const char *filename, char *group, gid_t gid)
 
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
        FILE *etc_gshadow;
-       char *gshadow = SHADOW_FILE;
+       char *gshadow = shadow_file;
 #endif
 
        struct group gr;
@@ -162,7 +159,7 @@ int addgroup_main(int argc, char **argv)
        }
 
        /* werk */
-       return addgroup(GROUP_FILE, group, gid);
+       return addgroup(group_file, group, gid);
 }
 
-/* $Id: addgroup.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */
+/* $Id: addgroup.c,v 1.2 2002/06/23 04:24:24 andersen Exp $ */
index 66fcaa23f110d51b373c1805f2cd43bc541ce069..7aa7fcfd3ce2e547910d2b163eb19b6de1a1ffc7 100644 (file)
 #include <sys/stat.h>
 #include <sys/types.h>
 #include "busybox.h"
-#include "pwd.h"
-#include "grp.h"
 
-#define PASSWD_FILE     "/etc/passwd"
-#define SHADOW_FILE            "/etc/shadow"
 
 
 /* structs __________________________ */
@@ -56,9 +52,6 @@ static const char default_home_prefix[] = "/home";
 static const char default_shell[] = "/bin/sh";
 
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
-
-#include "shadow.h"
-
 /* shadow in use? */
 static int shadow_enabled = 0;
 #endif
@@ -138,47 +131,6 @@ static void passwd_wrapper(const char *login)
        error_msg_and_die("Failed to execute 'passwd', you must set the password for '%s' manually", login);
 }
 
-#ifdef CONFIG_FEATURE_SHADOWPASSWDS
-/*
- * pwd_to_spwd - create entries for new spwd structure
- *
- *     pwd_to_spwd() creates a new (struct spwd) containing the
- *     information in the pointed-to (struct passwd).
- */
-#define DAY (24L*3600L)
-#define WEEK (7*DAY)
-#define SCALE DAY
-static struct spwd *pwd_to_spwd(const struct passwd *pw)
-{
-       static struct spwd sp;
-
-       /*
-        * Nice, easy parts first.  The name and passwd map directly
-        * from the old password structure to the new one.
-        */
-       sp.sp_namp = pw->pw_name;
-       sp.sp_pwdp = pw->pw_passwd;
-
-       /*
-        * Defaults used if there is no pw_age information.
-        */
-       sp.sp_min = 0;
-       sp.sp_max = (10000L * DAY) / SCALE;
-       sp.sp_lstchg = time((time_t *) 0) / SCALE;
-
-       /*
-        * These fields have no corresponding information in the password
-        * file.  They are set to uninitialized values.
-        */
-       sp.sp_warn = -1;
-       sp.sp_expire = -1;
-       sp.sp_inact = -1;
-       sp.sp_flag = -1;
-
-       return &sp;
-}
-#endif
-
 /* putpwent(3) remix */
 static int adduser(const char *filename, struct passwd *p)
 {
@@ -222,7 +174,7 @@ static int adduser(const char *filename, struct passwd *p)
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
        /* add to shadow if necessary */
        if (shadow_enabled) {
-               shadow = wfopen(SHADOW_FILE, "a");
+               shadow = wfopen(shadow_file, "a");
                if (shadow == NULL) {
                        /* return -1; */
                        return 1;
@@ -333,7 +285,7 @@ int adduser_main(int argc, char **argv)
        }
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
        /* is /etc/shadow in use? */
-       shadow_enabled = (0 == access(SHADOW_FILE, F_OK));
+       shadow_enabled = (0 == access(shadow_file, F_OK));
 #endif
 
        /* create a passwd struct */
@@ -346,7 +298,7 @@ int adduser_main(int argc, char **argv)
        pw.pw_shell = (char *)shell;
 
        /* grand finale */
-       return adduser(PASSWD_FILE, &pw);
+       return adduser(passwd_file, &pw);
 }
 
-/* $Id: adduser.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */
+/* $Id: adduser.c,v 1.2 2002/06/23 04:24:24 andersen Exp $ */
index 265d45ab4b723ba5f6e7711b87d176c4c236cae1..b3880aa3deaa8d0e2f512fa678e29bf3ad61b0d6 100644 (file)
@@ -7,19 +7,22 @@ mainmenu_option next_comment
 comment 'Login/Password Management Utilities'
 
 
-bool 'addgroup'                    CONFIG_ADDGROUP
-bool 'adduser'             CONFIG_ADDUSER
-bool 'deluser'             CONFIG_DELUSER
-bool 'delgroup'                    CONFIG_DELUSER
-bool 'getty'               CONFIG_GETTY
+bool 'addgroup'                        CONFIG_ADDGROUP
+bool 'adduser'                 CONFIG_ADDUSER
+bool 'deluser'                 CONFIG_DELUSER
+bool 'delgroup'                        CONFIG_DELUSER
+bool 'getty'                   CONFIG_GETTY
 bool 'login'                   CONFIG_LOGIN
 if [ "$CONFIG_LOGIN" = "y" ]; then
        bool '  Support for /etc/securetty'             CONFIG_FEATURE_SECURETTY
 fi
-bool 'su'                              CONFIG_SU
+bool 'passwd'                  CONFIG_PASSWD
+bool 'su'                      CONFIG_SU
 if [ "$CONFIG_ADDUSER" = "y" -o "$CONFIG_DELUSER" = "y" -o "$CONFIG_LOGIN" = "y" -o "$CONFIG_SU" = "y" ]; then
-    bool 'Support for shadow passwords'                CONFIG_FEATURE_SHADOWPASSWDS
+    bool '  Support for shadow passwords'              CONFIG_FEATURE_SHADOWPASSWDS
 fi
+bool 'sulogin'                 CONFIG_SULOGIN
+bool 'vlock'                   CONFIG_VLOCK
 
 endmenu
 
index 481a716e75ae8d43e9e30b058399b4fd905c41c4..c7d6ece64c45701d7a9bf4ec1e124dc780637985 100644 (file)
 #include <string.h>
 #include "busybox.h"
 
-#define PASSWD_FILE     "/etc/passwd"
-#define GROUP_FILE      "/etc/group"
-#define SHADOW_FILE            "/etc/shadow"
-#define GSHADOW_FILE   "/etc/gshadow"
 
 
 /* where to start and stop deletion */
@@ -123,11 +119,11 @@ int delgroup_main(int argc, char **argv)
                show_usage();
        } else {
 
-               failure = del_line_matching(argv[1], GROUP_FILE);
+               failure = del_line_matching(argv[1], group_file);
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
-               if (access(GSHADOW_FILE, W_OK) == 0) {
+               if (access(gshadow_file, W_OK) == 0) {
                        /* EDR the |= works if the error is not 0, so he had it wrong */
-                       failure |= del_line_matching(argv[1], GSHADOW_FILE);
+                       failure |= del_line_matching(argv[1], gshadow_file);
                }
 #endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
                /* if (!successful) { */
@@ -149,35 +145,35 @@ int deluser_main(int argc, char **argv)
                show_usage();
        } else {
 
-               failure = del_line_matching(argv[1], PASSWD_FILE);
+               failure = del_line_matching(argv[1], passwd_file);
                /* if (!successful) { */
                if (failure) {
                        error_msg_and_die("%s: User could not be removed from %s\n",
-                                                         argv[1], PASSWD_FILE);
+                                                         argv[1], passwd_file);
                }
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
-               failure = del_line_matching(argv[1], SHADOW_FILE);
+               failure = del_line_matching(argv[1], shadow_file);
                /* if (!successful) { */
                if (failure) {
                        error_msg_and_die("%s: User could not be removed from %s\n",
-                                                         argv[1], SHADOW_FILE);
+                                                         argv[1], shadow_file);
                }
-               failure = del_line_matching(argv[1], GSHADOW_FILE);
+               failure = del_line_matching(argv[1], gshadow_file);
                /* if (!successful) { */
                if (failure) {
                        error_msg_and_die("%s: User could not be removed from %s\n",
-                                                         argv[1], GSHADOW_FILE);
+                                                         argv[1], gshadow_file);
                }
 #endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
-               failure = del_line_matching(argv[1], GROUP_FILE);
+               failure = del_line_matching(argv[1], group_file);
                /* if (!successful) { */
                if (failure) {
                        error_msg_and_die("%s: User could not be removed from %s\n",
-                                                         argv[1], GROUP_FILE);
+                                                         argv[1], group_file);
                }
 
        }
        return (EXIT_SUCCESS);
 }
 
-/* $Id: deluser.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */
+/* $Id: deluser.c,v 1.2 2002/06/23 04:24:24 andersen Exp $ */
index 8ccc5bc8a4b1a8c47ee5b73fc1a96e468ff03e3b..7687556ba88c45ec2f3c2f0382e32babc0b7f07c 100644 (file)
 #include <sys/types.h>
 #include <ctype.h>
 #include <time.h>
-#include "busybox.h"
-
-#include "pwd.h"
-#include "grp.h"
 
-#ifdef CONFIG_FEATURE_SHADOWPASSWDS
-#include "shadow.h"
-#endif
+#include "busybox.h"
 
-#include "tinylogin.h"
 
 // import from utmp.c
 static void checkutmp(int picky);
@@ -35,12 +28,7 @@ extern char *pw_encrypt(const char *clear, const char *salt);
 
 // login defines
 #define TIMEOUT       60
-#define FAIL_DELAY    3
 #define EMPTY_USERNAME_COUNT    10
-#define MOTD_FILE     "/etc/motd"
-#define NOLOGIN_FILE  "/etc/nologin"
-#define SECURETTY_FILE "/etc/securetty"
-
 #define USERNAME_SIZE 32
 
 /* Stuff global to this file */
@@ -81,7 +69,9 @@ extern int login_main(int argc, char **argv)
        int failed;
        int count=0;
        struct passwd *pw, pw_copy;
-
+#ifdef CONFIG_WHEEL_GROUP
+       struct group *grp;
+#endif
        int opt_preserve = 0;
        int opt_fflag = 0;
        char *opt_host = 0;
@@ -283,11 +273,11 @@ static int login_prompt ( char *buf_name )
 
 static int check_nologin ( int amroot )
 {
-       if ( access ( NOLOGIN_FILE, F_OK ) == 0 ) {
+       if ( access ( nologin_file, F_OK ) == 0 ) {
                FILE *fp;
                int c;
 
-               if (( fp = fopen ( NOLOGIN_FILE, "r" ))) {
+               if (( fp = fopen ( nologin_file, "r" ))) {
                        while (( c = getc ( fp )) != EOF )
                                putchar (( c == '\n' ) ? '\r' : c );
 
@@ -312,7 +302,7 @@ static int check_tty ( const char *tty )
        int i;
        char buf[BUFSIZ];
 
-       if (( fp = fopen ( SECURETTY_FILE, "r" ))) {
+       if (( fp = fopen ( securetty_file, "r" ))) {
                while ( fgets ( buf, sizeof( buf ) - 1, fp )) {
                        for ( i = xstrlen( buf ) - 1; i >= 0; --i ) {
                                if ( !isspace ( buf[i] ))
@@ -358,7 +348,7 @@ static void motd ( )
        FILE *fp;
        register int c;
 
-       if (( fp = fopen ( MOTD_FILE, "r" ))) {
+       if (( fp = fopen ( motd_file, "r" ))) {
                while (( c = getc ( fp )) != EOF ) 
                        putchar ( c );          
                fclose ( fp );
@@ -429,23 +419,6 @@ static void checkutmp(int picky)
        }
 }
 
-#if __GNU_LIBRARY__ < 5
-/*
- * Some systems already have updwtmp() and possibly updwtmpx().  Others
- * don't, so we re-implement these functions if necessary.  --marekm
- */
-static void updwtmp(const char *filename, const struct utmp *ut)
-{
-       int fd;
-
-       fd = open(filename, O_APPEND | O_WRONLY, 0);
-       if (fd >= 0) {
-               write(fd, (const char *) ut, sizeof(*ut));
-               close(fd);
-       }
-}
-#endif
-
 /*
  * setutmp - put a USER_PROCESS entry in the utmp file
  *
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
new file mode 100644 (file)
index 0000000..9c84c16
--- /dev/null
@@ -0,0 +1,408 @@
+/* vi: set sw=4 ts=4: */
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
+#include <syslog.h>
+#include <time.h>
+#include <sys/resource.h>
+#include <errno.h>
+
+#include "busybox.h"
+
+static char crypt_passwd[128];
+
+static int create_backup(const char *backup, FILE * fp);
+static int new_password(const struct passwd *pw, int amroot, int algo);
+static void set_filesize_limit(int blocks);
+
+
+int get_algo(char *a)
+{
+       int x = 0;                                      /* standart: DES */
+
+       if (strcasecmp(a, "md5") == 0)
+               x = 1;
+       return x;
+}
+
+
+extern int update_passwd(const struct passwd *pw, char *crypt_pw)
+{
+       char filename[1024];
+       char buf[1025];
+       char buffer[80];
+       char username[32];
+       char *pw_rest;
+       int has_shadow = 0;
+       int mask;
+       int continued;
+       FILE *fp;
+       FILE *out_fp;
+       struct stat sb;
+       struct flock lock;
+
+       if (access(shadow_file, F_OK) == 0) {
+               has_shadow = 1;
+       }
+       if (has_shadow) {
+               snprintf(filename, sizeof filename, "%s", shadow_file);
+       } else {
+               snprintf(filename, sizeof filename, "%s", passwd_file);
+       }
+
+       if (((fp = fopen(filename, "r+")) == 0) || (fstat(fileno(fp), &sb))) {
+               /* return 0; */
+               return 1;
+       }
+
+       /* Lock the password file before updating */
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+       if (fcntl(fileno(fp), F_SETLK, &lock) < 0) {
+               fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+               return 1;
+       }
+       lock.l_type = F_UNLCK;
+
+       snprintf(buf, sizeof buf, "%s-", filename);
+       if (create_backup(buf, fp)) {
+               fcntl(fileno(fp), F_SETLK, &lock);
+               fclose(fp);
+               return 1;
+       }
+       snprintf(buf, sizeof buf, "%s+", filename);
+       mask = umask(0777);
+       out_fp = fopen(buf, "w");
+       umask(mask);
+       if ((!out_fp) || (fchmod(fileno(out_fp), sb.st_mode & 0777))
+               || (fchown(fileno(out_fp), sb.st_uid, sb.st_gid))) {
+               fcntl(fileno(fp), F_SETLK, &lock);
+               fclose(fp);
+               fclose(out_fp);
+               return 1;
+       }
+
+       continued = 0;
+       snprintf(username, sizeof username, "%s:", pw->pw_name);
+       rewind(fp);
+       while (!feof(fp)) {
+               fgets(buffer, sizeof buffer, fp);
+               if (!continued) {               // Check to see if we're updating this line.
+                       if (strncmp(username, buffer, strlen(username)) == 0) { // we have a match.
+                               pw_rest = strchr(buffer, ':');
+                               *pw_rest++ = '\0';
+                               pw_rest = strchr(pw_rest, ':');
+                               fprintf(out_fp, "%s:%s%s", buffer, crypt_pw, pw_rest);
+                       } else {
+                               fputs(buffer, out_fp);
+                       }
+               } else {
+                       fputs(buffer, out_fp);
+               }
+               if (buffer[strlen(buffer) - 1] == '\n') {
+                       continued = 0;
+               } else {
+                       continued = 1;
+               }
+               bzero(buffer, sizeof buffer);
+       }
+
+       if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) {
+               unlink(buf);
+               fcntl(fileno(fp), F_SETLK, &lock);
+               fclose(fp);
+               return 1;
+       }
+       if (rename(buf, filename) < 0) {
+               fcntl(fileno(fp), F_SETLK, &lock);
+               fclose(fp);
+               return 1;
+       } else {
+               fcntl(fileno(fp), F_SETLK, &lock);
+               fclose(fp);
+               return 0;
+       }
+}
+
+
+extern int passwd_main(int argc, char **argv)
+{
+       int amroot;
+       char *cp;
+       char *np;
+       char *name;
+       char *myname;
+       int flag;
+       int algo = 0;                           /* -a - password algorithm */
+       int lflg = 0;                           /* -l - lock account */
+       int uflg = 0;                           /* -u - unlock account */
+       int dflg = 0;                           /* -d - delete password */
+       const struct passwd *pw;
+       unsigned short ruid;
+
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+       const struct spwd *sp;
+#endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
+       amroot = (getuid() == 0);
+       openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
+       while ((flag = getopt(argc, argv, "a:dlu")) != EOF) {
+               switch (flag) {
+               case 'a':
+                       algo = get_algo(optarg);
+                       break;
+               case 'd':
+                       dflg++;
+                       break;
+               case 'l':
+                       lflg++;
+                       break;
+               case 'u':
+                       uflg++;
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+       ruid = getuid();
+       pw = (struct passwd *) getpwuid(ruid);
+       if (!pw) {
+               error_msg_and_die("Cannot determine your user name.\n");
+       }
+       myname = (char *) xstrdup(pw->pw_name);
+       if (optind < argc) {
+               name = argv[optind];
+       } else {
+               name = myname;
+       }
+       if ((lflg || uflg || dflg) && (optind >= argc || !amroot)) {
+               show_usage();
+       }
+       pw = getpwnam(name);
+       if (!pw) {
+               error_msg_and_die("Unknown user %s\n", name);
+       }
+       if (!amroot && pw->pw_uid != getuid()) {
+               syslog(LOG_WARNING, "can't change pwd for `%s'", name);
+               error_msg_and_die("Permission denied.\n");
+       }
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+       sp = getspnam(name);
+       if (!sp) {
+               sp = (struct spwd *) pwd_to_spwd(pw);
+       }
+       cp = sp->sp_pwdp;
+       np = sp->sp_namp;
+#else
+       cp = pw->pw_passwd;
+       np = name;
+#endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
+
+       safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
+       if (!(dflg || lflg || uflg)) {
+               if (!amroot) {
+                       if (cp[0] == '!') {
+                               syslog(LOG_WARNING, "password locked for `%s'", np);
+                               error_msg_and_die( "The password for `%s' cannot be changed.\n", np);
+                       }
+               }
+               printf("Changing password for %s\n", name);
+               if (new_password(pw, amroot, algo)) {
+                       error_msg_and_die( "The password for %s is unchanged.\n", name);
+               }
+       } else if (lflg) {
+               if (crypt_passwd[0] != '!') {
+                       memmove(&crypt_passwd[1], crypt_passwd,
+                                       sizeof crypt_passwd - 1);
+                       crypt_passwd[sizeof crypt_passwd - 1] = '\0';
+                       crypt_passwd[0] = '!';
+               }
+       } else if (uflg) {
+               if (crypt_passwd[0] == '!') {
+                       memmove(crypt_passwd, &crypt_passwd[1],
+                                       sizeof crypt_passwd - 1);
+               }
+       } else if (dflg) {
+               crypt_passwd[0] = '\0';
+       }
+       set_filesize_limit(30000);
+       signal(SIGHUP, SIG_IGN);
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       umask(077);
+       if (setuid(0)) {
+               syslog(LOG_ERR, "can't setuid(0)");
+               error_msg_and_die( "Cannot change ID to root.\n");
+       }
+       if (!update_passwd(pw, crypt_passwd)) {
+               syslog(LOG_INFO, "password for `%s' changed by user `%s'", name,
+                          myname);
+               printf("Password changed.\n");
+       } else {
+               syslog(LOG_WARNING,
+                          "an error occurred updating the password file");
+               error_msg_and_die("An error occurred updating the password file.\n");
+       }
+       return (0);
+}
+
+
+
+static int create_backup(const char *backup, FILE * fp)
+{
+       struct stat sb;
+       struct utimbuf ub;
+       FILE *bkfp;
+       int c, mask;
+
+       if (fstat(fileno(fp), &sb))
+               /* return -1; */
+               return 1;
+
+       mask = umask(077);
+       bkfp = fopen(backup, "w");
+       umask(mask);
+       if (!bkfp)
+               /* return -1; */
+               return 1;
+
+       /* TODO: faster copy, not one-char-at-a-time.  --marekm */
+       rewind(fp);
+       while ((c = getc(fp)) != EOF) {
+               if (putc(c, bkfp) == EOF)
+                       break;
+       }
+       if (c != EOF || fflush(bkfp)) {
+               fclose(bkfp);
+               /* return -1; */
+               return 1;
+       }
+       if (fclose(bkfp))
+               /* return -1; */
+               return 1;
+
+       ub.actime = sb.st_atime;
+       ub.modtime = sb.st_mtime;
+       utime(backup, &ub);
+       return 0;
+}
+
+static int i64c(int i)
+{
+       if (i <= 0)
+               return ('.');
+       if (i == 1)
+               return ('/');
+       if (i >= 2 && i < 12)
+               return ('0' - 2 + i);
+       if (i >= 12 && i < 38)
+               return ('A' - 12 + i);
+       if (i >= 38 && i < 63)
+               return ('a' - 38 + i);
+       return ('z');
+}
+
+static char *crypt_make_salt(void)
+{
+       time_t now;
+       static unsigned long x;
+       static char result[3];
+
+       time(&now);
+       x += now + getpid() + clock();
+       result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);
+       result[1] = i64c(((x >> 12) ^ x) & 077);
+       result[2] = '\0';
+       return result;
+}
+
+
+static int new_password(const struct passwd *pw, int amroot, int algo)
+{
+       char *clear;
+       char *cipher;
+       char *cp;
+       char orig[200];
+       char pass[200];
+       time_t start, now;
+
+       if (!amroot && crypt_passwd[0]) {
+               if (!(clear = getpass("Old password:"))) {
+                       /* return -1; */
+                       return 1;
+               }
+               cipher = pw_encrypt(clear, crypt_passwd);
+               if (strcmp(cipher, crypt_passwd) != 0) {
+                       syslog(LOG_WARNING, "incorrect password for `%s'",
+                                  pw->pw_name);
+                       time(&start);
+                       now = start;
+                       while (difftime(now, start) < FAIL_DELAY) {
+                               sleep(FAIL_DELAY);
+                               time(&now);
+                       }
+                       fprintf(stderr, "Incorrect password.\n");
+                       /* return -1; */
+                       return 1;
+               }
+               safe_strncpy(orig, clear, sizeof(orig));
+               bzero(clear, strlen(clear));
+               bzero(cipher, strlen(cipher));
+       } else {
+               orig[0] = '\0';
+       }
+       if (!
+               (cp =
+                getpass ("Enter the new password (minimum of 5, maximum of 8 characters)\n""
+                        Please use a combination of upper and lower case letters and numbers.\nEnter new password: ")))
+       {
+               bzero(orig, sizeof orig);
+               /* return -1; */
+               return 1;
+       }
+       safe_strncpy(pass, cp, sizeof(pass));
+       bzero(cp, strlen(cp));
+       /* if (!obscure(orig, pass, pw)) { */
+       if (obscure(orig, pass, pw)) {
+               if (amroot) {
+                       printf("\nWarning: weak password (continuing).\n");
+               } else {
+                       /* return -1; */
+                       return 1;
+               }
+       }
+       if (!(cp = getpass("Re-enter new password: "))) {
+               bzero(orig, sizeof orig);
+               /* return -1; */
+               return 1;
+       }
+       if (strcmp(cp, pass)) {
+               fprintf(stderr, "Passwords do not match.\n");
+               /* return -1; */
+               return 1;
+       }
+       bzero(cp, strlen(cp));
+       bzero(orig, sizeof(orig));
+
+       if (algo == 1) {
+               cp = pw_encrypt(pass, "$1$");
+       } else
+               cp = pw_encrypt(pass, crypt_make_salt());
+       bzero(pass, sizeof pass);
+       safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
+       return 0;
+}
+
+static void set_filesize_limit(int blocks)
+{
+       struct rlimit rlimit_fsize;
+
+       rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
+       setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
+}
index 33e62e837875c3171a58a0eba2c91357c0b86d68..6d427262efcecc36771611f0f99254aa26b33470 100644 (file)
@@ -1,7 +1,5 @@
 /* vi: set sw=4 ts=4: */
 
-#include "busybox.h"
-
 #include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <time.h>
 
-#include "pwd.h"
-#include "grp.h"
-
-#include "tinylogin.h"
+#include "busybox.h"
 
 
 
@@ -161,7 +156,7 @@ int su_main ( int argc, char **argv )
 
        change_identity ( pw ); 
        setup_environment ( opt_shell, opt_loginshell, !opt_preserve, pw );
-       run_shell ( opt_shell, opt_loginshell, opt_command, opt_args );
+       run_shell ( opt_shell, opt_loginshell, opt_command, (const char**)opt_args );
        
        return EXIT_FAILURE;
 }
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c
new file mode 100644 (file)
index 0000000..a654ffb
--- /dev/null
@@ -0,0 +1,184 @@
+/* vi: set sw=4 ts=4: */
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "busybox.h"
+
+
+// sulogin defines
+#define SULOGIN_PROMPT "\nGive root password for system maintenance\n" \
+       "(or type Control-D for normal startup):"
+
+static const char *forbid[] = {
+       "ENV",
+       "BASH_ENV",
+       "HOME",
+       "IFS",
+       "PATH",
+       "SHELL",
+       "LD_LIBRARY_PATH",
+       "LD_PRELOAD",
+       "LD_TRACE_LOADED_OBJECTS",
+       "LD_BIND_NOW",
+       "LD_AOUT_LIBRARY_PATH",
+       "LD_AOUT_PRELOAD",
+       "LD_NOWARN",
+       "LD_KEEPDIR",
+       (char *) 0
+};
+
+
+
+static void catchalarm(int junk)
+{
+       exit(EXIT_FAILURE);
+}
+
+
+extern int sulogin_main(int argc, char **argv)
+{
+       char *cp;
+       char *device = (char *) 0;
+       const char *name = "root";
+       int timeout = 0;
+       static char pass[BUFSIZ];
+       struct termios termio;
+       struct passwd pwent;
+       struct passwd *pwd;
+       time_t start, now;
+       const char **p;
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+       struct spwd *spwd = NULL;
+#endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
+
+       tcgetattr(0, &termio);
+       /* set control chars */
+       termio.c_cc[VINTR]  = 3;        /* C-c */
+       termio.c_cc[VQUIT]  = 28;       /* C-\ */
+       termio.c_cc[VERASE] = 127; /* C-? */
+       termio.c_cc[VKILL]  = 21;       /* C-u */
+       termio.c_cc[VEOF]   = 4;        /* C-d */
+       termio.c_cc[VSTART] = 17;       /* C-q */
+       termio.c_cc[VSTOP]  = 19;       /* C-s */
+       termio.c_cc[VSUSP]  = 26;       /* C-z */
+       /* use line dicipline 0 */
+       termio.c_line = 0;
+       /* Make it be sane */
+       termio.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+       termio.c_cflag |= CREAD|HUPCL|CLOCAL;
+       /* input modes */
+       termio.c_iflag = ICRNL | IXON | IXOFF;
+       /* output modes */
+       termio.c_oflag = OPOST | ONLCR;
+       /* local modes */
+       termio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
+       tcsetattr(0, TCSANOW, &termio);
+       openlog("sulogin", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
+       if (argc > 1) {
+               if (strncmp(argv[1], "-t", 2) == 0) {
+                       if (strcmp(argv[1], "-t") == 0) {
+                               if (argc > 2) {
+                                       timeout = atoi(argv[2]);
+                                       if (argc > 3) {
+                                               device = argv[3];
+                                       }
+                               }
+                       } else {
+                               if (argc > 2) {
+                                       device = argv[2];
+                               }
+                       }
+               } else {
+                       device = argv[1];
+               }
+               if (device) {
+                       close(0);
+                       close(1);
+                       close(2);
+                       if (open(device, O_RDWR) >= 0) {
+                               dup(0);
+                               dup(0);
+                       } else {
+                               syslog(LOG_WARNING, "cannot open %s\n", device);
+                               exit(EXIT_FAILURE);
+                       }
+               }
+       }
+       if (access(passwd_file, 0) == -1) {
+               syslog(LOG_WARNING, "No password file\n");
+               error_msg_and_die("No password file\n");
+       }
+       if (!isatty(0) || !isatty(1) || !isatty(2)) {
+               exit(EXIT_FAILURE);
+       }
+
+
+       /* Clear out anything dangerous from the environment */
+       for (p = forbid; *p; p++)
+               unsetenv(*p);
+
+
+       signal(SIGALRM, catchalarm);
+       alarm(timeout);
+       if (!(pwd = getpwnam(name))) {
+               syslog(LOG_WARNING, "No password entry for `root'\n");
+               error_msg_and_die("No password entry for `root'\n");
+       }
+       pwent = *pwd;
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+       spwd = NULL;
+       if (pwd && ((strcmp(pwd->pw_passwd, "x") == 0)
+                               || (strcmp(pwd->pw_passwd, "*") == 0))) {
+               endspent();
+               spwd = getspnam(name);
+               if (spwd) {
+                       pwent.pw_passwd = spwd->sp_pwdp;
+               }
+       }
+#endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
+       while (1) {
+               cp = getpass(SULOGIN_PROMPT);
+               if (!cp || !*cp) {
+                       puts("\n");
+                       fflush(stdout);
+                       syslog(LOG_INFO, "Normal startup\n");
+                       exit(EXIT_SUCCESS);
+               } else {
+                       safe_strncpy(pass, cp, sizeof(pass));
+                       bzero(cp, strlen(cp));
+               }
+               if (strcmp(pw_encrypt(pass, pwent.pw_passwd), pwent.pw_passwd) == 0) {
+                       break;
+               }
+               time(&start);
+               now = start;
+               while (difftime(now, start) < FAIL_DELAY) {
+                       sleep(FAIL_DELAY);
+                       time(&now);
+               }
+               puts("Login incorrect");
+               fflush(stdout);
+               syslog(LOG_WARNING, "Incorrect root password\n");
+       }
+       bzero(pass, strlen(pass));
+       alarm(0);
+       signal(SIGALRM, SIG_DFL);
+       puts("Entering System Maintenance Mode\n");
+       fflush(stdout);
+       syslog(LOG_INFO, "System Maintenance Mode\n");
+       run_shell(pwent.pw_shell, 1, 0, 0);
+       return (0);
+}
diff --git a/loginutils/tinylogin.c b/loginutils/tinylogin.c
deleted file mode 100644 (file)
index bd611fd..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "busybox.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <ctype.h>
-
-#include "pwd.h"
-#include "grp.h"
-
-#ifdef CONFIG_FEATURE_SHADOWPASSWDS
-#include "shadow.h"
-#endif
-
-#define DEFAULT_LOGIN_PATH      "/bin:/usr/bin"
-#define DEFAULT_ROOT_LOGIN_PATH "/usr/sbin:/bin:/usr/bin:/sbin"
-
-
-static void xsetenv ( const char *key, const char *value )
-{
-       if ( setenv ( key, value, 1 ))
-               error_msg_and_die ( "out of memory" );
-}
-
-/* Become the user and group(s) specified by PW.  */
-
-void change_identity ( const struct passwd *pw )
-{
-       if ( initgroups ( pw-> pw_name, pw-> pw_gid ) == -1 )
-               perror_msg_and_die ( "cannot set groups" );
-       endgrent ( );
-
-       if ( setgid ( pw-> pw_gid ))
-               perror_msg_and_die ( "cannot set group id" );
-       if ( setuid ( pw->pw_uid ))
-               perror_msg_and_die ( "cannot set user id" );
-}
-
-/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
-   If COMMAND is nonzero, pass it to the shell with the -c option.
-   If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
-   arguments.  */
-
-void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args )
-{
-       const char **args;
-       int argno = 1;
-       int additional_args_cnt = 0;
-       
-       for ( args = additional_args; args && *args; args++ )
-               additional_args_cnt++;
-
-       if ( additional_args )
-               args = (const char **) xmalloc (sizeof (char *) * ( 4  + additional_args_cnt ));
-       else
-               args = (const char **) xmalloc (sizeof (char *) * 4 );
-               
-       args [0] = get_last_path_component ( xstrdup ( shell ));
-       
-       if ( loginshell ) {
-               char *args0 = xmalloc ( xstrlen ( args [0] ) + 2 );
-               args0 [0] = '-';
-               strcpy ( args0 + 1, args [0] );
-               args [0] = args0;
-       }
-    
-       if ( command ) {
-               args [argno++] = "-c";
-               args [argno++] = command;
-       }
-       if ( additional_args ) {
-               for ( ; *additional_args; ++additional_args )
-                       args [argno++] = *additional_args;
-       }
-       args [argno] = 0;
-       execv ( shell, (char **) args );
-       perror_msg_and_die ( "cannot run %s", shell );
-}
-
-/* Return 1 if SHELL is a restricted shell (one not returned by
-   getusershell), else 0, meaning it is a standard shell.  */
-
-int restricted_shell ( const char *shell )
-{
-       char *line;
-
-       setusershell ( );
-       while (( line = getusershell ( ))) {
-               if (( *line != '#' ) && ( strcmp ( line, shell ) == 0 ))
-                       break;
-       }
-       endusershell ( );
-       return line ? 0 : 1;
-}
-
-/* Update `environ' for the new shell based on PW, with SHELL being
-   the value for the SHELL environment variable.  */
-
-void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw )
-{
-       if ( loginshell ) {
-               char *term;
-       
-               /* Change the current working directory to be the home directory
-                * of the user.  It is a fatal error for this process to be unable
-                * to change to that directory.  There is no "default" home
-                * directory.
-                * Some systems default to HOME=/
-                */              
-               if ( chdir ( pw-> pw_dir )) {
-                       if ( chdir ( "/" )) {
-                               syslog ( LOG_WARNING, "unable to cd to %s' for user %s'\n", pw-> pw_dir, pw-> pw_name );
-                               error_msg_and_die ( "cannot cd to home directory or /" );
-                       }
-                       fputs ( "warning: cannot change to home directory\n", stderr );
-               }
-
-               /* Leave TERM unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
-                  Unset all other environment variables.  */
-               term = getenv ("TERM");
-               clearenv ( );
-               if ( term )
-                       xsetenv ( "TERM", term );
-               xsetenv ( "HOME",    pw-> pw_dir );
-               xsetenv ( "SHELL",   shell );
-               xsetenv ( "USER",    pw-> pw_name );
-               xsetenv ( "LOGNAME", pw-> pw_name );
-               xsetenv ( "PATH",    ( pw-> pw_uid ? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH ));
-       }
-       else if ( changeenv ) {
-               /* Set HOME, SHELL, and if not becoming a super-user,
-                  USER and LOGNAME.  */
-               xsetenv ( "HOME",  pw-> pw_dir );
-               xsetenv ( "SHELL", shell );
-               if  ( pw-> pw_uid ) {
-                       xsetenv ( "USER",    pw-> pw_name );
-                       xsetenv ( "LOGNAME", pw-> pw_name );
-               }
-       }
-}
-
-/* Ask the user for a password.
-   Return 1 if the user gives the correct password for entry PW,
-   0 if not.  Return 1 without asking for a password if run by UID 0
-   or if PW has an empty password.  */
-
-int correct_password ( const struct passwd *pw )
-{
-       char *unencrypted, *encrypted, *correct;
-       
-#ifdef CONFIG_FEATURE_SHADOWPASSWDS
-       if (( strcmp ( pw-> pw_passwd, "x" ) == 0 ) || ( strcmp ( pw-> pw_passwd, "*" ) == 0 )) {
-               struct spwd *sp = getspnam ( pw-> pw_name );
-               
-               if ( !sp )
-                       error_msg_and_die ( "no valid shadow password" );
-               
-               correct = sp-> sp_pwdp;
-       }
-       else
-#endif
-       correct = pw-> pw_passwd;
-
-       if ( correct == 0 || correct[0] == '\0' )
-               return 1;
-
-       unencrypted = getpass ( "Password: " );
-       if ( !unencrypted )
-       {
-               fputs ( "getpass: cannot open /dev/tty\n", stderr );
-               return 0;
-       }
-       encrypted = crypt ( unencrypted, correct );
-       memset ( unencrypted, 0, xstrlen ( unencrypted ));
-       return ( strcmp ( encrypted, correct ) == 0 ) ? 1 : 0;
-}
diff --git a/loginutils/tinylogin.h b/loginutils/tinylogin.h
deleted file mode 100644 (file)
index 5e56a2c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef BB_LOGINUTILS_SHELL_H
-#define BB_LOGINUTILS_SHELL_H
-
-extern void change_identity ( const struct passwd *pw );
-extern void run_shell ( const char *shell, int loginshell, const char *command, char **additional_args );
-extern int restricted_shell ( const char *shell );
-extern void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw );
-extern int correct_password ( const struct passwd *pw );
-
-#endif
diff --git a/loginutils/vlock.c b/loginutils/vlock.c
new file mode 100644 (file)
index 0000000..a26999f
--- /dev/null
@@ -0,0 +1,229 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * vlock implementation for busybox
+ *
+ * Copyright (C) 2000 by spoon <spoon@ix.netcom.com>
+ * Written by spoon <spon@ix.netcom.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Shoutz to Michael K. Johnson <johnsonm@redhat.com>, author of the
+ * original vlock.  I snagged a bunch of his code to write this
+ * minimalistic vlock.
+ */
+/* Fixed by Erik Andersen to do passwords the tinylogin way...
+ * It now works with md5, sha1, etc passwords. */
+
+#include <stdio.h>
+#include <sys/vt.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#include "busybox.h"
+
+static struct passwd *pw;
+static struct spwd *spw;
+static struct vt_mode ovtm;
+static struct termios oterm;
+static int vfd;
+static int o_lock_all = 0;
+
+/* getspuid - get a shadow entry by uid */
+struct spwd *getspuid(uid_t uid)
+{
+       struct spwd *sp;
+       struct passwd *mypw;
+
+       if ((mypw = getpwuid(getuid())) == NULL) {
+               return (NULL);
+       }
+       setspent();
+       while ((sp = getspent()) != NULL) {
+               if (strcmp(mypw->pw_name, sp->sp_namp) == 0)
+                       break;
+       }
+       endspent();
+       return (sp);
+}
+
+static void release_vt(int signo)
+{
+       if (!o_lock_all)
+               ioctl(vfd, VT_RELDISP, 1);
+       else
+               ioctl(vfd, VT_RELDISP, 0);
+}
+
+static void acquire_vt(int signo)
+{
+       ioctl(vfd, VT_RELDISP, VT_ACKACQ);
+}
+
+static void restore_terminal(void)
+{
+       ioctl(vfd, VT_SETMODE, &ovtm);
+       tcsetattr(STDIN_FILENO, TCSANOW, &oterm);
+}
+
+extern int vlock_main(int argc, char **argv)
+{
+       sigset_t sig;
+       struct sigaction sa;
+       struct vt_mode vtm;
+       int times = 0;
+       struct termios term;
+
+       if (argc > 2) {
+               show_usage();
+       }
+
+       if (argc == 2) {
+               if (strncmp(argv[1], "-a", 2)) {
+                       show_usage();
+               } else {
+                       o_lock_all = 1;
+               }
+       }
+
+       if ((pw = getpwuid(getuid())) == NULL) {
+               error_msg_and_die("no password for uid %d\n", getuid());
+       }
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+       if ((strcmp(pw->pw_passwd, "x") == 0)
+               || (strcmp(pw->pw_passwd, "*") == 0)) {
+
+               if ((spw = getspuid(getuid())) == NULL) {
+                       error_msg_and_die("could not read shadow password for uid %d: %s\n",
+                                          getuid(), strerror(errno));
+               }
+               if (spw->sp_pwdp) {
+                       pw->pw_passwd = spw->sp_pwdp;
+               }
+       }
+#endif                                                 /* CONFIG_FEATURE_SHADOWPASSWDS */
+       if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') {
+               error_msg_and_die("Account disabled for uid %d\n", getuid());
+       }
+
+       /* we no longer need root privs */
+       setuid(getuid());
+       setgid(getgid());
+
+       if ((vfd = open("/dev/tty", O_RDWR)) < 0) {
+               error_msg_and_die("/dev/tty");
+       };
+
+       if (ioctl(vfd, VT_GETMODE, &vtm) < 0) {
+               error_msg_and_die("/dev/tty");
+       };
+
+       /* mask a bunch of signals */
+       sigprocmask(SIG_SETMASK, NULL, &sig);
+       sigdelset(&sig, SIGUSR1);
+       sigdelset(&sig, SIGUSR2);
+       sigaddset(&sig, SIGTSTP);
+       sigaddset(&sig, SIGTTIN);
+       sigaddset(&sig, SIGTTOU);
+       sigaddset(&sig, SIGHUP);
+       sigaddset(&sig, SIGCHLD);
+       sigaddset(&sig, SIGQUIT);
+       sigaddset(&sig, SIGINT);
+
+       sigemptyset(&(sa.sa_mask));
+       sa.sa_flags = SA_RESTART;
+       sa.sa_handler = release_vt;
+       sigaction(SIGUSR1, &sa, NULL);
+       sa.sa_handler = acquire_vt;
+       sigaction(SIGUSR2, &sa, NULL);
+
+       /* need to handle some signals so that we don't get killed by them */
+       sa.sa_handler = SIG_IGN;
+       sigaction(SIGHUP, &sa, NULL);
+       sigaction(SIGQUIT, &sa, NULL);
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTSTP, &sa, NULL);
+
+       ovtm = vtm;
+       vtm.mode = VT_PROCESS;
+       vtm.relsig = SIGUSR1;
+       vtm.acqsig = SIGUSR2;
+       ioctl(vfd, VT_SETMODE, &vtm);
+
+       tcgetattr(STDIN_FILENO, &oterm);
+       term = oterm;
+       term.c_iflag &= ~BRKINT;
+       term.c_iflag |= IGNBRK;
+       term.c_lflag &= ~ISIG;
+       term.c_lflag &= ~(ECHO | ECHOCTL);
+       tcsetattr(STDIN_FILENO, TCSANOW, &term);
+
+       do {
+               char *pass, *crypt_pass;
+               char prompt[100];
+
+               if (o_lock_all) {
+                       printf("All Virtual Consoles locked.\n");
+               } else {
+                       printf("This Virtual Console locked.\n");
+               }
+               fflush(stdout);
+
+               snprintf(prompt, 100, "%s's password: ", pw->pw_name);
+
+               if ((pass = getpass(prompt)) == NULL) {
+                       perror("getpass");
+                       restore_terminal();
+                       exit(1);
+               }
+
+               crypt_pass = pw_encrypt(pass, pw->pw_passwd);
+               if (strncmp(crypt_pass, pw->pw_passwd, sizeof(crypt_pass)) == 0) {
+                       memset(pass, 0, strlen(pass));
+                       memset(crypt_pass, 0, strlen(crypt_pass));
+                       restore_terminal();
+                       return 0;
+               }
+               memset(pass, 0, strlen(pass));
+               memset(crypt_pass, 0, strlen(crypt_pass));
+
+               if (isatty(STDIN_FILENO) == 0) {
+                       perror("isatty");
+                       restore_terminal();
+                       exit(1);
+               }
+
+               sleep(++times);
+               printf("Password incorrect.\n");
+               if (times >= 3) {
+                       sleep(15);
+                       times = 2;
+               }
+       } while (1);
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/