diff --git a/include/applets.h b/include/applets.h index 3a8c731a5..c2d7acf4b 100644 --- a/include/applets.h +++ b/include/applets.h @@ -335,6 +335,9 @@ #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 @@ -419,6 +422,9 @@ #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 @@ -505,6 +511,9 @@ #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 diff --git a/include/libbb.h b/include/libbb.h index 0b2411fcd..2b9fd5fd6 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -39,6 +39,16 @@ #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 index 000000000..a677d5262 --- /dev/null +++ b/include/shadow_.h @@ -0,0 +1,82 @@ +/* + * Copyright 1988 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _H_SHADOW +#define _H_SHADOW + + +#ifdef USE_SYSTEM_SHADOW +#include +#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 /* 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 */ diff --git a/include/usage.h b/include/usage.h index 08ee00d77..18593fb1d 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1321,6 +1321,24 @@ "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 \ @@ -1586,6 +1604,15 @@ "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 \ @@ -1956,6 +1983,13 @@ "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 \ diff --git a/libbb/Makefile.in b/libbb/Makefile.in index c6493bfa6..2af70f8c7 100644 --- a/libbb/Makefile.in +++ b/libbb/Makefile.in @@ -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 index 000000000..819b216e0 --- /dev/null +++ b/libbb/change_identity.c @@ -0,0 +1,54 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 1989 - 1991, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..758b89eed --- /dev/null +++ b/libbb/correct_password.c @@ -0,0 +1,78 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 1989 - 1991, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/libbb/libc5.c b/libbb/libc5.c index df622f65b..af15d1ac7 100644 --- a/libbb/libc5.c +++ b/libbb/libc5.c @@ -11,6 +11,24 @@ #if __GNU_LIBRARY__ < 5 +/* + * Some systems already have updwtmp(). Some don't... This is + * the updwtmp() implementation from uClibc, Copyright 2002 by + * Erik Andersen + */ +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. diff --git a/libbb/messages.c b/libbb/messages.c index 895cfdc2b..185c1ee91 100644 --- a/libbb/messages.c +++ b/libbb/messages.c @@ -66,3 +66,39 @@ #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 index 000000000..dc7de751d --- /dev/null +++ b/libbb/obscure.c @@ -0,0 +1,246 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 1989 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 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 +#include +#include +#include +#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 index 000000000..0e4eb9f8a --- /dev/null +++ b/libbb/pw_encrypt.c @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routine. + * + * Copyright (C) 1999-2002 by Erik Andersen + * + * 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 +#include +#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 index 000000000..95a2e4684 --- /dev/null +++ b/libbb/pwd2spwd.c @@ -0,0 +1,73 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 1989 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#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 index 000000000..74a64140f --- /dev/null +++ b/libbb/restricted_shell.c @@ -0,0 +1,57 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 1989 - 1991, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#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 index 000000000..30050fecb --- /dev/null +++ b/libbb/run_shell.c @@ -0,0 +1,81 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 1989 - 1991, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#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/loginutils/tinylogin.c b/libbb/setup_environment.c similarity index 51% rename from loginutils/tinylogin.c rename to libbb/setup_environment.c index bd611fd70..dc171fa1f 100644 --- a/loginutils/tinylogin.c +++ b/libbb/setup_environment.c @@ -28,8 +28,6 @@ * SUCH DAMAGE. */ -#include "busybox.h" - #include #include #include @@ -37,98 +35,19 @@ #include #include #include +#include "libbb.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" ); + 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 ) { @@ -172,38 +91,3 @@ void setup_environment ( const char *shell, int loginshell, int changeenv, const } } -/* 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/Makefile.in b/loginutils/Makefile.in index adee35baa..cb6452c39 100644 --- a/loginutils/Makefile.in +++ b/loginutils/Makefile.in @@ -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) diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c index e04a8d784..87e98fb18 100644 --- a/loginutils/addgroup.c +++ b/loginutils/addgroup.c @@ -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 $ */ diff --git a/loginutils/adduser.c b/loginutils/adduser.c index 66fcaa23f..7aa7fcfd3 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c @@ -33,11 +33,7 @@ #include #include #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 $ */ diff --git a/loginutils/config.in b/loginutils/config.in index 265d45ab4..b3880aa3d 100644 --- a/loginutils/config.in +++ b/loginutils/config.in @@ -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 diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 481a716e7..c7d6ece64 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -28,10 +28,6 @@ #include #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 $ */ diff --git a/loginutils/login.c b/loginutils/login.c index 8ccc5bc8a..7687556ba 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -14,16 +14,9 @@ #include #include #include + #include "busybox.h" -#include "pwd.h" -#include "grp.h" - -#ifdef CONFIG_FEATURE_SHADOWPASSWDS -#include "shadow.h" -#endif - -#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 index 000000000..9c84c167c --- /dev/null +++ b/loginutils/passwd.c @@ -0,0 +1,408 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/loginutils/su.c b/loginutils/su.c index 33e62e837..6d427262e 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -1,7 +1,5 @@ /* vi: set sw=4 ts=4: */ -#include "busybox.h" - #include #include #include @@ -18,10 +16,7 @@ #include #include -#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 index 000000000..a654ffb89 --- /dev/null +++ b/loginutils/sulogin.c @@ -0,0 +1,184 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.h b/loginutils/tinylogin.h deleted file mode 100644 index 5e56a2c7f..000000000 --- a/loginutils/tinylogin.h +++ /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 index 000000000..a26999f89 --- /dev/null +++ b/loginutils/vlock.c @@ -0,0 +1,229 @@ +/* vi: set sw=4 ts=4: */ +/* + * vlock implementation for busybox + * + * Copyright (C) 2000 by spoon + * Written by spoon + * + * 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 , 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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: +*/