Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/loginutils
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (17 years ago)
- Location:
- branches/stable/mindi-busybox/loginutils
- Files:
-
- 2 deleted
- 10 edited
- 3 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/loginutils/Config.in
r902 r1770 6 6 menu "Login/Password Management Utilities" 7 7 8 config CONFIG_FEATURE_SHADOWPASSWDS8 config FEATURE_SHADOWPASSWDS 9 9 bool "Support for shadow passwords" 10 10 default n … … 14 14 publicly readable. 15 15 16 config CONFIG_USE_BB_SHADOW16 config USE_BB_SHADOW 17 17 bool " Use busybox shadow password functions" 18 18 default y 19 depends on CONFIG_USE_BB_PWD_GRP && CONFIG_FEATURE_SHADOWPASSWDS19 depends on USE_BB_PWD_GRP && FEATURE_SHADOWPASSWDS 20 20 help 21 21 If you leave this disabled, busybox will use the system's shadow … … 33 33 password servers and whatnot. 34 34 35 config CONFIG_USE_BB_PWD_GRP35 config USE_BB_PWD_GRP 36 36 bool "Use internal password and group functions rather than system functions" 37 37 default n … … 54 54 If you enable this option, it will add about 1.5k to busybox. 55 55 56 config CONFIG_ADDGROUP56 config ADDGROUP 57 57 bool "addgroup" 58 58 default n … … 60 60 Utility for creating a new group account. 61 61 62 config CONFIG_DELGROUP 62 config FEATURE_ADDUSER_TO_GROUP 63 bool "Support for adding users to groups" 64 default n 65 depends on ADDGROUP 66 help 67 If called with two non-option arguments, 68 addgroup will add an existing user to an 69 existing group. 70 71 config DELGROUP 63 72 bool "delgroup" 64 73 default n … … 66 75 Utility for deleting a group account. 67 76 68 config CONFIG_ADDUSER 77 config FEATURE_DEL_USER_FROM_GROUP 78 bool "Support for removing users from groups." 79 default n 80 depends on DELGROUP 81 help 82 If called with two non-option arguments, deluser 83 or delgroup will remove an user from a specified group. 84 85 config ADDUSER 69 86 bool "adduser" 70 87 default n … … 72 89 Utility for creating a new user account. 73 90 74 config CONFIG_DELUSER91 config DELUSER 75 92 bool "deluser" 76 93 default n … … 78 95 Utility for deleting a user account. 79 96 80 config CONFIG_GETTY97 config GETTY 81 98 bool "getty" 82 99 default n 100 select FEATURE_SYSLOG 83 101 help 84 102 getty lets you log in on a tty, it is normally invoked by init. 85 103 86 config CONFIG_FEATURE_UTMP104 config FEATURE_UTMP 87 105 bool "Support utmp file" 88 depends on CONFIG_GETTY || CONFIG_LOGIN || CONFIG_SU || CONFIG_WHO106 depends on GETTY || LOGIN || SU || WHO 89 107 default n 90 108 help 91 109 The file /var/run/utmp is used to track who is currently logged in. 92 110 93 config CONFIG_FEATURE_WTMP111 config FEATURE_WTMP 94 112 bool "Support wtmp file" 95 depends on CONFIG_GETTY || CONFIG_LOGIN || CONFIG_SU || CONFIG_LAST96 default n 97 select CONFIG_FEATURE_UTMP113 depends on GETTY || LOGIN || SU || LAST 114 default n 115 select FEATURE_UTMP 98 116 help 99 117 The file /var/run/wtmp is used to track when user's have logged into 100 118 and logged out of the system. 101 119 102 config CONFIG_LOGIN120 config LOGIN 103 121 bool "login" 104 122 default n 105 select CONFIG_FEATURE_SUID 123 select FEATURE_SUID 124 select FEATURE_SYSLOG 106 125 help 107 126 login is used when signing onto a system. … … 110 129 work properly. 111 130 112 config CONFIG_FEATURE_SECURETTY 131 config PAM 132 bool "Support for PAM (Pluggable Authentication Modules)" 133 default n 134 depends on LOGIN 135 help 136 Use PAM in login(1) instead of direct access to password database. 137 138 config LOGIN_SCRIPTS 139 bool "Support for login scripts" 140 depends on LOGIN 141 default n 142 help 143 Enable this if you want login to execute $LOGIN_PRE_SUID_SCRIPT 144 just prior to switching from root to logged-in user. 145 146 config FEATURE_NOLOGIN 147 bool "Support for /etc/nologin" 148 default y 149 depends on LOGIN 150 help 151 The file /etc/nologin is used by (some versions of) login(1). 152 If it exists, non-root logins are prohibited. 153 154 config FEATURE_SECURETTY 113 155 bool "Support for /etc/securetty" 114 156 default y 115 depends on CONFIG_LOGIN116 help 117 The file /etc/securettyis used by (some versions of) login(1).157 depends on LOGIN 158 help 159 The file /etc/securetty is used by (some versions of) login(1). 118 160 The file contains the device names of tty lines (one per line, 119 161 without leading /dev/) on which root is allowed to login. 120 162 121 config CONFIG_PASSWD163 config PASSWD 122 164 bool "passwd" 123 165 default n 124 select CONFIG_FEATURE_SUID 166 select FEATURE_SUID 167 select FEATURE_SYSLOG 125 168 help 126 169 passwd changes passwords for user and group accounts. A normal user … … 132 175 work properly. 133 176 134 config CONFIG_SU 177 config FEATURE_PASSWD_WEAK_CHECK 178 bool "Check new passwords for weakness" 179 default y 180 depends on PASSWD 181 help 182 With this option passwd will refuse new passwords which are "weak". 183 184 config CRYPTPW 185 bool "cryptpw" 186 default n 187 help 188 Applet for crypting a string. 189 190 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. 197 198 config SU 135 199 bool "su" 136 200 default n 137 select CONFIG_FEATURE_SUID 201 select FEATURE_SUID 202 select FEATURE_SYSLOG 138 203 help 139 204 su is used to become another user during a login session. … … 143 208 work properly. 144 209 145 config CONFIG_SULOGIN 210 config FEATURE_SU_SYSLOG 211 bool "Enable su to write to syslog" 212 default y 213 depends on SU 214 215 config FEATURE_SU_CHECKS_SHELLS 216 bool "Enable su to check user's shell to be listed in /etc/shells" 217 depends on SU 218 default y 219 220 config SULOGIN 146 221 bool "sulogin" 147 222 default n 223 select FEATURE_SYSLOG 148 224 help 149 225 sulogin is invoked when the system goes into single user 150 226 mode (this is done through an entry in inittab). 151 227 152 config CONFIG_VLOCK228 config VLOCK 153 229 bool "vlock" 154 230 default n 155 select CONFIG_FEATURE_SUID231 select FEATURE_SUID 156 232 help 157 233 Build the "vlock" applet which allows you to lock (virtual) terminals. -
branches/stable/mindi-busybox/loginutils/addgroup.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * addgroup - add users to /etc/passwd and /etc/shadow3 * addgroup - add groups to /etc/group and /etc/gshadow 4 4 * 5 5 * Copyright (C) 1999 by Lineo, inc. and John Beppu 6 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> 7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it> 7 8 * 8 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. … … 10 11 */ 11 12 12 #include <stdio.h> 13 #include <string.h> 14 #include <sys/types.h> 15 #include <unistd.h> 13 #include "libbb.h" 16 14 17 #include "busybox.h" 15 static void xgroup_study(struct group *g) 16 { 17 /* Make sure gr_name is unused */ 18 if (getgrnam(g->gr_name)) { 19 goto error; 20 } 18 21 19 /* make sure gr_name isn't taken, make sure gid is kosher 20 * return 1 on failure */ 21 static int group_study(struct group *g) 22 { 23 FILE *etc_group; 24 gid_t desired; 25 26 struct group *grp; 27 const int max = 65000; 28 29 etc_group = bb_xfopen(bb_path_group_file, "r"); 30 31 /* make sure gr_name isn't taken, make sure gid is kosher */ 32 desired = g->gr_gid; 33 while ((grp = fgetgrent(etc_group))) { 34 if ((strcmp(grp->gr_name, g->gr_name)) == 0) { 35 bb_error_msg_and_die("%s: group already in use", g->gr_name); 22 /* Check if the desired gid is free 23 * or find the first free one */ 24 while (1) { 25 if (!getgrgid(g->gr_gid)) { 26 return; /* found free group: return */ 36 27 } 37 if ((desired) && grp->gr_gid == desired) { 38 bb_error_msg_and_die("%d: gid already in use", 39 desired); 28 if (option_mask32) { 29 /* -g N, cannot pick gid other than N: error */ 30 g->gr_name = itoa(g->gr_gid); 31 goto error; 40 32 } 41 if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) { 42 g->gr_gid = grp->gr_gid; 33 g->gr_gid++; 34 if (g->gr_gid <= 0) { 35 /* overflowed: error */ 36 bb_error_msg_and_die("no gids left"); 43 37 } 44 38 } 45 fclose(etc_group);46 39 47 /* gid */ 48 if (desired) { 49 g->gr_gid = desired; 50 } else { 51 g->gr_gid++; 52 } 53 /* return 1; */ 54 return 0; 40 error: 41 /* exit */ 42 bb_error_msg_and_die("group %s already exists", g->gr_name); 55 43 } 56 44 57 45 /* append a new user to the passwd file */ 58 static int addgroup(char *group, gid_t gid, const char *user)46 static void new_group(char *group, gid_t gid) 59 47 { 60 48 FILE *file; … … 64 52 gr.gr_gid = gid; 65 53 gr.gr_name = group; 66 if (group_study(&gr)) 67 return 1; 54 xgroup_study(&gr); 68 55 69 56 /* add entry to group */ 70 file = bb_xfopen(bb_path_group_file, "a");57 file = xfopen(bb_path_group_file, "a"); 71 58 /* group:passwd:gid:userlist */ 72 fprintf(file, "%s:%s:%d:%s\n", group, "x", gr.gr_gid, user); 73 fclose(file); 59 fprintf(file, "%s:x:%d:\n", group, gr.gr_gid); 60 if (ENABLE_FEATURE_CLEAN_UP) 61 fclose(file); 62 #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 } 69 #endif 70 } 74 71 75 #if ENABLE_FEATURE_SHADOWPASSWDS 76 file = bb_xfopen(bb_path_gshadow_file, "a"); 77 fprintf(file, "%s:!::\n", group); 78 fclose(file); 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 } 79 116 #endif 80 81 /* return 1; */82 return 0;83 }84 117 85 118 /* 86 119 * addgroup will take a login_name as its first parameter. 87 120 * 88 * gid 89 * 90 * can be customized via command-line parameters. 91 * ________________________________________________________________________ */ 121 * gid can be customized via command-line parameters. 122 * If called with two non-option arguments, addgroup 123 * will add an existing user to an existing group. 124 */ 125 int addgroup_main(int argc, char **argv); 92 126 int addgroup_main(int argc, char **argv) 93 127 { 94 128 char *group; 95 129 gid_t gid = 0; 96 97 /* check for min, max and missing args and exit on error */98 bb_opt_complementally = "-1:?2:?";99 130 100 if (bb_getopt_ulflags(argc, argv, "g:", &group)) { 101 gid = bb_xgetlarg(group, 10, 0, LONG_MAX); 131 /* need to be root */ 132 if (geteuid()) { 133 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 134 } 135 136 /* Syntax: 137 * addgroup group 138 * addgroup -g num group 139 * addgroup user group 140 * 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); 102 144 } 103 145 /* move past the commandline options */ 104 146 argv += optind; 147 argc -= optind; 105 148 106 /* need to be root */ 107 if(geteuid()) { 108 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 109 } 149 #if ENABLE_FEATURE_ADDUSER_TO_GROUP 150 if (argc == 2) { 151 struct group *gr; 110 152 111 /* werk */ 112 return addgroup(argv[0], gid, (argv[1]) ? argv[1] : ""); 153 if (option_mask32) { 154 /* -g was there, but "addgroup -g num user group" 155 * is a no-no */ 156 bb_show_usage(); 157 } 158 159 /* check if group and user exist */ 160 xuname2uid(argv[0]); /* unknown user: exit */ 161 xgroup2gid(argv[1]); /* unknown group: exit */ 162 /* check if user is already in this group */ 163 gr = getgrnam(argv[1]); 164 for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) { 165 if (!strcmp(argv[0], *(gr->gr_mem))) { 166 /* user is already in group: do nothing */ 167 return EXIT_SUCCESS; 168 } 169 } 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 */ 174 } else 175 #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */ 176 new_group(argv[0], gid); 177 178 /* Reached only on success */ 179 return EXIT_SUCCESS; 113 180 } -
branches/stable/mindi-busybox/loginutils/adduser.c
r821 r1770 9 9 */ 10 10 11 #include <stdio.h> 12 #include <sys/types.h> 13 #include <string.h> 14 #include <unistd.h> 15 #include <time.h> 16 #include <getopt.h> 17 #include <sys/stat.h> 18 19 #include "busybox.h" 20 21 #define DONT_SET_PASS (1 << 4) 22 #define DONT_MAKE_HOME (1 << 6) 11 #include "libbb.h" 12 13 #define OPT_DONT_SET_PASS (1 << 4) 14 #define OPT_DONT_MAKE_HOME (1 << 6) 23 15 24 16 … … 27 19 static int passwd_study(const char *filename, struct passwd *p) 28 20 { 29 struct passwd *pw;21 enum { min = 500, max = 65000 }; 30 22 FILE *passwd; 31 32 const int min = 500; 33 const int max = 65000; 34 35 passwd = bb_xfopen(filename, "r"); 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"); 36 30 37 31 /* EDR if uid is out of bounds, set to min */ … … 43 37 * find free uid and gid; 44 38 */ 45 while ( (pw = fgetpwent(passwd))) {46 if (strcmp(pw ->pw_name, p->pw_name) == 0) {39 while (!fgetpwent_r(passwd, &pw, buffer, sizeof(buffer), &result)) { 40 if (strcmp(pw.pw_name, p->pw_name) == 0) { 47 41 /* return 0; */ 48 42 return 1; 49 43 } 50 if ((pw ->pw_uid >= p->pw_uid) && (pw->pw_uid < max)51 && (pw ->pw_uid >= min)) {52 p->pw_uid = pw ->pw_uid + 1;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; 53 47 } 54 48 } … … 79 73 char *cmd; 80 74 81 cmd = bb_xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name);75 cmd = xasprintf("addgroup -g %d \"%s\"", p->pw_gid, p->pw_name); 82 76 system(cmd); 83 77 free(cmd); … … 88 82 static void passwd_wrapper(const char *login) 89 83 { 90 static const char prog[] = "passwd"; 91 execlp(prog, prog, login, NULL); 92 bb_error_msg_and_die("Failed to execute '%s', you must set the password for '%s' manually", prog, login); 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); 93 88 } 94 89 95 90 /* putpwent(3) remix */ 96 static int adduser(struct passwd *p , unsigned long flags)91 static int adduser(struct passwd *p) 97 92 { 98 93 FILE *file; … … 100 95 101 96 /* make sure everything is kosher and setup uid && gid */ 102 file = bb_xfopen(bb_path_passwd_file, "a");97 file = xfopen(bb_path_passwd_file, "a"); 103 98 fseek(file, 0, SEEK_END); 104 99 … … 110 105 case 3: 111 106 bb_error_msg_and_die("%s: group name already in use", p->pw_name); 112 107 } 113 108 114 109 /* add to passwd */ … … 116 111 bb_perror_nomsg_and_die(); 117 112 } 113 /* Do fclose even if !ENABLE_FEATURE_CLEAN_UP. 114 * We will exec passwd, files must be flushed & closed before that! */ 118 115 fclose(file); 119 116 120 117 #if ENABLE_FEATURE_SHADOWPASSWDS 121 118 /* add to shadow if necessary */ 122 file = bb_xfopen(bb_path_shadow_file, "a"); 123 fseek(file, 0, SEEK_END); 124 fprintf(file, "%s:!:%ld:%d:%d:%d:::\n", 125 p->pw_name, /* username */ 126 time(NULL) / 86400, /* sp->sp_lstchg */ 127 0, /* sp->sp_min */ 128 99999, /* sp->sp_max */ 129 7); /* sp->sp_warn */ 130 fclose(file); 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 } 131 130 #endif 132 131 … … 137 136 138 137 /* Clear the umask for this process so it doesn't 139 * *screw up the permissions on the mkdir and chown. */138 * screw up the permissions on the mkdir and chown. */ 140 139 umask(0); 141 if (!( flags &DONT_MAKE_HOME)) {140 if (!(option_mask32 & OPT_DONT_MAKE_HOME)) { 142 141 /* Set the owner and group so it is owned by the new user, 143 142 then fix up the permissions to 2755. Can't do it before … … 146 145 || chown(p->pw_dir, p->pw_uid, p->pw_gid) 147 146 || chmod(p->pw_dir, 02755)) { 148 149 150 } 151 152 if (!( flags &DONT_SET_PASS)) {147 bb_perror_msg("%s", p->pw_dir); 148 } 149 } 150 151 if (!(option_mask32 & OPT_DONT_SET_PASS)) { 153 152 /* interactively set passwd */ 154 153 passwd_wrapper(p->pw_name); … … 166 165 * 167 166 * can be customized via command-line parameters. 168 * ________________________________________________________________________ */ 167 */ 168 int adduser_main(int argc, char **argv); 169 169 int adduser_main(int argc, char **argv) 170 170 { 171 171 struct passwd pw; 172 172 const char *usegroup = NULL; 173 unsigned long flags; 174 175 pw.pw_gecos = "Linux User,,,"; 173 174 /* got root? */ 175 if (geteuid()) { 176 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 177 } 178 179 pw.pw_gecos = (char *)"Linux User,,,"; 176 180 pw.pw_shell = (char *)DEFAULT_SHELL; 177 181 pw.pw_dir = NULL; 178 182 179 /* check for min, max and missing args and exit on error */ 180 bb_opt_complementally = "-1:?1:?"; 181 flags = bb_getopt_ulflags(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); 182 183 /* got root? */ 184 if(geteuid()) { 185 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 186 } 187 188 /* create string for $HOME if not specified already */ 183 /* 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); 186 argv += optind; 187 188 /* create a passwd struct */ 189 pw.pw_name = argv[0]; 189 190 if (!pw.pw_dir) { 190 snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]); 191 pw.pw_dir = &bb_common_bufsiz1[0]; 192 } 193 194 /* create a passwd struct */ 195 pw.pw_name = argv[optind]; 196 pw.pw_passwd = "x"; 191 /* create string for $HOME if not specified already */ 192 pw.pw_dir = xasprintf("/home/%s", argv[0]); 193 } 194 pw.pw_passwd = (char *)"x"; 197 195 pw.pw_uid = 0; 198 pw.pw_gid = (usegroup) ? bb_xgetgrnam(usegroup) : 0; /* exits on failure */196 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */ 199 197 200 198 /* grand finale */ 201 return adduser(&pw , flags);202 } 199 return adduser(&pw); 200 } -
branches/stable/mindi-busybox/loginutils/deluser.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * deluser (remove lusers from the system ;) for TinyLogin3 * deluser/delgroup implementation for busybox 4 4 * 5 5 * Copyright (C) 1999 by Lineo, inc. and John Beppu 6 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> 7 * Unified with delgroupby Tito Ragusa <farmatito@tiscali.it>7 * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it> 8 8 * 9 * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.9 * Licensed under GPL version 2, see file LICENSE in this tarball for details. 10 10 * 11 11 */ 12 12 13 #include <sys/stat.h> 14 #include <unistd.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include "busybox.h" 13 #include "libbb.h" 19 14 20 /* where to start and stop deletion */ 21 typedef struct { 22 size_t start; 23 size_t stop; 24 } Bounds; 15 /* Status */ 16 #define STATUS_OK 0 17 #define NAME_NOT_FOUND 1 18 #define MEMBER_NOT_FOUND 2 25 19 26 /* An interesting side-effect of boundary()'s 27 * implementation is that the first user (typically root) 28 * cannot be removed. Let's call it a feature. */ 29 static inline Bounds boundary(const char *buffer, const char *login) 20 static void del_line_matching(char **args, 21 const char *filename, 22 FILE *(*fopen_func)(const char *fileName, const char *mode)) 30 23 { 31 char needle[256]; 32 char *start; 33 char *stop; 34 Bounds b; 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); 35 29 36 snprintf(needle, 256, "\n%s:", login); 37 needle[255] = 0; 38 start = strstr(buffer, needle); 39 if (!start) { 40 b.start = 0; 41 b.stop = 0; 42 return b; 30 passwd = fopen_func(filename, "r"); 31 if (passwd) { 32 while ((line = xmalloc_fgets(passwd))) { 33 int len = strlen(name); 34 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; 67 } 68 } 69 del = new; 70 new = xasprintf("%s%s", new, line); 71 free(del); 72 skip: 73 free(line); 74 } 75 76 if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); 77 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 } 91 } 43 92 } 44 start++; 45 46 stop = strchr(start, '\n'); 47 b.start = start - buffer; 48 b.stop = stop - buffer; 49 return b; 93 free(new); 50 94 } 51 95 52 /* grep -v ^login (except it only deletes the first match) */ 53 /* ...in fact, I think I'm going to simplify this later */ 54 static void del_line_matching(const char *login, const char *filename) 55 { 56 char *buffer; 57 FILE *passwd; 58 Bounds b; 59 struct stat statbuf; 60 61 62 if ((passwd = bb_wfopen(filename, "r"))) { 63 xstat(filename, &statbuf); 64 buffer = (char *) xmalloc(statbuf.st_size * sizeof(char)); 65 fread(buffer, statbuf.st_size, sizeof(char), passwd); 66 fclose(passwd); 67 /* find the user to remove */ 68 b = boundary(buffer, login); 69 if (b.stop != 0) { 70 /* write the file w/o the user */ 71 if ((passwd = bb_wfopen(filename, "w"))) { 72 fwrite(buffer, (b.start - 1), sizeof(char), passwd); 73 fwrite(&buffer[b.stop], (statbuf.st_size - b.stop), sizeof(char), passwd); 74 fclose(passwd); 75 } 76 } else { 77 bb_error_msg("Can't find '%s' in '%s'", login, filename); 78 } 79 free(buffer); 80 } 81 } 82 96 int deluser_main(int argc, char **argv); 83 97 int deluser_main(int argc, char **argv) 84 98 { 85 if (argc != 2) { 99 if (argc == 2 100 || (ENABLE_FEATURE_DEL_USER_FROM_GROUP 101 && (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_DELUSER 108 || (ENABLE_DELGROUP && ENABLE_DESKTOP) 109 ) { 110 if (ENABLE_DELUSER 111 && (!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 } else 86 124 bb_show_usage(); 87 } else {88 if (ENABLE_DELUSER && bb_applet_name[3] == 'u') {89 del_line_matching(argv[1], bb_path_passwd_file);90 if (ENABLE_FEATURE_SHADOWPASSWDS)91 del_line_matching(argv[1], bb_path_shadow_file);92 }93 del_line_matching(argv[1], bb_path_group_file);94 if (ENABLE_FEATURE_SHADOWPASSWDS)95 del_line_matching(argv[1], bb_path_gshadow_file);96 }97 return (EXIT_SUCCESS);98 125 } 99 100 /* $Id: deluser.c,v 1.4 2003/07/14 20:20:45 andersen Exp $ */ -
branches/stable/mindi-busybox/loginutils/getty.c
r902 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* agetty.c - another getty program for Linux. By W. Z. Venema 1989 3 Ported to Linux by Peter Orbaek <poe@daimi.aau.dk> 4 This program is freely distributable. The entire man-page used to 5 be here. Now read the real man-page agetty.8 instead. 6 7 -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 8 9 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> 10 - added Native Language Support 11 12 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> 13 - enable hardware flow control before displaying /etc/issue 14 15 */ 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <unistd.h> 20 #include <string.h> 21 #include <sys/ioctl.h> 22 #include <errno.h> 23 #include <sys/stat.h> 24 #include <signal.h> 25 #include <fcntl.h> 26 #include <stdarg.h> 27 #include <ctype.h> 28 #include <getopt.h> 29 #include <termios.h> 30 #include "busybox.h" 31 32 #ifdef CONFIG_FEATURE_UTMP 3 * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk> 4 * This program is freely distributable. The entire man-page used to 5 * be here. Now read the real man-page agetty.8 instead. 6 * 7 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 8 * 9 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> 10 * - added Native Language Support 11 12 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> 13 * - enable hardware flow control before displaying /etc/issue 14 * 15 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 16 * 17 */ 18 19 #include "libbb.h" 20 #include <syslog.h> 21 22 #if ENABLE_FEATURE_UTMP 33 23 #include <utmp.h> 34 24 #endif 35 25 36 #define _PATH_LOGIN "/bin/login" 37 38 /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */ 39 #ifdef CONFIG_SYSLOGD 40 #include <sys/param.h> 41 #include <syslog.h> 42 #endif 43 44 45 /* 46 * Some heuristics to find out what environment we are in: if it is not 47 * System V, assume it is SunOS 4. 48 */ 49 26 /* 27 * Some heuristics to find out what environment we are in: if it is not 28 * System V, assume it is SunOS 4. 29 */ 50 30 #ifdef LOGIN_PROCESS /* defined in System V utmp.h */ 51 31 #define SYSV_STYLE /* select System V style getty */ 52 #ifdef CONFIG_FEATURE_WTMP53 extern void updwtmp(const char *filename, const struct utmp *ut);54 #endif55 #endif /* LOGIN_PROCESS */56 57 /*58 * Things you may want to modify.59 *60 * You may disagree with the default line-editing etc. characters defined61 * below. Note, however, that DEL cannot be used for interrupt generation62 * and for line editing at the same time.63 */64 65 #ifdef SYSV_STYLE66 32 #include <sys/utsname.h> 67 33 #include <time.h> 68 #endif 69 70 /* If ISSUE is not defined, agetty will never display the contents of the 71 * /etc/issue file. You will not want to spit out large "issue" files at the 72 * wrong baud rate. 73 */ 34 #if ENABLE_FEATURE_WTMP 35 extern void updwtmp(const char *filename, const struct utmp *ut); 36 static void update_utmp(const char *line); 37 #endif 38 #endif /* LOGIN_PROCESS */ 39 40 /* 41 * Things you may want to modify. 42 * 43 * You may disagree with the default line-editing etc. characters defined 44 * below. Note, however, that DEL cannot be used for interrupt generation 45 * and for line editing at the same time. 46 */ 47 48 /* I doubt there are systems which still need this */ 49 #undef HANDLE_ALLCAPS 50 51 #define _PATH_LOGIN "/bin/login" 52 53 /* If ISSUE is not defined, getty will never display the contents of the 54 * /etc/issue file. You will not want to spit out large "issue" files at the 55 * wrong baud rate. 56 */ 74 57 #define ISSUE "/etc/issue" /* displayed before the login prompt */ 75 58 76 59 /* Some shorthands for control characters. */ 77 78 60 #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */ 79 61 #define CR CTL('M') /* carriage return */ … … 83 65 84 66 /* Defaults for line-editing etc. characters; you may want to change this. */ 85 86 67 #define DEF_ERASE DEL /* default erase character */ 87 68 #define DEF_INTR CTL('C') /* default interrupt character */ … … 92 73 #define DEF_SWITCH 0 /* default switch char */ 93 74 94 /* 95 * SunOS 4.1.1 termio is broken. We must use the termios stuff instead, 96 * because the termio -> termios translation does not clear the termios 97 * CIBAUD bits. Therefore, the tty driver would sometimes report that input 98 * baud rate != output baud rate. I did not notice that problem with SunOS 99 * 4.1. We will use termios where available, and termio otherwise. 100 */ 101 102 /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set 103 properly, but all is well if we use termios?! */ 104 105 #ifdef TCGETS 106 #undef TCGETA 107 #undef TCSETA 108 #undef TCSETAW 109 #define termio termios 110 #define TCGETA TCGETS 111 #define TCSETA TCSETS 112 #define TCSETAW TCSETSW 113 #endif 114 115 /* 116 * When multiple baud rates are specified on the command line, the first one 117 * we will try is the first one specified. 118 */ 119 75 /* 76 * When multiple baud rates are specified on the command line, the first one 77 * we will try is the first one specified. 78 */ 120 79 #define FIRST_SPEED 0 121 80 … … 126 85 struct options { 127 86 int flags; /* toggle switches, see below */ 128 int timeout;/* time-out period */129 c har *login; /* login program */130 c har *tty; /* name of tty */131 c har *initstring; /* modem init string */132 c har *issue; /* alternative issue file */87 unsigned timeout; /* time-out period */ 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 */ 133 92 int numspeed; /* number of baud rates to try */ 134 93 int speeds[MAX_SPEED]; /* baud rates to be tried */ 135 94 }; 136 95 137 static const char opt_string[] = "I:LH:f:hil:mt:wn";96 static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn"; 138 97 #define F_INITSTRING (1<<0) /* initstring is set */ 139 98 #define F_LOCAL (1<<1) /* force local */ … … 149 108 150 109 /* Storage for things detected while the login name was read. */ 151 152 110 struct chardata { 153 int erase; /* erase character */ 154 int kill; /* kill character */ 155 int eol; /* end-of-line character */ 156 int parity; /* what parity did we see */ 157 int capslock; /* upper case without lower case */ 111 unsigned char erase; /* erase character */ 112 unsigned char kill; /* kill character */ 113 unsigned char eol; /* end-of-line character */ 114 unsigned char parity; /* what parity did we see */ 115 #ifdef HANDLE_ALLCAPS 116 unsigned char capslock; /* upper case without lower case */ 117 #endif 158 118 }; 159 119 160 120 /* Initial values for the above. */ 161 162 static struct chardata init_chardata = { 121 static const struct chardata init_chardata = { 163 122 DEF_ERASE, /* default erase character */ 164 123 DEF_KILL, /* default kill character */ 165 124 13, /* default eol char */ 166 125 0, /* space parity */ 126 #ifdef HANDLE_ALLCAPS 167 127 0, /* no capslock */ 128 #endif 168 129 }; 169 170 #if 0171 struct Speedtab {172 long speed;173 int code;174 };175 176 static struct Speedtab speedtab[] = {177 {50, B50},178 {75, B75},179 {110, B110},180 {134, B134},181 {150, B150},182 {200, B200},183 {300, B300},184 {600, B600},185 {1200, B1200},186 {1800, B1800},187 {2400, B2400},188 {4800, B4800},189 {9600, B9600},190 #ifdef B19200191 {19200, B19200},192 #endif193 #ifdef B38400194 {38400, B38400},195 #endif196 #ifdef EXTA197 {19200, EXTA},198 #endif199 #ifdef EXTB200 {38400, EXTB},201 #endif202 #ifdef B57600203 {57600, B57600},204 #endif205 #ifdef B115200206 {115200, B115200},207 #endif208 #ifdef B230400209 {230400, B230400},210 #endif211 {0, 0},212 };213 #endif214 215 216 #ifdef SYSV_STYLE217 #ifdef CONFIG_FEATURE_UTMP218 static void update_utmp(char *line);219 #endif220 #endif221 130 222 131 /* The following is used for understandable diagnostics. */ … … 229 138 #define debug(s) fprintf(dbf,s); fflush(dbf) 230 139 #define DEBUGTERM "/dev/ttyp0" 231 FILE *dbf;140 static FILE *dbf; 232 141 #else 233 #define debug(s) /* nothing */ 234 #endif 235 236 237 /* 238 * output error messages 239 */ 240 static void error(const char *fmt, ...) ATTRIBUTE_NORETURN; 241 static void error(const char *fmt, ...) 242 { 243 va_list va_alist; 244 char buf[256]; 245 246 #ifdef CONFIG_SYSLOGD 247 va_start(va_alist, fmt); 248 vsnprintf(buf, sizeof(buf), fmt, va_alist); 249 openlog(bb_applet_name, 0, LOG_AUTH); 250 syslog(LOG_ERR, "%s", buf); 251 closelog(); 252 #else 253 int fd; 254 size_t l; 255 256 snprintf(buf, sizeof(buf), "%s: ", bb_applet_name); 257 l = strlen(buf); 258 va_start(va_alist, fmt); 259 vsnprintf(buf + l, sizeof(buf) - l, fmt, va_alist); 260 l = strlen(buf); 261 /* truncate if need */ 262 if((l + 3) > sizeof(buf)) 263 l = sizeof(buf) - 3; 264 /* add \r\n always */ 265 buf[l++] = '\r'; 266 buf[l++] = '\n'; 267 buf[l] = 0; 268 if ((fd = open("/dev/console", 1)) >= 0) { 269 write(fd, buf, l); 270 close(fd); 271 } 272 #endif 273 274 va_end(va_alist); 275 276 (void) sleep((unsigned) 10); /* be kind to init(8) */ 277 exit(1); 278 } 279 142 #define debug(s) /* nothing */ 143 #endif 280 144 281 145 … … 284 148 { 285 149 int r; 286 unsigned long value;287 if ( safe_strtoul((char *)s, &value)) {150 unsigned value = bb_strtou(s, NULL, 10); 151 if (errno) { 288 152 return -1; 289 153 } 290 if ((r = tty_value_to_baud(value)) > 0) { 154 r = tty_value_to_baud(value); 155 if (r > 0) { 291 156 return r; 292 157 } … … 303 168 for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { 304 169 if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0) 305 error("bad speed: %s", cp);170 bb_error_msg_and_die("bad speed: %s", cp); 306 171 if (op->numspeed > MAX_SPEED) 307 error("too many alternate speeds");172 bb_error_msg_and_die("too many alternate speeds"); 308 173 } 309 174 debug("exiting parsespeeds\n"); … … 311 176 312 177 313 /* parse -args - parse command-line arguments */178 /* parse_args - parse command-line arguments */ 314 179 static void parse_args(int argc, char **argv, struct options *op) 315 180 { 316 181 char *ts; 317 182 318 op->flags = bb_getopt_ulflags(argc,argv, opt_string,183 op->flags = getopt32(argv, opt_string, 319 184 &(op->initstring), &fakehost, &(op->issue), 320 185 &(op->login), &ts); 321 if (op->flags & F_INITSTRING) {186 if (op->flags & F_INITSTRING) { 322 187 const char *p = op->initstring; 323 188 char *q; 324 189 325 q = op->initstring = bb_xstrdup(op->initstring);190 op->initstring = q = xstrdup(op->initstring); 326 191 /* copy optarg into op->initstring decoding \ddd 327 192 octal codes into chars */ … … 337 202 } 338 203 op->flags ^= F_ISSUE; /* revert flag show /etc/issue */ 339 if(op->flags & F_TIMEOUT) { 340 if ((op->timeout = atoi(ts)) <= 0) 341 error("bad timeout value: %s", ts); 342 } 204 if (op->flags & F_TIMEOUT) { 205 op->timeout = xatoul_range(ts, 1, INT_MAX); 206 } 207 argv += optind; 208 argc -= optind; 343 209 debug("after getopt loop\n"); 344 if (argc < optind +2) /* check parameter count */210 if (argc < 2) /* check parameter count */ 345 211 bb_show_usage(); 346 212 347 213 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ 348 if ( '0' <= argv[optind][0] && argv[optind][0] <= '9') {214 if (isdigit(argv[0][0])) { 349 215 /* a number first, assume it's a speed (BSD style) */ 350 parse_speeds(op, argv[ optind++]); /* baud rate(s) */351 op->tty = argv[ optind]; /* tty name */216 parse_speeds(op, argv[0]); /* baud rate(s) */ 217 op->tty = argv[1]; /* tty name */ 352 218 } else { 353 op->tty = argv[optind++]; /* tty name */ 354 parse_speeds(op, argv[optind]); /* baud rate(s) */ 355 } 356 357 optind++; 358 if (argc > optind && argv[optind]) 359 setenv("TERM", argv[optind], 1); 219 op->tty = argv[0]; /* tty name */ 220 parse_speeds(op, argv[1]); /* baud rate(s) */ 221 } 222 223 if (argv[2]) 224 setenv("TERM", argv[2], 1); 360 225 361 226 debug("exiting parseargs\n"); … … 363 228 364 229 /* open_tty - set up tty as standard { input, output, error } */ 365 static void open_tty(c har *tty, struct termio*tp, int local)230 static void open_tty(const char *tty, struct termios *tp, int local) 366 231 { 367 232 int chdir_to_root = 0; 368 233 369 234 /* Set up new standard input, unless we are given an already opened port. */ 370 371 if (strcmp(tty, "-")) { 235 if (NOT_LONE_DASH(tty)) { 372 236 struct stat st; 373 237 int fd; 374 238 375 239 /* Sanity checks... */ 376 377 if (chdir("/dev")) 378 error("/dev: chdir() failed: %m"); 240 xchdir("/dev"); 379 241 chdir_to_root = 1; 380 if (stat(tty, &st) < 0) 381 error("/dev/%s: %m", tty); 242 xstat(tty, &st); 382 243 if ((st.st_mode & S_IFMT) != S_IFCHR) 383 error("/dev/%s: not a character device", tty);244 bb_error_msg_and_die("%s: not a character device", tty); 384 245 385 246 /* Open the tty as standard input. */ 386 387 close(0);388 247 debug("open(2)\n"); 389 fd = open(tty, O_RDWR | O_NONBLOCK, 0); 390 if (fd != 0) 391 error("/dev/%s: cannot open as standard input: %m", tty); 248 fd = xopen(tty, O_RDWR | O_NONBLOCK); 249 xdup2(fd, 0); 250 while (fd > 2) 251 close(fd--); 392 252 } else { 393 394 253 /* 395 254 * Standard input should already be connected to an open port. Make 396 255 * sure it is open for read/write. 397 256 */ 398 399 if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) 400 error("%s: not open for read/write", tty); 257 if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR) 258 bb_error_msg_and_die("stdin is not open for read/write"); 401 259 } 402 260 403 261 /* Replace current standard output/error fd's with new ones */ 404 262 debug("duping\n"); 405 if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1 || 406 dup2(STDIN_FILENO, STDERR_FILENO) == -1) 407 error("%s: dup problem: %m", tty); /* we have a problem */ 263 xdup2(0, 1); 264 xdup2(0, 2); 408 265 409 266 /* … … 415 272 * 5 seconds seems to be a good value. 416 273 */ 417 418 if (ioctl(0, TCGETA, tp) < 0) 419 error("%s: ioctl: %m", tty); 274 ioctl_or_perror_and_die(0, TCGETS, tp, "%s: TCGETS", tty); 420 275 421 276 /* … … 427 282 428 283 #ifdef DEBIAN 284 #warning Debian /dev/vcs[a]NN hack is deprecated and will be removed 429 285 { 430 286 /* tty to root.dialout 660 */ … … 432 288 int id; 433 289 434 id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0; 290 gr = getgrnam("dialout"); 291 id = gr ? gr->gr_gid : 0; 435 292 chown(tty, 0, id); 436 293 chmod(tty, 0660); … … 440 297 char *vcs, *vcsa; 441 298 442 if (!(vcs = strdup(tty))) 443 error("Can't malloc for vcs"); 444 if (!(vcsa = malloc(strlen(tty) + 2))) 445 error("Can't malloc for vcsa"); 299 vcs = xstrdup(tty); 300 vcsa = xmalloc(strlen(tty) + 2); 446 301 strcpy(vcs, "vcs"); 447 302 strcpy(vcs + 3, tty + 3); … … 449 304 strcpy(vcsa + 4, tty + 3); 450 305 451 id = (gr = getgrnam("sys")) ? gr->gr_gid : 0; 306 gr = getgrnam("sys"); 307 id = gr ? gr->gr_gid : 0; 452 308 chown(vcs, 0, id); 453 309 chmod(vcs, 0600); … … 460 316 } 461 317 #else 462 (void) chown(tty, 0, 0); /* root, sys */ 463 (void) chmod(tty, 0622); /* crw--w--w- */ 464 #endif 465 if(chdir_to_root && chdir("/")) 466 error("chdir to / failed: %m"); 467 } 468 469 /* termio_init - initialize termio settings */ 470 static void termio_init(struct termio *tp, int speed, struct options *op) 318 if (NOT_LONE_DASH(tty)) { 319 chown(tty, 0, 0); /* 0:0 */ 320 chmod(tty, 0622); /* crw--w--w- */ 321 } 322 #endif 323 if (chdir_to_root) 324 xchdir("/"); 325 } 326 327 /* termios_init - initialize termios settings */ 328 static void termios_init(struct termios *tp, int speed, struct options *op) 471 329 { 472 330 /* 473 * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.331 * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. 474 332 * Special characters are set after we have read the login name; all 475 333 * reads will be done in raw mode anyway. Errors will be dealt with 476 * later on.334 * later on. 477 335 */ 478 336 #ifdef __linux__ 479 337 /* flush input and output queues, important for modems! */ 480 (void)ioctl(0, TCFLSH, TCIOFLUSH);338 ioctl(0, TCFLSH, TCIOFLUSH); 481 339 #endif 482 340 … … 498 356 #endif 499 357 500 (void) ioctl(0, TCSETA, tp);358 ioctl(0, TCSETS, tp); 501 359 502 360 /* go to blocking input even in local mode */ 503 fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK);361 ndelay_off(0); 504 362 505 363 debug("term_io 2\n"); … … 507 365 508 366 /* auto_baud - extract baud rate from modem status message */ 509 static void auto_baud( struct termio*tp)367 static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) 510 368 { 511 369 int speed; 512 370 int vmin; 513 371 unsigned iflag; 514 char buf[BUFSIZ];515 372 char *bp; 516 373 int nread; … … 533 390 /* 534 391 * Use 7-bit characters, don't block if input queue is empty. Errors will 535 * be dealt with later on.392 * be dealt with later on. 536 393 */ 537 394 … … 540 397 vmin = tp->c_cc[VMIN]; 541 398 tp->c_cc[VMIN] = 0; /* don't block if queue empty */ 542 (void) ioctl(0, TCSETA, tp);399 ioctl(0, TCSETS, tp); 543 400 544 401 /* … … 547 404 */ 548 405 549 (void) sleep(1); 550 if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) { 406 sleep(1); 407 nread = read(0, buf, size_buf - 1); 408 if (nread > 0) { 551 409 buf[nread] = '\0'; 552 410 for (bp = buf; bp < buf + nread; bp++) { 553 411 if (isascii(*bp) && isdigit(*bp)) { 554 if ((speed = bcode(bp))) { 412 speed = bcode(bp); 413 if (speed) { 555 414 tp->c_cflag &= ~CBAUD; 556 415 tp->c_cflag |= speed; … … 560 419 } 561 420 } 562 /* Restore terminal settings. Errors will be dealt with later on. */421 /* Restore terminal settings. Errors will be dealt with later on. */ 563 422 564 423 tp->c_iflag = iflag; 565 424 tp->c_cc[VMIN] = vmin; 566 (void) ioctl(0, TCSETA, tp);425 ioctl(0, TCSETS, tp); 567 426 } 568 427 569 428 /* next_speed - select next baud rate */ 570 static void next_speed(struct termio *tp, struct options *op)429 static void next_speed(struct termios *tp, struct options *op) 571 430 { 572 431 static int baud_index = FIRST_SPEED; /* current speed index */ … … 575 434 tp->c_cflag &= ~CBAUD; 576 435 tp->c_cflag |= op->speeds[baud_index]; 577 (void) ioctl(0, TCSETA, tp);436 ioctl(0, TCSETS, tp); 578 437 } 579 438 580 439 581 440 /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ 582 static void do_prompt(struct options *op, struct termio *tp)583 { 584 #ifdef ISSUE /* optional: show /etc/issue */441 static void do_prompt(struct options *op, struct termios *tp) 442 { 443 #ifdef ISSUE 585 444 print_login_issue(op->issue, op->tty); 586 445 #endif … … 588 447 } 589 448 449 #ifdef HANDLE_ALLCAPS 590 450 /* caps_lock - string contains upper case without lower case */ 591 451 /* returns 1 if true, 0 if false */ 592 452 static int caps_lock(const char *s) 593 453 { 594 int capslock; 595 596 for (capslock = 0; *s; s++) { 597 if (islower(*s)) 598 return (0); 599 if (capslock == 0) 600 capslock = isupper(*s); 601 } 602 return (capslock); 603 } 604 605 #define logname bb_common_bufsiz1 454 while (*s) 455 if (islower(*s++)) 456 return 0; 457 return 1; 458 } 459 #endif 460 606 461 /* get_logname - get user name, establish parity, speed, erase, kill, eol */ 607 462 /* return NULL on failure, logname on success */ 608 static char *get_logname(struct options *op, struct chardata *cp, struct termio *tp) 463 static char *get_logname(char *logname, unsigned size_logname, 464 struct options *op, struct chardata *cp, struct termios *tp) 609 465 { 610 466 char *bp; … … 613 469 int bits; /* # of "1" bits per character */ 614 470 int mask; /* mask with 1 bit up */ 615 static c har *erase[] = {/* backspace-space-backspace */471 static const char erase[][3] = { /* backspace-space-backspace */ 616 472 "\010\040\010", /* space parity */ 617 473 "\010\040\010", /* odd parity */ … … 626 482 /* Flush pending input (esp. after parsing or switching the baud rate). */ 627 483 628 (void)sleep(1);629 (void)ioctl(0, TCFLSH, TCIFLUSH);484 sleep(1); 485 ioctl(0, TCFLSH, TCIFLUSH); 630 486 631 487 /* Prompt for and read a login name. */ 632 488 633 for (*logname = 0; *logname == 0; /* void */ ) { 489 logname[0] = '\0'; 490 while (!logname[0]) { 634 491 635 492 /* Write issue file and prompt, with "parity" bit == 0. */ … … 639 496 /* Read name, watch for break, parity, erase, kill, end-of-line. */ 640 497 641 for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) { 498 bp = logname; 499 cp->eol = '\0'; 500 while (cp->eol == '\0') { 642 501 643 502 /* Do not report trivial EINTR/EIO errors. */ 644 645 503 if (read(0, &c, 1) < 1) { 646 504 if (errno == EINTR || errno == EIO) 647 505 exit(0); 648 error("%s: read: %m", op->tty);506 bb_perror_msg_and_die("%s: read", op->tty); 649 507 } 508 650 509 /* Do BREAK handling elsewhere. */ 651 652 if ((c == 0) && op->numspeed > 1) 653 /* return (0); */ 510 if (c == '\0' && op->numspeed > 1) 654 511 return NULL; 655 512 656 513 /* Do parity bit handling. */ 657 658 if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */ 659 for (bits = 1, mask = 1; mask & 0177; mask <<= 1) 514 ascval = c & 0177; 515 if (c != ascval) { /* "parity" bit on ? */ 516 bits = 1; 517 mask = 1; 518 while (mask & 0177) { 660 519 if (mask & ascval) 661 520 bits++; /* count "1" bits */ 662 cp->parity |= ((bits & 1) ? 1 : 2); 521 mask <<= 1; 522 } 523 /* ... |= 2 - even, 1 - odd */ 524 cp->parity |= 2 - (bits & 1); 663 525 } 526 664 527 /* Do erase, kill and end-of-line processing. */ 665 666 528 switch (ascval) { 667 529 case CR: 668 530 case NL: 669 *bp = 0;/* terminate logname */531 *bp = '\0'; /* terminate logname */ 670 532 cp->eol = ascval; /* set end-of-line char */ 671 533 break; … … 675 537 cp->erase = ascval; /* set erase character */ 676 538 if (bp > logname) { 677 (void)write(1, erase[cp->parity], 3);539 write(1, erase[cp->parity], 3); 678 540 bp--; 679 541 } … … 683 545 cp->kill = ascval; /* set kill character */ 684 546 while (bp > logname) { 685 (void)write(1, erase[cp->parity], 3);547 write(1, erase[cp->parity], 3); 686 548 bp--; 687 549 } … … 691 553 default: 692 554 if (!isascii(ascval) || !isprint(ascval)) { 693 /* ignore garbage characters */ ;694 } else if (bp - logname >= size of(logname)- 1) {695 error("%s: input overrun", op->tty);555 /* ignore garbage characters */ 556 } else if (bp - logname >= size_logname - 1) { 557 bb_error_msg_and_die("%s: input overrun", op->tty); 696 558 } else { 697 (void)write(1, &c, 1); /* echo the character */559 write(1, &c, 1); /* echo the character */ 698 560 *bp++ = ascval; /* and store it */ 699 561 } … … 704 566 /* Handle names with upper case and no lower case. */ 705 567 706 if ((cp->capslock = caps_lock(logname))) { 568 #ifdef HANDLE_ALLCAPS 569 cp->capslock = caps_lock(logname); 570 if (cp->capslock) { 707 571 for (bp = logname; *bp; bp++) 708 572 if (isupper(*bp)) 709 573 *bp = tolower(*bp); /* map name to lower case */ 710 574 } 711 return (logname); 712 } 713 714 /* termio_final - set the final tty mode bits */ 715 static void termio_final(struct options *op, struct termio *tp, struct chardata *cp) 575 #endif 576 return logname; 577 } 578 579 /* termios_final - set the final tty mode bits */ 580 static void termios_final(struct options *op, struct termios *tp, struct chardata *cp) 716 581 { 717 582 /* General terminal-independent stuff. */ … … 754 619 break; 755 620 } 621 756 622 /* Account for upper case without lower case. */ 757 623 #ifdef HANDLE_ALLCAPS 758 624 if (cp->capslock) { 759 625 tp->c_iflag |= IUCLC; … … 761 627 tp->c_oflag |= OLCUC; 762 628 } 629 #endif 763 630 /* Optionally enable hardware flow control */ 764 631 … … 770 637 /* Finally, make the new settings effective */ 771 638 772 if (ioctl(0, TCSETA, tp) < 0) 773 error("%s: ioctl: TCSETA: %m", op->tty); 774 } 775 776 777 #ifdef SYSV_STYLE 778 #ifdef CONFIG_FEATURE_UTMP 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 779 645 /* update_utmp - update our utmp entry */ 780 static void update_utmp(c har *line)646 static void update_utmp(const char *line) 781 647 { 782 648 struct utmp ut; … … 784 650 time_t t; 785 651 int mypid = getpid(); 786 #if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))787 struct flock lock;788 #endif789 652 790 653 /* … … 802 665 setutent(); 803 666 while ((utp = getutent()) 804 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) /* nothing */805 ;667 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) 668 /* nothing */; 806 669 807 670 if (utp) { … … 812 675 safe_strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); 813 676 } 814 /* endutent(); */677 /* endutent(); */ 815 678 816 679 strcpy(ut.ut_user, "LOGIN"); … … 826 689 endutent(); 827 690 828 #if def CONFIG_FEATURE_WTMP691 #if ENABLE_FEATURE_WTMP 829 692 if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) 830 693 close(creat(bb_path_wtmp_file, 0664)); … … 837 700 838 701 839 #undef logname 702 int getty_main(int argc, char **argv); 840 703 int getty_main(int argc, char **argv) 841 704 { 705 int nullfd; 842 706 char *logname = NULL; /* login name, given to /bin/login */ 707 /* Merging these into "struct local" may _seem_ to reduce 708 * parameter passing, but today's gcc will inline 709 * statics which are called once anyway, so don't do that */ 843 710 struct chardata chardata; /* set by get_logname() */ 844 struct termio termio; /* terminal mode bits */845 st atic struct options options = {711 struct termios termios; /* terminal mode bits */ 712 struct options options = { 846 713 0, /* show /etc/issue (SYSV_STYLE) */ 847 714 0, /* no timeout */ … … 857 724 }; 858 725 726 /* Already too late because of theoretical 727 * possibility of getty --help somehow triggered 728 * inadvertently before we reach this. Oh well. */ 729 logmode = LOGMODE_NONE; 730 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 */ 738 die_sleep = 10; 739 msg_eol = "\r\n"; 740 openlog(applet_name, LOG_PID, LOG_AUTH); 741 logmode = LOGMODE_BOTH; 742 859 743 #ifdef DEBUGGING 860 dbf = bb_xfopen(DEBUGTERM, "w");744 dbf = xfopen(DEBUGTERM, "w"); 861 745 862 746 { … … 871 755 872 756 /* Parse command-line arguments. */ 873 874 757 parse_args(argc, argv, &options); 875 758 876 #ifdef __linux__ 877 setsid(); 878 #endif 879 759 #ifdef SYSV_STYLE 760 #if ENABLE_FEATURE_UTMP 880 761 /* Update the utmp file. */ 881 882 883 #ifdef SYSV_STYLE884 #ifdef CONFIG_FEATURE_UTMP885 762 update_utmp(options.tty); 886 763 #endif … … 889 766 debug("calling open_tty\n"); 890 767 /* Open the tty as standard { input, output, error }. */ 891 open_tty(options.tty, &termio , options.flags & F_LOCAL);768 open_tty(options.tty, &termios, options.flags & F_LOCAL); 892 769 893 770 #ifdef __linux__ … … 899 776 } 900 777 #endif 901 /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */902 debug("calling termio _init\n");903 termio _init(&termio, options.speeds[FIRST_SPEED], &options);778 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ 779 debug("calling termios_init\n"); 780 termios_init(&termios, options.speeds[FIRST_SPEED], &options); 904 781 905 782 /* write the modem init string and DON'T flush the buffers */ … … 911 788 if (!(options.flags & F_LOCAL)) { 912 789 /* go to blocking write mode unless -L is specified */ 913 fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK);790 ndelay_off(1); 914 791 } 915 792 … … 917 794 debug("before autobaud\n"); 918 795 if (options.flags & F_PARSE) 919 auto_baud( &termio);796 auto_baud(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), &termios); 920 797 921 798 /* Set the optional timer. */ 922 799 if (options.timeout) 923 (void) alarm((unsigned)options.timeout);800 alarm(options.timeout); 924 801 925 802 /* optionally wait for CR or LF before writing /etc/issue */ … … 942 819 /* Read the login name. */ 943 820 debug("reading login name\n"); 944 /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */ 945 while ((logname = get_logname(&options, &chardata, &termio)) == 946 NULL) next_speed(&termio, &options); 821 logname = get_logname(bb_common_bufsiz1, sizeof(bb_common_bufsiz1), 822 &options, &chardata, &termios); 823 while (logname == NULL) 824 next_speed(&termios, &options); 947 825 } 948 826 … … 950 828 951 829 if (options.timeout) 952 (void)alarm(0);953 954 /* Finalize the termio settings. */955 956 termio _final(&options, &termio, &chardata);830 alarm(0); 831 832 /* Finalize the termios settings. */ 833 834 termios_final(&options, &termios, &chardata); 957 835 958 836 /* Now the newline character should be properly written. */ 959 837 960 (void)write(1, "\n", 1);838 write(1, "\n", 1); 961 839 962 840 /* Let the login program take care of password validation. */ 963 841 964 (void) execl(options.login, options.login, "--", logname, (char *) 0); 965 error("%s: can't exec %s: %m", options.tty, options.login); 966 } 967 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 } -
branches/stable/mindi-busybox/loginutils/login.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 #include <fcntl.h> 3 #include <signal.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <syslog.h> 8 #include <termios.h> 9 #include <unistd.h> 2 /* 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 4 */ 5 6 #include "libbb.h" 10 7 #include <utmp.h> 11 8 #include <sys/resource.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 #include <ctype.h> 15 #include <time.h> 16 17 #include "busybox.h" 18 #ifdef CONFIG_SELINUX 9 #include <syslog.h> 10 11 #if ENABLE_SELINUX 19 12 #include <selinux/selinux.h> /* for is_selinux_enabled() */ 20 13 #include <selinux/get_context_list.h> /* for get_default_context() */ 21 14 #include <selinux/flask.h> /* for security class definitions */ 22 #include <errno.h> 23 #endif 24 25 #ifdef CONFIG_FEATURE_UTMP 26 // import from utmp.c 27 static void checkutmp(int picky); 28 static void setutmp(const char *name, const char *line); 29 /* Stuff global to this file */ 30 static struct utmp utent; 31 #endif 32 33 // login defines 34 #define TIMEOUT 60 35 #define EMPTY_USERNAME_COUNT 10 36 #define USERNAME_SIZE 32 37 38 39 static int check_nologin ( int amroot ); 40 41 #if defined CONFIG_FEATURE_SECURETTY 42 static int check_tty ( const char *tty ); 43 44 #else 45 static inline int check_tty ( const char *tty ) { return 1; } 46 47 #endif 48 49 static int is_my_tty ( const char *tty ); 50 static int login_prompt ( char *buf_name ); 51 static void motd ( void ); 52 53 54 static void alarm_handler ( int sig ATTRIBUTE_UNUSED) 55 { 56 fprintf (stderr, "\nLogin timed out after %d seconds.\n", TIMEOUT ); 57 exit ( EXIT_SUCCESS ); 58 } 59 60 61 int login_main(int argc, char **argv) 62 { 63 char tty[BUFSIZ]; 64 char full_tty[200]; 65 char fromhost[512]; 66 char username[USERNAME_SIZE]; 67 const char *tmp; 68 int amroot; 69 int flag; 70 int failed; 71 int count=0; 72 struct passwd *pw, pw_copy; 73 #ifdef CONFIG_WHEEL_GROUP 74 struct group *grp; 75 #endif 76 int opt_preserve = 0; 77 int opt_fflag = 0; 78 char *opt_host = 0; 79 int alarmstarted = 0; 80 #ifdef CONFIG_SELINUX 81 security_context_t user_sid = NULL; 82 #endif 83 84 username[0]=0; 85 amroot = ( getuid ( ) == 0 ); 86 signal ( SIGALRM, alarm_handler ); 87 alarm ( TIMEOUT ); 88 alarmstarted = 1; 89 90 while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) { 91 switch ( flag ) { 92 case 'p': 93 opt_preserve = 1; 94 break; 95 case 'f': 96 /* 97 * username must be a separate token 98 * (-f root, *NOT* -froot). --marekm 99 */ 100 if ( optarg != argv[optind-1] ) 101 bb_show_usage( ); 102 103 if ( !amroot ) /* Auth bypass only if real UID is zero */ 104 bb_error_msg_and_die ( "-f permission denied" ); 105 106 safe_strncpy(username, optarg, USERNAME_SIZE); 107 opt_fflag = 1; 108 break; 109 case 'h': 110 opt_host = optarg; 111 break; 112 default: 113 bb_show_usage( ); 114 } 115 } 116 117 if (optind < argc) // user from command line (getty) 118 safe_strncpy(username, argv[optind], USERNAME_SIZE); 119 120 if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 )) 121 return EXIT_FAILURE; /* Must be a terminal */ 122 123 #ifdef CONFIG_FEATURE_UTMP 124 checkutmp ( !amroot ); 125 #endif 126 127 tmp = ttyname ( 0 ); 128 if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 )) 129 safe_strncpy ( tty, tmp + 5, sizeof( tty )); 130 else if ( tmp && *tmp == '/' ) 131 safe_strncpy ( tty, tmp, sizeof( tty )); 132 else 133 safe_strncpy ( tty, "UNKNOWN", sizeof( tty )); 134 135 #ifdef CONFIG_FEATURE_UTMP 136 if ( amroot ) 137 memset ( utent.ut_host, 0, sizeof utent.ut_host ); 138 #endif 139 140 if ( opt_host ) { 141 #ifdef CONFIG_FEATURE_UTMP 142 safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host )); 143 #endif 144 snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host ); 145 } 146 else 147 snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty ); 148 149 bb_setpgrp; 150 151 openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH ); 152 153 while ( 1 ) { 154 failed = 0; 155 156 if ( !username[0] ) 157 if(!login_prompt ( username )) 158 return EXIT_FAILURE; 159 160 if ( !alarmstarted && ( TIMEOUT > 0 )) { 161 alarm ( TIMEOUT ); 162 alarmstarted = 1; 163 } 164 165 if (!( pw = getpwnam ( username ))) { 166 pw_copy.pw_name = "UNKNOWN"; 167 pw_copy.pw_passwd = "!"; 168 opt_fflag = 0; 169 failed = 1; 170 } else 171 pw_copy = *pw; 172 173 pw = &pw_copy; 174 175 if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' )) 176 failed = 1; 177 178 if ( opt_fflag ) { 179 opt_fflag = 0; 180 goto auth_ok; 181 } 182 183 if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty ))) 184 failed = 1; 185 186 /* Don't check the password if password entry is empty (!) */ 187 if ( !pw-> pw_passwd[0] ) 188 goto auth_ok; 189 190 /* authorization takes place here */ 191 if ( correct_password ( pw )) 192 goto auth_ok; 193 194 failed = 1; 195 196 auth_ok: 197 if ( !failed) 198 break; 199 200 bb_do_delay(FAIL_DELAY); 201 puts("Login incorrect"); 202 username[0] = 0; 203 if ( ++count == 3 ) { 204 syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost); 205 return EXIT_FAILURE; 206 } 207 } 208 209 alarm ( 0 ); 210 if ( check_nologin ( pw-> pw_uid == 0 )) 211 return EXIT_FAILURE; 212 213 #ifdef CONFIG_FEATURE_UTMP 214 setutmp ( username, tty ); 215 #endif 216 217 if ( *tty != '/' ) 218 snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty); 219 else 220 safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 ); 221 222 #ifdef CONFIG_SELINUX 223 if (is_selinux_enabled()) 224 { 225 security_context_t old_tty_sid, new_tty_sid; 226 227 if (get_default_context(username, NULL, &user_sid)) 228 { 229 fprintf(stderr, "Unable to get SID for %s\n", username); 230 exit(1); 231 } 232 if (getfilecon(full_tty, &old_tty_sid) < 0) 233 { 234 fprintf(stderr, "getfilecon(%.100s) failed: %.100s\n", full_tty, strerror(errno)); 235 return EXIT_FAILURE; 236 } 237 if (security_compute_relabel(user_sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0) 238 { 239 fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno)); 240 return EXIT_FAILURE; 241 } 242 if(setfilecon(full_tty, new_tty_sid) != 0) 243 { 244 fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno)); 245 return EXIT_FAILURE; 246 } 247 } 248 #endif 249 if ( !is_my_tty ( full_tty )) 250 syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty ); 251 252 /* Try these, but don't complain if they fail 253 * (for example when the root fs is read only) */ 254 chown ( full_tty, pw-> pw_uid, pw-> pw_gid ); 255 chmod ( full_tty, 0600 ); 256 257 change_identity ( pw ); 258 tmp = pw-> pw_shell; 259 if(!tmp || !*tmp) 260 tmp = DEFAULT_SHELL; 261 setup_environment ( tmp, 1, !opt_preserve, pw ); 262 263 motd ( ); 264 signal ( SIGALRM, SIG_DFL ); /* default alarm signal */ 265 266 if ( pw-> pw_uid == 0 ) 267 syslog ( LOG_INFO, "root login %s\n", fromhost ); 268 #ifdef CONFIG_SELINUX 269 /* well, a simple setexeccon() here would do the job as well, 270 * but let's play the game for now */ 271 set_current_security_context(user_sid); 272 #endif 273 run_shell ( tmp, 1, 0, 0); /* exec the shell finally. */ 274 275 return EXIT_FAILURE; 276 } 277 278 279 280 static int login_prompt ( char *buf_name ) 281 { 282 char buf [1024]; 283 char *sp, *ep; 284 int i; 285 286 for(i=0; i<EMPTY_USERNAME_COUNT; i++) { 287 print_login_prompt(); 288 289 if ( !fgets ( buf, sizeof( buf ) - 1, stdin )) 290 return 0; 291 292 if ( !strchr ( buf, '\n' )) 293 return 0; 294 295 for ( sp = buf; isspace ( *sp ); sp++ ) { } 296 for ( ep = sp; isgraph ( *ep ); ep++ ) { } 297 298 *ep = 0; 299 safe_strncpy(buf_name, sp, USERNAME_SIZE); 300 if(buf_name[0]) 301 return 1; 302 } 303 return 0; 304 } 305 306 307 static int check_nologin ( int amroot ) 308 { 309 if ( access ( bb_path_nologin_file, F_OK ) == 0 ) { 310 FILE *fp; 311 int c; 312 313 if (( fp = fopen ( bb_path_nologin_file, "r" ))) { 314 while (( c = getc ( fp )) != EOF ) 315 putchar (( c == '\n' ) ? '\r' : c ); 316 317 fflush ( stdout ); 318 fclose ( fp ); 319 } else { 320 puts ( "\r\nSystem closed for routine maintenance.\r" ); 321 } 322 if ( !amroot ) 323 return 1; 324 325 puts ( "\r\n[Disconnect bypassed -- root login allowed.]\r" ); 326 } 327 return 0; 328 } 329 330 #ifdef CONFIG_FEATURE_SECURETTY 331 332 static int check_tty ( const char *tty ) 333 { 334 FILE *fp; 335 int i; 336 char buf[BUFSIZ]; 337 338 if (( fp = fopen ( bb_path_securetty_file, "r" ))) { 339 while ( fgets ( buf, sizeof( buf ) - 1, fp )) { 340 for ( i = strlen( buf ) - 1; i >= 0; --i ) { 341 if ( !isspace ( buf[i] )) 342 break; 343 } 344 buf[++i] = '\0'; 345 if (( buf [0] == '\0' ) || ( buf [0] == '#' )) 346 continue; 347 348 if ( strcmp ( buf, tty ) == 0 ) { 349 fclose ( fp ); 350 return 1; 351 } 352 } 353 fclose(fp); 354 return 0; 355 } 356 /* A missing securetty file is not an error. */ 357 return 1; 358 } 359 360 #endif 361 362 /* returns 1 if true */ 363 static int is_my_tty ( const char *tty ) 364 { 365 struct stat by_name, by_fd; 366 367 if ( stat ( tty, &by_name ) || fstat ( 0, &by_fd )) 368 return 0; 369 370 if ( by_name. st_rdev != by_fd. st_rdev ) 371 return 0; 372 else 373 return 1; 374 } 375 376 377 static void motd (void) 378 { 379 FILE *fp; 380 register int c; 381 382 if (( fp = fopen ( bb_path_motd_file, "r" ))) { 383 while (( c = getc ( fp )) != EOF ) 384 putchar ( c ); 385 fclose ( fp ); 386 } 387 } 388 389 390 #ifdef CONFIG_FEATURE_UTMP 391 // vv Taken from tinylogin utmp.c vv 392 393 #define NO_UTENT \ 394 "No utmp entry. You must exec \"login\" from the lowest level \"sh\"" 395 #define NO_TTY \ 396 "Unable to determine your tty name." 397 15 #endif 16 17 #if ENABLE_PAM 18 /* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 19 #undef setlocale 20 /* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. 21 * Apparently they like to confuse people. */ 22 #include <security/pam_appl.h> 23 #include <security/pam_misc.h> 24 static const struct pam_conv conv = { 25 misc_conv, 26 NULL 27 }; 28 #endif 29 30 enum { 31 TIMEOUT = 60, 32 EMPTY_USERNAME_COUNT = 10, 33 USERNAME_SIZE = 32, 34 TTYNAME_SIZE = 32, 35 }; 36 37 static char* short_tty; 38 39 #if ENABLE_FEATURE_UTMP 40 /* vv Taken from tinylogin utmp.c vv */ 398 41 /* 399 * checkutmp- see if utmp file is correct for this process42 * read_or_build_utent - see if utmp file is correct for this process 400 43 * 401 44 * System V is very picky about the contents of the utmp file … … 410 53 */ 411 54 412 static void checkutmp(int picky) 413 { 414 char *line; 55 static void read_or_build_utent(struct utmp *utptr, int picky) 56 { 415 57 struct utmp *ut; 416 58 pid_t pid = getpid(); … … 421 63 while ((ut = getutent())) 422 64 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && 423 65 (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) 424 66 break; 425 67 426 68 /* If there is one, just use it, otherwise create a new one. */ 427 69 if (ut) { 428 utent= *ut;70 *utptr = *ut; 429 71 } else { 430 time_t t_tmp; 431 432 if (picky) { 433 puts(NO_UTENT); 434 exit(1); 435 } 436 line = ttyname(0); 437 if (!line) { 438 puts(NO_TTY); 439 exit(1); 440 } 441 if (strncmp(line, "/dev/", 5) == 0) 442 line += 5; 443 memset((void *) &utent, 0, sizeof utent); 444 utent.ut_type = LOGIN_PROCESS; 445 utent.ut_pid = pid; 446 strncpy(utent.ut_line, line, sizeof utent.ut_line); 447 /* XXX - assumes /dev/tty?? */ 448 strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id); 449 strncpy(utent.ut_user, "LOGIN", sizeof utent.ut_user); 450 t_tmp = (time_t)utent.ut_time; 451 time(&t_tmp); 452 } 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 something 80 * 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)); 453 87 } 454 88 455 89 /* 456 * setutmp- put a USER_PROCESS entry in the utmp file90 * write_utent - put a USER_PROCESS entry in the utmp file 457 91 * 458 * setutmpchanges the type of the current utmp entry to92 * write_utent changes the type of the current utmp entry to 459 93 * USER_PROCESS. the wtmp file will be updated as well. 460 94 */ 461 462 static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED) 463 { 464 time_t t_tmp = (time_t)utent.ut_time; 465 466 utent.ut_type = USER_PROCESS; 467 strncpy(utent.ut_user, name, sizeof utent.ut_user); 468 time(&t_tmp); 469 /* other fields already filled in by checkutmp above */ 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 */ 470 101 setutent(); 471 pututline( &utent);102 pututline(utptr); 472 103 endutent(); 473 #if def CONFIG_FEATURE_WTMP104 #if ENABLE_FEATURE_WTMP 474 105 if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { 475 106 close(creat(bb_path_wtmp_file, 0664)); 476 107 } 477 updwtmp(bb_path_wtmp_file, &utent); 478 #endif 479 } 480 #endif /* CONFIG_FEATURE_UTMP */ 108 updwtmp(bb_path_wtmp_file, utptr); 109 #endif 110 } 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 #if ENABLE_FEATURE_NOLOGIN 117 static void die_if_nologin_and_non_root(int amroot) 118 { 119 FILE *fp; 120 int c; 121 122 if (access("/etc/nologin", F_OK)) 123 return; 124 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 } else 132 puts("\r\nSystem closed for routine maintenance\r"); 133 if (!amroot) 134 exit(1); 135 puts("\r\n[Disconnect bypassed -- root login allowed]\r"); 136 } 137 #else 138 static ALWAYS_INLINE void die_if_nologin_and_non_root(int amroot) {} 139 #endif 140 141 #if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM 142 static int check_securetty(void) 143 { 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; 168 } 169 #else 170 static ALWAYS_INLINE int check_securetty(void) { return 1; } 171 #endif 172 173 static void get_username_or_die(char *buf, int size_buf) 174 { 175 int c, cntdown; 176 177 cntdown = EMPTY_USERNAME_COUNT; 178 prompt: 179 print_login_prompt(); 180 /* skip whitespace */ 181 do { 182 c = getchar(); 183 if (c == EOF) exit(1); 184 if (c == '\n') { 185 if (!--cntdown) exit(1); 186 goto prompt; 187 } 188 } while (isspace(c)); 189 190 *buf++ = c; 191 if (!fgets(buf, size_buf-2, stdin)) 192 exit(1); 193 if (!strchr(buf, '\n')) 194 exit(1); 195 while (isgraph(*buf)) buf++; 196 *buf = '\0'; 197 } 198 199 static void motd(void) 200 { 201 int fd; 202 203 fd = open(bb_path_motd_file, O_RDONLY); 204 if (fd) { 205 fflush(stdout); 206 bb_copyfd_eof(fd, STDOUT_FILENO); 207 close(fd); 208 } 209 } 210 211 static void alarm_handler(int sig ATTRIBUTE_UNUSED) 212 { 213 /* This is the escape hatch! Poor serial line users and the like 214 * arrive here when their connection is broken. 215 * We don't want to block here */ 216 ndelay_on(1); 217 ndelay_on(2); 218 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) 224 { 225 enum { 226 LOGIN_OPT_f = (1<<0), 227 LOGIN_OPT_h = (1<<1), 228 LOGIN_OPT_p = (1<<2), 229 }; 230 char *fromhost; 231 char username[USERNAME_SIZE]; 232 const char *tmp; 233 int amroot; 234 unsigned opt; 235 int count = 0; 236 struct passwd *pw; 237 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; 247 username[0] = '\0'; 248 amroot = (getuid() == 0); 249 signal(SIGALRM, alarm_handler); 250 alarm(TIMEOUT); 251 252 /* Mandatory paranoia for suid applet: 253 * ensure that fd# 0,1,2 are opened (at least to /dev/null) 254 * and any extra open fd's are closed. 255 * (The name of the function is misleading. Not daemonizing here.) */ 256 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); 257 258 opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); 259 if (opt & LOGIN_OPT_f) { 260 if (!amroot) 261 bb_error_msg_and_die("-f is for root only"); 262 safe_strncpy(username, opt_user, sizeof(username)); 263 } 264 if (optind < argc) /* user from command line (getty) */ 265 safe_strncpy(username, argv[optind], sizeof(username)); 266 267 /* 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); 279 280 if (opt_host) { 281 USE_FEATURE_UTMP( 282 safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host)); 283 ) 284 fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host); 285 } else 286 fromhost = xasprintf(" on '%s'", short_tty); 287 288 /* Was breaking "login <username>" from shell command line: */ 289 /*bb_setpgrp();*/ 290 291 openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); 292 293 while (1) { 294 if (!username[0]) 295 get_username_or_die(username, sizeof(username)); 296 297 #if ENABLE_PAM 298 pamret = pam_start("login", username, &conv, &pamh); 299 if (pamret != PAM_SUCCESS) { 300 failed_msg = "pam_start"; 301 goto pam_auth_failed; 302 } 303 /* set TTY (so things like securetty work) */ 304 pamret = pam_set_item(pamh, PAM_TTY, short_tty); 305 if (pamret != PAM_SUCCESS) { 306 failed_msg = "pam_set_item(TTY)"; 307 goto pam_auth_failed; 308 } 309 pamret = pam_authenticate(pamh, 0); 310 if (pamret != PAM_SUCCESS) { 311 failed_msg = "pam_authenticate"; 312 goto pam_auth_failed; 313 /* TODO: or just "goto auth_failed" 314 * since user seems to enter wrong password 315 * (in this case pamret == 7) 316 */ 317 } 318 /* check that the account is healthy */ 319 pamret = pam_acct_mgmt(pamh, 0); 320 if (pamret != PAM_SUCCESS) { 321 failed_msg = "account setup"; 322 goto pam_auth_failed; 323 } 324 /* 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; 341 pam_auth_failed: 342 bb_error_msg("%s failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret); 343 safe_strncpy(username, "UNKNOWN", sizeof(username)); 344 #else /* not PAM */ 345 pw = getpwnam(username); 346 if (!pw) { 347 strcpy(username, "UNKNOWN"); 348 goto fake_it; 349 } 350 351 if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') 352 goto auth_failed; 353 354 if (opt & LOGIN_OPT_f) 355 break; /* -f USER: success without asking passwd */ 356 357 if (pw->pw_uid == 0 && !check_securetty()) 358 goto auth_failed; 359 360 /* Don't check the password if password entry is empty (!) */ 361 if (!pw->pw_passwd[0]) 362 break; 363 fake_it: 364 /* authorization takes place here */ 365 if (correct_password(pw)) 366 break; 367 #endif /* ENABLE_PAM */ 368 auth_failed: 369 opt &= ~LOGIN_OPT_f; 370 bb_do_delay(FAIL_DELAY); 371 /* TODO: doesn't sound like correct English phrase to me */ 372 puts("Login incorrect"); 373 if (++count == 3) { 374 syslog(LOG_WARNING, "invalid password for '%s'%s", 375 username, fromhost); 376 return EXIT_FAILURE; 377 } 378 username[0] = '\0'; 379 } 380 381 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 409 /* Try these, but don't complain if they fail. 410 * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ 411 fchown(0, pw->pw_uid, pw->pw_gid); 412 fchmod(0, 0600); 413 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 } 430 431 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! */ 438 439 motd(); 440 441 if (pw->pw_uid == 0) 442 syslog(LOG_INFO, "root login%s", fromhost); 443 #if ENABLE_SELINUX 444 /* well, a simple setexeccon() here would do the job as well, 445 * but let's play the game for now */ 446 set_current_security_context(user_sid); 447 #endif 448 449 // util-linux login also does: 450 // /* start new session */ 451 // setsid(); 452 // /* TIOCSCTTY: steal tty from other process group */ 453 // if (ioctl(0, TIOCSCTTY, 1)) error_msg... 454 // BBox login used to do this (see above): 455 // bb_setpgrp(); 456 // If this stuff is really needed, add it and explain why! 457 458 /* set signals to defaults */ 459 signal(SIGALRM, SIG_DFL); 460 /* Is this correct? This way user can ctrl-c out of /etc/profile, 461 * potentially creating security breach (tested with bash 3.0). 462 * But without this, bash 3.0 will not enable ctrl-c either. 463 * Maybe bash is buggy? 464 * Need to find out what standards say about /bin/login - 465 * should it leave SIGINT etc enabled or disabled? */ 466 signal(SIGINT, SIG_DFL); 467 468 /* Exec login shell with no additional parameters */ 469 run_shell(tmp, 1, NULL, NULL); 470 471 /* return EXIT_FAILURE; - not reached */ 472 } -
branches/stable/mindi-busybox/loginutils/passwd.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <signal.h> 6 #include <sys/stat.h> 7 #include <sys/types.h> 8 #include <unistd.h> 9 #include <utime.h> 2 /* 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 4 */ 5 6 #include "libbb.h" 10 7 #include <syslog.h> 11 #include <time.h> 12 #include <sys/resource.h> 13 #include <errno.h> 14 15 #include "busybox.h" 16 17 static char crypt_passwd[128]; 18 19 static int create_backup(const char *backup, FILE * fp); 20 static int new_password(const struct passwd *pw, int amroot, int algo); 21 static void set_filesize_limit(int blocks); 22 23 24 static int get_algo(char *a) 8 9 10 static void nuke_str(char *str) 25 11 { 26 int x = 1; /* standard: MD5 */ 27 28 if (strcasecmp(a, "des") == 0) 29 x = 0; 30 return x; 12 if (str) memset(str, 0, strlen(str)); 31 13 } 32 14 33 34 static int update_passwd(const struct passwd *pw, const char *crypt_pw) 15 static char* new_password(const struct passwd *pw, uid_t myuid, int algo) 35 16 { 36 char filename[1024]; 37 char buf[1025]; 38 char buffer[80]; 39 char username[32]; 40 char *pw_rest; 41 int mask; 42 int continued; 43 FILE *fp; 44 FILE *out_fp; 45 struct stat sb; 46 struct flock lock; 47 48 #if ENABLE_FEATURE_SHADOWPASSWDS 49 if (access(bb_path_shadow_file, F_OK) == 0) { 50 snprintf(filename, sizeof filename, "%s", bb_path_shadow_file); 51 } else 52 #endif 53 { 54 snprintf(filename, sizeof filename, "%s", bb_path_passwd_file); 55 } 56 57 if (((fp = fopen(filename, "r+")) == 0) || (fstat(fileno(fp), &sb))) { 58 /* return 0; */ 59 return 1; 60 } 61 62 /* Lock the password file before updating */ 63 lock.l_type = F_WRLCK; 64 lock.l_whence = SEEK_SET; 65 lock.l_start = 0; 66 lock.l_len = 0; 67 if (fcntl(fileno(fp), F_SETLK, &lock) < 0) { 68 fprintf(stderr, "%s: %s\n", filename, strerror(errno)); 69 return 1; 70 } 71 lock.l_type = F_UNLCK; 72 73 snprintf(buf, sizeof buf, "%s-", filename); 74 if (create_backup(buf, fp)) { 75 fcntl(fileno(fp), F_SETLK, &lock); 76 fclose(fp); 77 return 1; 78 } 79 snprintf(buf, sizeof buf, "%s+", filename); 80 mask = umask(0777); 81 out_fp = fopen(buf, "w"); 82 umask(mask); 83 if ((!out_fp) || (fchmod(fileno(out_fp), sb.st_mode & 0777)) 84 || (fchown(fileno(out_fp), sb.st_uid, sb.st_gid))) { 85 fcntl(fileno(fp), F_SETLK, &lock); 86 fclose(fp); 87 fclose(out_fp); 88 return 1; 89 } 90 91 continued = 0; 92 snprintf(username, sizeof username, "%s:", pw->pw_name); 93 rewind(fp); 94 while (!feof(fp)) { 95 fgets(buffer, sizeof buffer, fp); 96 if (!continued) { /* Check to see if we're updating this line. */ 97 if (strncmp(username, buffer, strlen(username)) == 0) { 98 /* we have a match. */ 99 pw_rest = strchr(buffer, ':'); 100 *pw_rest++ = '\0'; 101 pw_rest = strchr(pw_rest, ':'); 102 fprintf(out_fp, "%s:%s%s", buffer, crypt_pw, pw_rest); 103 } else { 104 fputs(buffer, out_fp); 105 } 106 } else { 107 fputs(buffer, out_fp); 17 char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */ 18 char *orig = (char*)""; 19 char *newp = NULL; 20 char *cipher = NULL; 21 char *cp = NULL; 22 char *ret = NULL; /* failure so far */ 23 24 if (myuid && pw->pw_passwd[0]) { 25 orig = bb_askpass(0, "Old password:"); /* returns ptr to static */ 26 if (!orig) 27 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'", 31 pw->pw_name); 32 bb_do_delay(FAIL_DELAY); 33 puts("Incorrect password"); 34 goto err_ret; 108 35 } 109 if (buffer[strlen(buffer) - 1] == '\n') { 110 continued = 0; 111 } else { 112 continued = 1; 113 } 114 memset(buffer, 0, sizeof buffer); 115 } 116 117 if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) { 118 unlink(buf); 119 fcntl(fileno(fp), F_SETLK, &lock); 120 fclose(fp); 121 return 1; 122 } 123 if (rename(buf, filename) < 0) { 124 fcntl(fileno(fp), F_SETLK, &lock); 125 fclose(fp); 126 return 1; 127 } else { 128 fcntl(fileno(fp), F_SETLK, &lock); 129 fclose(fp); 130 return 0; 131 } 36 } 37 orig = xstrdup(orig); /* or else bb_askpass() will destroy it */ 38 newp = bb_askpass(0, "New password:"); /* returns ptr to static */ 39 if (!newp) 40 goto err_ret; 41 newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */ 42 if (ENABLE_FEATURE_PASSWD_WEAK_CHECK 43 && obscure(orig, newp, pw) && myuid) 44 goto err_ret; /* non-root is not allowed to have weak passwd */ 45 46 cp = bb_askpass(0, "Retype password:"); 47 if (!cp) 48 goto err_ret; 49 if (strcmp(cp, newp)) { 50 puts("Passwords don't match"); 51 goto err_ret; 52 } 53 54 crypt_make_salt(salt, 1, 0); /* des */ 55 if (algo) { /* MD5 */ 56 strcpy(salt, "$1$"); 57 crypt_make_salt(salt + 3, 4, 0); 58 } 59 /* pw_encrypt returns ptr to static */ 60 ret = xstrdup(pw_encrypt(newp, salt)); 61 /* whee, success! */ 62 63 err_ret: 64 nuke_str(orig); 65 if (ENABLE_FEATURE_CLEAN_UP) free(orig); 66 nuke_str(newp); 67 if (ENABLE_FEATURE_CLEAN_UP) free(newp); 68 nuke_str(cipher); 69 nuke_str(cp); 70 return ret; 132 71 } 133 72 134 73 int passwd_main(int argc, char **argv); 135 74 int passwd_main(int argc, char **argv) 136 75 { 137 int amroot; 138 char *cp; 139 char *np; 76 enum { 77 OPT_algo = 0x1, /* -a - password algorithm */ 78 OPT_lock = 0x2, /* -l - lock account */ 79 OPT_unlock = 0x4, /* -u - unlock account */ 80 OPT_delete = 0x8, /* -d - delete password */ 81 OPT_lud = 0xe, 82 STATE_ALGO_md5 = 0x10, 83 //STATE_ALGO_des = 0x20, not needed yet 84 }; 85 unsigned opt; 86 int rc; 87 const char *opt_a = ""; 88 const char *filename; 89 char *myname; 140 90 char *name; 141 char *myname; 142 int flag; 143 int algo = 1; /* -a - password algorithm */ 144 int lflg = 0; /* -l - lock account */ 145 int uflg = 0; /* -u - unlock account */ 146 int dflg = 0; /* -d - delete password */ 147 const struct passwd *pw; 91 char *newp; 92 struct passwd *pw; 93 uid_t myuid; 94 struct rlimit rlimit_fsize; 95 char c; 148 96 149 97 #if ENABLE_FEATURE_SHADOWPASSWDS 150 const struct spwd *sp; 98 /* Using _r function to avoid pulling in static buffers */ 99 struct spwd spw; 100 struct spwd *result; 101 char buffer[256]; 151 102 #endif 152 amroot = (getuid() == 0); 153 openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); 154 while ((flag = getopt(argc, argv, "a:dlu")) != EOF) { 155 switch (flag) { 156 case 'a': 157 algo = get_algo(optarg); 158 break; 159 case 'd': 160 dflg++; 161 break; 162 case 'l': 163 lflg++; 164 break; 165 case 'u': 166 uflg++; 167 break; 168 default: 169 bb_show_usage(); 170 } 171 } 172 myname = (char *) bb_xstrdup(bb_getpwuid(NULL, getuid(), -1)); 173 /* exits on error */ 174 if (optind < argc) { 175 name = argv[optind]; 103 104 logmode = LOGMODE_BOTH; 105 openlog(applet_name, LOG_NOWAIT, LOG_AUTH); 106 opt = getopt32(argv, "a:lud", &opt_a); 107 //argc -= optind; 108 argv += optind; 109 110 if (strcasecmp(opt_a, "des") != 0) /* -a */ 111 opt |= STATE_ALGO_md5; 112 //else 113 // opt |= STATE_ALGO_des; 114 myuid = getuid(); 115 /* -l, -u, -d require root priv and username argument */ 116 if ((opt & OPT_lud) && (myuid || !argv[0])) 117 bb_show_usage(); 118 119 /* Will complain and die if username not found */ 120 myname = xstrdup(bb_getpwuid(NULL, -1, myuid)); 121 name = argv[0] ? argv[0] : myname; 122 123 pw = getpwnam(name); 124 if (!pw) bb_error_msg_and_die("unknown user %s", name); 125 if (myuid && pw->pw_uid != myuid) { 126 /* LOGMODE_BOTH */ 127 bb_error_msg_and_die("%s can't change password for %s", myname, name); 128 } 129 130 #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); 176 139 } else { 177 name = myname; 178 } 179 if ((lflg || uflg || dflg) && (optind >= argc || !amroot)) { 180 bb_show_usage(); 181 } 182 pw = getpwnam(name); 183 if (!pw) { 184 bb_error_msg_and_die("Unknown user %s\n", name); 185 } 186 if (!amroot && pw->pw_uid != getuid()) { 187 syslog(LOG_WARNING, "can't change pwd for `%s'", name); 188 bb_error_msg_and_die("Permission denied.\n"); 189 } 190 #if ENABLE_FEATURE_SHADOWPASSWDS 191 sp = getspnam(name); 192 if (!sp) { 193 sp = (struct spwd *) pwd_to_spwd(pw); 194 } 195 cp = sp->sp_pwdp; 196 np = sp->sp_namp; 197 #else 198 cp = pw->pw_passwd; 199 np = name; 140 pw->pw_passwd = spw.sp_pwdp; 141 } 200 142 #endif 201 143 202 safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd)); 203 if (!(dflg || lflg || uflg)) { 204 if (!amroot) { 205 if (cp[0] == '!') { 206 syslog(LOG_WARNING, "password locked for `%s'", np); 207 bb_error_msg_and_die( "The password for `%s' cannot be changed.\n", np); 208 } 144 /* Decide what the new password will be */ 145 newp = NULL; 146 c = pw->pw_passwd[0] - '!'; 147 if (!(opt & OPT_lud)) { 148 if (myuid && !c) { /* passwd starts with '!' */ 149 /* LOGMODE_BOTH */ 150 bb_error_msg_and_die("cannot change " 151 "locked password for %s", name); 209 152 } 210 153 printf("Changing password for %s\n", name); 211 if (new_password(pw, amroot, algo)) { 212 bb_error_msg_and_die( "The password for %s is unchanged.\n", name); 154 newp = new_password(pw, myuid, opt & STATE_ALGO_md5); 155 if (!newp) { 156 logmode = LOGMODE_STDIO; 157 bb_error_msg_and_die("password for %s is unchanged", name); 213 158 } 214 } else if (lflg) { 215 if (crypt_passwd[0] != '!') { 216 memmove(&crypt_passwd[1], crypt_passwd, 217 sizeof crypt_passwd - 1); 218 crypt_passwd[sizeof crypt_passwd - 1] = '\0'; 219 crypt_passwd[0] = '!'; 220 } 221 } else if (uflg) { 222 if (crypt_passwd[0] == '!') { 223 memmove(crypt_passwd, &crypt_passwd[1], 224 sizeof crypt_passwd - 1); 225 } 226 } else if (dflg) { 227 crypt_passwd[0] = '\0'; 228 } 229 set_filesize_limit(30000); 159 } else if (opt & OPT_lock) { 160 if (!c) goto skip; /* passwd starts with '!' */ 161 newp = xasprintf("!%s", pw->pw_passwd); 162 } else if (opt & OPT_unlock) { 163 if (c) goto skip; /* not '!' */ 164 /* pw->pw_passwd pints to static storage, 165 * strdup'ing to avoid nasty surprizes */ 166 newp = xstrdup(&pw->pw_passwd[1]); 167 } else if (opt & OPT_delete) { 168 //newp = xstrdup(""); 169 newp = (char*)""; 170 } 171 172 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000; 173 setrlimit(RLIMIT_FSIZE, &rlimit_fsize); 230 174 signal(SIGHUP, SIG_IGN); 231 175 signal(SIGINT, SIG_IGN); … … 233 177 umask(077); 234 178 xsetuid(0); 235 if (!update_passwd(pw, crypt_passwd)) { 236 syslog(LOG_INFO, "password for `%s' changed by user `%s'", name, 237 myname); 238 printf("Password changed.\n"); 239 } else { 240 syslog(LOG_WARNING, "an error occurred updating the password file"); 241 bb_error_msg_and_die("An error occurred updating the password file.\n"); 242 } 243 return (0); 244 } 245 246 247 248 static int create_backup(const char *backup, FILE * fp) 249 { 250 struct stat sb; 251 struct utimbuf ub; 252 FILE *bkfp; 253 int c, mask; 254 255 if (fstat(fileno(fp), &sb)) 256 /* return -1; */ 257 return 1; 258 259 mask = umask(077); 260 bkfp = fopen(backup, "w"); 261 umask(mask); 262 if (!bkfp) 263 /* return -1; */ 264 return 1; 265 266 /* TODO: faster copy, not one-char-at-a-time. --marekm */ 267 rewind(fp); 268 while ((c = getc(fp)) != EOF) { 269 if (putc(c, bkfp) == EOF) 270 break; 271 } 272 if (c != EOF || fflush(bkfp)) { 273 fclose(bkfp); 274 /* return -1; */ 275 return 1; 276 } 277 if (fclose(bkfp)) 278 /* return -1; */ 279 return 1; 280 281 ub.actime = sb.st_atime; 282 ub.modtime = sb.st_mtime; 283 utime(backup, &ub); 179 180 #if ENABLE_FEATURE_SHADOWPASSWDS 181 filename = bb_path_shadow_file; 182 rc = update_passwd(bb_path_shadow_file, name, newp); 183 if (rc == 0) /* no lines updated, no errors detected */ 184 #endif 185 { 186 filename = bb_path_passwd_file; 187 rc = update_passwd(bb_path_passwd_file, name, newp); 188 } 189 /* LOGMODE_BOTH */ 190 if (rc < 0) 191 bb_error_msg_and_die("cannot update password file %s", 192 filename); 193 bb_info_msg("Password for %s changed by %s", name, myname); 194 195 //if (ENABLE_FEATURE_CLEAN_UP) free(newp); 196 skip: 197 if (!newp) { 198 bb_error_msg_and_die("password for %s is already %slocked", 199 name, (opt & OPT_unlock) ? "un" : ""); 200 } 201 if (ENABLE_FEATURE_CLEAN_UP) free(myname); 284 202 return 0; 285 203 } 286 287 static int i64c(int i)288 {289 if (i <= 0)290 return ('.');291 if (i == 1)292 return ('/');293 if (i >= 2 && i < 12)294 return ('0' - 2 + i);295 if (i >= 12 && i < 38)296 return ('A' - 12 + i);297 if (i >= 38 && i < 63)298 return ('a' - 38 + i);299 return ('z');300 }301 302 static char *crypt_make_salt(void)303 {304 time_t now;305 static unsigned long x;306 static char result[3];307 308 time(&now);309 x += now + getpid() + clock();310 result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);311 result[1] = i64c(((x >> 12) ^ x) & 077);312 result[2] = '\0';313 return result;314 }315 316 317 static int new_password(const struct passwd *pw, int amroot, int algo)318 {319 char *clear;320 char *cipher;321 char *cp;322 char salt[12]; /* "$N$XXXXXXXX" or "XX" */323 char orig[200];324 char pass[200];325 326 if (!amroot && crypt_passwd[0]) {327 if (!(clear = bb_askpass(0, "Old password:"))) {328 /* return -1; */329 return 1;330 }331 cipher = pw_encrypt(clear, crypt_passwd);332 if (strcmp(cipher, crypt_passwd) != 0) {333 syslog(LOG_WARNING, "incorrect password for `%s'",334 pw->pw_name);335 bb_do_delay(FAIL_DELAY);336 fprintf(stderr, "Incorrect password.\n");337 /* return -1; */338 return 1;339 }340 safe_strncpy(orig, clear, sizeof(orig));341 memset(clear, 0, strlen(clear));342 memset(cipher, 0, strlen(cipher));343 } else {344 orig[0] = '\0';345 }346 if (! (cp=bb_askpass(0, "Enter the new password (minimum of 5, maximum of 8 characters)\n"347 "Please use a combination of upper and lower case letters and numbers.\n"348 "Enter new password: ")))349 {350 memset(orig, 0, sizeof orig);351 /* return -1; */352 return 1;353 }354 safe_strncpy(pass, cp, sizeof(pass));355 memset(cp, 0, strlen(cp));356 /* if (!obscure(orig, pass, pw)) { */357 if (obscure(orig, pass, pw)) {358 if (amroot) {359 printf("\nWarning: weak password (continuing).\n");360 } else {361 /* return -1; */362 return 1;363 }364 }365 if (!(cp = bb_askpass(0, "Re-enter new password: "))) {366 memset(orig, 0, sizeof orig);367 /* return -1; */368 return 1;369 }370 if (strcmp(cp, pass)) {371 fprintf(stderr, "Passwords do not match.\n");372 /* return -1; */373 return 1;374 }375 memset(cp, 0, strlen(cp));376 memset(orig, 0, sizeof(orig));377 memset(salt, 0, sizeof(salt));378 379 if (algo == 1) {380 strcpy(salt, "$1$");381 strcat(salt, crypt_make_salt());382 strcat(salt, crypt_make_salt());383 strcat(salt, crypt_make_salt());384 }385 386 strcat(salt, crypt_make_salt());387 cp = pw_encrypt(pass, salt);388 389 memset(pass, 0, sizeof pass);390 safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));391 return 0;392 }393 394 static void set_filesize_limit(int blocks)395 {396 struct rlimit rlimit_fsize;397 398 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;399 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);400 } -
branches/stable/mindi-busybox/loginutils/su.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 Licensed under the GPL v2, see the file LICENSE in this tarball. 4 */ 3 * Mini su implementation for busybox 4 * 5 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 6 */ 5 7 6 #include <fcntl.h> 7 #include <signal.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 8 #include "libbb.h" 11 9 #include <syslog.h> 12 #include <termios.h>13 #include <unistd.h>14 #include <utmp.h>15 #include <sys/resource.h>16 #include <sys/stat.h>17 #include <sys/types.h>18 #include <ctype.h>19 #include <time.h>20 10 21 #include "busybox.h" 11 #define SU_OPT_mp (3) 12 #define SU_OPT_l (4) 22 13 23 /* The shell to run if none is given in the user's passwd entry. */ 24 #ifndef DEFAULT_SHELL 25 #define DEFAULT_SHELL "/bin/sh" 26 #endif 27 28 /* Default user. */ 29 #define DEFAULT_USER "root" 30 31 /* #define SYSLOG_SUCCESS */ 32 #define SYSLOG_FAILURE 33 34 35 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) 36 /* Log the fact that someone has run su */ 37 38 # if defined( SYSLOG_SUCCESS ) && defined( SYSLOG_FAILURE ) 39 static void log_su (const char *successful, const char *old_user, 40 const char *tty) 14 int su_main(int argc, char **argv); 15 int su_main(int argc, char **argv) 41 16 { 42 syslog ( LOG_NOTICE, "%s%s on %s", successful, old_user, tty); 43 } 44 # define log_su_successful(cu, u, tty) if(!cu) log_su("", u, tty) 45 # define log_su_failure(cu, u, tty) if(!cu) log_su("FAILED SU ", u, tty) 46 # else 47 /* partial logging */ 48 # if !defined( SYSLOG_SUCESS ) 49 # define log_su_successful(cu, u, tty) 50 # define log_su_failure(cu, u, t) if(!cu) \ 51 syslog(LOG_NOTICE, "FAILED SU %s on %s", u, t) 52 # else 53 # define log_su_successful(cu, u, t) if(!cu) \ 54 syslog(LOG_NOTICE, "%s on %s", u, t) 55 # define log_su_failure(cu, u, tty) 56 # endif 57 # endif 58 #else 59 /* logging not used */ 60 # define log_su_successful(cu, u, tty) 61 # define log_su_failure(cu, u, tty) 62 #endif 63 64 65 int su_main ( int argc, char **argv ) 66 { 67 unsigned long flags; 68 char *opt_shell = 0; 69 char *opt_command = 0; 70 char *opt_username = DEFAULT_USER; 71 char **opt_args = 0; 17 unsigned flags; 18 char *opt_shell = NULL; 19 char *opt_command = NULL; 20 const char *opt_username = "root"; 72 21 struct passwd *pw; 73 22 uid_t cur_uid = getuid(); 23 const char *tty; 24 char *old_user; 74 25 75 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) 76 const char *tty; 77 const char *old_user; 78 #endif 26 flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); 27 argc -= optind; 28 argv += optind; 79 29 80 flags = bb_getopt_ulflags(argc, argv, "mplc:s:", 81 &opt_command, &opt_shell); 82 #define SU_OPT_m (3) 83 #define SU_OPT_p (3) 84 #define SU_OPT_l (4) 85 86 if (optind < argc && argv[optind][0] == '-' && argv[optind][1] == 0) { 30 if (argc && LONE_DASH(argv[0])) { 87 31 flags |= SU_OPT_l; 88 ++optind; 89 } 32 argc--; 33 argv++; 34 } 90 35 91 36 /* get user if specified */ 92 if ( optind < argc ) 93 opt_username = argv [optind++]; 37 if (argc) { 38 opt_username = argv[0]; 39 // argc--; 40 argv++; 41 } 94 42 95 if ( optind < argc ) 96 opt_args = argv + optind; 43 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"; 50 openlog(applet_name, 0, LOG_AUTH); 51 } 97 52 98 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) 99 #ifdef CONFIG_FEATURE_UTMP 100 /* The utmp entry (via getlogin) is probably the best way to identify 101 the user, especially if someone su's from a su-shell. */ 102 old_user = getlogin ( ); 103 if ( !old_user ) 104 #endif 105 { 106 /* getlogin can fail -- usually due to lack of utmp entry. 107 Resort to getpwuid. */ 108 pw = getpwuid ( cur_uid ); 109 old_user = ( pw ? pw->pw_name : "" ); 110 } 111 tty = ttyname ( 2 ); 112 if(!tty) 113 tty = "none"; 114 115 openlog ( bb_applet_name, 0, LOG_AUTH ); 116 #endif 117 118 pw = getpwnam ( opt_username ); 119 if ( !pw ) 120 bb_error_msg_and_die ( "user %s does not exist", opt_username ); 53 pw = getpwnam(opt_username); 54 if (!pw) 55 bb_error_msg_and_die("unknown id: %s", opt_username); 121 56 122 57 /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER 123 58 is a username that is retrieved via NIS (YP), but that doesn't have 124 59 a default shell listed. */ 125 if ( !pw->pw_shell || !pw->pw_shell [0])126 pw->pw_shell = (char *) 60 if (!pw->pw_shell || !pw->pw_shell[0]) 61 pw->pw_shell = (char *)DEFAULT_SHELL; 127 62 128 if ((( cur_uid == 0 ) || correct_password ( pw ))) { 129 log_su_successful(pw->pw_uid, old_user, tty ); 63 if ((cur_uid == 0) || correct_password(pw)) { 64 if (ENABLE_FEATURE_SU_SYSLOG) 65 syslog(LOG_NOTICE, "%c %s %s:%s", 66 '+', tty, old_user, opt_username); 130 67 } else { 131 log_su_failure (pw->pw_uid, old_user, tty ); 132 bb_error_msg_and_die ( "incorrect password" ); 68 if (ENABLE_FEATURE_SU_SYSLOG) 69 syslog(LOG_NOTICE, "%c %s %s:%s", 70 '-', tty, old_user, opt_username); 71 bb_error_msg_and_die("incorrect password"); 133 72 } 134 73 135 #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) 136 closelog(); 137 #endif 74 if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { 75 closelog(); 76 free(old_user); 77 } 138 78 139 if ( !opt_shell && (flags & SU_OPT_p))140 opt_shell = getenv ( "SHELL");79 if (!opt_shell && (flags & SU_OPT_mp)) 80 opt_shell = getenv("SHELL"); 141 81 142 if ( opt_shell && cur_uid && restricted_shell ( pw->pw_shell )) { 82 #if ENABLE_FEATURE_SU_CHECKS_SHELLS 83 if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) { 143 84 /* The user being su'd to has a nonstandard shell, and so is 144 85 probably a uucp account or has restricted access. Don't 145 86 compromise the account by allowing access with a standard 146 87 shell. */ 147 fputs ( "using restricted shell\n", stderr);88 bb_error_msg("using restricted shell"); 148 89 opt_shell = 0; 149 90 } 150 151 if ( !opt_shell)91 #endif 92 if (!opt_shell) 152 93 opt_shell = pw->pw_shell; 153 94 154 change_identity ( pw);155 setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_ p), pw);156 #if ENABLE_SELINUX 157 set_current_security_context(NULL); 158 #endif 159 run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**) opt_args);95 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);) 98 99 /* Never returns */ 100 run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv); 160 101 161 102 return EXIT_FAILURE; -
branches/stable/mindi-busybox/loginutils/sulogin.c
r902 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 #include <fcntl.h> 3 #include <signal.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 2 /* 3 * Mini sulogin implementation for busybox 4 * 5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 6 */ 7 7 8 #include <syslog.h> 8 #include <unistd.h>9 #include <utmp.h>10 #include <sys/resource.h>11 #include <sys/stat.h>12 #include <sys/types.h>13 #include <ctype.h>14 #include <time.h>15 9 16 #include " busybox.h"10 #include "libbb.h" 17 11 18 19 #define SULOGIN_PROMPT "\nGive root password for system maintenance\n" \ 20 "(or type Control-D for normal startup):" 21 22 static const char * const forbid[] = { 12 static const char *const forbid[] = { 23 13 "ENV", 24 14 "BASH_ENV", … … 39 29 40 30 41 42 31 static void catchalarm(int ATTRIBUTE_UNUSED junk) 43 32 { … … 46 35 47 36 37 int sulogin_main(int argc, char **argv); 48 38 int sulogin_main(int argc, char **argv) 49 39 { 50 40 char *cp; 51 char *device = NULL;52 const char *name = "root";53 41 int timeout = 0; 54 55 #define pass bb_common_bufsiz1 56 57 struct passwd pwent; 42 char *timeout_arg; 43 const char *const *p; 58 44 struct passwd *pwd; 59 const char * const *p;45 const char *shell; 60 46 #if ENABLE_FEATURE_SHADOWPASSWDS 61 struct spwd *spwd = NULL; 47 /* Using _r function to avoid pulling in static buffers */ 48 char buffer[256]; 49 struct spwd spw; 50 struct spwd *result; 62 51 #endif 63 52 64 openlog("sulogin", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); 65 if (argc > 1) { 66 if (strncmp(argv[1], "-t", 2) == 0) { 67 if (argv[1][2] == '\0') { /* -t NN */ 68 if (argc > 2) { 69 timeout = atoi(argv[2]); 70 if (argc > 3) { 71 device = argv[3]; 72 } 73 } 74 } else { /* -tNNN */ 75 timeout = atoi(&argv[1][2]); 76 if (argc > 2) { 77 device = argv[2]; 78 } 79 } 80 } else { 81 device = argv[1]; 82 } 83 if (device) { 84 close(0); 85 close(1); 86 close(2); 87 if (open(device, O_RDWR) == 0) { 88 dup(0); 89 dup(0); 90 } else { 91 syslog(LOG_WARNING, "cannot open %s\n", device); 92 exit(EXIT_FAILURE); 93 } 94 } 95 } 96 if (access(bb_path_passwd_file, 0) == -1) { 97 syslog(LOG_WARNING, "No password file\n"); 98 bb_error_msg_and_die("No password file\n"); 99 } 100 if (!isatty(0) || !isatty(1) || !isatty(2)) { 101 exit(EXIT_FAILURE); 53 logmode = LOGMODE_BOTH; 54 openlog(applet_name, 0, LOG_AUTH); 55 56 if (getopt32(argv, "t:", &timeout_arg)) { 57 timeout = xatoi_u(timeout_arg); 102 58 } 103 59 60 if (argv[optind]) { 61 close(0); 62 close(1); 63 dup(xopen(argv[optind], O_RDWR)); 64 close(2); 65 dup(0); 66 } 67 68 if (!isatty(0) || !isatty(1) || !isatty(2)) { 69 logmode = LOGMODE_SYSLOG; 70 bb_error_msg_and_die("not a tty"); 71 } 104 72 105 73 /* Clear out anything dangerous from the environment */ … … 107 75 unsetenv(*p); 108 76 77 signal(SIGALRM, catchalarm); 109 78 110 signal(SIGALRM, catchalarm); 111 if (!(pwd = getpwnam(name))) { 112 syslog(LOG_WARNING, "No password entry for `root'\n"); 113 bb_error_msg_and_die("No password entry for `root'\n"); 79 pwd = getpwuid(0); 80 if (!pwd) { 81 goto auth_error; 114 82 } 115 pwent = *pwd; 83 116 84 #if ENABLE_FEATURE_SHADOWPASSWDS 117 spwd = NULL; 118 if (pwd && ((strcmp(pwd->pw_passwd, "x") == 0) 119 || (strcmp(pwd->pw_passwd, "*") == 0))) { 120 endspent(); 121 spwd = getspnam(name); 122 if (spwd) { 123 pwent.pw_passwd = spwd->sp_pwdp; 85 if (getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result)) { 86 goto auth_error; 87 } 88 pwd->pw_passwd = spw.sp_pwdp; 89 #endif 90 91 while (1) { 92 /* cp points to a static buffer that is zeroed every time */ 93 cp = bb_askpass(timeout, 94 "Give root password for system maintenance\n" 95 "(or type Control-D for normal startup):"); 96 97 if (!cp || !*cp) { 98 bb_info_msg("Normal startup"); 99 return 0; 124 100 } 125 } 126 #endif 127 while (1) { 128 cp = bb_askpass(timeout, SULOGIN_PROMPT); 129 if (!cp || !*cp) { 130 puts("\n"); 131 fflush(stdout); 132 syslog(LOG_INFO, "Normal startup\n"); 133 exit(EXIT_SUCCESS); 134 } else { 135 safe_strncpy(pass, cp, sizeof(pass)); 136 memset(cp, 0, strlen(cp)); 137 } 138 if (strcmp(pw_encrypt(pass, pwent.pw_passwd), pwent.pw_passwd) == 0) { 101 if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) { 139 102 break; 140 103 } 141 104 bb_do_delay(FAIL_DELAY); 142 puts("Login incorrect"); 143 fflush(stdout); 144 syslog(LOG_WARNING, "Incorrect root password\n"); 105 bb_error_msg("login incorrect"); 145 106 } 146 memset( pass, 0, strlen(pass));107 memset(cp, 0, strlen(cp)); 147 108 signal(SIGALRM, SIG_DFL); 148 puts("Entering System Maintenance Mode\n");149 fflush(stdout);150 syslog(LOG_INFO, "System Maintenance Mode\n");151 109 152 #if ENABLE_SELINUX 153 renew_current_security_context(); 154 #endif 110 bb_info_msg("System Maintenance Mode"); 155 111 156 run_shell(pwent.pw_shell, 1, 0, 0);112 USE_SELINUX(renew_current_security_context()); 157 113 158 return (0); 114 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 */ 123 124 auth_error: 125 bb_error_msg_and_die("no password entry for 'root'"); 159 126 } -
branches/stable/mindi-busybox/loginutils/vlock.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 2 3 /* 3 4 * vlock implementation for busybox … … 16 17 * It now works with md5, sha1, etc passwords. */ 17 18 18 #include <stdio.h> 19 #include <stdlib.h> 19 #include "libbb.h" 20 20 #include <sys/vt.h> 21 #include <signal.h>22 #include <string.h>23 #include <unistd.h>24 #include <fcntl.h>25 #include <errno.h>26 #include <sys/ioctl.h>27 #include <termios.h>28 29 #include "busybox.h"30 21 31 22 static struct passwd *pw; … … 37 28 static void release_vt(int signo) 38 29 { 39 if (!o_lock_all) 40 ioctl(vfd, VT_RELDISP, 1); 41 else 42 ioctl(vfd, VT_RELDISP, 0); 30 ioctl(vfd, VT_RELDISP, !o_lock_all); 43 31 } 44 32 … … 54 42 } 55 43 44 int vlock_main(int argc, char **argv); 56 45 int vlock_main(int argc, char **argv) 57 46 { … … 60 49 struct vt_mode vtm; 61 50 struct termios term; 51 uid_t uid = getuid(); 52 53 pw = getpwuid(uid); 54 if (pw == NULL) 55 bb_error_msg_and_die("unknown uid %d", uid); 62 56 63 57 if (argc > 2) { … … 65 59 } 66 60 67 o_lock_all = bb_getopt_ulflags (argc,argv, "a");61 o_lock_all = getopt32(argv, "a"); 68 62 69 if((pw = getpwuid(getuid())) == NULL) { 70 bb_error_msg_and_die("Unknown uid %d", getuid()); 71 } 63 vfd = xopen(CURRENT_TTY, O_RDWR); 72 64 73 vfd = bb_xopen(CURRENT_TTY, O_RDWR); 74 75 if (ioctl(vfd, VT_GETMODE, &vtm) < 0) { 76 bb_perror_msg_and_die("VT_GETMODE"); 77 } 65 xioctl(vfd, VT_GETMODE, &vtm); 78 66 79 67 /* mask a bunch of signals */ … … 118 106 119 107 do { 120 printf("Virtual Console%s locked.\n%s's ", (o_lock_all) ? "s" : "", pw->pw_name); 121 fflush(stdout); 122 if (correct_password (pw)) { 108 printf("Virtual Console%s locked by %s.\n", (o_lock_all) ? "s" : "", pw->pw_name); 109 if (correct_password(pw)) { 123 110 break; 124 111 } 125 112 bb_do_delay(FAIL_DELAY); 126 puts("Password incorrect .");113 puts("Password incorrect"); 127 114 } while (1); 128 115 restore_terminal(); 129 return 0;116 fflush_stdout_and_exit(0); 130 117 }
Note:
See TracChangeset
for help on using the changeset viewer.