Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/loginutils
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (14 years ago)
- Location:
- branches/2.2.9/mindi-busybox/loginutils
- Files:
-
- 3 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/loginutils/Config.in
r1765 r2725 1 # DO NOT EDIT. This file is generated from Config.src 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 6 7 menu "Login/Password Management Utilities" 7 8 9 config ADD_SHELL 10 bool "add-shell" 11 default y if DESKTOP 12 help 13 Add shells to /etc/shells. 14 15 config REMOVE_SHELL 16 bool "remove-shell" 17 default y if DESKTOP 18 help 19 Remove shells from /etc/shells. 20 8 21 config FEATURE_SHADOWPASSWDS 9 22 bool "Support for shadow passwords" 10 default n11 help 12 Build support for shadow password in /etc/shadow. 23 default y 24 help 25 Build support for shadow password in /etc/shadow. This file is only 13 26 readable by root and thus the encrypted passwords are no longer 14 27 publicly readable. 15 28 16 config USE_BB_SHADOW17 bool " Use busybox shadow password functions"18 default y19 depends on USE_BB_PWD_GRP && FEATURE_SHADOWPASSWDS20 help21 If you leave this disabled, busybox will use the system's shadow22 password handling functions. And if you are using the GNU C library23 (glibc), you will then need to install the /etc/nsswitch.conf24 configuration file and the required /lib/libnss_* libraries in25 order for the shadow password functions to work. This generally26 makes your embedded system quite a bit larger.27 28 Enabling this option will cause busybox to directly access the29 system's /etc/shadow file when handling shadow passwords. This30 makes your system smaller and I will get fewer emails asking about31 how glibc NSS works). When this option is enabled, you will not be32 able to use PAM to access shadow passwords from remote LDAP33 password servers and whatnot.34 35 29 config USE_BB_PWD_GRP 36 30 bool "Use internal password and group functions rather than system functions" 31 default y 32 help 33 If you leave this disabled, busybox will use the system's password 34 and group functions. And if you are using the GNU C library 35 (glibc), you will then need to install the /etc/nsswitch.conf 36 configuration file and the required /lib/libnss_* libraries in 37 order for the password and group functions to work. This generally 38 makes your embedded system quite a bit larger. 39 40 Enabling this option will cause busybox to directly access the 41 system's /etc/password, /etc/group files (and your system will be 42 smaller, and I will get fewer emails asking about how glibc NSS 43 works). When this option is enabled, you will not be able to use 44 PAM to access remote LDAP password servers and whatnot. And if you 45 want hostname resolution to work with glibc, you still need the 46 /lib/libnss_* libraries. 47 48 If you need to use glibc's nsswitch.conf mechanism 49 (e.g. if user/group database is NOT stored in /etc/passwd etc), 50 you must NOT use this option. 51 52 If you enable this option, it will add about 1.5k. 53 54 config USE_BB_SHADOW 55 bool "Use internal shadow password functions" 56 default y 57 depends on USE_BB_PWD_GRP && FEATURE_SHADOWPASSWDS 58 help 59 If you leave this disabled, busybox will use the system's shadow 60 password handling functions. And if you are using the GNU C library 61 (glibc), you will then need to install the /etc/nsswitch.conf 62 configuration file and the required /lib/libnss_* libraries in 63 order for the shadow password functions to work. This generally 64 makes your embedded system quite a bit larger. 65 66 Enabling this option will cause busybox to directly access the 67 system's /etc/shadow file when handling shadow passwords. This 68 makes your system smaller (and I will get fewer emails asking about 69 how glibc NSS works). When this option is enabled, you will not be 70 able to use PAM to access shadow passwords from remote LDAP 71 password servers and whatnot. 72 73 config USE_BB_CRYPT 74 bool "Use internal crypt functions" 75 default y 76 help 77 Busybox has internal DES and MD5 crypt functions. 78 They produce results which are identical to corresponding 79 standard C library functions. 80 81 If you leave this disabled, busybox will use the system's 82 crypt functions. Most C libraries use large (~70k) 83 static buffers there, and also combine them with more general 84 DES encryption/decryption. 85 86 For busybox, having large static buffers is undesirable, 87 especially on NOMMU machines. Busybox also doesn't need 88 DES encryption/decryption and can do with smaller code. 89 90 If you enable this option, it will add about 4.8k of code 91 if you are building dynamically linked executable. 92 In static build, it makes code _smaller_ by about 1.2k, 93 and likely many kilobytes less of bss. 94 95 config USE_BB_CRYPT_SHA 96 bool "Enable SHA256/512 crypt functions" 97 default y 98 depends on USE_BB_CRYPT 99 help 100 Enable this if you have passwords starting with "$5$" or "$6$" 101 in your /etc/passwd or /etc/shadow files. These passwords 102 are hashed using SHA256 and SHA512 algorithms. Support for them 103 was added to glibc in 2008. 104 With this option off, login will fail password check for any 105 user which has password encrypted with these algorithms. 106 107 config ADDUSER 108 bool "adduser" 109 default y 110 help 111 Utility for creating a new user account. 112 113 config FEATURE_ADDUSER_LONG_OPTIONS 114 bool "Enable long options" 115 default y 116 depends on ADDUSER && LONG_OPTS 117 help 118 Support long options for the adduser applet. 119 120 config FEATURE_CHECK_NAMES 121 bool "Enable sanity check on user/group names in adduser and addgroup" 37 122 default n 38 help 39 If you leave this disabled, busybox will use the system's password 40 and group functions. And if you are using the GNU C library 41 (glibc), you will then need to install the /etc/nsswitch.conf 42 configuration file and the required /lib/libnss_* libraries in 43 order for the password and group functions to work. This generally 44 makes your embedded system quite a bit larger. 45 46 Enabling this option will cause busybox to directly access the 47 system's /etc/password, /etc/group files (and your system will be 48 smaller, and I will get fewer emails asking about how glibc NSS 49 works). When this option is enabled, you will not be able to use 50 PAM to access remote LDAP password servers and whatnot. And if you 51 want hostname resolution to work with glibc, you still need the 52 /lib/libnss_* libraries. 53 54 If you enable this option, it will add about 1.5k to busybox. 123 depends on ADDUSER || ADDGROUP 124 help 125 Enable sanity check on user and group names in adduser and addgroup. 126 To avoid problems, the user or group name should consist only of 127 letters, digits, underscores, periods, at signs and dashes, 128 and not start with a dash (as defined by IEEE Std 1003.1-2001). 129 For compatibility with Samba machine accounts "$" is also supported 130 at the end of the user or group name. 131 132 config FIRST_SYSTEM_ID 133 int "First valid system uid or gid for adduser and addgroup" 134 depends on ADDUSER || ADDGROUP 135 range 0 64900 136 default 100 137 help 138 First valid system uid or gid for adduser and addgroup 139 140 config LAST_SYSTEM_ID 141 int "Last valid system uid or gid for adduser and addgroup" 142 depends on ADDUSER || ADDGROUP 143 range 0 64900 144 default 999 145 help 146 Last valid system uid or gid for adduser and addgroup 55 147 56 148 config ADDGROUP 57 149 bool "addgroup" 58 default n150 default y 59 151 help 60 152 Utility for creating a new group account. 153 154 config FEATURE_ADDGROUP_LONG_OPTIONS 155 bool "Enable long options" 156 default y 157 depends on ADDGROUP && LONG_OPTS 158 help 159 Support long options for the addgroup applet. 61 160 62 161 config FEATURE_ADDUSER_TO_GROUP 63 162 bool "Support for adding users to groups" 64 default n163 default y 65 164 depends on ADDGROUP 66 165 help … … 69 168 existing group. 70 169 170 config DELUSER 171 bool "deluser" 172 default y 173 help 174 Utility for deleting a user account. 175 71 176 config DELGROUP 72 177 bool "delgroup" 73 default n178 default y 74 179 help 75 180 Utility for deleting a group account. 76 181 77 182 config FEATURE_DEL_USER_FROM_GROUP 78 bool "Support for removing users from groups ."79 default n183 bool "Support for removing users from groups" 184 default y 80 185 depends on DELGROUP 81 186 help … … 83 188 or delgroup will remove an user from a specified group. 84 189 85 config ADDUSER86 bool "adduser"87 default n88 help89 Utility for creating a new user account.90 91 config DELUSER92 bool "deluser"93 default n94 help95 Utility for deleting a user account.96 97 190 config GETTY 98 191 bool "getty" 99 default n192 default y 100 193 select FEATURE_SYSLOG 101 194 help 102 195 getty lets you log in on a tty, it is normally invoked by init. 103 104 config FEATURE_UTMP105 bool "Support utmp file"106 depends on GETTY || LOGIN || SU || WHO107 default n108 help109 The file /var/run/utmp is used to track who is currently logged in.110 111 config FEATURE_WTMP112 bool "Support wtmp file"113 depends on GETTY || LOGIN || SU || LAST114 default n115 select FEATURE_UTMP116 help117 The file /var/run/wtmp is used to track when user's have logged into118 and logged out of the system.119 196 120 197 config LOGIN 121 198 bool "login" 122 default n 123 select FEATURE_SUID 199 default y 124 200 select FEATURE_SYSLOG 125 201 help … … 139 215 bool "Support for login scripts" 140 216 depends on LOGIN 141 default n217 default y 142 218 help 143 219 Enable this if you want login to execute $LOGIN_PRE_SUID_SCRIPT … … 163 239 config PASSWD 164 240 bool "passwd" 165 default n 166 select FEATURE_SUID 167 select FEATURE_SYSLOG 168 help 169 passwd changes passwords for user and group accounts. A normal user 241 default y 242 select FEATURE_SYSLOG 243 help 244 passwd changes passwords for user and group accounts. A normal user 170 245 may only change the password for his/her own account, the super user 171 may change the password for any account. 246 may change the password for any account. The administrator of a group 172 247 may change the password for the group. 173 248 … … 184 259 config CRYPTPW 185 260 bool "cryptpw" 186 default n 187 help 188 Applet for crypting a string. 261 default y 262 help 263 Encrypts the given password with the crypt(3) libc function 264 using the given salt. Debian has this utility under mkpasswd 265 name. Busybox provides mkpasswd as an alias for cryptpw. 189 266 190 267 config CHPASSWD 191 bool "chpasswd" 192 default n 193 help 194 chpasswd reads a file of user name and password pairs from 195 standard input and uses this information to update a group of 196 existing users. 268 bool "chpasswd" 269 default y 270 help 271 Reads a file of user name and password pairs from standard input 272 and uses this information to update a group of existing users. 197 273 198 274 config SU 199 275 bool "su" 200 default n 201 select FEATURE_SUID 276 default y 202 277 select FEATURE_SYSLOG 203 278 help … … 220 295 config SULOGIN 221 296 bool "sulogin" 222 default n297 default y 223 298 select FEATURE_SYSLOG 224 299 help … … 228 303 config VLOCK 229 304 bool "vlock" 230 default n 231 select FEATURE_SUID 305 default y 232 306 help 233 307 Build the "vlock" applet which allows you to lock (virtual) terminals. … … 237 311 238 312 endmenu 239 -
branches/2.2.9/mindi-busybox/loginutils/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 4 5 # 5 # Licensed under the GPL v2, see the file LICENSE in this tarball.6 # Licensed under GPLv2, see file LICENSE in this source tree. 6 7 7 8 lib-y:= 9 10 lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o 11 lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o 8 12 lib-$(CONFIG_ADDGROUP) += addgroup.o 9 13 lib-$(CONFIG_ADDUSER) += adduser.o -
branches/2.2.9/mindi-busybox/loginutils/addgroup.c
r1765 r2725 7 7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it> 8 8 * 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 10 * 11 11 */ 12 13 12 #include "libbb.h" 14 13 14 #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID 15 #error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config 16 #endif 17 18 #define OPT_GID (1 << 0) 19 #define OPT_SYSTEM_ACCOUNT (1 << 1) 20 21 /* We assume GID_T_MAX == INT_MAX */ 15 22 static void xgroup_study(struct group *g) 16 23 { 24 unsigned max = INT_MAX; 25 17 26 /* Make sure gr_name is unused */ 18 27 if (getgrnam(g->gr_name)) { 19 goto error; 28 bb_error_msg_and_die("%s '%s' in use", "group", g->gr_name); 29 /* these format strings are reused in adduser and addgroup */ 20 30 } 21 31 32 /* if a specific gid is requested, the --system switch and */ 33 /* min and max values are overridden, and the range of valid */ 34 /* gid values is set to [0, INT_MAX] */ 35 if (!(option_mask32 & OPT_GID)) { 36 if (option_mask32 & OPT_SYSTEM_ACCOUNT) { 37 g->gr_gid = CONFIG_FIRST_SYSTEM_ID; 38 max = CONFIG_LAST_SYSTEM_ID; 39 } else { 40 g->gr_gid = CONFIG_LAST_SYSTEM_ID + 1; 41 max = 64999; 42 } 43 } 22 44 /* Check if the desired gid is free 23 45 * or find the first free one */ … … 26 48 return; /* found free group: return */ 27 49 } 28 if (option_mask32 ) {50 if (option_mask32 & OPT_GID) { 29 51 /* -g N, cannot pick gid other than N: error */ 30 g->gr_name = itoa(g->gr_gid); 31 goto error; 52 bb_error_msg_and_die("%s '%s' in use", "gid", itoa(g->gr_gid)); 53 /* this format strings is reused in adduser and addgroup */ 54 } 55 if (g->gr_gid == max) { 56 /* overflowed: error */ 57 bb_error_msg_and_die("no %cids left", 'g'); 58 /* this format string is reused in adduser and addgroup */ 32 59 } 33 60 g->gr_gid++; 34 if (g->gr_gid <= 0) {35 /* overflowed: error */36 bb_error_msg_and_die("no gids left");37 }38 61 } 39 40 error:41 /* exit */42 bb_error_msg_and_die("group %s already exists", g->gr_name);43 62 } 44 63 … … 46 65 static void new_group(char *group, gid_t gid) 47 66 { 48 FILE *file;49 67 struct group gr; 68 char *p; 50 69 51 70 /* make sure gid and group haven't already been allocated */ … … 55 74 56 75 /* add entry to group */ 57 file = xfopen(bb_path_group_file, "a");58 /* group:passwd:gid:userlist */59 fprintf(file, "%s:x:%d:\n", group, gr.gr_gid);76 p = xasprintf("x:%u:", (unsigned) gr.gr_gid); 77 if (update_passwd(bb_path_group_file, group, p, NULL) < 0) 78 exit(EXIT_FAILURE); 60 79 if (ENABLE_FEATURE_CLEAN_UP) 61 f close(file);80 free(p); 62 81 #if ENABLE_FEATURE_SHADOWPASSWDS 63 file = fopen_or_warn(bb_path_gshadow_file, "a"); 64 if (file) { 65 fprintf(file, "%s:!::\n", group); 66 if (ENABLE_FEATURE_CLEAN_UP) 67 fclose(file); 68 } 82 /* /etc/gshadow fields: 83 * 1. Group name. 84 * 2. Encrypted password. 85 * If set, non-members of the group can join the group 86 * by typing the password for that group using the newgrp command. 87 * If the value is of this field ! then no user is allowed 88 * to access the group using the newgrp command. A value of !! 89 * is treated the same as a value of ! only it indicates 90 * that a password has never been set before. If the value is null, 91 * only group members can log into the group. 92 * 3. Group administrators (comma delimited list). 93 * Group members listed here can add or remove group members 94 * using the gpasswd command. 95 * 4. Group members (comma delimited list). 96 */ 97 /* Ignore errors: if file is missing we assume admin doesn't want it */ 98 update_passwd(bb_path_gshadow_file, group, "!::", NULL); 69 99 #endif 70 100 } 71 101 72 #if ENABLE_FEATURE_ADDUSER_TO_GROUP 73 static void add_user_to_group(char **args, 74 const char *path, 75 FILE *(*fopen_func)(const char *fileName, const char *mode)) 76 { 77 char *line; 78 int len = strlen(args[1]); 79 llist_t *plist = NULL; 80 FILE *group_file; 81 82 group_file = fopen_func(path, "r"); 83 84 if (!group_file) return; 85 86 while ((line = xmalloc_getline(group_file))) { 87 /* Find the group */ 88 if (!strncmp(line, args[1], len) 89 && line[len] == ':' 90 ) { 91 /* Add the new user */ 92 line = xasprintf("%s%s%s", line, 93 last_char_is(line, ':') ? "" : ",", 94 args[0]); 95 } 96 llist_add_to_end(&plist, line); 97 } 98 99 if (ENABLE_FEATURE_CLEAN_UP) { 100 fclose(group_file); 101 group_file = fopen_func(path, "w"); 102 while ((line = llist_pop(&plist))) { 103 if (group_file) 104 fprintf(group_file, "%s\n", line); 105 free(line); 106 } 107 if (group_file) 108 fclose(group_file); 109 } else { 110 group_file = fopen_func(path, "w"); 111 if (group_file) 112 while ((line = llist_pop(&plist))) 113 fprintf(group_file, "%s\n", line); 114 } 115 } 102 #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS 103 static const char addgroup_longopts[] ALIGN1 = 104 "gid\0" Required_argument "g" 105 "system\0" No_argument "S" 106 ; 116 107 #endif 117 108 … … 123 114 * will add an existing user to an existing group. 124 115 */ 125 int addgroup_main(int argc, char **argv) ;126 int addgroup_main(int argc , char **argv)116 int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 117 int addgroup_main(int argc UNUSED_PARAM, char **argv) 127 118 { 128 char *group;129 gid_tgid = 0;119 unsigned opts; 120 unsigned gid = 0; 130 121 131 122 /* need to be root */ … … 133 124 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 134 125 } 135 126 #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS 127 applet_long_options = addgroup_longopts; 128 #endif 136 129 /* Syntax: 137 130 * addgroup group … … 139 132 * addgroup user group 140 133 * Check for min, max and missing args */ 141 opt_complementary = "-1:?2"; 142 if (getopt32(argv, "g:", &group)) { 143 gid = xatoul_range(group, 0, ((unsigned long)(gid_t)ULONG_MAX) >> 1); 144 } 134 opt_complementary = "-1:?2:g+"; 135 opts = getopt32(argv, "g:S", &gid); 145 136 /* move past the commandline options */ 146 137 argv += optind; 147 argc -= optind;138 //argc -= optind; 148 139 149 140 #if ENABLE_FEATURE_ADDUSER_TO_GROUP 150 if (arg c == 2) {141 if (argv[1]) { 151 142 struct group *gr; 152 143 153 if (opt ion_mask32) {144 if (opts & OPT_GID) { 154 145 /* -g was there, but "addgroup -g num user group" 155 146 * is a no-no */ … … 159 150 /* check if group and user exist */ 160 151 xuname2uid(argv[0]); /* unknown user: exit */ 161 xgroup2gid(argv[1]); /* unknown group: exit */152 gr = xgetgrnam(argv[1]); /* unknown group: exit */ 162 153 /* check if user is already in this group */ 163 gr = getgrnam(argv[1]);164 154 for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) { 165 155 if (!strcmp(argv[0], *(gr->gr_mem))) { … … 168 158 } 169 159 } 170 add_user_to_group(argv, bb_path_group_file, xfopen); 171 #if ENABLE_FEATURE_SHADOWPASSWDS 172 add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn); 173 #endif /* ENABLE_FEATURE_SHADOWPASSWDS */ 160 if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) { 161 return EXIT_FAILURE; 162 } 163 # if ENABLE_FEATURE_SHADOWPASSWDS 164 update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]); 165 # endif 174 166 } else 175 167 #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */ 168 { 169 die_if_bad_username(argv[0]); 176 170 new_group(argv[0], gid); 177 171 } 178 172 /* Reached only on success */ 179 173 return EXIT_SUCCESS; -
branches/2.2.9/mindi-busybox/loginutils/adduser.c
r1765 r2725 6 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> 7 7 * 8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 9 */ 10 11 10 #include "libbb.h" 12 11 12 #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID 13 #error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config 14 #endif 15 16 /* #define OPT_HOME (1 << 0) */ /* unused */ 17 /* #define OPT_GECOS (1 << 1) */ /* unused */ 18 #define OPT_SHELL (1 << 2) 19 #define OPT_GID (1 << 3) 13 20 #define OPT_DONT_SET_PASS (1 << 4) 21 #define OPT_SYSTEM_ACCOUNT (1 << 5) 14 22 #define OPT_DONT_MAKE_HOME (1 << 6) 15 16 23 #define OPT_UID (1 << 7) 24 25 /* We assume UID_T_MAX == INT_MAX */ 17 26 /* remix */ 18 /* EDR recoded such that the uid may be passed in *p */ 19 static int passwd_study(const char *filename, struct passwd *p) 20 { 21 enum { min = 500, max = 65000 }; 22 FILE *passwd; 23 /* We are using reentrant fgetpwent_r() in order to avoid 24 * pulling in static buffers from libc (think static build here) */ 25 char buffer[256]; 26 struct passwd pw; 27 struct passwd *result; 28 29 passwd = xfopen(filename, "r"); 30 31 /* EDR if uid is out of bounds, set to min */ 32 if ((p->pw_uid > max) || (p->pw_uid < min)) 33 p->pw_uid = min; 34 35 /* stuff to do: 36 * make sure login isn't taken; 37 * find free uid and gid; 38 */ 39 while (!fgetpwent_r(passwd, &pw, buffer, sizeof(buffer), &result)) { 40 if (strcmp(pw.pw_name, p->pw_name) == 0) { 41 /* return 0; */ 42 return 1; 43 } 44 if ((pw.pw_uid >= p->pw_uid) && (pw.pw_uid < max) 45 && (pw.pw_uid >= min)) { 46 p->pw_uid = pw.pw_uid + 1; 47 } 48 } 49 50 if (p->pw_gid == 0) { 51 /* EDR check for an already existing gid */ 52 while (getgrgid(p->pw_uid) != NULL) 53 p->pw_uid++; 54 55 /* EDR also check for an existing group definition */ 56 if (getgrnam(p->pw_name) != NULL) 57 return 3; 58 59 /* EDR create new gid always = uid */ 60 p->pw_gid = p->pw_uid; 61 } 62 63 /* EDR bounds check */ 64 if ((p->pw_uid > max) || (p->pw_uid < min)) 65 return 2; 66 67 /* return 1; */ 68 return 0; 69 } 70 71 static void addgroup_wrapper(struct passwd *p) 27 /* recoded such that the uid may be passed in *p */ 28 static void passwd_study(struct passwd *p) 29 { 30 int max = UINT_MAX; 31 32 if (getpwnam(p->pw_name)) { 33 bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name); 34 /* this format string is reused in adduser and addgroup */ 35 } 36 37 if (!(option_mask32 & OPT_UID)) { 38 if (option_mask32 & OPT_SYSTEM_ACCOUNT) { 39 p->pw_uid = CONFIG_FIRST_SYSTEM_ID; 40 max = CONFIG_LAST_SYSTEM_ID; 41 } else { 42 p->pw_uid = CONFIG_LAST_SYSTEM_ID + 1; 43 max = 64999; 44 } 45 } 46 /* check for a free uid (and maybe gid) */ 47 while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) { 48 if (option_mask32 & OPT_UID) { 49 /* -u N, cannot pick uid other than N: error */ 50 bb_error_msg_and_die("%s '%s' in use", "uid", itoa(p->pw_uid)); 51 /* this format string is reused in adduser and addgroup */ 52 } 53 if (p->pw_uid == max) { 54 bb_error_msg_and_die("no %cids left", 'u'); 55 } 56 p->pw_uid++; 57 } 58 59 if (p->pw_gid == (gid_t)-1) { 60 p->pw_gid = p->pw_uid; /* new gid = uid */ 61 if (getgrnam(p->pw_name)) { 62 bb_error_msg_and_die("%s '%s' in use", "group", p->pw_name); 63 /* this format string is reused in adduser and addgroup */ 64 } 65 } 66 } 67 68 static void addgroup_wrapper(struct passwd *p, const char *group_name) 72 69 { 73 70 char *cmd; 74 71 75 cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name); 72 if (group_name) /* Add user to existing group */ 73 cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name); 74 else /* Add user to his own group with the first free gid found in passwd_study */ 75 cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name); 76 /* Warning: to be compatible with external addgroup programs we should use --gid instead */ 76 77 system(cmd); 77 78 free(cmd); 78 79 } 79 80 80 static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;81 static void passwd_wrapper(const char *login) NORETURN; 81 82 82 83 static void passwd_wrapper(const char *login) 83 84 { 84 static const char prog[] ALIGN1 = "passwd"; 85 86 BB_EXECLP(prog, prog, login, NULL); 87 bb_error_msg_and_die("failed to execute '%s', you must set the password for '%s' manually", prog, login); 88 } 89 90 /* putpwent(3) remix */ 91 static int adduser(struct passwd *p) 92 { 93 FILE *file; 94 int addgroup = !p->pw_gid; 95 96 /* make sure everything is kosher and setup uid && gid */ 97 file = xfopen(bb_path_passwd_file, "a"); 98 fseek(file, 0, SEEK_END); 99 100 switch (passwd_study(bb_path_passwd_file, p)) { 101 case 1: 102 bb_error_msg_and_die("%s: login already in use", p->pw_name); 103 case 2: 104 bb_error_msg_and_die("illegal uid or no uids left"); 105 case 3: 106 bb_error_msg_and_die("%s: group name already in use", p->pw_name); 107 } 108 109 /* add to passwd */ 110 if (putpwent(p, file) == -1) { 111 bb_perror_nomsg_and_die(); 112 } 113 /* Do fclose even if !ENABLE_FEATURE_CLEAN_UP. 114 * We will exec passwd, files must be flushed & closed before that! */ 115 fclose(file); 116 117 #if ENABLE_FEATURE_SHADOWPASSWDS 118 /* add to shadow if necessary */ 119 file = fopen_or_warn(bb_path_shadow_file, "a"); 120 if (file) { 121 fseek(file, 0, SEEK_END); 122 fprintf(file, "%s:!:%ld:%d:%d:%d:::\n", 123 p->pw_name, /* username */ 124 time(NULL) / 86400, /* sp->sp_lstchg */ 125 0, /* sp->sp_min */ 126 99999, /* sp->sp_max */ 127 7); /* sp->sp_warn */ 128 fclose(file); 129 } 130 #endif 131 132 /* add to group */ 133 /* addgroup should be responsible for dealing w/ gshadow */ 134 /* if using a pre-existing group, don't create one */ 135 if (addgroup) addgroup_wrapper(p); 136 137 /* Clear the umask for this process so it doesn't 138 * screw up the permissions on the mkdir and chown. */ 139 umask(0); 140 if (!(option_mask32 & OPT_DONT_MAKE_HOME)) { 141 /* Set the owner and group so it is owned by the new user, 142 then fix up the permissions to 2755. Can't do it before 143 since chown will clear the setgid bit */ 144 if (mkdir(p->pw_dir, 0755) 145 || chown(p->pw_dir, p->pw_uid, p->pw_gid) 146 || chmod(p->pw_dir, 02755)) { 147 bb_perror_msg("%s", p->pw_dir); 148 } 149 } 150 151 if (!(option_mask32 & OPT_DONT_SET_PASS)) { 152 /* interactively set passwd */ 153 passwd_wrapper(p->pw_name); 154 } 155 156 return 0; 157 } 85 BB_EXECLP("passwd", "passwd", login, NULL); 86 bb_error_msg_and_die("can't execute passwd, you must set password manually"); 87 } 88 89 #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS 90 static const char adduser_longopts[] ALIGN1 = 91 "home\0" Required_argument "h" 92 "gecos\0" Required_argument "g" 93 "shell\0" Required_argument "s" 94 "ingroup\0" Required_argument "G" 95 "disabled-password\0" No_argument "D" 96 "empty-password\0" No_argument "D" 97 "system\0" No_argument "S" 98 "no-create-home\0" No_argument "H" 99 "uid\0" Required_argument "u" 100 ; 101 #endif 158 102 159 103 /* 160 104 * adduser will take a login_name as its first parameter. 161 * 162 * home 163 * shell 164 * gecos 165 * 105 * home, shell, gecos: 166 106 * can be customized via command-line parameters. 167 107 */ 168 int adduser_main(int argc, char **argv) ;169 int adduser_main(int argc , char **argv)108 int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 109 int adduser_main(int argc UNUSED_PARAM, char **argv) 170 110 { 171 111 struct passwd pw; 172 112 const char *usegroup = NULL; 113 char *p; 114 unsigned opts; 115 116 #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS 117 applet_long_options = adduser_longopts; 118 #endif 173 119 174 120 /* got root? */ … … 182 128 183 129 /* exactly one non-option arg */ 184 opt_complementary = "=1"; 185 getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); 130 /* disable interactive passwd for system accounts */ 131 opt_complementary = "=1:SD:u+"; 132 if (sizeof(pw.pw_uid) == sizeof(int)) { 133 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid); 134 } else { 135 unsigned uid; 136 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid); 137 if (opts & OPT_UID) { 138 pw.pw_uid = uid; 139 } 140 } 186 141 argv += optind; 187 142 188 /* create apasswd struct */143 /* fill in the passwd struct */ 189 144 pw.pw_name = argv[0]; 145 die_if_bad_username(pw.pw_name); 190 146 if (!pw.pw_dir) { 191 147 /* create string for $HOME if not specified already */ … … 193 149 } 194 150 pw.pw_passwd = (char *)"x"; 195 pw.pw_uid = 0; 196 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */ 197 198 /* grand finale */ 199 return adduser(&pw); 200 } 151 if (opts & OPT_SYSTEM_ACCOUNT) { 152 if (!usegroup) { 153 usegroup = "nogroup"; 154 } 155 if (!(opts & OPT_SHELL)) { 156 pw.pw_shell = (char *) "/bin/false"; 157 } 158 } 159 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */ 160 161 /* make sure everything is kosher and setup uid && maybe gid */ 162 passwd_study(&pw); 163 164 p = xasprintf("x:%u:%u:%s:%s:%s", 165 (unsigned) pw.pw_uid, (unsigned) pw.pw_gid, 166 pw.pw_gecos, pw.pw_dir, pw.pw_shell); 167 if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) { 168 return EXIT_FAILURE; 169 } 170 if (ENABLE_FEATURE_CLEAN_UP) 171 free(p); 172 173 #if ENABLE_FEATURE_SHADOWPASSWDS 174 /* /etc/shadow fields: 175 * 1. username 176 * 2. encrypted password 177 * 3. last password change (unix date (unix time/24*60*60)) 178 * 4. minimum days required between password changes 179 * 5. maximum days password is valid 180 * 6. days before password is to expire that user is warned 181 * 7. days after password expires that account is disabled 182 * 8. unix date when login expires (i.e. when it may no longer be used) 183 */ 184 /* fields: 2 3 4 5 6 78 */ 185 p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL)) / (24*60*60)); 186 /* ignore errors: if file is missing we suppose admin doesn't want it */ 187 update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL); 188 if (ENABLE_FEATURE_CLEAN_UP) 189 free(p); 190 #endif 191 192 /* add to group */ 193 addgroup_wrapper(&pw, usegroup); 194 195 /* clear the umask for this process so it doesn't 196 * screw up the permissions on the mkdir and chown. */ 197 umask(0); 198 if (!(opts & OPT_DONT_MAKE_HOME)) { 199 /* set the owner and group so it is owned by the new user, 200 * then fix up the permissions to 2755. Can't do it before 201 * since chown will clear the setgid bit */ 202 int mkdir_err = mkdir(pw.pw_dir, 0755); 203 if (mkdir_err == 0) { 204 /* New home. Copy /etc/skel to it */ 205 const char *args[] = { 206 "chown", "-R", 207 xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid), 208 pw.pw_dir, NULL 209 }; 210 /* Be silent on any errors (like: no /etc/skel) */ 211 logmode = LOGMODE_NONE; 212 copy_file("/etc/skel", pw.pw_dir, FILEUTILS_RECUR); 213 logmode = LOGMODE_STDIO; 214 chown_main(4, (char**)args); 215 } 216 if ((mkdir_err != 0 && errno != EEXIST) 217 || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid) != 0 218 || chmod(pw.pw_dir, 02755) != 0 /* set setgid bit on homedir */ 219 ) { 220 bb_simple_perror_msg(pw.pw_dir); 221 } 222 } 223 224 if (!(opts & OPT_DONT_SET_PASS)) { 225 /* interactively set passwd */ 226 passwd_wrapper(pw.pw_name); 227 } 228 229 return EXIT_SUCCESS; 230 } -
branches/2.2.9/mindi-busybox/loginutils/chpasswd.c
r1765 r2725 4 4 * 5 5 * Written for SLIND (from passwd.c) by Alexander Shishkin <virtuoso@slind.org> 6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.6 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 7 */ 8 9 8 #include "libbb.h" 10 9 11 #if ENABLE_GETOPT_LONG 12 #include <getopt.h> 13 10 #if ENABLE_LONG_OPTS 14 11 static const char chpasswd_longopts[] ALIGN1 = 15 12 "encrypted\0" No_argument "e" … … 18 15 #endif 19 16 20 #define OPT_ENC 21 #define OPT_MD5 17 #define OPT_ENC 1 18 #define OPT_MD5 2 22 19 23 int chpasswd_main(int argc, char **argv) ;24 int chpasswd_main(int argc , char **argv)20 int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 21 int chpasswd_main(int argc UNUSED_PARAM, char **argv) 25 22 { 26 23 char *name, *pass; … … 33 30 34 31 opt_complementary = "m--e:e--m"; 35 USE_GETOPT_LONG(applet_long_options = chpasswd_longopts;)32 IF_LONG_OPTS(applet_long_options = chpasswd_longopts;) 36 33 opt = getopt32(argv, "em"); 37 34 38 while ((name = xmalloc_ getline(stdin)) != NULL) {35 while ((name = xmalloc_fgetline(stdin)) != NULL) { 39 36 pass = strchr(name, ':'); 40 37 if (!pass) … … 50 47 rnd = crypt_make_salt(salt + 3, 4, rnd); 51 48 } 52 pass = pw_encrypt(pass, salt );49 pass = pw_encrypt(pass, salt, 0); 53 50 } 54 51 … … 56 53 * we try to find & change his passwd in /etc/passwd */ 57 54 #if ENABLE_FEATURE_SHADOWPASSWDS 58 rc = update_passwd(bb_path_shadow_file, name, pass );55 rc = update_passwd(bb_path_shadow_file, name, pass, NULL); 59 56 if (rc == 0) /* no lines updated, no errors detected */ 60 57 #endif 61 rc = update_passwd(bb_path_passwd_file, name, pass );58 rc = update_passwd(bb_path_passwd_file, name, pass, NULL); 62 59 /* LOGMODE_BOTH logs to syslog also */ 63 60 logmode = LOGMODE_BOTH; … … 68 65 logmode = LOGMODE_STDIO; 69 66 free(name); 67 if (!(opt & OPT_ENC)) 68 free(pass); 70 69 } 71 72 return 0; 70 return EXIT_SUCCESS; 73 71 } -
branches/2.2.9/mindi-busybox/loginutils/cryptpw.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * cryptpw.c 3 * cryptpw.c - output a crypt(3)ed password to stdout. 4 * 5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 6 * 5 7 * Cooked from passwd.c by Thomas Lundquist <thomasez@zelow.no> 8 * mkpasswd compatible options added by Bernhard Reutner-Fischer 9 * 10 * Licensed under GPLv2, see file LICENSE in this source tree. 6 11 */ 7 12 8 13 #include "libbb.h" 9 14 10 int cryptpw_main(int argc, char **argv); 11 int cryptpw_main(int argc, char **argv) 15 /* Debian has 'mkpasswd' utility, manpage says: 16 17 NAME 18 mkpasswd - Overfeatured front end to crypt(3) 19 SYNOPSIS 20 mkpasswd PASSWORD SALT 21 ... 22 OPTIONS 23 -S, --salt=STRING 24 Use the STRING as salt. It must not contain prefixes such as 25 $1$. 26 -R, --rounds=NUMBER 27 Use NUMBER rounds. This argument is ignored if the method 28 choosen does not support variable rounds. For the OpenBSD Blowfish 29 method this is the logarithm of the number of rounds. 30 -m, --method=TYPE 31 Compute the password using the TYPE method. If TYPE is 'help' 32 then the available methods are printed. 33 -P, --password-fd=NUM 34 Read the password from file descriptor NUM instead of using getpass(3). 35 If the file descriptor is not connected to a tty then 36 no other message than the hashed password is printed on stdout. 37 -s, --stdin 38 Like --password-fd=0. 39 ENVIRONMENT 40 $MKPASSWD_OPTIONS 41 A list of options which will be evaluated before the ones 42 specified on the command line. 43 BUGS 44 This programs suffers of a bad case of featuritis. 45 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 46 47 Very true... 48 49 cryptpw was in bbox before this gem, so we retain it, and alias mkpasswd 50 to cryptpw. -a option (alias for -m) came from cryptpw. 51 */ 52 53 int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 54 int cryptpw_main(int argc UNUSED_PARAM, char **argv) 12 55 { 13 char salt[sizeof("$N$XXXXXXXX")]; 56 /* $N$ + sha_salt_16_bytes + NUL */ 57 char salt[3 + 16 + 1]; 58 char *salt_ptr; 59 const char *opt_m, *opt_S; 60 int len; 61 int fd; 14 62 15 if (!getopt32(argv, "a:", NULL) || argv[optind - 1][0] != 'd') { 16 strcpy(salt, "$1$"); 17 /* Too ugly, and needs even more magic to handle endianness: */ 18 //((uint32_t*)&salt)[0] = '$' + '1'*0x100 + '$'*0x10000; 19 /* Hope one day gcc will do it itself (inlining strcpy) */ 20 crypt_make_salt(salt + 3, 4, 0); /* md5 */ 21 } else { 22 crypt_make_salt(salt, 1, 0); /* des */ 63 #if ENABLE_LONG_OPTS 64 static const char mkpasswd_longopts[] ALIGN1 = 65 "stdin\0" No_argument "s" 66 "password-fd\0" Required_argument "P" 67 "salt\0" Required_argument "S" 68 "method\0" Required_argument "m" 69 ; 70 applet_long_options = mkpasswd_longopts; 71 #endif 72 fd = STDIN_FILENO; 73 opt_m = "d"; 74 opt_S = NULL; 75 /* at most two non-option arguments; -P NUM */ 76 opt_complementary = "?2:P+"; 77 getopt32(argv, "sP:S:m:a:", &fd, &opt_S, &opt_m, &opt_m); 78 argv += optind; 79 80 /* have no idea how to handle -s... */ 81 82 if (argv[0] && !opt_S) 83 opt_S = argv[1]; 84 85 len = 2/2; 86 salt_ptr = salt; 87 if (opt_m[0] != 'd') { /* not des */ 88 len = 8/2; /* so far assuming md5 */ 89 *salt_ptr++ = '$'; 90 *salt_ptr++ = '1'; 91 *salt_ptr++ = '$'; 92 #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA 93 if (opt_m[0] == 's') { /* sha */ 94 salt[1] = '5' + (strcmp(opt_m, "sha512") == 0); 95 len = 16/2; 96 } 97 #endif 23 98 } 99 if (opt_S) 100 safe_strncpy(salt_ptr, opt_S, sizeof(salt) - 3); 101 else 102 crypt_make_salt(salt_ptr, len, 0); 24 103 25 puts(pw_encrypt(argv[optind] ? argv[optind] : xmalloc_getline(stdin), salt));104 xmove_fd(fd, STDIN_FILENO); 26 105 27 return 0; 106 puts(pw_encrypt( 107 argv[0] ? argv[0] : ( 108 /* Only mkpasswd, and only from tty, prompts. 109 * Otherwise it is a plain read. */ 110 (isatty(STDIN_FILENO) && applet_name[0] == 'm') 111 ? bb_ask_stdin("Password: ") 112 : xmalloc_fgetline(stdin) 113 ), 114 salt, 1)); 115 116 return EXIT_SUCCESS; 28 117 } -
branches/2.2.9/mindi-busybox/loginutils/deluser.c
r1765 r2725 7 7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it> 8 8 * 9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.9 * Licensed under GPLv2, see file LICENSE in this source tree. 10 10 * 11 11 */ 12 13 12 #include "libbb.h" 14 13 15 /* Status */ 16 #define STATUS_OK 0 17 #define NAME_NOT_FOUND 1 18 #define MEMBER_NOT_FOUND 2 14 int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 15 int deluser_main(int argc, char **argv) 16 { 17 /* User or group name */ 18 char *name; 19 /* Username (non-NULL only in "delgroup USER GROUP" case) */ 20 char *member; 21 /* Name of passwd or group file */ 22 const char *pfile; 23 /* Name of shadow or gshadow file */ 24 const char *sfile; 25 /* Are we deluser or delgroup? */ 26 int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); 19 27 20 static void del_line_matching(char **args, 21 const char *filename, 22 FILE *(*fopen_func)(const char *fileName, const char *mode)) 23 { 24 FILE *passwd; 25 smallint error = NAME_NOT_FOUND; 26 char *name = (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) ? args[2] : args[1]; 27 char *line, *del; 28 char *new = xzalloc(1); 28 if (geteuid() != 0) 29 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 29 30 30 passwd = fopen_func(filename, "r"); 31 if (passwd) { 32 while ((line = xmalloc_fgets(passwd))) { 33 int len = strlen(name); 31 name = argv[1]; 32 member = NULL; 34 33 35 if (strncmp(line, name, len) == 0 36 && line[len] == ':' 37 ) { 38 error = STATUS_OK; 39 if (ENABLE_FEATURE_DEL_USER_FROM_GROUP) { 40 struct group *gr; 41 char *p; 42 if (args[2] 43 /* There were two args on commandline */ 44 && (gr = getgrnam(name)) 45 /* The group was not deleted in the meanwhile */ 46 && (p = strrchr(line, ':')) 47 /* We can find a pointer to the last ':' */ 48 ) { 49 error = MEMBER_NOT_FOUND; 50 /* Move past ':' (worst case to '\0') and cut the line */ 51 p[1] = '\0'; 52 /* Reuse p */ 53 for (p = xzalloc(1); *gr->gr_mem != NULL; gr->gr_mem++) { 54 /* Add all the other group members */ 55 if (strcmp(args[1], *gr->gr_mem) != 0) { 56 del = p; 57 p = xasprintf("%s%s%s", p, p[0] ? "," : "", *gr->gr_mem); 58 free(del); 59 } else 60 error = STATUS_OK; 61 } 62 /* Recompose the line */ 63 line = xasprintf("%s%s\n", line, p); 64 if (ENABLE_FEATURE_CLEAN_UP) free(p); 65 } else 66 goto skip; 34 switch (argc) { 35 case 3: 36 if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser) 37 break; 38 /* It's "delgroup USER GROUP" */ 39 member = name; 40 name = argv[2]; 41 /* Fallthrough */ 42 43 case 2: 44 if (do_deluser) { 45 /* "deluser USER" */ 46 xgetpwnam(name); /* bail out if USER is wrong */ 47 pfile = bb_path_passwd_file; 48 if (ENABLE_FEATURE_SHADOWPASSWDS) 49 sfile = bb_path_shadow_file; 50 } else { 51 struct group *gr; 52 do_delgroup: 53 /* "delgroup GROUP" or "delgroup USER GROUP" */ 54 if (do_deluser < 0) { /* delgroup after deluser? */ 55 gr = getgrnam(name); 56 if (!gr) 57 return EXIT_SUCCESS; 58 } else { 59 gr = xgetgrnam(name); /* bail out if GROUP is wrong */ 60 } 61 if (!member) { 62 /* "delgroup GROUP" */ 63 struct passwd *pw; 64 struct passwd pwent; 65 /* Check if the group is in use */ 66 #define passwd_buf bb_common_bufsiz1 67 while (!getpwent_r(&pwent, passwd_buf, sizeof(passwd_buf), &pw)) { 68 if (pwent.pw_gid == gr->gr_gid) 69 bb_error_msg_and_die("'%s' still has '%s' as their primary group!", pwent.pw_name, name); 67 70 } 71 //endpwent(); 68 72 } 69 del = new; 70 new = xasprintf("%s%s", new, line); 71 free(del); 72 skip: 73 free(line); 73 pfile = bb_path_group_file; 74 if (ENABLE_FEATURE_SHADOWPASSWDS) 75 sfile = bb_path_gshadow_file; 74 76 } 75 77 76 if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); 78 /* Modify pfile, then sfile */ 79 do { 80 if (update_passwd(pfile, name, NULL, member) == -1) 81 return EXIT_FAILURE; 82 if (ENABLE_FEATURE_SHADOWPASSWDS) { 83 pfile = sfile; 84 sfile = NULL; 85 } 86 } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); 77 87 78 if (error) { 79 if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && error == MEMBER_NOT_FOUND) { 80 /* Set the correct values for error message */ 81 filename = name; 82 name = args[1]; 83 } 84 bb_error_msg("can't find %s in %s", name, filename); 85 } else { 86 passwd = fopen_func(filename, "w"); 87 if (passwd) { 88 fputs(new, passwd); 89 if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); 90 } 88 if (ENABLE_DELGROUP && do_deluser > 0) { 89 /* "deluser USER" also should try to delete 90 * same-named group. IOW: do "delgroup USER" 91 */ 92 // On debian deluser is a perl script that calls userdel. 93 // From man userdel: 94 // If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will 95 // delete the group with the same name as the user. 96 do_deluser = -1; 97 goto do_delgroup; 91 98 } 99 return EXIT_SUCCESS; 92 100 } 93 free(new); 101 /* Reached only if number of command line args is wrong */ 102 bb_show_usage(); 94 103 } 95 96 int deluser_main(int argc, char **argv);97 int deluser_main(int argc, char **argv)98 {99 if (argc == 2100 || (ENABLE_FEATURE_DEL_USER_FROM_GROUP101 && (applet_name[3] == 'g' && argc == 3))102 ) {103 if (geteuid())104 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);105 106 if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3)107 || ENABLE_DELUSER108 || (ENABLE_DELGROUP && ENABLE_DESKTOP)109 ) {110 if (ENABLE_DELUSER111 && (!ENABLE_DELGROUP || applet_name[3] == 'u')112 ) {113 del_line_matching(argv, bb_path_passwd_file, xfopen);114 if (ENABLE_FEATURE_SHADOWPASSWDS)115 del_line_matching(argv, bb_path_shadow_file, fopen_or_warn);116 } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1]))117 bb_error_msg_and_die("can't remove primary group of user %s", argv[1]);118 }119 del_line_matching(argv, bb_path_group_file, xfopen);120 if (ENABLE_FEATURE_SHADOWPASSWDS)121 del_line_matching(argv, bb_path_gshadow_file, fopen_or_warn);122 return EXIT_SUCCESS;123 } else124 bb_show_usage();125 } -
branches/2.2.9/mindi-busybox/loginutils/getty.c
r1765 r2725 7 7 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 8 8 * 9 * 1999-02-22 Arkadiusz Mi ¶kiewicz <misiek@misiek.eu.org>9 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org> 10 10 * - added Native Language Support 11 11 * 12 12 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> 13 13 * - enable hardware flow control before displaying /etc/issue 14 14 * 15 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 16 * 15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 17 16 */ 18 17 … … 21 20 22 21 #if ENABLE_FEATURE_UTMP 23 #include <utmp.h> 22 # include <utmp.h> /* LOGIN_PROCESS */ 23 #endif 24 25 #ifndef IUCLC 26 # define IUCLC 0 24 27 #endif 25 28 … … 29 32 */ 30 33 #ifdef LOGIN_PROCESS /* defined in System V utmp.h */ 31 #define SYSV_STYLE /* select System V style getty */32 34 #include <sys/utsname.h> 33 # include <time.h>34 # if ENABLE_FEATURE_WTMP35 extern void updwtmp(const char *filename, const struct utmp *ut); 36 static void update_utmp(const char *line); 37 # endif35 #else /* if !sysV style, wtmp/utmp code is off */ 36 #undef ENABLE_FEATURE_UTMP 37 #undef ENABLE_FEATURE_WTMP 38 #define ENABLE_FEATURE_UTMP 0 39 #define ENABLE_FEATURE_WTMP 0 38 40 #endif /* LOGIN_PROCESS */ 39 41 … … 48 50 /* I doubt there are systems which still need this */ 49 51 #undef HANDLE_ALLCAPS 52 #undef ANCIENT_BS_KILL_CHARS 50 53 51 54 #define _PATH_LOGIN "/bin/login" … … 58 61 59 62 /* Some shorthands for control characters. */ 60 #define CTL(x) ( x ^ 0100)/* Assumes ASCII dialect */63 #define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ 61 64 #define CR CTL('M') /* carriage return */ 62 65 #define NL CTL('J') /* line feed */ … … 77 80 * we will try is the first one specified. 78 81 */ 79 #define FIRST_SPEED 082 #define MAX_SPEED 10 /* max. nr. of baud rates */ 80 83 81 84 /* Storage for command-line options. */ 82 83 #define MAX_SPEED 10 /* max. nr. of baud rates */84 85 85 struct options { 86 86 int flags; /* toggle switches, see below */ 87 87 unsigned timeout; /* time-out period */ 88 const char *login; 89 const char *tty; 90 const char *initstring; 91 const char *issue; 88 const char *login; /* login program */ 89 const char *tty; /* name of tty */ 90 const char *initstring; /* modem init string */ 91 const char *issue; /* alternative issue file */ 92 92 int numspeed; /* number of baud rates to try */ 93 93 int speeds[MAX_SPEED]; /* baud rates to be tried */ 94 94 }; 95 96 static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";97 #define F_INITSTRING (1<<0) /* initstring is set */98 #define F_LOCAL (1<<1) /* force local */99 #define F_FAKEHOST (1<<2) /* force fakehost */100 #define F_CUSTISSUE (1<<3) /* give alternative issue file */101 #define F_RTSCTS (1<<4) /* enable RTS/CTS flow control */102 #define F_ISSUE (1<<5) /* display /etc/issue */103 #define F_LOGIN (1<<6) /* non-default login program */104 #define F_PARSE (1<<7) /* process modem status messages */105 #define F_TIMEOUT (1<<8) /* time out */106 #define F_WAITCRLF (1<<9) /* wait for CR or LF */107 #define F_NOPROMPT (1<<10) /* don't ask for login name! */108 95 109 96 /* Storage for things detected while the login name was read. */ … … 113 100 unsigned char eol; /* end-of-line character */ 114 101 unsigned char parity; /* what parity did we see */ 102 /* (parity & 1): saw odd parity char with 7th bit set */ 103 /* (parity & 2): saw even parity char with 7th bit set */ 104 /* parity == 0: probably 7-bit, space parity? */ 105 /* parity == 1: probably 7-bit, odd parity? */ 106 /* parity == 2: probably 7-bit, even parity? */ 107 /* parity == 3: definitely 8 bit, no parity! */ 108 /* Hmm... with any value of "parity" 8 bit, no parity is possible */ 115 109 #ifdef HANDLE_ALLCAPS 116 110 unsigned char capslock; /* upper case without lower case */ 117 111 #endif 118 112 }; 113 119 114 120 115 /* Initial values for the above. */ … … 129 124 }; 130 125 126 static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn"; 127 #define F_INITSTRING (1 << 0) /* -I initstring is set */ 128 #define F_LOCAL (1 << 1) /* -L force local */ 129 #define F_FAKEHOST (1 << 2) /* -H fake hostname */ 130 #define F_CUSTISSUE (1 << 3) /* -f give alternative issue file */ 131 #define F_RTSCTS (1 << 4) /* -h enable RTS/CTS flow control */ 132 #define F_ISSUE (1 << 5) /* -i display /etc/issue */ 133 #define F_LOGIN (1 << 6) /* -l non-default login program */ 134 #define F_PARSE (1 << 7) /* -m process modem status messages */ 135 #define F_TIMEOUT (1 << 8) /* -t time out */ 136 #define F_WAITCRLF (1 << 9) /* -w wait for CR or LF */ 137 #define F_NOPROMPT (1 << 10) /* -n don't ask for login name */ 138 139 140 #define line_buf bb_common_bufsiz1 141 131 142 /* The following is used for understandable diagnostics. */ 132 133 /* Fake hostname for ut_host specified on command line. */134 static char *fakehost = NULL;135 136 /* ... */137 143 #ifdef DEBUGGING 138 #define debug(s) fprintf(dbf,s); fflush(dbf) 144 static FILE *dbf; 139 145 #define DEBUGTERM "/dev/ttyp0" 140 static FILE *dbf; 146 #define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0) 141 147 #else 142 #define debug( s) /* nothing */143 #endif 144 145 146 /* bcode - convert speed string to speed code; return 0 on failure */148 #define debug(...) ((void)0) 149 #endif 150 151 152 /* bcode - convert speed string to speed code; return <= 0 on failure */ 147 153 static int bcode(const char *s) 148 154 { 149 int r; 150 unsigned value = bb_strtou(s, NULL, 10); 151 if (errno) { 152 return -1; 153 } 154 r = tty_value_to_baud(value); 155 if (r > 0) { 156 return r; 157 } 158 return 0; 159 } 160 155 int value = bb_strtou(s, NULL, 10); /* yes, int is intended! */ 156 if (value < 0) /* bad terminating char, overflow, etc */ 157 return value; 158 return tty_value_to_baud(value); 159 } 161 160 162 161 /* parse_speeds - parse alternate baud rates */ … … 165 164 char *cp; 166 165 166 /* NB: at least one iteration is always done */ 167 167 debug("entered parse_speeds\n"); 168 for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { 169 if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0) 168 while ((cp = strsep(&arg, ",")) != NULL) { 169 op->speeds[op->numspeed] = bcode(cp); 170 if (op->speeds[op->numspeed] < 0) 170 171 bb_error_msg_and_die("bad speed: %s", cp); 172 /* note: arg "0" turns into speed B0 */ 173 op->numspeed++; 171 174 if (op->numspeed > MAX_SPEED) 172 175 bb_error_msg_and_die("too many alternate speeds"); 173 176 } 174 debug("exiting parsespeeds\n"); 175 } 176 177 debug("exiting parse_speeds\n"); 178 } 177 179 178 180 /* parse_args - parse command-line arguments */ 179 static void parse_args( int argc, char **argv, struct options *op)181 static void parse_args(char **argv, struct options *op, char **fakehost_p) 180 182 { 181 183 char *ts; 182 184 185 opt_complementary = "-2:t+"; /* at least 2 args; -t N */ 183 186 op->flags = getopt32(argv, opt_string, 184 &(op->initstring), &fakehost, &(op->issue), 185 &(op->login), &ts); 187 &(op->initstring), fakehost_p, &(op->issue), 188 &(op->login), &op->timeout); 189 argv += optind; 186 190 if (op->flags & F_INITSTRING) { 187 const char *p = op->initstring; 188 char *q; 189 190 op->initstring = q = xstrdup(op->initstring); 191 /* copy optarg into op->initstring decoding \ddd 192 octal codes into chars */ 193 while (*p) { 194 if (*p == '\\') { 195 p++; 196 *q++ = bb_process_escape_sequence(&p); 197 } else { 198 *q++ = *p++; 199 } 200 } 201 *q = '\0'; 202 } 203 op->flags ^= F_ISSUE; /* revert flag show /etc/issue */ 204 if (op->flags & F_TIMEOUT) { 205 op->timeout = xatoul_range(ts, 1, INT_MAX); 206 } 207 argv += optind; 208 argc -= optind; 209 debug("after getopt loop\n"); 210 if (argc < 2) /* check parameter count */ 211 bb_show_usage(); 191 op->initstring = xstrdup(op->initstring); 192 /* decode \ddd octal codes into chars */ 193 strcpy_and_process_escape_sequences((char*)op->initstring, op->initstring); 194 } 195 op->flags ^= F_ISSUE; /* invert flag "show /etc/issue" */ 196 debug("after getopt\n"); 212 197 213 198 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ 199 op->tty = argv[0]; /* tty name */ 200 ts = argv[1]; /* baud rate(s) */ 214 201 if (isdigit(argv[0][0])) { 215 202 /* a number first, assume it's a speed (BSD style) */ 216 parse_speeds(op, argv[0]); /* baud rate(s) */ 217 op->tty = argv[1]; /* tty name */ 218 } else { 219 op->tty = argv[0]; /* tty name */ 220 parse_speeds(op, argv[1]); /* baud rate(s) */ 221 } 203 op->tty = ts; /* tty name is in argv[1] */ 204 ts = argv[0]; /* baud rate(s) */ 205 } 206 parse_speeds(op, ts); 207 applet_name = xasprintf("getty: %s", op->tty); 222 208 223 209 if (argv[2]) 224 setenv("TERM", argv[2], 1);225 226 debug("exiting parse args\n");210 xsetenv("TERM", argv[2]); 211 212 debug("exiting parse_args\n"); 227 213 } 228 214 229 215 /* open_tty - set up tty as standard { input, output, error } */ 230 static void open_tty(const char *tty, struct termios *tp, int local) 231 { 232 int chdir_to_root = 0; 233 216 static void open_tty(const char *tty) 217 { 234 218 /* Set up new standard input, unless we are given an already opened port. */ 235 219 if (NOT_LONE_DASH(tty)) { 236 struct stat st; 237 int fd; 220 // struct stat st; 221 // int cur_dir_fd; 222 // int fd; 238 223 239 224 /* Sanity checks... */ 240 xchdir("/dev"); 241 chdir_to_root = 1; 242 xstat(tty, &st); 243 if ((st.st_mode & S_IFMT) != S_IFCHR) 244 bb_error_msg_and_die("%s: not a character device", tty); 225 // cur_dir_fd = xopen(".", O_DIRECTORY | O_NONBLOCK); 226 // xchdir("/dev"); 227 // xstat(tty, &st); 228 // if (!S_ISCHR(st.st_mode)) 229 // bb_error_msg_and_die("not a character device"); 230 231 if (tty[0] != '/') 232 tty = xasprintf("/dev/%s", tty); /* will leak it */ 245 233 246 234 /* Open the tty as standard input. */ 247 235 debug("open(2)\n"); 248 fd = xopen(tty, O_RDWR | O_NONBLOCK); 249 xdup2(fd, 0); 250 while (fd > 2) 251 close(fd--); 236 close(0); 237 /*fd =*/ xopen(tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */ 238 239 // /* Restore current directory */ 240 // fchdir(cur_dir_fd); 241 242 /* Open the tty as standard input, continued */ 243 // xmove_fd(fd, 0); 244 // /* fd is >= cur_dir_fd, and cur_dir_fd gets closed too here: */ 245 // while (fd > 2) 246 // close(fd--); 247 248 /* Set proper protections and ownership. */ 249 fchown(0, 0, 0); /* 0:0 */ 250 fchmod(0, 0620); /* crw--w---- */ 252 251 } else { 253 252 /* … … 258 257 bb_error_msg_and_die("stdin is not open for read/write"); 259 258 } 260 261 /* Replace current standard output/error fd's with new ones */262 debug("duping\n");263 xdup2(0, 1);264 xdup2(0, 2);265 266 /*267 * The following ioctl will fail if stdin is not a tty, but also when268 * there is noise on the modem control lines. In the latter case, the269 * common course of action is (1) fix your cables (2) give the modem more270 * time to properly reset after hanging up. SunOS users can achieve (2)271 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;272 * 5 seconds seems to be a good value.273 */274 ioctl_or_perror_and_die(0, TCGETS, tp, "%s: TCGETS", tty);275 276 /*277 * It seems to be a terminal. Set proper protections and ownership. Mode278 * 0622 is suitable for SYSV <4 because /bin/login does not change279 * protections. SunOS 4 login will change the protections to 0620 (write280 * access for group tty) after the login has succeeded.281 */282 283 #ifdef DEBIAN284 #warning Debian /dev/vcs[a]NN hack is deprecated and will be removed285 {286 /* tty to root.dialout 660 */287 struct group *gr;288 int id;289 290 gr = getgrnam("dialout");291 id = gr ? gr->gr_gid : 0;292 chown(tty, 0, id);293 chmod(tty, 0660);294 295 /* vcs,vcsa to root.sys 600 */296 if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) {297 char *vcs, *vcsa;298 299 vcs = xstrdup(tty);300 vcsa = xmalloc(strlen(tty) + 2);301 strcpy(vcs, "vcs");302 strcpy(vcs + 3, tty + 3);303 strcpy(vcsa, "vcsa");304 strcpy(vcsa + 4, tty + 3);305 306 gr = getgrnam("sys");307 id = gr ? gr->gr_gid : 0;308 chown(vcs, 0, id);309 chmod(vcs, 0600);310 chown(vcsa, 0, id);311 chmod(vcs, 0600);312 313 free(vcs);314 free(vcsa);315 }316 }317 #else318 if (NOT_LONE_DASH(tty)) {319 chown(tty, 0, 0); /* 0:0 */320 chmod(tty, 0622); /* crw--w--w- */321 }322 #endif323 if (chdir_to_root)324 xchdir("/");325 259 } 326 260 … … 328 262 static void termios_init(struct termios *tp, int speed, struct options *op) 329 263 { 264 speed_t ispeed, ospeed; 330 265 /* 331 266 * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. … … 334 269 * later on. 335 270 */ 336 #ifdef __linux__337 271 /* flush input and output queues, important for modems! */ 338 ioctl(0, TCFLSH, TCIOFLUSH); 339 #endif 340 341 tp->c_cflag = CS8 | HUPCL | CREAD | speed; 342 if (op->flags & F_LOCAL) { 272 tcflush(0, TCIOFLUSH); 273 ispeed = ospeed = speed; 274 if (speed == B0) { 275 /* Speed was specified as "0" on command line. 276 * Just leave it unchanged */ 277 ispeed = cfgetispeed(tp); 278 ospeed = cfgetospeed(tp); 279 } 280 tp->c_cflag = CS8 | HUPCL | CREAD; 281 if (op->flags & F_LOCAL) 343 282 tp->c_cflag |= CLOCAL; 344 } 345 346 tp->c_iflag = tp->c_lflag = tp->c_line = 0; 283 cfsetispeed(tp, ispeed); 284 cfsetospeed(tp, ospeed); 285 286 tp->c_iflag = tp->c_lflag = 0; 347 287 tp->c_oflag = OPOST | ONLCR; 348 288 tp->c_cc[VMIN] = 1; 349 289 tp->c_cc[VTIME] = 0; 290 #ifdef __linux__ 291 tp->c_line = 0; 292 #endif 350 293 351 294 /* Optionally enable hardware flow control */ 352 353 #ifdef CRTSCTS 295 #ifdef CRTSCTS 354 296 if (op->flags & F_RTSCTS) 355 297 tp->c_cflag |= CRTSCTS; 356 298 #endif 357 299 358 ioctl(0, TCSETS, tp); 359 360 /* go to blocking input even in local mode */ 361 ndelay_off(0); 300 tcsetattr_stdin_TCSANOW(tp); 362 301 363 302 debug("term_io 2\n"); … … 392 331 * be dealt with later on. 393 332 */ 394 395 333 iflag = tp->c_iflag; 396 334 tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ 397 335 vmin = tp->c_cc[VMIN]; 398 tp->c_cc[VMIN] = 0; 399 ioctl(0, TCSETS,tp);336 tp->c_cc[VMIN] = 0; /* don't block if queue empty */ 337 tcsetattr_stdin_TCSANOW(tp); 400 338 401 339 /* … … 403 341 * try to extract the speed of the dial-in call. 404 342 */ 405 406 343 sleep(1); 407 nread = read(0, buf, size_buf - 1);344 nread = safe_read(STDIN_FILENO, buf, size_buf - 1); 408 345 if (nread > 0) { 409 346 buf[nread] = '\0'; 410 347 for (bp = buf; bp < buf + nread; bp++) { 411 if (is ascii(*bp) && isdigit(*bp)) {348 if (isdigit(*bp)) { 412 349 speed = bcode(bp); 413 if (speed) { 414 tp->c_cflag &= ~CBAUD; 415 tp->c_cflag |= speed; 416 } 350 if (speed > 0) 351 cfsetspeed(tp, speed); 417 352 break; 418 353 } 419 354 } 420 355 } 356 421 357 /* Restore terminal settings. Errors will be dealt with later on. */ 422 423 358 tp->c_iflag = iflag; 424 359 tp->c_cc[VMIN] = vmin; 425 ioctl(0, TCSETS, tp); 426 } 427 428 /* next_speed - select next baud rate */ 429 static void next_speed(struct termios *tp, struct options *op) 430 { 431 static int baud_index = FIRST_SPEED; /* current speed index */ 432 433 baud_index = (baud_index + 1) % op->numspeed; 434 tp->c_cflag &= ~CBAUD; 435 tp->c_cflag |= op->speeds[baud_index]; 436 ioctl(0, TCSETS, tp); 437 } 438 360 tcsetattr_stdin_TCSANOW(tp); 361 } 439 362 440 363 /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ 441 static void do_prompt(struct options *op , struct termios *tp)364 static void do_prompt(struct options *op) 442 365 { 443 366 #ifdef ISSUE … … 448 371 449 372 #ifdef HANDLE_ALLCAPS 450 /* caps_lock- string contains upper case without lower case */373 /* all_is_upcase - string contains upper case without lower case */ 451 374 /* returns 1 if true, 0 if false */ 452 static int caps_lock(const char *s)375 static int all_is_upcase(const char *s) 453 376 { 454 377 while (*s) … … 459 382 #endif 460 383 461 /* get_logname - get user name, establish parity, speed, erase, kill, eol */462 /* return NULL on failure, logname on success */384 /* get_logname - get user name, establish parity, speed, erase, kill, eol; 385 * return NULL on BREAK, logname on success */ 463 386 static char *get_logname(char *logname, unsigned size_logname, 464 struct options *op, struct chardata *cp , struct termios *tp)387 struct options *op, struct chardata *cp) 465 388 { 466 389 char *bp; 467 char c; 390 char c; /* input character, full eight bits */ 468 391 char ascval; /* low 7 bits of input character */ 469 392 int bits; /* # of "1" bits per character */ 470 393 int mask; /* mask with 1 bit up */ 471 static const char erase[][3] = { 394 static const char erase[][3] = {/* backspace-space-backspace */ 472 395 "\010\040\010", /* space parity */ 473 396 "\010\040\010", /* odd parity */ 474 397 "\210\240\210", /* even parity */ 475 "\ 210\240\210", /*no parity */398 "\010\040\010", /* 8 bit no parity */ 476 399 }; 477 400 478 /* Initialize kill, erase, parity etc. (also after switching speeds). */ 479 480 *cp = init_chardata; 401 /* NB: *cp is pre-initialized with init_chardata */ 481 402 482 403 /* Flush pending input (esp. after parsing or switching the baud rate). */ 483 484 404 sleep(1); 485 ioctl(0, TCFLSH, TCIFLUSH);405 tcflush(0, TCIOFLUSH); 486 406 487 407 /* Prompt for and read a login name. */ 488 489 408 logname[0] = '\0'; 490 409 while (!logname[0]) { 491 492 410 /* Write issue file and prompt, with "parity" bit == 0. */ 493 494 do_prompt(op, tp); 411 do_prompt(op); 495 412 496 413 /* Read name, watch for break, parity, erase, kill, end-of-line. */ 497 498 414 bp = logname; 499 415 cp->eol = '\0'; … … 501 417 502 418 /* Do not report trivial EINTR/EIO errors. */ 503 if (read(0, &c, 1) < 1) { 419 errno = EINTR; /* make read of 0 bytes be silent too */ 420 if (read(STDIN_FILENO, &c, 1) < 1) { 504 421 if (errno == EINTR || errno == EIO) 505 exit( 0);506 bb_perror_msg_and_die( "%s: read", op->tty);422 exit(EXIT_SUCCESS); 423 bb_perror_msg_and_die(bb_msg_read_error); 507 424 } 508 425 509 /* Do BREAK handling elsewhere. */ 426 /* BREAK. If we have speeds to try, 427 * return NULL (will switch speeds and return here) */ 510 428 if (c == '\0' && op->numspeed > 1) 511 429 return NULL; 512 430 513 431 /* Do parity bit handling. */ 514 ascval = c & 0177; 515 if (c != ascval) { /* "parity" bit on ? */ 432 if (!(op->flags & F_LOCAL) && (c & 0x80)) { /* "parity" bit on? */ 516 433 bits = 1; 517 434 mask = 1; 518 while (mask & 0 177) {519 if (mask & ascval)435 while (mask & 0x7f) { 436 if (mask & c) 520 437 bits++; /* count "1" bits */ 521 438 mask <<= 1; … … 526 443 527 444 /* Do erase, kill and end-of-line processing. */ 445 ascval = c & 0x7f; 528 446 switch (ascval) { 529 447 case CR: … … 534 452 case BS: 535 453 case DEL: 454 #ifdef ANCIENT_BS_KILL_CHARS 536 455 case '#': 456 #endif 537 457 cp->erase = ascval; /* set erase character */ 538 458 if (bp > logname) { 539 write(1, erase[cp->parity], 3);459 full_write(STDOUT_FILENO, erase[cp->parity], 3); 540 460 bp--; 541 461 } 542 462 break; 543 463 case CTL('U'): 464 #ifdef ANCIENT_BS_KILL_CHARS 544 465 case '@': 466 #endif 545 467 cp->kill = ascval; /* set kill character */ 546 468 while (bp > logname) { 547 write(1, erase[cp->parity], 3);469 full_write(STDOUT_FILENO, erase[cp->parity], 3); 548 470 bp--; 549 471 } 550 472 break; 551 473 case CTL('D'): 552 exit( 0);474 exit(EXIT_SUCCESS); 553 475 default: 554 if ( !isascii(ascval) || !isprint(ascval)) {476 if (ascval < ' ') { 555 477 /* ignore garbage characters */ 556 } else if ( bp - logname>= size_logname - 1) {557 bb_error_msg_and_die(" %s: input overrun", op->tty);478 } else if ((int)(bp - logname) >= size_logname - 1) { 479 bb_error_msg_and_die("input overrun"); 558 480 } else { 559 write(1, &c, 1); /* echo the character */481 full_write(STDOUT_FILENO, &c, 1); /* echo the character */ 560 482 *bp++ = ascval; /* and store it */ 561 483 } … … 567 489 568 490 #ifdef HANDLE_ALLCAPS 569 cp->capslock = caps_lock(logname);491 cp->capslock = all_is_upcase(logname); 570 492 if (cp->capslock) { 571 493 for (bp = logname; *bp; bp++) … … 581 503 { 582 504 /* General terminal-independent stuff. */ 583 584 505 tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ 585 506 tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; … … 591 512 tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ 592 513 tp->c_cc[VEOL] = DEF_EOL; 514 #ifdef VSWTC 593 515 tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ 516 #endif 594 517 595 518 /* Account for special characters seen in input. */ 596 597 519 if (cp->eol == CR) { 598 520 tp->c_iflag |= ICRNL; /* map CR in input to NL */ … … 603 525 604 526 /* Account for the presence or absence of parity bits in input. */ 605 606 527 switch (cp->parity) { 607 528 case 0: /* space (always 0) parity */ 529 // I bet most people go here - they use only 7-bit chars in usernames.... 608 530 break; 609 531 case 1: /* odd parity */ … … 617 539 tp->c_cflag &= ~CSIZE; 618 540 tp->c_cflag |= CS7; 541 // FIXME: wtf? case 3: we saw both even and odd 8-bit bytes - 542 // it's probably some umlauts etc, but definitely NOT 7-bit!!! 543 // Entire parity detection madness here just begs for deletion... 619 544 break; 620 545 } … … 629 554 #endif 630 555 /* Optionally enable hardware flow control */ 631 632 #ifdef CRTSCTS 556 #ifdef CRTSCTS 633 557 if (op->flags & F_RTSCTS) 634 558 tp->c_cflag |= CRTSCTS; … … 636 560 637 561 /* Finally, make the new settings effective */ 638 639 ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty); 640 } 641 642 643 #ifdef SYSV_STYLE 644 #if ENABLE_FEATURE_UTMP 645 /* update_utmp - update our utmp entry */ 646 static void update_utmp(const char *line) 647 { 648 struct utmp ut; 649 struct utmp *utp; 650 time_t t; 651 int mypid = getpid(); 652 653 /* 654 * The utmp file holds miscellaneous information about things started by 655 * /sbin/init and other system-related events. Our purpose is to update 656 * the utmp entry for the current process, in particular the process type 657 * and the tty line we are listening to. Return successfully only if the 658 * utmp file can be opened for update, and if we are able to find our 659 * entry in the utmp file. 660 */ 661 if (access(_PATH_UTMP, R_OK|W_OK) == -1) { 662 close(creat(_PATH_UTMP, 0664)); 663 } 664 utmpname(_PATH_UTMP); 665 setutent(); 666 while ((utp = getutent()) 667 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) 668 /* nothing */; 669 670 if (utp) { 671 memcpy(&ut, utp, sizeof(ut)); 672 } else { 673 /* some inits don't initialize utmp... */ 674 memset(&ut, 0, sizeof(ut)); 675 safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); 676 } 677 /* endutent(); */ 678 679 strcpy(ut.ut_user, "LOGIN"); 680 safe_strncpy(ut.ut_line, line, sizeof(ut.ut_line)); 681 if (fakehost) 682 safe_strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); 683 time(&t); 684 ut.ut_time = t; 685 ut.ut_type = LOGIN_PROCESS; 686 ut.ut_pid = mypid; 687 688 pututline(&ut); 689 endutent(); 690 691 #if ENABLE_FEATURE_WTMP 692 if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) 693 close(creat(bb_path_wtmp_file, 0664)); 694 updwtmp(bb_path_wtmp_file, &ut); 695 #endif 696 } 697 698 #endif /* CONFIG_FEATURE_UTMP */ 699 #endif /* SYSV_STYLE */ 700 701 702 int getty_main(int argc, char **argv); 703 int getty_main(int argc, char **argv) 704 { 705 int nullfd; 706 char *logname = NULL; /* login name, given to /bin/login */ 562 if (tcsetattr_stdin_TCSANOW(tp) < 0) 563 bb_perror_msg_and_die("tcsetattr"); 564 } 565 566 int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 567 int getty_main(int argc UNUSED_PARAM, char **argv) 568 { 569 int n; 570 pid_t pid; 571 char *fakehost = NULL; /* Fake hostname for ut_host */ 572 char *logname; /* login name, given to /bin/login */ 707 573 /* Merging these into "struct local" may _seem_ to reduce 708 574 * parameter passing, but today's gcc will inline 709 575 * statics which are called once anyway, so don't do that */ 710 576 struct chardata chardata; /* set by get_logname() */ 711 struct termios termios; /* terminal mode bits */ 712 struct options options = { 713 0, /* show /etc/issue (SYSV_STYLE) */ 714 0, /* no timeout */ 715 _PATH_LOGIN, /* default login program */ 716 "tty1", /* default tty line */ 717 "", /* modem init string */ 577 struct termios termios; /* terminal mode bits */ 578 struct options options; 579 580 chardata = init_chardata; 581 582 memset(&options, 0, sizeof(options)); 583 options.login = _PATH_LOGIN; /* default login program */ 584 options.tty = "tty1"; /* default tty line */ 585 options.initstring = ""; /* modem init string */ 718 586 #ifdef ISSUE 719 ISSUE, /* default issue file */ 720 #else 721 NULL, 722 #endif 723 0, /* no baud rates known yet */ 724 }; 725 726 /* Already too late because of theoretical 727 * possibility of getty --help somehow triggered 728 * inadvertently before we reach this. Oh well. */ 587 options.issue = ISSUE; /* default issue file */ 588 #endif 589 590 /* Parse command-line arguments. */ 591 parse_args(argv, &options, &fakehost); 592 729 593 logmode = LOGMODE_NONE; 594 595 /* Create new session, lose controlling tty, if any */ 596 /* docs/ctty.htm says: 597 * "This is allowed only when the current process 598 * is not a process group leader" - is this a problem? */ 730 599 setsid(); 731 nullfd = xopen(bb_dev_null, O_RDWR); 732 /* dup2(nullfd, 0); - no, because of possible "getty - 9600" */ 733 /* open_tty() will take care of fd# 0 anyway */ 734 dup2(nullfd, 1); 735 dup2(nullfd, 2); 736 while (nullfd > 2) close(nullfd--); 737 /* We want special flavor of error_msg_and_die */ 600 /* close stdio, and stray descriptors, just in case */ 601 n = xopen(bb_dev_null, O_RDWR); 602 /* dup2(n, 0); - no, we need to handle "getty - 9600" too */ 603 xdup2(n, 1); 604 xdup2(n, 2); 605 while (n > 2) 606 close(n--); 607 608 /* Logging. We want special flavor of error_msg_and_die */ 738 609 die_sleep = 10; 739 610 msg_eol = "\r\n"; 611 /* most likely will internally use fd #3 in CLOEXEC mode: */ 740 612 openlog(applet_name, LOG_PID, LOG_AUTH); 741 613 logmode = LOGMODE_BOTH; 742 614 743 615 #ifdef DEBUGGING 744 dbf = xfopen(DEBUGTERM, "w"); 745 746 { 747 int i; 748 749 for (i = 1; i < argc; i++) { 750 debug(argv[i]); 751 debug("\n"); 752 } 753 } 754 #endif 755 756 /* Parse command-line arguments. */ 757 parse_args(argc, argv, &options); 758 759 #ifdef SYSV_STYLE 760 #if ENABLE_FEATURE_UTMP 761 /* Update the utmp file. */ 762 update_utmp(options.tty); 763 #endif 764 #endif 765 616 dbf = xfopen_for_write(DEBUGTERM); 617 for (n = 1; argv[n]; n++) { 618 debug(argv[n]); 619 debug("\n"); 620 } 621 #endif 622 623 /* Open the tty as standard input, if it is not "-" */ 624 /* If it's not "-" and not taken yet, it will become our ctty */ 766 625 debug("calling open_tty\n"); 767 /* Open the tty as standard { input, output, error }. */ 768 open_tty(options.tty, &termios, options.flags & F_LOCAL); 769 626 open_tty(options.tty); 627 ndelay_off(0); 628 debug("duping\n"); 629 xdup2(0, 1); 630 xdup2(0, 2); 631 632 /* 633 * The following ioctl will fail if stdin is not a tty, but also when 634 * there is noise on the modem control lines. In the latter case, the 635 * common course of action is (1) fix your cables (2) give the modem more 636 * time to properly reset after hanging up. SunOS users can achieve (2) 637 * by patching the SunOS kernel variable "zsadtrlow" to a larger value; 638 * 5 seconds seems to be a good value. 639 */ 640 if (tcgetattr(0, &termios) < 0) 641 bb_perror_msg_and_die("tcgetattr"); 642 643 pid = getpid(); 770 644 #ifdef __linux__ 771 { 772 int iv; 773 774 iv = getpid(); 775 ioctl(0, TIOCSPGRP, &iv); 776 } 777 #endif 645 // FIXME: do we need this? Otherwise "-" case seems to be broken... 646 // /* Forcibly make fd 0 our controlling tty, even if another session 647 // * has it as a ctty. (Another session loses ctty). */ 648 // ioctl(0, TIOCSCTTY, (void*)1); 649 /* Make ourself a foreground process group within our session */ 650 tcsetpgrp(0, pid); 651 #endif 652 653 /* Update the utmp file. This tty is ours now! */ 654 update_utmp(pid, LOGIN_PROCESS, options.tty, "LOGIN", fakehost); 655 778 656 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ 779 657 debug("calling termios_init\n"); 780 termios_init(&termios, options.speeds[ FIRST_SPEED], &options);781 782 /* write the modem init string and DON'T flush the buffers */658 termios_init(&termios, options.speeds[0], &options); 659 660 /* Write the modem init string and DON'T flush the buffers */ 783 661 if (options.flags & F_INITSTRING) { 784 662 debug("writing init string\n"); 785 write(1, options.initstring, strlen(options.initstring)); 786 } 787 788 if (!(options.flags & F_LOCAL)) { 789 /* go to blocking write mode unless -L is specified */ 790 ndelay_off(1); 791 } 792 793 /* Optionally detect the baud rate from the modem status message. */ 663 full_write1_str(options.initstring); 664 } 665 666 /* Optionally detect the baud rate from the modem status message */ 794 667 debug("before autobaud\n"); 795 668 if (options.flags & F_PARSE) 796 auto_baud(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), &termios); 797 798 /* Set the optional timer. */ 799 if (options.timeout) 800 alarm(options.timeout); 801 802 /* optionally wait for CR or LF before writing /etc/issue */ 669 auto_baud(line_buf, sizeof(line_buf), &termios); 670 671 /* Set the optional timer */ 672 alarm(options.timeout); /* if 0, alarm is not set */ 673 674 /* Optionally wait for CR or LF before writing /etc/issue */ 803 675 if (options.flags & F_WAITCRLF) { 804 676 char ch; 805 677 806 678 debug("waiting for cr-lf\n"); 807 while (read(0, &ch, 1) == 1) { 679 while (safe_read(STDIN_FILENO, &ch, 1) == 1) { 680 debug("read %x\n", (unsigned char)ch); 808 681 ch &= 0x7f; /* strip "parity bit" */ 809 #ifdef DEBUGGING810 fprintf(dbf, "read %c\n", ch);811 #endif812 682 if (ch == '\n' || ch == '\r') 813 683 break; … … 815 685 } 816 686 817 chardata = init_chardata;687 logname = NULL; 818 688 if (!(options.flags & F_NOPROMPT)) { 819 /* Read the login name. */ 820 debug("reading login name\n"); 821 logname = get_logname(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), 822 &options, &chardata, &termios); 823 while (logname == NULL) 824 next_speed(&termios, &options); 689 /* NB:termios_init already set line speed 690 * to options.speeds[0] */ 691 int baud_index = 0; 692 693 while (1) { 694 /* Read the login name. */ 695 debug("reading login name\n"); 696 logname = get_logname(line_buf, sizeof(line_buf), 697 &options, &chardata); 698 if (logname) 699 break; 700 /* we are here only if options.numspeed > 1 */ 701 baud_index = (baud_index + 1) % options.numspeed; 702 cfsetispeed(&termios, options.speeds[baud_index]); 703 cfsetospeed(&termios, options.speeds[baud_index]); 704 tcsetattr_stdin_TCSANOW(&termios); 705 } 825 706 } 826 707 827 708 /* Disable timer. */ 828 829 if (options.timeout) 830 alarm(0); 709 alarm(0); 831 710 832 711 /* Finalize the termios settings. */ 833 834 712 termios_final(&options, &termios, &chardata); 835 713 836 714 /* Now the newline character should be properly written. */ 837 838 write(1, "\n", 1); 715 full_write(STDOUT_FILENO, "\n", 1); 839 716 840 717 /* Let the login program take care of password validation. */ 841 842 execl(options.login, options.login, "--", logname, (char *) 0); 843 bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login); 844 } 718 /* We use PATH because we trust that root doesn't set "bad" PATH, 719 * and getty is not suid-root applet. */ 720 /* With -n, logname == NULL, and login will ask for username instead */ 721 BB_EXECLP(options.login, options.login, "--", logname, NULL); 722 bb_error_msg_and_die("can't execute '%s'", options.login); 723 } -
branches/2.2.9/mindi-busybox/loginutils/login.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 */ 5 6 5 #include "libbb.h" 7 #include <utmp.h> 6 #include <syslog.h> 7 #if ENABLE_FEATURE_UTMP 8 # include <utmp.h> /* USER_PROCESS */ 9 #endif 8 10 #include <sys/resource.h> 9 #include <syslog.h>10 11 11 12 #if ENABLE_SELINUX 12 # include <selinux/selinux.h> /* for is_selinux_enabled() */13 # include <selinux/get_context_list.h> /* for get_default_context() */14 # include <selinux/flask.h> /* for security class definitions */13 # include <selinux/selinux.h> /* for is_selinux_enabled() */ 14 # include <selinux/get_context_list.h> /* for get_default_context() */ 15 # include <selinux/flask.h> /* for security class definitions */ 15 16 #endif 16 17 17 18 #if ENABLE_PAM 18 19 /* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 19 # undef setlocale20 # undef setlocale 20 21 /* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. 21 22 * Apparently they like to confuse people. */ 22 # include <security/pam_appl.h>23 # include <security/pam_misc.h>23 # include <security/pam_appl.h> 24 # include <security/pam_misc.h> 24 25 static const struct pam_conv conv = { 25 26 misc_conv, … … 37 38 static char* short_tty; 38 39 39 #if ENABLE_FEATURE_UTMP40 /* vv Taken from tinylogin utmp.c vv */41 /*42 * read_or_build_utent - see if utmp file is correct for this process43 *44 * System V is very picky about the contents of the utmp file45 * and requires that a slot for the current process exist.46 * The utmp file is scanned for an entry with the same process47 * ID. If no entry exists the process exits with a message.48 *49 * The "picky" flag is for network and other logins that may50 * use special flags. It allows the pid checks to be overridden.51 * This means that getty should never invoke login with any52 * command line flags.53 */54 55 static void read_or_build_utent(struct utmp *utptr, int picky)56 {57 struct utmp *ut;58 pid_t pid = getpid();59 60 setutent();61 62 /* First, try to find a valid utmp entry for this process. */63 while ((ut = getutent()))64 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&65 (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))66 break;67 68 /* If there is one, just use it, otherwise create a new one. */69 if (ut) {70 *utptr = *ut;71 } else {72 if (picky)73 bb_error_msg_and_die("no utmp entry found");74 75 memset(utptr, 0, sizeof(*utptr));76 utptr->ut_type = LOGIN_PROCESS;77 utptr->ut_pid = pid;78 strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));79 /* This one is only 4 chars wide. Try to fit something80 * remotely meaningful by skipping "tty"... */81 strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));82 strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));83 utptr->ut_time = time(NULL);84 }85 if (!picky) /* root login */86 memset(utptr->ut_host, 0, sizeof(utptr->ut_host));87 }88 89 /*90 * write_utent - put a USER_PROCESS entry in the utmp file91 *92 * write_utent changes the type of the current utmp entry to93 * USER_PROCESS. the wtmp file will be updated as well.94 */95 static void write_utent(struct utmp *utptr, const char *username)96 {97 utptr->ut_type = USER_PROCESS;98 strncpy(utptr->ut_user, username, sizeof(utptr->ut_user));99 utptr->ut_time = time(NULL);100 /* other fields already filled in by read_or_build_utent above */101 setutent();102 pututline(utptr);103 endutent();104 #if ENABLE_FEATURE_WTMP105 if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {106 close(creat(bb_path_wtmp_file, 0664));107 }108 updwtmp(bb_path_wtmp_file, utptr);109 #endif110 }111 #else /* !ENABLE_FEATURE_UTMP */112 #define read_or_build_utent(utptr, picky) ((void)0)113 #define write_utent(utptr, username) ((void)0)114 #endif /* !ENABLE_FEATURE_UTMP */115 116 40 #if ENABLE_FEATURE_NOLOGIN 117 static void die_if_nologin _and_non_root(int amroot)41 static void die_if_nologin(void) 118 42 { 119 43 FILE *fp; 120 44 int c; 121 122 if (access("/etc/nologin", F_OK)) 45 int empty = 1; 46 47 fp = fopen_for_read("/etc/nologin"); 48 if (!fp) /* assuming it does not exist */ 123 49 return; 124 50 125 fp = fopen("/etc/nologin", "r");126 if (fp) {127 while ((c = getc(fp)) != EOF)128 putchar((c=='\n') ? '\r' :c);129 fflush(stdout);130 fclose(fp);131 } else51 while ((c = getc(fp)) != EOF) { 52 if (c == '\n') 53 bb_putchar('\r'); 54 bb_putchar(c); 55 empty = 0; 56 } 57 if (empty) 132 58 puts("\r\nSystem closed for routine maintenance\r"); 133 if (!amroot) 134 exit(1); 135 puts("\r\n[Disconnect bypassed -- root login allowed]\r"); 59 60 fclose(fp); 61 fflush_all(); 62 /* Users say that they do need this prior to exit: */ 63 tcdrain(STDOUT_FILENO); 64 exit(EXIT_FAILURE); 136 65 } 137 66 #else 138 static ALWAYS_INLINE void die_if_nologin_and_non_root(int amroot) {} 67 # define die_if_nologin() ((void)0) 139 68 #endif 140 69 … … 142 71 static int check_securetty(void) 143 72 { 144 FILE *fp; 145 int i; 146 char buf[256]; 147 148 fp = fopen("/etc/securetty", "r"); 149 if (!fp) { 150 /* A missing securetty file is not an error. */ 151 return 1; 152 } 153 while (fgets(buf, sizeof(buf)-1, fp)) { 154 for (i = strlen(buf)-1; i >= 0; --i) { 155 if (!isspace(buf[i])) 156 break; 157 } 158 buf[++i] = '\0'; 159 if (!buf[0] || (buf[0] == '#')) 160 continue; 161 if (strcmp(buf, short_tty) == 0) { 162 fclose(fp); 163 return 1; 164 } 165 } 166 fclose(fp); 167 return 0; 73 char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ 74 parser_t *parser = config_open2("/etc/securetty", fopen_for_read); 75 while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) { 76 if (strcmp(buf, short_tty) == 0) 77 break; 78 buf = NULL; 79 } 80 config_close(parser); 81 /* buf != NULL here if config file was not found, empty 82 * or line was found which equals short_tty */ 83 return buf != NULL; 168 84 } 169 85 #else 170 86 static ALWAYS_INLINE int check_securetty(void) { return 1; } 87 #endif 88 89 #if ENABLE_SELINUX 90 static void initselinux(char *username, char *full_tty, 91 security_context_t *user_sid) 92 { 93 security_context_t old_tty_sid, new_tty_sid; 94 95 if (!is_selinux_enabled()) 96 return; 97 98 if (get_default_context(username, NULL, user_sid)) { 99 bb_error_msg_and_die("can't get SID for %s", username); 100 } 101 if (getfilecon(full_tty, &old_tty_sid) < 0) { 102 bb_perror_msg_and_die("getfilecon(%s) failed", full_tty); 103 } 104 if (security_compute_relabel(*user_sid, old_tty_sid, 105 SECCLASS_CHR_FILE, &new_tty_sid) != 0) { 106 bb_perror_msg_and_die("security_change_sid(%s) failed", full_tty); 107 } 108 if (setfilecon(full_tty, new_tty_sid) != 0) { 109 bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid); 110 } 111 } 112 #endif 113 114 #if ENABLE_LOGIN_SCRIPTS 115 static void run_login_script(struct passwd *pw, char *full_tty) 116 { 117 char *t_argv[2]; 118 119 t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT"); 120 if (t_argv[0]) { 121 t_argv[1] = NULL; 122 xsetenv("LOGIN_TTY", full_tty); 123 xsetenv("LOGIN_USER", pw->pw_name); 124 xsetenv("LOGIN_UID", utoa(pw->pw_uid)); 125 xsetenv("LOGIN_GID", utoa(pw->pw_gid)); 126 xsetenv("LOGIN_SHELL", pw->pw_shell); 127 spawn_and_wait(t_argv); /* NOMMU-friendly */ 128 unsetenv("LOGIN_TTY"); 129 unsetenv("LOGIN_USER"); 130 unsetenv("LOGIN_UID"); 131 unsetenv("LOGIN_GID"); 132 unsetenv("LOGIN_SHELL"); 133 } 134 } 135 #else 136 void run_login_script(struct passwd *pw, char *full_tty); 171 137 #endif 172 138 … … 181 147 do { 182 148 c = getchar(); 183 if (c == EOF) exit(1); 149 if (c == EOF) 150 exit(EXIT_FAILURE); 184 151 if (c == '\n') { 185 if (!--cntdown) exit(1); 152 if (!--cntdown) 153 exit(EXIT_FAILURE); 186 154 goto prompt; 187 155 } 188 } while (isspace(c)); 156 } while (isspace(c)); /* maybe isblank? */ 189 157 190 158 *buf++ = c; 191 159 if (!fgets(buf, size_buf-2, stdin)) 192 exit( 1);160 exit(EXIT_FAILURE); 193 161 if (!strchr(buf, '\n')) 194 exit(1); 195 while (isgraph(*buf)) buf++; 162 exit(EXIT_FAILURE); 163 while ((unsigned char)*buf > ' ') 164 buf++; 196 165 *buf = '\0'; 197 166 } … … 202 171 203 172 fd = open(bb_path_motd_file, O_RDONLY); 204 if (fd ) {205 fflush (stdout);173 if (fd >= 0) { 174 fflush_all(); 206 175 bb_copyfd_eof(fd, STDOUT_FILENO); 207 176 close(fd); … … 209 178 } 210 179 211 static void alarm_handler(int sig ATTRIBUTE_UNUSED)180 static void alarm_handler(int sig UNUSED_PARAM) 212 181 { 213 182 /* This is the escape hatch! Poor serial line users and the like … … 215 184 * We don't want to block here */ 216 185 ndelay_on(1); 217 ndelay_on(2);218 186 printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT); 219 exit(EXIT_SUCCESS); 220 } 221 222 int login_main(int argc, char **argv); 223 int login_main(int argc, char **argv) 187 fflush_all(); 188 /* unix API is brain damaged regarding O_NONBLOCK, 189 * we should undo it, or else we can affect other processes */ 190 ndelay_off(1); 191 _exit(EXIT_SUCCESS); 192 } 193 194 int login_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 195 int login_main(int argc UNUSED_PARAM, char **argv) 224 196 { 225 197 enum { … … 230 202 char *fromhost; 231 203 char username[USERNAME_SIZE]; 232 const char * tmp;233 int amroot;204 const char *shell; 205 int run_by_root; 234 206 unsigned opt; 235 207 int count = 0; 236 208 struct passwd *pw; 237 209 char *opt_host = NULL; 238 char *opt_user = NULL; 239 char full_tty[TTYNAME_SIZE]; 240 USE_SELINUX(security_context_t user_sid = NULL;) 241 USE_FEATURE_UTMP(struct utmp utent;) 242 USE_PAM(pam_handle_t *pamh;) 243 USE_PAM(int pamret;) 244 USE_PAM(const char *failed_msg;) 245 246 short_tty = full_tty; 210 char *opt_user = opt_user; /* for compiler */ 211 char *full_tty; 212 IF_SELINUX(security_context_t user_sid = NULL;) 213 #if ENABLE_PAM 214 int pamret; 215 pam_handle_t *pamh; 216 const char *pamuser; 217 const char *failed_msg; 218 struct passwd pwdstruct; 219 char pwdbuf[256]; 220 #endif 221 247 222 username[0] = '\0'; 248 amroot = (getuid() == 0);249 223 signal(SIGALRM, alarm_handler); 250 224 alarm(TIMEOUT); 225 226 /* More of suid paranoia if called by non-root: */ 227 /* Clear dangerous stuff, set PATH */ 228 run_by_root = !sanitize_env_if_suid(); 251 229 252 230 /* Mandatory paranoia for suid applet: … … 258 236 opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); 259 237 if (opt & LOGIN_OPT_f) { 260 if (! amroot)238 if (!run_by_root) 261 239 bb_error_msg_and_die("-f is for root only"); 262 240 safe_strncpy(username, opt_user, sizeof(username)); 263 241 } 264 if (optind < argc) /* user from command line (getty) */ 265 safe_strncpy(username, argv[optind], sizeof(username)); 242 argv += optind; 243 if (argv[0]) /* user from command line (getty) */ 244 safe_strncpy(username, argv[0], sizeof(username)); 266 245 267 246 /* Let's find out and memorize our tty */ 268 if (!isatty(0) || !isatty(1) || !isatty(2)) 269 return EXIT_FAILURE; /* Must be a terminal */ 270 safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty)); 271 tmp = ttyname(0); 272 if (tmp) { 273 safe_strncpy(full_tty, tmp, sizeof(full_tty)); 274 if (strncmp(full_tty, "/dev/", 5) == 0) 275 short_tty = full_tty + 5; 276 } 277 278 read_or_build_utent(&utent, !amroot); 247 if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) 248 return EXIT_FAILURE; /* Must be a terminal */ 249 full_tty = xmalloc_ttyname(STDIN_FILENO); 250 if (!full_tty) 251 full_tty = xstrdup("UNKNOWN"); 252 short_tty = skip_dev_pfx(full_tty); 279 253 280 254 if (opt_host) { 281 USE_FEATURE_UTMP(282 safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));283 )284 255 fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host); 285 } else 256 } else { 286 257 fromhost = xasprintf(" on '%s'", short_tty); 258 } 287 259 288 260 /* Was breaking "login <username>" from shell command line: */ 289 261 /*bb_setpgrp();*/ 290 262 291 openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);263 openlog(applet_name, LOG_PID | LOG_CONS, LOG_AUTH); 292 264 293 265 while (1) { 266 /* flush away any type-ahead (as getty does) */ 267 tcflush(0, TCIFLUSH); 268 294 269 if (!username[0]) 295 270 get_username_or_die(username, sizeof(username)); … … 298 273 pamret = pam_start("login", username, &conv, &pamh); 299 274 if (pamret != PAM_SUCCESS) { 300 failed_msg = " pam_start";275 failed_msg = "start"; 301 276 goto pam_auth_failed; 302 277 } … … 304 279 pamret = pam_set_item(pamh, PAM_TTY, short_tty); 305 280 if (pamret != PAM_SUCCESS) { 306 failed_msg = " pam_set_item(TTY)";281 failed_msg = "set_item(TTY)"; 307 282 goto pam_auth_failed; 308 283 } 309 284 pamret = pam_authenticate(pamh, 0); 310 285 if (pamret != PAM_SUCCESS) { 311 failed_msg = " pam_authenticate";286 failed_msg = "authenticate"; 312 287 goto pam_auth_failed; 313 288 /* TODO: or just "goto auth_failed" … … 319 294 pamret = pam_acct_mgmt(pamh, 0); 320 295 if (pamret != PAM_SUCCESS) { 321 failed_msg = "acc ount setup";296 failed_msg = "acct_mgmt"; 322 297 goto pam_auth_failed; 323 298 } 324 299 /* read user back */ 325 { 326 const char *pamuser; 327 /* gcc: "dereferencing type-punned pointer breaks aliasing rules..." 328 * thus we cast to (void*) */ 329 if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) { 330 failed_msg = "pam_get_item(USER)"; 331 goto pam_auth_failed; 332 } 333 safe_strncpy(username, pamuser, sizeof(username)); 334 } 335 /* If we get here, the user was authenticated, and is 336 * granted access. */ 337 pw = getpwnam(username); 338 if (pw) 339 break; 340 goto auth_failed; 300 pamuser = NULL; 301 /* gcc: "dereferencing type-punned pointer breaks aliasing rules..." 302 * thus we cast to (void*) */ 303 if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) { 304 failed_msg = "get_item(USER)"; 305 goto pam_auth_failed; 306 } 307 if (!pamuser || !pamuser[0]) 308 goto auth_failed; 309 safe_strncpy(username, pamuser, sizeof(username)); 310 /* Don't use "pw = getpwnam(username);", 311 * PAM is said to be capable of destroying static storage 312 * used by getpwnam(). We are using safe(r) function */ 313 pw = NULL; 314 getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw); 315 if (!pw) 316 goto auth_failed; 317 pamret = pam_open_session(pamh, 0); 318 if (pamret != PAM_SUCCESS) { 319 failed_msg = "open_session"; 320 goto pam_auth_failed; 321 } 322 pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED); 323 if (pamret != PAM_SUCCESS) { 324 failed_msg = "setcred"; 325 goto pam_auth_failed; 326 } 327 break; /* success, continue login process */ 328 341 329 pam_auth_failed: 342 bb_error_msg("%s failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret); 330 /* syslog, because we don't want potential attacker 331 * to know _why_ login failed */ 332 syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg, 333 pam_strerror(pamh, pamret), pamret); 343 334 safe_strncpy(username, "UNKNOWN", sizeof(username)); 344 335 #else /* not PAM */ … … 374 365 syslog(LOG_WARNING, "invalid password for '%s'%s", 375 366 username, fromhost); 367 368 if (ENABLE_FEATURE_CLEAN_UP) 369 free(fromhost); 370 376 371 return EXIT_FAILURE; 377 372 } 378 373 username[0] = '\0'; 379 } 374 } /* while (1) */ 380 375 381 376 alarm(0); 382 die_if_nologin_and_non_root(pw->pw_uid == 0); 383 384 write_utent(&utent, username); 385 386 #if ENABLE_SELINUX 387 if (is_selinux_enabled()) { 388 security_context_t old_tty_sid, new_tty_sid; 389 390 if (get_default_context(username, NULL, &user_sid)) { 391 bb_error_msg_and_die("cannot get SID for %s", 392 username); 393 } 394 if (getfilecon(full_tty, &old_tty_sid) < 0) { 395 bb_perror_msg_and_die("getfilecon(%s) failed", 396 full_tty); 397 } 398 if (security_compute_relabel(user_sid, old_tty_sid, 399 SECCLASS_CHR_FILE, &new_tty_sid) != 0) { 400 bb_perror_msg_and_die("security_change_sid(%s) failed", 401 full_tty); 402 } 403 if (setfilecon(full_tty, new_tty_sid) != 0) { 404 bb_perror_msg_and_die("chsid(%s, %s) failed", 405 full_tty, new_tty_sid); 406 } 407 } 408 #endif 377 /* We can ignore /etc/nologin if we are logging in as root, 378 * it doesn't matter whether we are run by root or not */ 379 if (pw->pw_uid != 0) 380 die_if_nologin(); 381 382 IF_SELINUX(initselinux(username, full_tty, &user_sid)); 383 409 384 /* Try these, but don't complain if they fail. 410 385 * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ … … 412 387 fchmod(0, 0600); 413 388 414 if (ENABLE_LOGIN_SCRIPTS) { 415 char *t_argv[2]; 416 417 t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT"); 418 if (t_argv[0]) { 419 t_argv[1] = NULL; 420 xsetenv("LOGIN_TTY", full_tty); 421 xsetenv("LOGIN_USER", pw->pw_name); 422 xsetenv("LOGIN_UID", utoa(pw->pw_uid)); 423 xsetenv("LOGIN_GID", utoa(pw->pw_gid)); 424 xsetenv("LOGIN_SHELL", pw->pw_shell); 425 xspawn(t_argv); /* NOMMU-friendly */ 426 /* All variables are unset by setup_environment */ 427 wait(NULL); 428 } 429 } 389 update_utmp(getpid(), USER_PROCESS, short_tty, username, run_by_root ? opt_host : NULL); 390 391 /* We trust environment only if we run by root */ 392 if (ENABLE_LOGIN_SCRIPTS && run_by_root) 393 run_login_script(pw, full_tty); 430 394 431 395 change_identity(pw); 432 tmp= pw->pw_shell;433 if (! tmp || !*tmp)434 tmp= DEFAULT_SHELL;435 /* setup_environment params: shell, loginshell, changeenv, pw */436 setup_environment(tmp, 1, !(opt & LOGIN_OPT_p), pw);437 /* FIXME: login shell = 1 -> 3rd parameter is ignored! */396 shell = pw->pw_shell; 397 if (!shell || !shell[0]) 398 shell = DEFAULT_SHELL; 399 setup_environment(shell, 400 (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, 401 pw); 438 402 439 403 motd(); … … 441 405 if (pw->pw_uid == 0) 442 406 syslog(LOG_INFO, "root login%s", fromhost); 443 #if ENABLE_SELINUX 407 408 if (ENABLE_FEATURE_CLEAN_UP) 409 free(fromhost); 410 444 411 /* well, a simple setexeccon() here would do the job as well, 445 412 * but let's play the game for now */ 446 set_current_security_context(user_sid); 447 #endif 413 IF_SELINUX(set_current_security_context(user_sid);) 448 414 449 415 // util-linux login also does: … … 456 422 // If this stuff is really needed, add it and explain why! 457 423 458 /* set signals to defaults */ 459 signal(SIGALRM, SIG_DFL); 424 /* Set signals to defaults */ 425 /* Non-ignored signals revert to SIG_DFL on exec anyway */ 426 /*signal(SIGALRM, SIG_DFL);*/ 427 460 428 /* Is this correct? This way user can ctrl-c out of /etc/profile, 461 429 * potentially creating security breach (tested with bash 3.0). … … 463 431 * Maybe bash is buggy? 464 432 * Need to find out what standards say about /bin/login - 465 * should itleave SIGINT etc enabled or disabled? */433 * should we leave SIGINT etc enabled or disabled? */ 466 434 signal(SIGINT, SIG_DFL); 467 435 468 436 /* Exec login shell with no additional parameters */ 469 run_shell( tmp, 1, NULL, NULL);437 run_shell(shell, 1, NULL, NULL); 470 438 471 439 /* return EXIT_FAILURE; - not reached */ -
branches/2.2.9/mindi-busybox/loginutils/passwd.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 */ 5 6 5 #include "libbb.h" 7 6 #include <syslog.h> 8 9 7 10 8 static void nuke_str(char *str) … … 18 16 char *orig = (char*)""; 19 17 char *newp = NULL; 20 char *cipher = NULL;21 18 char *cp = NULL; 22 19 char *ret = NULL; /* failure so far */ 23 20 24 21 if (myuid && pw->pw_passwd[0]) { 25 orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ 22 char *encrypted; 23 24 orig = bb_ask_stdin("Old password: "); /* returns ptr to static */ 26 25 if (!orig) 27 26 goto err_ret; 28 cipher = pw_encrypt(orig, pw->pw_passwd); /* returns ptr to static*/29 if (strcmp( cipher, pw->pw_passwd) != 0) {30 syslog(LOG_WARNING, "incorrect password for '%s'",27 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */ 28 if (strcmp(encrypted, pw->pw_passwd) != 0) { 29 syslog(LOG_WARNING, "incorrect password for %s", 31 30 pw->pw_name); 32 31 bb_do_delay(FAIL_DELAY); … … 34 33 goto err_ret; 35 34 } 36 } 37 orig = xstrdup(orig); /* or else bb_askpass() will destroy it */ 38 newp = bb_askpass(0, "New password:"); /* returns ptr to static */ 35 if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); 36 } 37 orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */ 38 newp = bb_ask_stdin("New password: "); /* returns ptr to static */ 39 39 if (!newp) 40 40 goto err_ret; 41 newp = xstrdup(newp); /* we are going to bb_ask pass() again, so save it */41 newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */ 42 42 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK 43 43 && obscure(orig, newp, pw) && myuid) 44 44 goto err_ret; /* non-root is not allowed to have weak passwd */ 45 45 46 cp = bb_ask pass(0, "Retype password:");46 cp = bb_ask_stdin("Retype password: "); 47 47 if (!cp) 48 48 goto err_ret; … … 57 57 crypt_make_salt(salt + 3, 4, 0); 58 58 } 59 /* pw_encrypt returns ptr to static*/60 ret = xstrdup(pw_encrypt(newp, salt));59 /* pw_encrypt returns malloced str */ 60 ret = pw_encrypt(newp, salt, 1); 61 61 /* whee, success! */ 62 62 … … 66 66 nuke_str(newp); 67 67 if (ENABLE_FEATURE_CLEAN_UP) free(newp); 68 nuke_str(cipher);69 68 nuke_str(cp); 70 69 return ret; 71 70 } 72 71 73 int passwd_main(int argc, char **argv) ;74 int passwd_main(int argc , char **argv)72 int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 73 int passwd_main(int argc UNUSED_PARAM, char **argv) 75 74 { 76 75 enum { … … 94 93 struct rlimit rlimit_fsize; 95 94 char c; 96 97 95 #if ENABLE_FEATURE_SHADOWPASSWDS 98 96 /* Using _r function to avoid pulling in static buffers */ 99 97 struct spwd spw; 100 struct spwd *result;101 98 char buffer[256]; 102 99 #endif 103 100 104 101 logmode = LOGMODE_BOTH; 105 openlog(applet_name, LOG_NOWAIT, LOG_AUTH);102 openlog(applet_name, 0, LOG_AUTH); 106 103 opt = getopt32(argv, "a:lud", &opt_a); 107 104 //argc -= optind; … … 118 115 119 116 /* Will complain and die if username not found */ 120 myname = xstrdup( bb_getpwuid(NULL, -1,myuid));117 myname = xstrdup(xuid2uname(myuid)); 121 118 name = argv[0] ? argv[0] : myname; 122 119 123 pw = getpwnam(name); 124 if (!pw) bb_error_msg_and_die("unknown user %s", name); 120 pw = xgetpwnam(name); 125 121 if (myuid && pw->pw_uid != myuid) { 126 122 /* LOGMODE_BOTH */ … … 129 125 130 126 #if ENABLE_FEATURE_SHADOWPASSWDS 131 /* getspnam_r() can lie! Even if user isn't in shadow, it can 132 * return success (pwd field was seen set to "!" in this case) */ 133 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) 134 || LONE_CHAR(spw.sp_pwdp, '!')) { 135 /* LOGMODE_BOTH */ 136 bb_error_msg("no record of %s in %s, using %s", 137 name, bb_path_shadow_file, 138 bb_path_passwd_file); 139 } else { 140 pw->pw_passwd = spw.sp_pwdp; 127 { 128 /* getspnam_r may return 0 yet set result to NULL. 129 * At least glibc 2.4 does this. Be extra paranoid here. */ 130 struct spwd *result = NULL; 131 errno = 0; 132 if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0 133 || !result /* no error, but no record found either */ 134 || strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */ 135 ) { 136 if (errno != ENOENT) { 137 /* LOGMODE_BOTH */ 138 bb_perror_msg("no record of %s in %s, using %s", 139 name, bb_path_shadow_file, 140 bb_path_passwd_file); 141 } 142 /* else: /etc/shadow does not exist, 143 * apparently we are on a shadow-less system, 144 * no surprise there */ 145 } else { 146 pw->pw_passwd = result->sp_pwdp; 147 } 141 148 } 142 149 #endif … … 148 155 if (myuid && !c) { /* passwd starts with '!' */ 149 156 /* LOGMODE_BOTH */ 150 bb_error_msg_and_die("can not change "157 bb_error_msg_and_die("can't change " 151 158 "locked password for %s", name); 152 159 } … … 162 169 } else if (opt & OPT_unlock) { 163 170 if (c) goto skip; /* not '!' */ 164 /* pw->pw_passwd p ints to static storage,171 /* pw->pw_passwd points to static storage, 165 172 * strdup'ing to avoid nasty surprizes */ 166 173 newp = xstrdup(&pw->pw_passwd[1]); … … 172 179 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; 173 180 setrlimit(RLIMIT_FSIZE, &rlimit_fsize); 174 signal(SIGHUP, SIG_IGN); 175 signal(SIGINT, SIG_IGN); 176 signal(SIGQUIT, SIG_IGN); 181 bb_signals(0 182 + (1 << SIGHUP) 183 + (1 << SIGINT) 184 + (1 << SIGQUIT) 185 , SIG_IGN); 177 186 umask(077); 178 187 xsetuid(0); … … 180 189 #if ENABLE_FEATURE_SHADOWPASSWDS 181 190 filename = bb_path_shadow_file; 182 rc = update_passwd(bb_path_shadow_file, name, newp );191 rc = update_passwd(bb_path_shadow_file, name, newp, NULL); 183 192 if (rc == 0) /* no lines updated, no errors detected */ 184 193 #endif 185 194 { 186 195 filename = bb_path_passwd_file; 187 rc = update_passwd(bb_path_passwd_file, name, newp );196 rc = update_passwd(bb_path_passwd_file, name, newp, NULL); 188 197 } 189 198 /* LOGMODE_BOTH */ 190 199 if (rc < 0) 191 bb_error_msg_and_die("can not update password file %s",200 bb_error_msg_and_die("can't update password file %s", 192 201 filename); 193 202 bb_info_msg("Password for %s changed by %s", name, myname); -
branches/2.2.9/mindi-busybox/loginutils/su.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * 3 * Mini su implementation for busybox 4 4 * 5 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 6 */ 7 7 … … 9 9 #include <syslog.h> 10 10 11 #if ENABLE_FEATURE_SU_CHECKS_SHELLS 12 /* Return 1 if SHELL is a restricted shell (one not returned by 13 * getusershell), else 0, meaning it is a standard shell. */ 14 static int restricted_shell(const char *shell) 15 { 16 char *line; 17 int result = 1; 18 19 /*setusershell(); - getusershell does it itself*/ 20 while ((line = getusershell()) != NULL) { 21 if (/* *line != '#' && */ strcmp(line, shell) == 0) { 22 result = 0; 23 break; 24 } 25 } 26 if (ENABLE_FEATURE_CLEAN_UP) 27 endusershell(); 28 return result; 29 } 30 #endif 31 11 32 #define SU_OPT_mp (3) 12 #define SU_OPT_l (4)33 #define SU_OPT_l (4) 13 34 14 int su_main(int argc, char **argv) ;15 int su_main(int argc , char **argv)35 int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 36 int su_main(int argc UNUSED_PARAM, char **argv) 16 37 { 17 38 unsigned flags; … … 22 43 uid_t cur_uid = getuid(); 23 44 const char *tty; 24 char *old_user; 45 char user_buf[64]; 46 const char *old_user; 25 47 26 48 flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); 27 argc -= optind;49 //argc -= optind; 28 50 argv += optind; 29 51 30 if (arg c&& LONE_DASH(argv[0])) {52 if (argv[0] && LONE_DASH(argv[0])) { 31 53 flags |= SU_OPT_l; 32 argc--;33 54 argv++; 34 55 } 35 56 36 57 /* get user if specified */ 37 if (arg c) {58 if (argv[0]) { 38 59 opt_username = argv[0]; 39 // argc--;40 60 argv++; 41 61 } 42 62 43 63 if (ENABLE_FEATURE_SU_SYSLOG) { 44 /* The utmp entry (via getlogin) is probably the best way to identify 45 the user, especially if someone su's from a su-shell. 46 But getlogin can fail -- usually due to lack of utmp entry. 47 in this case resort to getpwuid. */ 48 old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : ""); 49 tty = ttyname(2) ? : "none"; 64 /* The utmp entry (via getlogin) is probably the best way to 65 * identify the user, especially if someone su's from a su-shell. 66 * But getlogin can fail -- usually due to lack of utmp entry. 67 * in this case resort to getpwuid. */ 68 #if ENABLE_FEATURE_UTMP 69 old_user = user_buf; 70 if (getlogin_r(user_buf, sizeof(user_buf)) != 0) 71 #endif 72 { 73 pw = getpwuid(cur_uid); 74 old_user = pw ? xstrdup(pw->pw_name) : ""; 75 } 76 tty = xmalloc_ttyname(2); 77 if (!tty) { 78 tty = "none"; 79 } 50 80 openlog(applet_name, 0, LOG_AUTH); 51 81 } 52 82 53 pw = getpwnam(opt_username); 54 if (!pw) 55 bb_error_msg_and_die("unknown id: %s", opt_username); 83 pw = xgetpwnam(opt_username); 56 84 57 /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER 58 is a username that is retrieved via NIS (YP), but that doesn't have 59 a default shell listed. */ 60 if (!pw->pw_shell || !pw->pw_shell[0]) 61 pw->pw_shell = (char *)DEFAULT_SHELL; 62 63 if ((cur_uid == 0) || correct_password(pw)) { 85 if (cur_uid == 0 || correct_password(pw)) { 64 86 if (ENABLE_FEATURE_SU_SYSLOG) 65 87 syslog(LOG_NOTICE, "%c %s %s:%s", … … 74 96 if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { 75 97 closelog(); 76 free(old_user);77 98 } 78 99 79 if (!opt_shell && (flags & SU_OPT_mp)) 100 if (!opt_shell && (flags & SU_OPT_mp)) { 101 /* -s SHELL is not given, but "preserve env" opt is */ 80 102 opt_shell = getenv("SHELL"); 103 } 104 105 /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER 106 * is a username that is retrieved via NIS (YP), that doesn't have 107 * a default shell listed. */ 108 if (!pw->pw_shell || !pw->pw_shell[0]) 109 pw->pw_shell = (char *)DEFAULT_SHELL; 81 110 82 111 #if ENABLE_FEATURE_SU_CHECKS_SHELLS 83 if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) {112 if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) { 84 113 /* The user being su'd to has a nonstandard shell, and so is 85 86 87 114 * probably a uucp account or has restricted access. Don't 115 * compromise the account by allowing access with a standard 116 * shell. */ 88 117 bb_error_msg("using restricted shell"); 89 opt_shell = 0;118 opt_shell = NULL; 90 119 } 120 /* else: user can run whatever he wants via "su -s PROG USER". 121 * This is safe since PROG is run under user's uid/gid. */ 91 122 #endif 92 123 if (!opt_shell) … … 94 125 95 126 change_identity(pw); 96 setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw); 97 USE_SELINUX(set_current_security_context(NULL);) 127 setup_environment(opt_shell, 128 ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV) 129 + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV), 130 pw); 131 IF_SELINUX(set_current_security_context(NULL);) 98 132 99 133 /* Never returns */ 100 134 run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv); 101 135 102 return EXIT_FAILURE;136 /* return EXIT_FAILURE; - not reached */ 103 137 } -
branches/2.2.9/mindi-busybox/loginutils/sulogin.c
r1765 r2725 3 3 * Mini sulogin implementation for busybox 4 4 * 5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 6 */ 7 7 8 #include "libbb.h" 8 9 #include <syslog.h> 9 10 10 #include "libbb.h" 11 12 static const char *const forbid[] = { 13 "ENV", 14 "BASH_ENV", 15 "HOME", 16 "IFS", 17 "PATH", 18 "SHELL", 19 "LD_LIBRARY_PATH", 20 "LD_PRELOAD", 21 "LD_TRACE_LOADED_OBJECTS", 22 "LD_BIND_NOW", 23 "LD_AOUT_LIBRARY_PATH", 24 "LD_AOUT_PRELOAD", 25 "LD_NOWARN", 26 "LD_KEEPDIR", 27 (char *) 0 28 }; 11 //static void catchalarm(int UNUSED_PARAM junk) 12 //{ 13 // exit(EXIT_FAILURE); 14 //} 29 15 30 16 31 static void catchalarm(int ATTRIBUTE_UNUSED junk) 32 { 33 exit(EXIT_FAILURE); 34 } 35 36 37 int sulogin_main(int argc, char **argv); 38 int sulogin_main(int argc, char **argv) 17 int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 18 int sulogin_main(int argc UNUSED_PARAM, char **argv) 39 19 { 40 20 char *cp; 41 21 int timeout = 0; 42 char *timeout_arg;43 const char *const *p;44 22 struct passwd *pwd; 45 23 const char *shell; … … 48 26 char buffer[256]; 49 27 struct spwd spw; 50 struct spwd *result;51 28 #endif 52 29 … … 54 31 openlog(applet_name, 0, LOG_AUTH); 55 32 56 if (getopt32(argv, "t:", &timeout_arg)) {57 timeout = xatoi_u(timeout_arg);58 }33 opt_complementary = "t+"; /* -t N */ 34 getopt32(argv, "t:", &timeout); 35 argv += optind; 59 36 60 if (argv[ optind]) {37 if (argv[0]) { 61 38 close(0); 62 39 close(1); 63 dup(xopen(argv[ optind], O_RDWR));40 dup(xopen(argv[0], O_RDWR)); 64 41 close(2); 65 42 dup(0); 66 43 } 67 44 45 /* Malicious use like "sulogin /dev/sda"? */ 68 46 if (!isatty(0) || !isatty(1) || !isatty(2)) { 69 47 logmode = LOGMODE_SYSLOG; … … 71 49 } 72 50 73 /* Clear out anything dangerous from the environment */ 74 for (p = forbid; *p; p++) 75 unsetenv(*p); 76 77 signal(SIGALRM, catchalarm); 51 /* Clear dangerous stuff, set PATH */ 52 sanitize_env_if_suid(); 78 53 79 54 pwd = getpwuid(0); … … 83 58 84 59 #if ENABLE_FEATURE_SHADOWPASSWDS 85 if (getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result)) { 86 goto auth_error; 60 { 61 /* getspnam_r may return 0 yet set result to NULL. 62 * At least glibc 2.4 does this. Be extra paranoid here. */ 63 struct spwd *result = NULL; 64 int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result); 65 if (r || !result) { 66 goto auth_error; 67 } 68 pwd->pw_passwd = result->sp_pwdp; 87 69 } 88 pwd->pw_passwd = spw.sp_pwdp;89 70 #endif 90 71 91 72 while (1) { 73 char *encrypted; 74 int r; 75 92 76 /* cp points to a static buffer that is zeroed every time */ 93 cp = bb_ask pass(timeout,77 cp = bb_ask(STDIN_FILENO, timeout, 94 78 "Give root password for system maintenance\n" 95 79 "(or type Control-D for normal startup):"); … … 99 83 return 0; 100 84 } 101 if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) { 85 encrypted = pw_encrypt(cp, pwd->pw_passwd, 1); 86 r = strcmp(encrypted, pwd->pw_passwd); 87 free(encrypted); 88 if (r == 0) { 102 89 break; 103 90 } … … 106 93 } 107 94 memset(cp, 0, strlen(cp)); 108 signal(SIGALRM, SIG_DFL);95 // signal(SIGALRM, SIG_DFL); 109 96 110 97 bb_info_msg("System Maintenance Mode"); 111 98 112 USE_SELINUX(renew_current_security_context());99 IF_SELINUX(renew_current_security_context()); 113 100 114 101 shell = getenv("SUSHELL"); 115 if (!shell) shell = getenv("sushell"); 116 if (!shell) { 117 shell = "/bin/sh"; 118 if (pwd->pw_shell[0]) 119 shell = pwd->pw_shell; 120 } 121 run_shell(shell, 1, 0, 0); 122 /* never returns */ 102 if (!shell) 103 shell = getenv("sushell"); 104 if (!shell) 105 shell = pwd->pw_shell; 123 106 124 auth_error: 125 bb_error_msg_and_die("no password entry for 'root'"); 107 /* Exec login shell with no additional parameters. Never returns. */ 108 run_shell(shell, 1, NULL, NULL); 109 110 auth_error: 111 bb_error_msg_and_die("no password entry for root"); 126 112 } -
branches/2.2.9/mindi-busybox/loginutils/vlock.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 3 2 /* 4 3 * vlock implementation for busybox … … 7 6 * Written by spoon <spon@ix.netcom.com> 8 7 * 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 9 */ 11 10 … … 18 17 19 18 #include "libbb.h" 19 20 #ifdef __linux__ 20 21 #include <sys/vt.h> 21 22 22 static struct passwd *pw; 23 static struct vt_mode ovtm; 24 static struct termios oterm; 25 static int vfd; 26 static unsigned long o_lock_all; 27 28 static void release_vt(int signo) 23 static void release_vt(int signo UNUSED_PARAM) 29 24 { 30 ioctl(vfd, VT_RELDISP, !o_lock_all); 25 /* If -a, param is 0, which means: 26 * "no, kernel, we don't allow console switch away from us!" */ 27 ioctl(STDIN_FILENO, VT_RELDISP, (unsigned long) !option_mask32); 31 28 } 32 29 33 static void acquire_vt(int signo )30 static void acquire_vt(int signo UNUSED_PARAM) 34 31 { 35 ioctl(vfd, VT_RELDISP, VT_ACKACQ); 32 /* ACK to kernel that switch to console is successful */ 33 ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); 36 34 } 35 #endif 37 36 38 static void restore_terminal(void) 37 int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 38 int vlock_main(int argc UNUSED_PARAM, char **argv) 39 39 { 40 ioctl(vfd, VT_SETMODE, &ovtm); 41 tcsetattr(STDIN_FILENO, TCSANOW, &oterm); 42 } 40 #ifdef __linux__ 41 struct vt_mode vtm; 42 struct vt_mode ovtm; 43 #endif 44 struct termios term; 45 struct termios oterm; 46 struct passwd *pw; 43 47 44 int vlock_main(int argc, char **argv); 45 int vlock_main(int argc, char **argv) 46 { 47 sigset_t sig; 48 struct sigaction sa; 49 struct vt_mode vtm; 50 struct termios term; 51 uid_t uid = getuid(); 48 pw = xgetpwuid(getuid()); 49 opt_complementary = "=0"; /* no params! */ 50 getopt32(argv, "a"); 52 51 53 pw = getpwuid(uid); 54 if (pw == NULL) 55 bb_error_msg_and_die("unknown uid %d", uid); 52 /* Ignore some signals so that we don't get killed by them */ 53 bb_signals(0 54 + (1 << SIGTSTP) 55 + (1 << SIGTTIN) 56 + (1 << SIGTTOU) 57 + (1 << SIGHUP ) 58 + (1 << SIGCHLD) /* paranoia :) */ 59 + (1 << SIGQUIT) 60 + (1 << SIGINT ) 61 , SIG_IGN); 56 62 57 if (argc > 2) { 58 bb_show_usage(); 59 } 63 #ifdef __linux__ 64 /* We will use SIGUSRx for console switch control: */ 65 /* 1: set handlers */ 66 signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); 67 signal_SA_RESTART_empty_mask(SIGUSR2, acquire_vt); 68 /* 2: unmask them */ 69 sig_unblock(SIGUSR1); 70 sig_unblock(SIGUSR2); 71 #endif 60 72 61 o_lock_all = getopt32(argv, "a"); 73 /* Revert stdin/out to our controlling tty 74 * (or die if we have none) */ 75 xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); 76 xdup2(STDIN_FILENO, STDOUT_FILENO); 62 77 63 vfd = xopen(CURRENT_TTY, O_RDWR); 64 65 xioctl(vfd, VT_GETMODE, &vtm); 66 67 /* mask a bunch of signals */ 68 sigprocmask(SIG_SETMASK, NULL, &sig); 69 sigdelset(&sig, SIGUSR1); 70 sigdelset(&sig, SIGUSR2); 71 sigaddset(&sig, SIGTSTP); 72 sigaddset(&sig, SIGTTIN); 73 sigaddset(&sig, SIGTTOU); 74 sigaddset(&sig, SIGHUP); 75 sigaddset(&sig, SIGCHLD); 76 sigaddset(&sig, SIGQUIT); 77 sigaddset(&sig, SIGINT); 78 79 sigemptyset(&(sa.sa_mask)); 80 sa.sa_flags = SA_RESTART; 81 sa.sa_handler = release_vt; 82 sigaction(SIGUSR1, &sa, NULL); 83 sa.sa_handler = acquire_vt; 84 sigaction(SIGUSR2, &sa, NULL); 85 86 /* need to handle some signals so that we don't get killed by them */ 87 sa.sa_handler = SIG_IGN; 88 sigaction(SIGHUP, &sa, NULL); 89 sigaction(SIGQUIT, &sa, NULL); 90 sigaction(SIGINT, &sa, NULL); 91 sigaction(SIGTSTP, &sa, NULL); 92 78 #ifdef __linux__ 79 xioctl(STDIN_FILENO, VT_GETMODE, &vtm); 93 80 ovtm = vtm; 81 /* "console switches are controlled by us, not kernel!" */ 94 82 vtm.mode = VT_PROCESS; 95 83 vtm.relsig = SIGUSR1; 96 84 vtm.acqsig = SIGUSR2; 97 ioctl(vfd, VT_SETMODE, &vtm); 85 ioctl(STDIN_FILENO, VT_SETMODE, &vtm); 86 #endif 98 87 99 88 tcgetattr(STDIN_FILENO, &oterm); … … 103 92 term.c_lflag &= ~ISIG; 104 93 term.c_lflag &= ~(ECHO | ECHOCTL); 105 tcsetattr (STDIN_FILENO, TCSANOW,&term);94 tcsetattr_stdin_TCSANOW(&term); 106 95 107 96 do { 108 printf("Virtual Console%s locked by %s.\n", (o_lock_all) ? "s" : "", pw->pw_name); 97 printf("Virtual console%s locked by %s.\n", 98 option_mask32 /*o_lock_all*/ ? "s" : "", 99 pw->pw_name); 109 100 if (correct_password(pw)) { 110 101 break; … … 113 104 puts("Password incorrect"); 114 105 } while (1); 115 restore_terminal(); 116 fflush_stdout_and_exit(0); 106 107 #ifdef __linux__ 108 ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); 109 #endif 110 tcsetattr_stdin_TCSANOW(&oterm); 111 fflush_stdout_and_exit(EXIT_SUCCESS); 117 112 }
Note:
See TracChangeset
for help on using the changeset viewer.