From 5e1a84ab74d5e97582427f016f291a8c11e66f99 Mon Sep 17 00:00:00 2001 From: jutteau Date: Fri, 11 May 2007 18:10:19 +0000 Subject: Completion du script de mise à jour de la pc-104 : * Ajout des sources de busybox dans ./conf/busybox/ * Ajout d'un fichier réclamé par les script dans ./conf/busybox.links --- i/pc104/initrd/conf/busybox/loginutils/Config.in | 193 +++++ i/pc104/initrd/conf/busybox/loginutils/Kbuild | 17 + i/pc104/initrd/conf/busybox/loginutils/addgroup.c | 111 +++ i/pc104/initrd/conf/busybox/loginutils/adduser.c | 196 +++++ i/pc104/initrd/conf/busybox/loginutils/deluser.c | 83 +++ i/pc104/initrd/conf/busybox/loginutils/getty.c | 856 ++++++++++++++++++++++ i/pc104/initrd/conf/busybox/loginutils/login.c | 403 ++++++++++ i/pc104/initrd/conf/busybox/loginutils/passwd.c | 347 +++++++++ i/pc104/initrd/conf/busybox/loginutils/su.c | 103 +++ i/pc104/initrd/conf/busybox/loginutils/sulogin.c | 126 ++++ i/pc104/initrd/conf/busybox/loginutils/vlock.c | 119 +++ 11 files changed, 2554 insertions(+) create mode 100644 i/pc104/initrd/conf/busybox/loginutils/Config.in create mode 100644 i/pc104/initrd/conf/busybox/loginutils/Kbuild create mode 100644 i/pc104/initrd/conf/busybox/loginutils/addgroup.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/adduser.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/deluser.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/getty.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/login.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/passwd.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/su.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/sulogin.c create mode 100644 i/pc104/initrd/conf/busybox/loginutils/vlock.c (limited to 'i/pc104/initrd/conf/busybox/loginutils') diff --git a/i/pc104/initrd/conf/busybox/loginutils/Config.in b/i/pc104/initrd/conf/busybox/loginutils/Config.in new file mode 100644 index 0000000..03a638c --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/Config.in @@ -0,0 +1,193 @@ +# +# For a description of the syntax of this configuration file, +# see scripts/kbuild/config-language.txt. +# + +menu "Login/Password Management Utilities" + +config FEATURE_SHADOWPASSWDS + bool "Support for shadow passwords" + default n + help + Build support for shadow password in /etc/shadow. This file is only + readable by root and thus the encrypted passwords are no longer + publicly readable. + +config USE_BB_SHADOW + bool " Use busybox shadow password functions" + default y + depends on USE_BB_PWD_GRP && FEATURE_SHADOWPASSWDS + help + If you leave this disabled, busybox will use the system's shadow + password handling functions. And if you are using the GNU C library + (glibc), you will then need to install the /etc/nsswitch.conf + configuration file and the required /lib/libnss_* libraries in + order for the shadow password functions to work. This generally + makes your embedded system quite a bit larger. + + Enabling this option will cause busybox to directly access the + system's /etc/shadow file when handling shadow passwords. This + makes your system smaller and I will get fewer emails asking about + how glibc NSS works). When this option is enabled, you will not be + able to use PAM to access shadow passwords from remote LDAP + password servers and whatnot. + +config USE_BB_PWD_GRP + bool "Use internal password and group functions rather than system functions" + default n + help + If you leave this disabled, busybox will use the system's password + and group functions. And if you are using the GNU C library + (glibc), you will then need to install the /etc/nsswitch.conf + configuration file and the required /lib/libnss_* libraries in + order for the password and group functions to work. This generally + makes your embedded system quite a bit larger. + + Enabling this option will cause busybox to directly access the + system's /etc/password, /etc/group files (and your system will be + smaller, and I will get fewer emails asking about how glibc NSS + works). When this option is enabled, you will not be able to use + PAM to access remote LDAP password servers and whatnot. And if you + want hostname resolution to work with glibc, you still need the + /lib/libnss_* libraries. + + If you enable this option, it will add about 1.5k to busybox. + +config ADDGROUP + bool "addgroup" + default n + help + Utility for creating a new group account. + +config DELGROUP + bool "delgroup" + default n + help + Utility for deleting a group account. + +config ADDUSER + bool "adduser" + default n + help + Utility for creating a new user account. + +config DELUSER + bool "deluser" + default n + help + Utility for deleting a user account. + +config GETTY + bool "getty" + default n + select FEATURE_SYSLOG + help + getty lets you log in on a tty, it is normally invoked by init. + +config FEATURE_UTMP + bool "Support utmp file" + depends on GETTY || LOGIN || SU || WHO + default n + help + The file /var/run/utmp is used to track who is currently logged in. + +config FEATURE_WTMP + bool "Support wtmp file" + depends on GETTY || LOGIN || SU || LAST + default n + select FEATURE_UTMP + help + The file /var/run/wtmp is used to track when user's have logged into + and logged out of the system. + +config LOGIN + bool "login" + default n + select FEATURE_SUID + select FEATURE_SYSLOG + help + login is used when signing onto a system. + + Note that Busybox binary must be setuid root for this applet to + work properly. + +config LOGIN_SCRIPTS + bool "Support for login scripts" + depends on LOGIN + default n + help + Enable this if you want login to execute $LOGIN_PRE_SUID_SCRIPT + just prior to switching from root to logged-in user. + +config FEATURE_SECURETTY + bool "Support for /etc/securetty" + default y + depends on LOGIN + help + The file /etc/securetty is used by (some versions of) login(1). + The file contains the device names of tty lines (one per line, + without leading /dev/) on which root is allowed to login. + +config PASSWD + bool "passwd" + default n + select FEATURE_SUID + select FEATURE_SYSLOG + help + passwd changes passwords for user and group accounts. A normal user + may only change the password for his/her own account, the super user + may change the password for any account. The administrator of a group + may change the password for the group. + + Note that Busybox binary must be setuid root for this applet to + work properly. + +config FEATURE_PASSWD_WEAK_CHECK + bool "Check new passwords for weakness" + default y + depends on PASSWD + help + With this option passwd will refuse new passwords which are "weak". + +config SU + bool "su" + default n + select FEATURE_SUID + select FEATURE_SYSLOG + help + su is used to become another user during a login session. + Invoked without a username, su defaults to becoming the super user. + + Note that Busybox binary must be setuid root for this applet to + work properly. + +config FEATURE_SU_SYSLOG + bool "Enable su to write to syslog" + default y + depends on SU + +config FEATURE_SU_CHECKS_SHELLS + bool "Enable su to check user's shell to be listed in /etc/shells" + depends on SU + default y + +config SULOGIN + bool "sulogin" + default n + select FEATURE_SYSLOG + help + sulogin is invoked when the system goes into single user + mode (this is done through an entry in inittab). + +config VLOCK + bool "vlock" + default n + select FEATURE_SUID + help + Build the "vlock" applet which allows you to lock (virtual) terminals. + + Note that Busybox binary must be setuid root for this applet to + work properly. + +endmenu + diff --git a/i/pc104/initrd/conf/busybox/loginutils/Kbuild b/i/pc104/initrd/conf/busybox/loginutils/Kbuild new file mode 100644 index 0000000..6c9d193 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/Kbuild @@ -0,0 +1,17 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under the GPL v2, see the file LICENSE in this tarball. + +lib-y:= +lib-$(CONFIG_ADDGROUP) += addgroup.o +lib-$(CONFIG_ADDUSER) += adduser.o +lib-$(CONFIG_GETTY) += getty.o +lib-$(CONFIG_LOGIN) += login.o +lib-$(CONFIG_PASSWD) += passwd.o +lib-$(CONFIG_SU) += su.o +lib-$(CONFIG_SULOGIN) += sulogin.o +lib-$(CONFIG_VLOCK) += vlock.o +lib-$(CONFIG_DELUSER) += deluser.o +lib-$(CONFIG_DELGROUP) += deluser.o diff --git a/i/pc104/initrd/conf/busybox/loginutils/addgroup.c b/i/pc104/initrd/conf/busybox/loginutils/addgroup.c new file mode 100644 index 0000000..78250a4 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/addgroup.c @@ -0,0 +1,111 @@ +/* vi: set sw=4 ts=4: */ +/* + * addgroup - add users to /etc/passwd and /etc/shadow + * + * Copyright (C) 1999 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + */ + +#include "busybox.h" + +/* make sure gr_name isn't taken, make sure gid is kosher + * return 1 on failure */ +static int group_study(struct group *g) +{ + enum { max = 65000 }; + FILE *etc_group; + gid_t desired; + /* Using _r function to avoid static buffers pulled in */ + char buffer[256]; + struct group grp; + struct group *result; + + etc_group = xfopen(bb_path_group_file, "r"); + + /* make sure gr_name isn't taken, make sure gid is kosher */ + desired = g->gr_gid; + while (!fgetgrent_r(etc_group, &grp, buffer, sizeof(buffer), &result)) { + if ((strcmp(grp.gr_name, g->gr_name)) == 0) { + bb_error_msg_and_die("%s: group already in use", g->gr_name); + } + if ((desired) && grp.gr_gid == desired) { + bb_error_msg_and_die("%d: gid already in use", + desired); + } + if ((grp.gr_gid > g->gr_gid) && (grp.gr_gid < max)) { + g->gr_gid = grp.gr_gid; + } + } + if (ENABLE_FEATURE_CLEAN_UP) + fclose(etc_group); + + /* gid */ + g->gr_gid++; + if (desired) { + g->gr_gid = desired; + } + /* return 1; */ + return 0; +} + +/* append a new user to the passwd file */ +static int addgroup(char *group, gid_t gid, const char *user) +{ + FILE *file; + struct group gr; + + /* make sure gid and group haven't already been allocated */ + gr.gr_gid = gid; + gr.gr_name = group; + if (group_study(&gr)) + return 1; + + /* add entry to group */ + file = xfopen(bb_path_group_file, "a"); + /* group:passwd:gid:userlist */ + fprintf(file, "%s:%s:%d:%s\n", group, "x", gr.gr_gid, user); + if (ENABLE_FEATURE_CLEAN_UP) + fclose(file); + +#if ENABLE_FEATURE_SHADOWPASSWDS + file = fopen_or_warn(bb_path_gshadow_file, "a"); + if (file) { + fprintf(file, "%s:!::\n", group); + if (ENABLE_FEATURE_CLEAN_UP) + fclose(file); + } +#endif + + /* return 1; */ + return 0; +} + +/* + * addgroup will take a login_name as its first parameter. + * + * gid can be customized via command-line parameters. + */ +int addgroup_main(int argc, char **argv); +int addgroup_main(int argc, char **argv) +{ + char *group; + gid_t gid = 0; + + /* check for min, max and missing args and exit on error */ + opt_complementary = "-1:?2:?"; + if (getopt32(argc, argv, "g:", &group)) { + gid = xatoul_range(group, 0, (gid_t)ULONG_MAX); + } + /* move past the commandline options */ + argv += optind; + + /* need to be root */ + if (geteuid()) { + bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); + } + + return addgroup(argv[0], gid, argv[1] ? argv[1] : ""); +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/adduser.c b/i/pc104/initrd/conf/busybox/loginutils/adduser.c new file mode 100644 index 0000000..4c03790 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/adduser.c @@ -0,0 +1,196 @@ +/* vi: set sw=4 ts=4: */ +/* + * adduser - add users to /etc/passwd and /etc/shadow + * + * Copyright (C) 1999 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + */ + +#include "busybox.h" + +#define OPT_DONT_SET_PASS (1 << 4) +#define OPT_DONT_MAKE_HOME (1 << 6) + + +/* remix */ +/* EDR recoded such that the uid may be passed in *p */ +static int passwd_study(const char *filename, struct passwd *p) +{ + enum { min = 500, max = 65000 }; + FILE *passwd; + /* We are using reentrant fgetpwent_r() in order to avoid + * pulling in static buffers from libc (think static build here) */ + char buffer[256]; + struct passwd pw; + struct passwd *result; + + passwd = xfopen(filename, "r"); + + /* EDR if uid is out of bounds, set to min */ + if ((p->pw_uid > max) || (p->pw_uid < min)) + p->pw_uid = min; + + /* stuff to do: + * make sure login isn't taken; + * find free uid and gid; + */ + while (!fgetpwent_r(passwd, &pw, buffer, sizeof(buffer), &result)) { + if (strcmp(pw.pw_name, p->pw_name) == 0) { + /* return 0; */ + return 1; + } + if ((pw.pw_uid >= p->pw_uid) && (pw.pw_uid < max) + && (pw.pw_uid >= min)) { + p->pw_uid = pw.pw_uid + 1; + } + } + + if (p->pw_gid == 0) { + /* EDR check for an already existing gid */ + while (getgrgid(p->pw_uid) != NULL) + p->pw_uid++; + + /* EDR also check for an existing group definition */ + if (getgrnam(p->pw_name) != NULL) + return 3; + + /* EDR create new gid always = uid */ + p->pw_gid = p->pw_uid; + } + + /* EDR bounds check */ + if ((p->pw_uid > max) || (p->pw_uid < min)) + return 2; + + /* return 1; */ + return 0; +} + +static void addgroup_wrapper(struct passwd *p) +{ + char *cmd; + + cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name); + system(cmd); + free(cmd); +} + +static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN; + +static void passwd_wrapper(const char *login) +{ + static const char prog[] = "passwd"; + BB_EXECLP(prog, prog, login, NULL); + bb_error_msg_and_die("failed to execute '%s', you must set the password for '%s' manually", prog, login); +} + +/* putpwent(3) remix */ +static int adduser(struct passwd *p) +{ + FILE *file; + int addgroup = !p->pw_gid; + + /* make sure everything is kosher and setup uid && gid */ + file = xfopen(bb_path_passwd_file, "a"); + fseek(file, 0, SEEK_END); + + switch (passwd_study(bb_path_passwd_file, p)) { + case 1: + bb_error_msg_and_die("%s: login already in use", p->pw_name); + case 2: + bb_error_msg_and_die("illegal uid or no uids left"); + case 3: + bb_error_msg_and_die("%s: group name already in use", p->pw_name); + } + + /* add to passwd */ + if (putpwent(p, file) == -1) { + bb_perror_nomsg_and_die(); + } + fclose(file); + +#if ENABLE_FEATURE_SHADOWPASSWDS + /* add to shadow if necessary */ + file = xfopen(bb_path_shadow_file, "a"); + fseek(file, 0, SEEK_END); + fprintf(file, "%s:!:%ld:%d:%d:%d:::\n", + p->pw_name, /* username */ + time(NULL) / 86400, /* sp->sp_lstchg */ + 0, /* sp->sp_min */ + 99999, /* sp->sp_max */ + 7); /* sp->sp_warn */ + fclose(file); +#endif + + /* add to group */ + /* addgroup should be responsible for dealing w/ gshadow */ + /* if using a pre-existing group, don't create one */ + if (addgroup) addgroup_wrapper(p); + + /* Clear the umask for this process so it doesn't + * * screw up the permissions on the mkdir and chown. */ + umask(0); + if (!(option_mask32 & OPT_DONT_MAKE_HOME)) { + /* Set the owner and group so it is owned by the new user, + then fix up the permissions to 2755. Can't do it before + since chown will clear the setgid bit */ + if (mkdir(p->pw_dir, 0755) + || chown(p->pw_dir, p->pw_uid, p->pw_gid) + || chmod(p->pw_dir, 02755)) { + bb_perror_msg("%s", p->pw_dir); + } + } + + if (!(option_mask32 & OPT_DONT_SET_PASS)) { + /* interactively set passwd */ + passwd_wrapper(p->pw_name); + } + + return 0; +} + +/* + * adduser will take a login_name as its first parameter. + * + * home + * shell + * gecos + * + * can be customized via command-line parameters. + */ +int adduser_main(int argc, char **argv); +int adduser_main(int argc, char **argv) +{ + struct passwd pw; + const char *usegroup = NULL; + + /* got root? */ + if (geteuid()) { + bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); + } + + pw.pw_gecos = (char *)"Linux User,,,"; + pw.pw_shell = (char *)DEFAULT_SHELL; + pw.pw_dir = NULL; + + /* check for min, max and missing args and exit on error */ + opt_complementary = "-1:?1:?"; + getopt32(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); + + /* create string for $HOME if not specified already */ + if (!pw.pw_dir) { + snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]); + pw.pw_dir = bb_common_bufsiz1; + } + + /* create a passwd struct */ + pw.pw_name = argv[optind]; + pw.pw_passwd = (char *)"x"; + pw.pw_uid = 0; + pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */ + + /* grand finale */ + return adduser(&pw); +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/deluser.c b/i/pc104/initrd/conf/busybox/loginutils/deluser.c new file mode 100644 index 0000000..e9bde00 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/deluser.c @@ -0,0 +1,83 @@ +/* vi: set sw=4 ts=4: */ +/* + * deluser (remove lusers from the system ;) for TinyLogin + * + * Copyright (C) 1999 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * Unified with delgroup by Tito Ragusa + * + * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * + */ + +#include "busybox.h" + +static void del_line_matching(const char *login, const char *filename) +{ + char *line; + FILE *passwd; + int len = strlen(login); + int found = 0; + llist_t *plist = NULL; + + passwd = fopen_or_warn(filename, "r"); + if (!passwd) return; + + while ((line = xmalloc_fgets(passwd))) { + if (!strncmp(line, login, len) + && line[len] == ':' + ) { + found++; + free(line); + } else { + llist_add_to_end(&plist, line); + } + } + + if (!ENABLE_FEATURE_CLEAN_UP) { + if (!found) { + bb_error_msg("can't find '%s' in '%s'", login, filename); + return; + } + passwd = fopen_or_warn(filename, "w"); + if (passwd) + while ((line = llist_pop(&plist))) + fputs(line, passwd); + } else { + if (!found) { + bb_error_msg("can't find '%s' in '%s'", login, filename); + goto clean_up; + } + fclose(passwd); + passwd = fopen_or_warn(filename, "w"); + if (passwd) { + clean_up: + while ((line = llist_pop(&plist))) { + if (found) fputs(line, passwd); + free(line); + } + fclose(passwd); + } + } +} + +int deluser_main(int argc, char **argv); +int deluser_main(int argc, char **argv) +{ + if (argc != 2) + bb_show_usage(); + + if (ENABLE_DELUSER + && (!ENABLE_DELGROUP || applet_name[3] == 'u') + ) { + del_line_matching(argv[1], bb_path_passwd_file); + if (ENABLE_FEATURE_SHADOWPASSWDS) + del_line_matching(argv[1], bb_path_shadow_file); + } + del_line_matching(argv[1], bb_path_group_file); + if (ENABLE_FEATURE_SHADOWPASSWDS) + del_line_matching(argv[1], bb_path_gshadow_file); + + return EXIT_SUCCESS; +} + diff --git a/i/pc104/initrd/conf/busybox/loginutils/getty.c b/i/pc104/initrd/conf/busybox/loginutils/getty.c new file mode 100644 index 0000000..64d2d08 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/getty.c @@ -0,0 +1,856 @@ +/* vi: set sw=4 ts=4: */ +/* agetty.c - another getty program for Linux. By W. Z. Venema 1989 + * Ported to Linux by Peter Orbaek + * This program is freely distributable. The entire man-page used to + * be here. Now read the real man-page agetty.8 instead. + * + * option added by Eric Rasmussen - 12/28/95 + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + + * 1999-05-05 Thorsten Kranzkowski + * - enable hardware flow control before displaying /etc/issue + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + */ + +#include "busybox.h" +#include + +#if ENABLE_FEATURE_UTMP +#include +#endif + +/* + * Some heuristics to find out what environment we are in: if it is not + * System V, assume it is SunOS 4. + */ +#ifdef LOGIN_PROCESS /* defined in System V utmp.h */ +#define SYSV_STYLE /* select System V style getty */ +#include +#include +#if ENABLE_FEATURE_WTMP +extern void updwtmp(const char *filename, const struct utmp *ut); +static void update_utmp(const char *line); +#endif +#endif /* LOGIN_PROCESS */ + +/* + * Things you may want to modify. + * + * You may disagree with the default line-editing etc. characters defined + * below. Note, however, that DEL cannot be used for interrupt generation + * and for line editing at the same time. + */ + +/* I doubt there are systems which still need this */ +#undef HANDLE_ALLCAPS + +#define _PATH_LOGIN "/bin/login" + +/* If ISSUE is not defined, getty will never display the contents of the + * /etc/issue file. You will not want to spit out large "issue" files at the + * wrong baud rate. + */ +#define ISSUE "/etc/issue" /* displayed before the login prompt */ + +/* Some shorthands for control characters. */ +#define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */ +#define CR CTL('M') /* carriage return */ +#define NL CTL('J') /* line feed */ +#define BS CTL('H') /* back space */ +#define DEL CTL('?') /* delete */ + +/* Defaults for line-editing etc. characters; you may want to change this. */ +#define DEF_ERASE DEL /* default erase character */ +#define DEF_INTR CTL('C') /* default interrupt character */ +#define DEF_QUIT CTL('\\') /* default quit char */ +#define DEF_KILL CTL('U') /* default kill char */ +#define DEF_EOF CTL('D') /* default EOF char */ +#define DEF_EOL '\n' +#define DEF_SWITCH 0 /* default switch char */ + +/* + * When multiple baud rates are specified on the command line, the first one + * we will try is the first one specified. + */ +#define FIRST_SPEED 0 + +/* Storage for command-line options. */ + +#define MAX_SPEED 10 /* max. nr. of baud rates */ + +struct options { + int flags; /* toggle switches, see below */ + unsigned timeout; /* time-out period */ + const char *login; /* login program */ + const char *tty; /* name of tty */ + const char *initstring; /* modem init string */ + const char *issue; /* alternative issue file */ + int numspeed; /* number of baud rates to try */ + int speeds[MAX_SPEED]; /* baud rates to be tried */ +}; + +static const char opt_string[] = "I:LH:f:hil:mt:wn"; +#define F_INITSTRING (1<<0) /* initstring is set */ +#define F_LOCAL (1<<1) /* force local */ +#define F_FAKEHOST (1<<2) /* force fakehost */ +#define F_CUSTISSUE (1<<3) /* give alternative issue file */ +#define F_RTSCTS (1<<4) /* enable RTS/CTS flow control */ +#define F_ISSUE (1<<5) /* display /etc/issue */ +#define F_LOGIN (1<<6) /* non-default login program */ +#define F_PARSE (1<<7) /* process modem status messages */ +#define F_TIMEOUT (1<<8) /* time out */ +#define F_WAITCRLF (1<<9) /* wait for CR or LF */ +#define F_NOPROMPT (1<<10) /* don't ask for login name! */ + +/* Storage for things detected while the login name was read. */ +struct chardata { + unsigned char erase; /* erase character */ + unsigned char kill; /* kill character */ + unsigned char eol; /* end-of-line character */ + unsigned char parity; /* what parity did we see */ +#ifdef HANDLE_ALLCAPS + unsigned char capslock; /* upper case without lower case */ +#endif +}; + +/* Initial values for the above. */ +static const struct chardata init_chardata = { + DEF_ERASE, /* default erase character */ + DEF_KILL, /* default kill character */ + 13, /* default eol char */ + 0, /* space parity */ +#ifdef HANDLE_ALLCAPS + 0, /* no capslock */ +#endif +}; + +/* The following is used for understandable diagnostics. */ + +/* Fake hostname for ut_host specified on command line. */ +static char *fakehost = NULL; + +/* ... */ +#ifdef DEBUGGING +#define debug(s) fprintf(dbf,s); fflush(dbf) +#define DEBUGTERM "/dev/ttyp0" +static FILE *dbf; +#else +#define debug(s) /* nothing */ +#endif + + +/* bcode - convert speed string to speed code; return 0 on failure */ +static int bcode(const char *s) +{ + int r; + unsigned value = bb_strtou(s, NULL, 10); + if (errno) { + return -1; + } + r = tty_value_to_baud(value); + if (r > 0) { + return r; + } + return 0; +} + + +/* parse_speeds - parse alternate baud rates */ +static void parse_speeds(struct options *op, char *arg) +{ + char *cp; + + debug("entered parse_speeds\n"); + for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { + if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0) + bb_error_msg_and_die("bad speed: %s", cp); + if (op->numspeed > MAX_SPEED) + bb_error_msg_and_die("too many alternate speeds"); + } + debug("exiting parsespeeds\n"); +} + + +/* parse_args - parse command-line arguments */ +static void parse_args(int argc, char **argv, struct options *op) +{ + char *ts; + + op->flags = getopt32(argc, argv, opt_string, + &(op->initstring), &fakehost, &(op->issue), + &(op->login), &ts); + if (op->flags & F_INITSTRING) { + const char *p = op->initstring; + char *q; + + op->initstring = q = xstrdup(op->initstring); + /* copy optarg into op->initstring decoding \ddd + octal codes into chars */ + while (*p) { + if (*p == '\\') { + p++; + *q++ = bb_process_escape_sequence(&p); + } else { + *q++ = *p++; + } + } + *q = '\0'; + } + op->flags ^= F_ISSUE; /* revert flag show /etc/issue */ + if (op->flags & F_TIMEOUT) { + op->timeout = xatoul_range(ts, 1, INT_MAX); + } + argv += optind; + argc -= optind; + debug("after getopt loop\n"); + if (argc < 2) /* check parameter count */ + bb_show_usage(); + + /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ + if (isdigit(argv[0][0])) { + /* a number first, assume it's a speed (BSD style) */ + parse_speeds(op, argv[0]); /* baud rate(s) */ + op->tty = argv[1]; /* tty name */ + } else { + op->tty = argv[0]; /* tty name */ + parse_speeds(op, argv[1]); /* baud rate(s) */ + } + + if (argv[2]) + setenv("TERM", argv[2], 1); + + debug("exiting parseargs\n"); +} + +static void xdup2(int srcfd, int dstfd, const char *tty) +{ + if (dup2(srcfd, dstfd) == -1) + bb_perror_msg_and_die("%s: dup", tty); +} + +/* open_tty - set up tty as standard { input, output, error } */ +static void open_tty(const char *tty, struct termios *tp, int local) +{ + int chdir_to_root = 0; + + /* Set up new standard input, unless we are given an already opened port. */ + + if (NOT_LONE_DASH(tty)) { + struct stat st; + int fd; + + /* Sanity checks... */ + + xchdir("/dev"); + chdir_to_root = 1; + xstat(tty, &st); + if ((st.st_mode & S_IFMT) != S_IFCHR) + bb_error_msg_and_die("%s: not a character device", tty); + + /* Open the tty as standard input. */ + + debug("open(2)\n"); + fd = xopen(tty, O_RDWR | O_NONBLOCK); + xdup2(fd, 0, tty); + while (fd > 2) close(fd--); + } else { + /* + * Standard input should already be connected to an open port. Make + * sure it is open for read/write. + */ + + if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) + bb_error_msg_and_die("stdin is not open for read/write"); + } + + /* Replace current standard output/error fd's with new ones */ + debug("duping\n"); + xdup2(0, 1, tty); + xdup2(0, 2, tty); + + /* + * The following ioctl will fail if stdin is not a tty, but also when + * there is noise on the modem control lines. In the latter case, the + * common course of action is (1) fix your cables (2) give the modem more + * time to properly reset after hanging up. SunOS users can achieve (2) + * by patching the SunOS kernel variable "zsadtrlow" to a larger value; + * 5 seconds seems to be a good value. + */ + + if (ioctl(0, TCGETS, tp) < 0) + bb_perror_msg_and_die("%s: ioctl(TCGETS)", tty); + + /* + * It seems to be a terminal. Set proper protections and ownership. Mode + * 0622 is suitable for SYSV <4 because /bin/login does not change + * protections. SunOS 4 login will change the protections to 0620 (write + * access for group tty) after the login has succeeded. + */ + +#ifdef DEBIAN +#warning Debian /dev/vcs[a]NN hack is deprecated and will be removed + { + /* tty to root.dialout 660 */ + struct group *gr; + int id; + + gr = getgrnam("dialout"); + id = gr ? gr->gr_gid : 0; + chown(tty, 0, id); + chmod(tty, 0660); + + /* vcs,vcsa to root.sys 600 */ + if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) { + char *vcs, *vcsa; + + vcs = xstrdup(tty); + vcsa = xmalloc(strlen(tty) + 2); + strcpy(vcs, "vcs"); + strcpy(vcs + 3, tty + 3); + strcpy(vcsa, "vcsa"); + strcpy(vcsa + 4, tty + 3); + + gr = getgrnam("sys"); + id = gr ? gr->gr_gid : 0; + chown(vcs, 0, id); + chmod(vcs, 0600); + chown(vcsa, 0, id); + chmod(vcs, 0600); + + free(vcs); + free(vcsa); + } + } +#else + if (NOT_LONE_DASH(tty)) { + chown(tty, 0, 0); /* 0:0 */ + chmod(tty, 0622); /* crw--w--w- */ + } +#endif + if (chdir_to_root) + xchdir("/"); +} + +/* termios_init - initialize termios settings */ +static void termios_init(struct termios *tp, int speed, struct options *op) +{ + /* + * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. + * Special characters are set after we have read the login name; all + * reads will be done in raw mode anyway. Errors will be dealt with + * later on. + */ +#ifdef __linux__ + /* flush input and output queues, important for modems! */ + ioctl(0, TCFLSH, TCIOFLUSH); +#endif + + tp->c_cflag = CS8 | HUPCL | CREAD | speed; + if (op->flags & F_LOCAL) { + tp->c_cflag |= CLOCAL; + } + + tp->c_iflag = tp->c_lflag = tp->c_line = 0; + tp->c_oflag = OPOST | ONLCR; + tp->c_cc[VMIN] = 1; + tp->c_cc[VTIME] = 0; + + /* Optionally enable hardware flow control */ + +#ifdef CRTSCTS + if (op->flags & F_RTSCTS) + tp->c_cflag |= CRTSCTS; +#endif + + ioctl(0, TCSETS, tp); + + /* go to blocking input even in local mode */ + fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK); + + debug("term_io 2\n"); +} + +/* auto_baud - extract baud rate from modem status message */ +static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) +{ + int speed; + int vmin; + unsigned iflag; + char *bp; + int nread; + + /* + * This works only if the modem produces its status code AFTER raising + * the DCD line, and if the computer is fast enough to set the proper + * baud rate before the message has gone by. We expect a message of the + * following format: + * + * + * + * The number is interpreted as the baud rate of the incoming call. If the + * modem does not tell us the baud rate within one second, we will keep + * using the current baud rate. It is advisable to enable BREAK + * processing (comma-separated list of baud rates) if the processing of + * modem status messages is enabled. + */ + + /* + * Use 7-bit characters, don't block if input queue is empty. Errors will + * be dealt with later on. + */ + + iflag = tp->c_iflag; + tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ + vmin = tp->c_cc[VMIN]; + tp->c_cc[VMIN] = 0; /* don't block if queue empty */ + ioctl(0, TCSETS, tp); + + /* + * Wait for a while, then read everything the modem has said so far and + * try to extract the speed of the dial-in call. + */ + + sleep(1); + nread = read(0, buf, size_buf - 1); + if (nread > 0) { + buf[nread] = '\0'; + for (bp = buf; bp < buf + nread; bp++) { + if (isascii(*bp) && isdigit(*bp)) { + speed = bcode(bp); + if (speed) { + tp->c_cflag &= ~CBAUD; + tp->c_cflag |= speed; + } + break; + } + } + } + /* Restore terminal settings. Errors will be dealt with later on. */ + + tp->c_iflag = iflag; + tp->c_cc[VMIN] = vmin; + ioctl(0, TCSETS, tp); +} + +/* next_speed - select next baud rate */ +static void next_speed(struct termios *tp, struct options *op) +{ + static int baud_index = FIRST_SPEED; /* current speed index */ + + baud_index = (baud_index + 1) % op->numspeed; + tp->c_cflag &= ~CBAUD; + tp->c_cflag |= op->speeds[baud_index]; + ioctl(0, TCSETS, tp); +} + + +/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ +static void do_prompt(struct options *op, struct termios *tp) +{ +#ifdef ISSUE + print_login_issue(op->issue, op->tty); +#endif + print_login_prompt(); +} + +#ifdef HANDLE_ALLCAPS +/* caps_lock - string contains upper case without lower case */ +/* returns 1 if true, 0 if false */ +static int caps_lock(const char *s) +{ + while (*s) + if (islower(*s++)) + return 0; + return 1; +} +#endif + +/* get_logname - get user name, establish parity, speed, erase, kill, eol */ +/* return NULL on failure, logname on success */ +static char *get_logname(char *logname, unsigned size_logname, + struct options *op, struct chardata *cp, struct termios *tp) +{ + char *bp; + char c; /* input character, full eight bits */ + char ascval; /* low 7 bits of input character */ + int bits; /* # of "1" bits per character */ + int mask; /* mask with 1 bit up */ + static const char erase[][3] = { /* backspace-space-backspace */ + "\010\040\010", /* space parity */ + "\010\040\010", /* odd parity */ + "\210\240\210", /* even parity */ + "\210\240\210", /* no parity */ + }; + + /* Initialize kill, erase, parity etc. (also after switching speeds). */ + + *cp = init_chardata; + + /* Flush pending input (esp. after parsing or switching the baud rate). */ + + sleep(1); + ioctl(0, TCFLSH, TCIFLUSH); + + /* Prompt for and read a login name. */ + + logname[0] = '\0'; + while (!logname[0]) { + + /* Write issue file and prompt, with "parity" bit == 0. */ + + do_prompt(op, tp); + + /* Read name, watch for break, parity, erase, kill, end-of-line. */ + + bp = logname; + cp->eol = '\0'; + while (cp->eol == '\0') { + + /* Do not report trivial EINTR/EIO errors. */ + if (read(0, &c, 1) < 1) { + if (errno == EINTR || errno == EIO) + exit(0); + bb_perror_msg_and_die("%s: read", op->tty); + } + + /* Do BREAK handling elsewhere. */ + if (c == '\0' && op->numspeed > 1) + return NULL; + + /* Do parity bit handling. */ + ascval = c & 0177; + if (c != ascval) { /* "parity" bit on ? */ + bits = 1; + mask = 1; + while (mask & 0177) { + if (mask & ascval) + bits++; /* count "1" bits */ + mask <<= 1; + } + /* ... |= 2 - even, 1 - odd */ + cp->parity |= 2 - (bits & 1); + } + + /* Do erase, kill and end-of-line processing. */ + switch (ascval) { + case CR: + case NL: + *bp = '\0'; /* terminate logname */ + cp->eol = ascval; /* set end-of-line char */ + break; + case BS: + case DEL: + case '#': + cp->erase = ascval; /* set erase character */ + if (bp > logname) { + write(1, erase[cp->parity], 3); + bp--; + } + break; + case CTL('U'): + case '@': + cp->kill = ascval; /* set kill character */ + while (bp > logname) { + write(1, erase[cp->parity], 3); + bp--; + } + break; + case CTL('D'): + exit(0); + default: + if (!isascii(ascval) || !isprint(ascval)) { + /* ignore garbage characters */ + } else if (bp - logname >= size_logname - 1) { + bb_error_msg_and_die("%s: input overrun", op->tty); + } else { + write(1, &c, 1); /* echo the character */ + *bp++ = ascval; /* and store it */ + } + break; + } + } + } + /* Handle names with upper case and no lower case. */ + +#ifdef HANDLE_ALLCAPS + cp->capslock = caps_lock(logname); + if (cp->capslock) { + for (bp = logname; *bp; bp++) + if (isupper(*bp)) + *bp = tolower(*bp); /* map name to lower case */ + } +#endif + return logname; +} + +/* termios_final - set the final tty mode bits */ +static void termios_final(struct options *op, struct termios *tp, struct chardata *cp) +{ + /* General terminal-independent stuff. */ + + tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ + tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; + /* no longer| ECHOCTL | ECHOPRT */ + tp->c_oflag |= OPOST; + /* tp->c_cflag = 0; */ + tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ + tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ + tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ + tp->c_cc[VEOL] = DEF_EOL; + tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ + + /* Account for special characters seen in input. */ + + if (cp->eol == CR) { + tp->c_iflag |= ICRNL; /* map CR in input to NL */ + tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ + } + tp->c_cc[VERASE] = cp->erase; /* set erase character */ + tp->c_cc[VKILL] = cp->kill; /* set kill character */ + + /* Account for the presence or absence of parity bits in input. */ + + switch (cp->parity) { + case 0: /* space (always 0) parity */ + break; + case 1: /* odd parity */ + tp->c_cflag |= PARODD; + /* FALLTHROUGH */ + case 2: /* even parity */ + tp->c_cflag |= PARENB; + tp->c_iflag |= INPCK | ISTRIP; + /* FALLTHROUGH */ + case (1 | 2): /* no parity bit */ + tp->c_cflag &= ~CSIZE; + tp->c_cflag |= CS7; + break; + } + + /* Account for upper case without lower case. */ +#ifdef HANDLE_ALLCAPS + if (cp->capslock) { + tp->c_iflag |= IUCLC; + tp->c_lflag |= XCASE; + tp->c_oflag |= OLCUC; + } +#endif + /* Optionally enable hardware flow control */ + +#ifdef CRTSCTS + if (op->flags & F_RTSCTS) + tp->c_cflag |= CRTSCTS; +#endif + + /* Finally, make the new settings effective */ + + if (ioctl(0, TCSETS, tp) < 0) + bb_perror_msg_and_die("%s: ioctl(TCSETS)", op->tty); +} + + +#ifdef SYSV_STYLE +#if ENABLE_FEATURE_UTMP +/* update_utmp - update our utmp entry */ +static void update_utmp(const char *line) +{ + struct utmp ut; + struct utmp *utp; + time_t t; + int mypid = getpid(); + + /* + * The utmp file holds miscellaneous information about things started by + * /sbin/init and other system-related events. Our purpose is to update + * the utmp entry for the current process, in particular the process type + * and the tty line we are listening to. Return successfully only if the + * utmp file can be opened for update, and if we are able to find our + * entry in the utmp file. + */ + if (access(_PATH_UTMP, R_OK|W_OK) == -1) { + close(creat(_PATH_UTMP, 0664)); + } + utmpname(_PATH_UTMP); + setutent(); + while ((utp = getutent()) + && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) + /* nothing */; + + if (utp) { + memcpy(&ut, utp, sizeof(ut)); + } else { + /* some inits don't initialize utmp... */ + memset(&ut, 0, sizeof(ut)); + safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); + } + /* endutent(); */ + + strcpy(ut.ut_user, "LOGIN"); + safe_strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + if (fakehost) + safe_strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); + time(&t); + ut.ut_time = t; + ut.ut_type = LOGIN_PROCESS; + ut.ut_pid = mypid; + + pututline(&ut); + endutent(); + +#if ENABLE_FEATURE_WTMP + if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) + close(creat(bb_path_wtmp_file, 0664)); + updwtmp(bb_path_wtmp_file, &ut); +#endif +} + +#endif /* CONFIG_FEATURE_UTMP */ +#endif /* SYSV_STYLE */ + + +int getty_main(int argc, char **argv); +int getty_main(int argc, char **argv) +{ + int nullfd; + char *logname = NULL; /* login name, given to /bin/login */ + /* Merging these into "struct local" may _seem_ to reduce + * parameter passing, but today's gcc will inline + * statics which are called once anyway, so don't do that */ + struct chardata chardata; /* set by get_logname() */ + struct termios termios; /* terminal mode bits */ + struct options options = { + 0, /* show /etc/issue (SYSV_STYLE) */ + 0, /* no timeout */ + _PATH_LOGIN, /* default login program */ + "tty1", /* default tty line */ + "", /* modem init string */ +#ifdef ISSUE + ISSUE, /* default issue file */ +#else + NULL, +#endif + 0, /* no baud rates known yet */ + }; + + /* Already too late because of theoretical + * possibility of getty --help somehow triggered + * inadvertently before we reach this. Oh well. */ + logmode = LOGMODE_NONE; + setsid(); + nullfd = xopen(bb_dev_null, O_RDWR); + /* dup2(nullfd, 0); - no, because of possible "getty - 9600" */ + /* open_tty() will take care of fd# 0 anyway */ + dup2(nullfd, 1); + dup2(nullfd, 2); + while (nullfd > 2) close(nullfd--); + /* We want special flavor of error_msg_and_die */ + die_sleep = 10; + msg_eol = "\r\n"; + openlog(applet_name, LOG_PID, LOG_AUTH); + logmode = LOGMODE_BOTH; + +#ifdef DEBUGGING + dbf = xfopen(DEBUGTERM, "w"); + + { + int i; + + for (i = 1; i < argc; i++) { + debug(argv[i]); + debug("\n"); + } + } +#endif + + /* Parse command-line arguments. */ + parse_args(argc, argv, &options); + +#ifdef SYSV_STYLE +#if ENABLE_FEATURE_UTMP + /* Update the utmp file. */ + update_utmp(options.tty); +#endif +#endif + + debug("calling open_tty\n"); + /* Open the tty as standard { input, output, error }. */ + open_tty(options.tty, &termios, options.flags & F_LOCAL); + +#ifdef __linux__ + { + int iv; + + iv = getpid(); + ioctl(0, TIOCSPGRP, &iv); + } +#endif + /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ + debug("calling termios_init\n"); + termios_init(&termios, options.speeds[FIRST_SPEED], &options); + + /* write the modem init string and DON'T flush the buffers */ + if (options.flags & F_INITSTRING) { + debug("writing init string\n"); + write(1, options.initstring, strlen(options.initstring)); + } + + if (!(options.flags & F_LOCAL)) { + /* go to blocking write mode unless -L is specified */ + fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK); + } + + /* Optionally detect the baud rate from the modem status message. */ + debug("before autobaud\n"); + if (options.flags & F_PARSE) + auto_baud(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), &termios); + + /* Set the optional timer. */ + if (options.timeout) + alarm(options.timeout); + + /* optionally wait for CR or LF before writing /etc/issue */ + if (options.flags & F_WAITCRLF) { + char ch; + + debug("waiting for cr-lf\n"); + while (read(0, &ch, 1) == 1) { + ch &= 0x7f; /* strip "parity bit" */ +#ifdef DEBUGGING + fprintf(dbf, "read %c\n", ch); +#endif + if (ch == '\n' || ch == '\r') + break; + } + } + + chardata = init_chardata; + if (!(options.flags & F_NOPROMPT)) { + /* Read the login name. */ + debug("reading login name\n"); + logname = get_logname(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), + &options, &chardata, &termios); + while (logname == NULL) + next_speed(&termios, &options); + } + + /* Disable timer. */ + + if (options.timeout) + alarm(0); + + /* Finalize the termios settings. */ + + termios_final(&options, &termios, &chardata); + + /* Now the newline character should be properly written. */ + + write(1, "\n", 1); + + /* Let the login program take care of password validation. */ + + execl(options.login, options.login, "--", logname, (char *) 0); + bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login); +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/login.c b/i/pc104/initrd/conf/busybox/loginutils/login.c new file mode 100644 index 0000000..830df0a --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/login.c @@ -0,0 +1,403 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "busybox.h" +#include +#include +#include + +#ifdef CONFIG_SELINUX +#include /* for is_selinux_enabled() */ +#include /* for get_default_context() */ +#include /* for security class definitions */ +#include +#endif + +enum { + TIMEOUT = 60, + EMPTY_USERNAME_COUNT = 10, + USERNAME_SIZE = 32, + TTYNAME_SIZE = 32, +}; + +static char full_tty[TTYNAME_SIZE]; +static char* short_tty = full_tty; + +#if ENABLE_FEATURE_UTMP +/* vv Taken from tinylogin utmp.c vv */ +/* + * read_or_build_utent - see if utmp file is correct for this process + * + * System V is very picky about the contents of the utmp file + * and requires that a slot for the current process exist. + * The utmp file is scanned for an entry with the same process + * ID. If no entry exists the process exits with a message. + * + * The "picky" flag is for network and other logins that may + * use special flags. It allows the pid checks to be overridden. + * This means that getty should never invoke login with any + * command line flags. + */ + +static struct utmp utent; + +static void read_or_build_utent(int picky) +{ + struct utmp *ut; + pid_t pid = getpid(); + + setutent(); + + /* First, try to find a valid utmp entry for this process. */ + while ((ut = getutent())) + if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && + (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) + break; + + /* If there is one, just use it, otherwise create a new one. */ + if (ut) { + utent = *ut; + } else { + if (picky) + bb_error_msg_and_die("no utmp entry found"); + + memset(&utent, 0, sizeof(utent)); + utent.ut_type = LOGIN_PROCESS; + utent.ut_pid = pid; + strncpy(utent.ut_line, short_tty, sizeof(utent.ut_line)); + /* This one is only 4 chars wide. Try to fit something + * remotely meaningful by skipping "tty"... */ + strncpy(utent.ut_id, short_tty + 3, sizeof(utent.ut_id)); + strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user)); + utent.ut_time = time(NULL); + } + if (!picky) /* root login */ + memset(utent.ut_host, 0, sizeof(utent.ut_host)); +} + +/* + * write_utent - put a USER_PROCESS entry in the utmp file + * + * write_utent changes the type of the current utmp entry to + * USER_PROCESS. the wtmp file will be updated as well. + */ +static void write_utent(const char *username) +{ + utent.ut_type = USER_PROCESS; + strncpy(utent.ut_user, username, sizeof(utent.ut_user)); + utent.ut_time = time(NULL); + /* other fields already filled in by read_or_build_utent above */ + setutent(); + pututline(&utent); + endutent(); +#if ENABLE_FEATURE_WTMP + if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { + close(creat(bb_path_wtmp_file, 0664)); + } + updwtmp(bb_path_wtmp_file, &utent); +#endif +} +#else /* !ENABLE_FEATURE_UTMP */ +static inline void read_or_build_utent(int ATTRIBUTE_UNUSED picky) {} +static inline void write_utent(const char ATTRIBUTE_UNUSED *username) {} +#endif /* !ENABLE_FEATURE_UTMP */ + +static void die_if_nologin_and_non_root(int amroot) +{ + FILE *fp; + int c; + + if (access(bb_path_nologin_file, F_OK)) + return; + + fp = fopen(bb_path_nologin_file, "r"); + if (fp) { + while ((c = getc(fp)) != EOF) + putchar((c=='\n') ? '\r' : c); + fflush(stdout); + fclose(fp); + } else + puts("\r\nSystem closed for routine maintenance\r"); + if (!amroot) + exit(1); + puts("\r\n[Disconnect bypassed -- root login allowed.]\r"); +} + +#if ENABLE_FEATURE_SECURETTY +static int check_securetty(void) +{ + FILE *fp; + int i; + char buf[BUFSIZ]; + + fp = fopen(bb_path_securetty_file, "r"); + if (!fp) { + /* A missing securetty file is not an error. */ + return 1; + } + while (fgets(buf, sizeof(buf)-1, fp)) { + for (i = strlen(buf)-1; i>=0; --i) { + if (!isspace(buf[i])) + break; + } + buf[++i] = '\0'; + if ((buf[0]=='\0') || (buf[0]=='#')) + continue; + if (strcmp(buf, short_tty) == 0) { + fclose(fp); + return 1; + } + } + fclose(fp); + return 0; +} +#else +static inline int check_securetty(void) { return 1; } +#endif + +static void get_username_or_die(char *buf, int size_buf) +{ + int c, cntdown; + cntdown = EMPTY_USERNAME_COUNT; +prompt: + /* skip whitespace */ + print_login_prompt(); + do { + c = getchar(); + if (c == EOF) exit(1); + if (c == '\n') { + if (!--cntdown) exit(1); + goto prompt; + } + } while (isspace(c)); + + *buf++ = c; + if (!fgets(buf, size_buf-2, stdin)) + exit(1); + if (!strchr(buf, '\n')) + exit(1); + while (isgraph(*buf)) buf++; + *buf = '\0'; +} + +static void motd(void) +{ + FILE *fp; + int c; + + fp = fopen(bb_path_motd_file, "r"); + if (fp) { + while ((c = getc(fp)) != EOF) + putchar(c); + fclose(fp); + } +} + +static void nonblock(int fd) +{ + fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL)); +} + +static void alarm_handler(int sig ATTRIBUTE_UNUSED) +{ + /* This is the escape hatch! Poor serial line users and the like + * arrive here when their connection is broken. + * We don't want to block here */ + nonblock(1); + nonblock(2); + bb_info_msg("\r\nLogin timed out after %d seconds\r", TIMEOUT); + exit(EXIT_SUCCESS); +} + +int login_main(int argc, char **argv); +int login_main(int argc, char **argv) +{ + enum { + LOGIN_OPT_f = (1<<0), + LOGIN_OPT_h = (1<<1), + LOGIN_OPT_p = (1<<2), + }; + char fromhost[512]; + char username[USERNAME_SIZE]; + const char *tmp; + int amroot; + unsigned opt; + int count = 0; + struct passwd *pw; + char *opt_host = NULL; + char *opt_user = NULL; + USE_SELINUX(security_context_t user_sid = NULL;) + + username[0] = '\0'; + amroot = (getuid() == 0); + signal(SIGALRM, alarm_handler); + alarm(TIMEOUT); + + opt = getopt32(argc, argv, "f:h:p", &opt_user, &opt_host); + if (opt & LOGIN_OPT_f) { + if (!amroot) + bb_error_msg_and_die("-f is for root only"); + safe_strncpy(username, opt_user, sizeof(username)); + } + if (optind < argc) /* user from command line (getty) */ + safe_strncpy(username, argv[optind], sizeof(username)); + + /* Let's find out and memorize our tty */ + if (!isatty(0) || !isatty(1) || !isatty(2)) + return EXIT_FAILURE; /* Must be a terminal */ + safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty)); + tmp = ttyname(0); + if (tmp) { + safe_strncpy(full_tty, tmp, sizeof(full_tty)); + if (strncmp(full_tty, "/dev/", 5) == 0) + short_tty = full_tty + 5; + } + + read_or_build_utent(!amroot); + + if (opt_host) { + USE_FEATURE_UTMP( + safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host)); + ) + snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s' from " + "'%.200s'", short_tty, opt_host); + } + else + snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s'", short_tty); + + bb_setpgrp; + + openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); + + while (1) { + if (!username[0]) + get_username_or_die(username, sizeof(username)); + + pw = getpwnam(username); + if (!pw) { + safe_strncpy(username, "UNKNOWN", sizeof(username)); + goto auth_failed; + } + + if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') + goto auth_failed; + + if (opt & LOGIN_OPT_f) + break; /* -f USER: success without asking passwd */ + + if (pw->pw_uid == 0 && !check_securetty()) + goto auth_failed; + + /* Don't check the password if password entry is empty (!) */ + if (!pw->pw_passwd[0]) + break; + + /* authorization takes place here */ + if (correct_password(pw)) + break; + +auth_failed: + opt &= ~LOGIN_OPT_f; + bb_do_delay(FAIL_DELAY); + puts("Login incorrect"); + if (++count == 3) { + syslog(LOG_WARNING, "invalid password for '%s'%s", + username, fromhost); + return EXIT_FAILURE; + } + username[0] = '\0'; + } + + alarm(0); + die_if_nologin_and_non_root(pw->pw_uid == 0); + + write_utent(username); + +#ifdef CONFIG_SELINUX + if (is_selinux_enabled()) { + security_context_t old_tty_sid, new_tty_sid; + + if (get_default_context(username, NULL, &user_sid)) { + bb_error_msg_and_die("cannot get SID for %s", + username); + } + if (getfilecon(full_tty, &old_tty_sid) < 0) { + bb_perror_msg_and_die("getfilecon(%s) failed", + full_tty); + } + if (security_compute_relabel(user_sid, old_tty_sid, + SECCLASS_CHR_FILE, &new_tty_sid) != 0) { + bb_perror_msg_and_die("security_change_sid(%s) failed", + full_tty); + } + if (setfilecon(full_tty, new_tty_sid) != 0) { + bb_perror_msg_and_die("chsid(%s, %s) failed", + full_tty, new_tty_sid); + } + } +#endif + /* Try these, but don't complain if they fail. + * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ + fchown(0, pw->pw_uid, pw->pw_gid); + fchmod(0, 0600); + + /* TODO: be nommu-friendly, use spawn? */ + if (ENABLE_LOGIN_SCRIPTS) { + char *script = getenv("LOGIN_PRE_SUID_SCRIPT"); + if (script) { + char *t_argv[2] = { script, NULL }; + switch (fork()) { + case -1: break; + case 0: /* child */ + xchdir("/"); + setenv("LOGIN_TTY", full_tty, 1); + setenv("LOGIN_USER", pw->pw_name, 1); + setenv("LOGIN_UID", utoa(pw->pw_uid), 1); + setenv("LOGIN_GID", utoa(pw->pw_gid), 1); + setenv("LOGIN_SHELL", pw->pw_shell, 1); + BB_EXECVP(script, t_argv); + exit(1); + default: /* parent */ + wait(NULL); + } + } + } + + change_identity(pw); + tmp = pw->pw_shell; + if (!tmp || !*tmp) + tmp = DEFAULT_SHELL; + setup_environment(tmp, 1, !(opt & LOGIN_OPT_p), pw); + + motd(); + + if (pw->pw_uid == 0) + syslog(LOG_INFO, "root login%s", fromhost); +#ifdef CONFIG_SELINUX + /* well, a simple setexeccon() here would do the job as well, + * but let's play the game for now */ + set_current_security_context(user_sid); +#endif + + // util-linux login also does: + // /* start new session */ + // setsid(); + // /* TIOCSCTTY: steal tty from other process group */ + // if (ioctl(0, TIOCSCTTY, 1)) error_msg... + + /* set signals to defaults */ + signal(SIGALRM, SIG_DFL); + /* Is this correct? This way user can ctrl-c out of /etc/profile, + * potentially creating security breach (tested with bash 3.0). + * But without this, bash 3.0 will not enable ctrl-c either. + * Maybe bash is buggy? + * Need to find out what standards say about /bin/login - + * should it leave SIGINT etc enabled or disabled? */ + signal(SIGINT, SIG_DFL); + + run_shell(tmp, 1, 0, 0); /* exec the shell finally */ + + return EXIT_FAILURE; +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/passwd.c b/i/pc104/initrd/conf/busybox/loginutils/passwd.c new file mode 100644 index 0000000..b937ce4 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/passwd.c @@ -0,0 +1,347 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "busybox.h" +#include + + +static void nuke_str(char *str) +{ + if (str) memset(str, 0, strlen(str)); +} + + +static int i64c(int i) +{ + i &= 0x3f; + if (i == 0) + return '.'; + if (i == 1) + return '/'; + if (i < 12) + return ('0' - 2 + i); + if (i < 38) + return ('A' - 12 + i); + return ('a' - 38 + i); +} + + +static void crypt_make_salt(char *p, int cnt) +{ + unsigned x = x; /* it's pointless to initialize it anyway :) */ + + x += getpid() + time(NULL) + clock(); + do { + /* x = (x*1664525 + 1013904223) % 2^32 generator is lame + * (low-order bit is not "random", etc...), + * but for our purposes it is good enough */ + x = x*1664525 + 1013904223; + /* BTW, Park and Miller's "minimal standard generator" is + * x = x*16807 % ((2^31)-1) + * It has no problem with visibly alternating lowest bit + * but is also weak in cryptographic sense + needs div, + * which needs more code (and slower) on many CPUs */ + *p++ = i64c(x >> 16); + *p++ = i64c(x >> 22); + } while (--cnt); + *p = '\0'; +} + + +static char* new_password(const struct passwd *pw, uid_t myuid, int algo) +{ + char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */ + char *orig = (char*)""; + char *newp = NULL; + char *cipher = NULL; + char *cp = NULL; + char *ret = NULL; /* failure so far */ + + if (myuid && pw->pw_passwd[0]) { + orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ + if (!orig) + goto err_ret; + cipher = pw_encrypt(orig, pw->pw_passwd); /* returns ptr to static */ + if (strcmp(cipher, pw->pw_passwd) != 0) { + syslog(LOG_WARNING, "incorrect password for '%s'", + pw->pw_name); + bb_do_delay(FAIL_DELAY); + puts("Incorrect password"); + goto err_ret; + } + } + orig = xstrdup(orig); /* or else bb_askpass() will destroy it */ + newp = bb_askpass(0, "New password:"); /* returns ptr to static */ + if (!newp) + goto err_ret; + newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */ + if (ENABLE_FEATURE_PASSWD_WEAK_CHECK + && obscure(orig, newp, pw) && myuid) + goto err_ret; /* non-root is not allowed to have weak passwd */ + + cp = bb_askpass(0, "Retype password:"); + if (!cp) + goto err_ret; + if (strcmp(cp, newp)) { + puts("Passwords don't match"); + goto err_ret; + } + + /*memset(salt, 0, sizeof(salt)); - why?*/ + crypt_make_salt(salt, 1); /* des */ + if (algo) { /* MD5 */ + strcpy(salt, "$1$"); + crypt_make_salt(salt + 3, 4); + } + ret = xstrdup(pw_encrypt(newp, salt)); /* returns ptr to static */ + /* whee, success! */ + + err_ret: + nuke_str(orig); + if (ENABLE_FEATURE_CLEAN_UP) free(orig); + nuke_str(newp); + if (ENABLE_FEATURE_CLEAN_UP) free(newp); + nuke_str(cipher); + nuke_str(cp); + return ret; +} + + +#if 0 +static int get_algo(char *a) +{ + /* standard: MD5 */ + int x = 1; + if (strcasecmp(a, "des") == 0) + x = 0; + return x; +} +#endif + + +static int update_passwd(const char *filename, const char *username, + const char *new_pw) +{ + struct stat sb; + struct flock lock; + FILE *old_fp; + FILE *new_fp; + char *new_name; + char *last_char; + unsigned user_len; + int old_fd; + int new_fd; + int i; + int ret = 1; /* failure */ + + logmode = LOGMODE_STDIO; + /* New passwd file, "/etc/passwd+" for now */ + new_name = xasprintf("%s+", filename); + last_char = &new_name[strlen(new_name)-1]; + username = xasprintf("%s:", username); + user_len = strlen(username); + + old_fp = fopen(filename, "r+"); + if (!old_fp) + goto free_mem; + old_fd = fileno(old_fp); + + /* Try to create "/etc/passwd+". Wait if it exists. */ + i = 30; + do { + // FIXME: on last iteration try w/o O_EXCL but with O_TRUNC? + new_fd = open(new_name, O_WRONLY|O_CREAT|O_EXCL,0600); + if (new_fd >= 0) goto created; + if (errno != EEXIST) break; + usleep(100000); /* 0.1 sec */ + } while (--i); + bb_perror_msg("cannot create '%s'", new_name); + goto close_old_fp; + created: + if (!fstat(old_fd, &sb)) { + fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ + fchown(new_fd, sb.st_uid, sb.st_gid); + } + new_fp = fdopen(new_fd, "w"); + if (!new_fp) { + close(new_fd); + goto unlink_new; + } + + /* Backup file is "/etc/passwd-" */ + last_char[0] = '-'; + /* Delete old one, create new as a hardlink to current */ + i = (unlink(new_name) && errno != ENOENT); + if (i || link(filename, new_name)) + bb_perror_msg("warning: cannot create backup copy '%s'", new_name); + last_char[0] = '+'; + + /* 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(old_fd, F_SETLK, &lock) < 0) + bb_perror_msg("warning: cannot lock '%s'", filename); + lock.l_type = F_UNLCK; + + /* Read current password file, write updated one */ + while (1) { + char *line = xmalloc_fgets(old_fp); + if (!line) break; /* EOF/error */ + if (strncmp(username, line, user_len) == 0) { + /* we have a match with "username:"... */ + const char *cp = line + user_len; + /* now cp -> old passwd, skip it: */ + cp = strchr(cp, ':'); + if (!cp) cp = ""; + /* now cp -> ':' after old passwd or -> "" */ + fprintf(new_fp, "%s%s%s", username, new_pw, cp); + /* Erase password in memory */ + } else + fputs(line, new_fp); + free(line); + } + fcntl(old_fd, F_SETLK, &lock); + + /* We do want all of them to execute, thus | instead of || */ + if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp)) + || rename(new_name, filename) + ) { + /* At least one of those failed */ + goto unlink_new; + } + ret = 0; /* whee, success! */ + + unlink_new: + if (ret) unlink(new_name); + + close_old_fp: + fclose(old_fp); + + free_mem: + if (ENABLE_FEATURE_CLEAN_UP) free(new_name); + if (ENABLE_FEATURE_CLEAN_UP) free((char*)username); + logmode = LOGMODE_BOTH; + return ret; +} + + +int passwd_main(int argc, char **argv); +int passwd_main(int argc, char **argv) +{ + enum { + OPT_algo = 0x1, /* -a - password algorithm */ + OPT_lock = 0x2, /* -l - lock account */ + OPT_unlock = 0x4, /* -u - unlock account */ + OPT_delete = 0x8, /* -d - delete password */ + OPT_lud = 0xe, + STATE_ALGO_md5 = 0x10, + /*STATE_ALGO_des = 0x20, not needed yet */ + }; + unsigned opt; + const char *opt_a = ""; + const char *filename; + char *myname; + char *name; + char *newp; + struct passwd *pw; + uid_t myuid; + struct rlimit rlimit_fsize; + char c; + +#if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ + struct spwd spw; + struct spwd *result; + char buffer[256]; +#endif + + logmode = LOGMODE_BOTH; + openlog(applet_name, LOG_NOWAIT, LOG_AUTH); + opt = getopt32(argc, argv, "a:lud", &opt_a); + argc -= optind; + argv += optind; + + if (strcasecmp(opt_a, "des") != 0) /* -a */ + opt |= STATE_ALGO_md5; + //else + // opt |= STATE_ALGO_des; + myuid = getuid(); + if ((opt & OPT_lud) && (!argc || myuid)) + bb_show_usage(); + + myname = xstrdup(bb_getpwuid(NULL, myuid, -1)); + name = argc ? argv[0] : myname; + + pw = getpwnam(name); + if (!pw) bb_error_msg_and_die("unknown user %s", name); + if (myuid && pw->pw_uid != myuid) { + /* LOGMODE_BOTH */ + bb_error_msg_and_die("%s can't change password for %s", myname, name); + } + + filename = bb_path_passwd_file; +#if ENABLE_FEATURE_SHADOWPASSWDS + if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result)) { + /* LOGMODE_BOTH */ + bb_error_msg("no record of %s in %s, using %s", + name, bb_path_shadow_file, + bb_path_passwd_file); + } else { + filename = bb_path_shadow_file; + pw->pw_passwd = spw.sp_pwdp; + } +#endif + + /* Decide what the new password will be */ + newp = NULL; + c = pw->pw_passwd[0] - '!'; + if (!(opt & OPT_lud)) { + if (myuid && !c) { /* passwd starts with '!' */ + /* LOGMODE_BOTH */ + bb_error_msg_and_die("cannot change " + "locked password for %s", name); + } + printf("Changing password for %s\n", name); + newp = new_password(pw, myuid, opt & STATE_ALGO_md5); + if (!newp) { + logmode = LOGMODE_STDIO; + bb_error_msg_and_die("password for %s is unchanged", name); + } + } else if (opt & OPT_lock) { + if (!c) goto skip; /* passwd starts with '!' */ + newp = xasprintf("!%s", pw->pw_passwd); + } else if (opt & OPT_unlock) { + if (c) goto skip; /* not '!' */ + newp = xstrdup(&pw->pw_passwd[1]); + } else if (opt & OPT_delete) { + newp = xstrdup(""); + } + + rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; + setrlimit(RLIMIT_FSIZE, &rlimit_fsize); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + umask(077); + xsetuid(0); + if (update_passwd(filename, name, newp) != 0) { + /* LOGMODE_BOTH */ + bb_error_msg_and_die("cannot update password file %s", + filename); + } + /* LOGMODE_BOTH */ + bb_info_msg("Password for %s changed by %s", name, myname); + + if (ENABLE_FEATURE_CLEAN_UP) free(newp); +skip: + if (!newp) { + bb_error_msg_and_die("password for %s is already %slocked", + name, (opt & OPT_unlock) ? "un" : ""); + } + if (ENABLE_FEATURE_CLEAN_UP) free(myname); + return 0; +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/su.c b/i/pc104/initrd/conf/busybox/loginutils/su.c new file mode 100644 index 0000000..0a786cb --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/su.c @@ -0,0 +1,103 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini su implementation for busybox + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + */ + +#include "busybox.h" +#include + +#define SU_OPT_mp (3) +#define SU_OPT_l (4) + +int su_main(int argc, char **argv); +int su_main(int argc, char **argv) +{ + unsigned flags; + char *opt_shell = NULL; + char *opt_command = NULL; + const char *opt_username = "root"; + struct passwd *pw; + uid_t cur_uid = getuid(); + const char *tty; + char *old_user; + + flags = getopt32(argc, argv, "mplc:s:", &opt_command, &opt_shell); + argc -= optind; + argv += optind; + + if (argc && LONE_DASH(argv[0])) { + flags |= SU_OPT_l; + argc--; + argv++; + } + + /* get user if specified */ + if (argc) { + opt_username = argv[0]; +// argc--; + argv++; + } + + if (ENABLE_FEATURE_SU_SYSLOG) { + /* The utmp entry (via getlogin) is probably the best way to identify + the user, especially if someone su's from a su-shell. + But getlogin can fail -- usually due to lack of utmp entry. + in this case resort to getpwuid. */ + old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : ""); + tty = ttyname(2) ? : "none"; + openlog(applet_name, 0, LOG_AUTH); + } + + pw = getpwnam(opt_username); + if (!pw) + bb_error_msg_and_die("unknown id: %s", opt_username); + + /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER + is a username that is retrieved via NIS (YP), but that doesn't have + a default shell listed. */ + if (!pw->pw_shell || !pw->pw_shell[0]) + pw->pw_shell = (char *)DEFAULT_SHELL; + + if ((cur_uid == 0) || correct_password(pw)) { + if (ENABLE_FEATURE_SU_SYSLOG) + syslog(LOG_NOTICE, "%c %s %s:%s", + '+', tty, old_user, opt_username); + } else { + if (ENABLE_FEATURE_SU_SYSLOG) + syslog(LOG_NOTICE, "%c %s %s:%s", + '-', tty, old_user, opt_username); + bb_error_msg_and_die("incorrect password"); + } + + if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { + closelog(); + free(old_user); + } + + if (!opt_shell && (flags & SU_OPT_mp)) + opt_shell = getenv("SHELL"); + +#if ENABLE_FEATURE_SU_CHECKS_SHELLS + if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) { + /* The user being su'd to has a nonstandard shell, and so is + probably a uucp account or has restricted access. Don't + compromise the account by allowing access with a standard + shell. */ + bb_error_msg("using restricted shell"); + opt_shell = 0; + } +#endif + if (!opt_shell) + opt_shell = pw->pw_shell; + + change_identity(pw); + setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw); + USE_SELINUX(set_current_security_context(NULL);) + + /* Never returns */ + run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv); + + return EXIT_FAILURE; +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/sulogin.c b/i/pc104/initrd/conf/busybox/loginutils/sulogin.c new file mode 100644 index 0000000..38503f7 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/sulogin.c @@ -0,0 +1,126 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini sulogin implementation for busybox + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include + +#include "busybox.h" + +static const char * const 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 ATTRIBUTE_UNUSED junk) +{ + exit(EXIT_FAILURE); +} + + +int sulogin_main(int argc, char **argv); +int sulogin_main(int argc, char **argv) +{ + char *cp; + int timeout = 0; + char *timeout_arg; + const char * const *p; + struct passwd *pwd; + const char *shell; +#if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ + char buffer[256]; + struct spwd spw; + struct spwd *result; +#endif + + logmode = LOGMODE_BOTH; + openlog(applet_name, 0, LOG_AUTH); + + if (getopt32(argc, argv, "t:", &timeout_arg)) { + timeout = xatoi_u(timeout_arg); + } + + if (argv[optind]) { + close(0); + close(1); + dup(xopen(argv[optind], O_RDWR)); + close(2); + dup(0); + } + + if (!isatty(0) || !isatty(1) || !isatty(2)) { + logmode = LOGMODE_SYSLOG; + bb_error_msg_and_die("not a tty"); + } + + /* Clear out anything dangerous from the environment */ + for (p = forbid; *p; p++) + unsetenv(*p); + + signal(SIGALRM, catchalarm); + + pwd = getpwuid(0); + if (!pwd) { + goto auth_error; + } + +#if ENABLE_FEATURE_SHADOWPASSWDS + if (getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result)) { + goto auth_error; + } + pwd->pw_passwd = spw.sp_pwdp; +#endif + + while (1) { + /* cp points to a static buffer that is zeroed every time */ + cp = bb_askpass(timeout, + "Give root password for system maintenance\n" + "(or type Control-D for normal startup):"); + + if (!cp || !*cp) { + bb_info_msg("Normal startup"); + return 0; + } + if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) { + break; + } + bb_do_delay(FAIL_DELAY); + bb_error_msg("login incorrect"); + } + memset(cp, 0, strlen(cp)); + signal(SIGALRM, SIG_DFL); + + bb_info_msg("System Maintenance Mode"); + + USE_SELINUX(renew_current_security_context()); + + shell = getenv("SUSHELL"); + if (!shell) shell = getenv("sushell"); + if (!shell) { + shell = "/bin/sh"; + if (pwd->pw_shell[0]) + shell = pwd->pw_shell; + } + run_shell(shell, 1, 0, 0); + /* never returns */ + +auth_error: + bb_error_msg_and_die("no password entry for 'root'"); +} diff --git a/i/pc104/initrd/conf/busybox/loginutils/vlock.c b/i/pc104/initrd/conf/busybox/loginutils/vlock.c new file mode 100644 index 0000000..06a7169 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/loginutils/vlock.c @@ -0,0 +1,119 @@ +/* vi: set sw=4 ts=4: */ + +/* + * vlock implementation for busybox + * + * Copyright (C) 2000 by spoon + * Written by spoon + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +/* 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 "busybox.h" +#include + +static struct passwd *pw; +static struct vt_mode ovtm; +static struct termios oterm; +static int vfd; +static unsigned long o_lock_all; + +static void release_vt(int signo) +{ + ioctl(vfd, VT_RELDISP, !o_lock_all); +} + +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); +} + +int vlock_main(int argc, char **argv); +int vlock_main(int argc, char **argv) +{ + sigset_t sig; + struct sigaction sa; + struct vt_mode vtm; + struct termios term; + uid_t uid = getuid(); + + pw = getpwuid(uid); + if (pw == NULL) + bb_error_msg_and_die("unknown uid %d", uid); + + if (argc > 2) { + bb_show_usage(); + } + + o_lock_all = getopt32(argc, argv, "a"); + + vfd = xopen(CURRENT_TTY, O_RDWR); + + if (ioctl(vfd, VT_GETMODE, &vtm) < 0) { + bb_perror_msg_and_die("VT_GETMODE"); + } + + /* 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 { + printf("Virtual Console%s locked by %s.\n", (o_lock_all) ? "s" : "", pw->pw_name); + if (correct_password(pw)) { + break; + } + bb_do_delay(FAIL_DELAY); + puts("Password incorrect"); + } while (1); + restore_terminal(); + fflush_stdout_and_exit(0); +} -- cgit v1.2.3