aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-09-08 17:29:53 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-09-08 17:29:53 +0000
commit9a9edf200b797a92380b634d57dec6cd9410919f (patch)
tree392722803ffdcd6165fe15e191349a7e246a0481
parent6bbd174593d1e116351a9402b5bd237afbe3cb89 (diff)
downloadbusybox-w32-9a9edf200b797a92380b634d57dec6cd9410919f.tar.gz
busybox-w32-9a9edf200b797a92380b634d57dec6cd9410919f.tar.bz2
busybox-w32-9a9edf200b797a92380b634d57dec6cd9410919f.zip
login: make it saner and smaller by ~0.5k.
-rw-r--r--loginutils/login.c316
1 files changed, 131 insertions, 185 deletions
diff --git a/loginutils/login.c b/loginutils/login.c
index c05ec066a..19f865550 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -29,59 +29,59 @@
29 29
30#ifdef CONFIG_FEATURE_UTMP 30#ifdef CONFIG_FEATURE_UTMP
31// import from utmp.c 31// import from utmp.c
32static void checkutmp(int picky);
33static void setutmp(const char *name, const char *line);
34/* Stuff global to this file */
35static struct utmp utent; 32static struct utmp utent;
33static void read_or_build_utent(int picky);
34static void write_utent(const char *username);
36#endif 35#endif
37 36
38enum { 37enum {
39 TIMEOUT = 60, 38 TIMEOUT = 60,
40 EMPTY_USERNAME_COUNT = 10, 39 EMPTY_USERNAME_COUNT = 10,
41 USERNAME_SIZE = 32, 40 USERNAME_SIZE = 32,
41 TTYNAME_SIZE = 32,
42}; 42};
43 43
44static int check_nologin(int amroot); 44static void die_if_nologin_and_non_root(int amroot);
45 45
46#if defined CONFIG_FEATURE_SECURETTY 46#if defined CONFIG_FEATURE_SECURETTY
47static int check_tty(const char *tty); 47static int check_securetty(void);
48 48
49#else 49#else
50static inline int check_tty(const char *tty) { return 1; } 50static inline int check_securetty(void) { return 1; }
51 51
52#endif 52#endif
53 53
54static int is_my_tty(const char *tty); 54static int is_my_tty(void);
55static int login_prompt(char *buf_name); 55static void get_username_or_die(char *buf, int size_buf);
56static void motd(void); 56static void motd(void);
57 57
58 58
59static void alarm_handler(int sig ATTRIBUTE_UNUSED) 59static void alarm_handler(int sig ATTRIBUTE_UNUSED)
60{ 60{
61 fprintf(stderr, "\r\nLogin timed out after %s seconds\r\n", TIMEOUT); 61 fprintf(stderr, "\r\nLogin timed out after %d seconds\r\n", TIMEOUT);
62 exit(EXIT_SUCCESS); 62 exit(EXIT_SUCCESS);
63} 63}
64 64
65 65
66static char full_tty[TTYNAME_SIZE];
67static char* short_tty = full_tty;
68
69
66int login_main(int argc, char **argv) 70int login_main(int argc, char **argv)
67{ 71{
68 char tty[BUFSIZ];
69 char full_tty[200];
70 char fromhost[512]; 72 char fromhost[512];
71 char username[USERNAME_SIZE]; 73 char username[USERNAME_SIZE];
72 const char *tmp; 74 const char *tmp;
73 int amroot; 75 int amroot;
74 int flag; 76 int flag;
75 int failed;
76 int count = 0; 77 int count = 0;
77 struct passwd *pw, pw_copy; 78 struct passwd *pw;
78#ifdef CONFIG_WHEEL_GROUP 79#ifdef CONFIG_WHEEL_GROUP
79 struct group *grp; 80 struct group *grp;
80#endif 81#endif
81 int opt_preserve = 0; 82 int opt_preserve = 0;
82 int opt_fflag = 0; 83 int opt_fflag = 0;
83 char *opt_host = 0; 84 char *opt_host = 0;
84 int alarmstarted = 0;
85#ifdef CONFIG_SELINUX 85#ifdef CONFIG_SELINUX
86 security_context_t user_sid = NULL; 86 security_context_t user_sid = NULL;
87#endif 87#endif
@@ -90,7 +90,6 @@ int login_main(int argc, char **argv)
90 amroot = (getuid() == 0); 90 amroot = (getuid() == 0);
91 signal(SIGALRM, alarm_handler); 91 signal(SIGALRM, alarm_handler);
92 alarm(TIMEOUT); 92 alarm(TIMEOUT);
93 alarmstarted = 1;
94 93
95 while ((flag = getopt(argc, argv, "f:h:p")) != EOF) { 94 while ((flag = getopt(argc, argv, "f:h:p")) != EOF) {
96 switch (flag) { 95 switch (flag) {
@@ -105,10 +104,10 @@ int login_main(int argc, char **argv)
105 if (optarg != argv[optind-1]) 104 if (optarg != argv[optind-1])
106 bb_show_usage(); 105 bb_show_usage();
107 106
108 if (!amroot) /* Auth bypass only if real UID is zero */ 107 if (!amroot) /* Auth bypass only if real UID is zero */
109 bb_error_msg_and_die("-f permission denied"); 108 bb_error_msg_and_die("-f is for root only");
110 109
111 safe_strncpy(username, optarg, USERNAME_SIZE); 110 safe_strncpy(username, optarg, sizeof(username));
112 opt_fflag = 1; 111 opt_fflag = 1;
113 break; 112 break;
114 case 'h': 113 case 'h':
@@ -118,113 +117,83 @@ int login_main(int argc, char **argv)
118 bb_show_usage(); 117 bb_show_usage();
119 } 118 }
120 } 119 }
121
122 if (optind < argc) /* user from command line (getty) */ 120 if (optind < argc) /* user from command line (getty) */
123 safe_strncpy(username, argv[optind], USERNAME_SIZE); 121 safe_strncpy(username, argv[optind], sizeof(username));
124 122
123 /* Let's find out and memorize our tty */
125 if (!isatty(0) || !isatty(1) || !isatty(2)) 124 if (!isatty(0) || !isatty(1) || !isatty(2))
126 return EXIT_FAILURE; /* Must be a terminal */ 125 return EXIT_FAILURE; /* Must be a terminal */
127 126 safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty));
128#ifdef CONFIG_FEATURE_UTMP
129 checkutmp(!amroot);
130#endif
131
132 tmp = ttyname(0); 127 tmp = ttyname(0);
133 if (tmp && (strncmp(tmp, "/dev/", 5) == 0)) 128 if (tmp) {
134 safe_strncpy(tty, tmp + 5, sizeof(tty)); 129 safe_strncpy(full_tty, tmp, sizeof(full_tty));
135 else if (tmp && *tmp == '/') 130 if (strncmp(full_tty, "/dev/", 5) == 0)
136 safe_strncpy(tty, tmp, sizeof(tty)); 131 short_tty = full_tty + 5;
137 else 132 }
138 safe_strncpy(tty, "UNKNOWN", sizeof(tty));
139 133
140#ifdef CONFIG_FEATURE_UTMP 134 if (ENABLE_FEATURE_UTMP) {
141 if (amroot) 135 read_or_build_utent(!amroot);
142 memset(utent.ut_host, 0, sizeof(utent.ut_host)); 136 if (amroot)
143#endif 137 memset(utent.ut_host, 0, sizeof(utent.ut_host));
138 }
144 139
145 if (opt_host) { 140 if (opt_host) {
146#ifdef CONFIG_FEATURE_UTMP 141 if (ENABLE_FEATURE_UTMP)
147 safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host)); 142 safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
148#endif
149 snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s' from " 143 snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s' from "
150 "`%.200s'", tty, opt_host); 144 "`%.200s'", short_tty, opt_host);
151 } 145 }
152 else 146 else
153 snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s'", tty); 147 snprintf(fromhost, sizeof(fromhost)-1, " on `%.100s'", short_tty);
154 148
155 bb_setpgrp; 149 bb_setpgrp;
156 150
157 openlog(bb_applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); 151 openlog(bb_applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
158 152
159 while (1) { 153 while (1) {
160 failed = 0;
161
162 if (!username[0]) 154 if (!username[0])
163 if (!login_prompt(username)) 155 get_username_or_die(username, sizeof(username));
164 return EXIT_FAILURE;
165
166 if (!alarmstarted && (TIMEOUT > 0)) {
167 alarm(TIMEOUT);
168 alarmstarted = 1;
169 }
170 156
171 pw = getpwnam(username); 157 pw = getpwnam(username);
172 if (!pw) { 158 if (!pw) {
173 pw_copy.pw_name = "UNKNOWN"; 159 safe_strncpy(username, "UNKNOWN", sizeof(username));
174 pw_copy.pw_passwd = "!"; 160 goto auth_failed;
175 opt_fflag = 0; 161 }
176 failed = 1;
177 } else
178 pw_copy = *pw;
179
180 pw = &pw_copy;
181 162
182 if ((pw->pw_passwd[0] == '!') || (pw->pw_passwd[0] == '*')) 163 if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
183 failed = 1; 164 goto auth_failed;
184 165
185 if (opt_fflag) { 166 if (opt_fflag)
186 opt_fflag = 0; 167 break; /* -f USER: success without asking passwd */
187 goto auth_ok;
188 }
189 168
190 if (!failed && (pw->pw_uid == 0) && (!check_tty(tty))) 169 if (pw->pw_uid == 0 && !check_securetty())
191 failed = 1; 170 goto auth_failed;
192 171
193 /* Don't check the password if password entry is empty (!) */ 172 /* Don't check the password if password entry is empty (!) */
194 if (!pw->pw_passwd[0]) 173 if (!pw->pw_passwd[0])
195 goto auth_ok; 174 break;
196 175
197 /* authorization takes place here */ 176 /* authorization takes place here */
198 if (correct_password(pw)) 177 if (correct_password(pw))
199 goto auth_ok; 178 break;
200
201 failed = 1;
202
203auth_ok:
204 if (!failed)
205 break;
206 179
180auth_failed:
181 opt_fflag = 0;
207 bb_do_delay(FAIL_DELAY); 182 bb_do_delay(FAIL_DELAY);
208 puts("Login incorrect"); 183 puts("Login incorrect");
209 username[0] = 0;
210 if (++count == 3) { 184 if (++count == 3) {
211 syslog(LOG_WARNING, "invalid password for `%s'%s", pw->pw_name, fromhost); 185 syslog(LOG_WARNING, "invalid password for `%s'%s",
186 username, fromhost);
212 return EXIT_FAILURE; 187 return EXIT_FAILURE;
213 } 188 }
189 username[0] = '\0';
214 } 190 }
215 191
216 alarm(0); 192 alarm(0);
217 if (check_nologin(pw->pw_uid == 0)) 193 die_if_nologin_and_non_root(pw->pw_uid == 0);
218 return EXIT_FAILURE;
219
220#ifdef CONFIG_FEATURE_UTMP
221 setutmp(username, tty);
222#endif
223 194
224 if (*tty != '/') 195 if (ENABLE_FEATURE_UTMP)
225 snprintf(full_tty, sizeof(full_tty)-1, "/dev/%s", tty); 196 write_utent(username);
226 else
227 safe_strncpy(full_tty, tty, sizeof(full_tty)-1);
228 197
229#ifdef CONFIG_SELINUX 198#ifdef CONFIG_SELINUX
230 if (is_selinux_enabled()) { 199 if (is_selinux_enabled()) {
@@ -249,7 +218,7 @@ auth_ok:
249 } 218 }
250 } 219 }
251#endif 220#endif
252 if (!is_my_tty(full_tty)) 221 if (!is_my_tty())
253 syslog(LOG_ERR, "unable to determine TTY name, got %s", full_tty); 222 syslog(LOG_ERR, "unable to determine TTY name, got %s", full_tty);
254 223
255 /* Try these, but don't complain if they fail 224 /* Try these, but don't complain if they fail
@@ -300,96 +269,91 @@ auth_ok:
300} 269}
301 270
302 271
303static int login_prompt(char *buf_name) 272static void get_username_or_die(char *buf, int size_buf)
304{ 273{
305 char buf[1024]; 274 int c, cntdown;
306 char *sp, *ep; 275 cntdown = EMPTY_USERNAME_COUNT;
307 int i; 276prompt:
308 277 /* skip whitespace */
309 for (i=0; i<EMPTY_USERNAME_COUNT; i++) { 278 print_login_prompt();
310 print_login_prompt(); 279 do {
311 280 c = getchar();
312 if (!fgets(buf, sizeof(buf)-1, stdin)) 281 if (c == EOF) exit(1);
313 return 0; 282 if (c == '\n') {
314 283 if (!--cntdown) exit(1);
315 if (!strchr(buf, '\n')) 284 goto prompt;
316 return 0; 285 }
317 286 } while (isspace(c));
318 for (sp = buf; isspace(*sp); sp++) { } 287
319 for (ep = sp; isgraph(*ep); ep++) { } 288 *buf++ = c;
320 289 if (!fgets(buf, size_buf-2, stdin))
321 *ep = '\0'; 290 exit(1);
322 safe_strncpy(buf_name, sp, USERNAME_SIZE); 291 if (!strchr(buf, '\n'))
323 if (buf_name[0]) 292 exit(1);
324 return 1; 293 while (isgraph(*buf)) buf++;
325 } 294 *buf = '\0';
326 return 0;
327} 295}
328 296
329 297
330static int check_nologin(int amroot) 298static void die_if_nologin_and_non_root(int amroot)
331{ 299{
332 if (access(bb_path_nologin_file, F_OK) == 0) { 300 FILE *fp;
333 FILE *fp; 301 int c;
334 int c;
335
336 fp = fopen(bb_path_nologin_file, "r");
337 if (fp) {
338 while ((c = getc(fp)) != EOF)
339 putchar((c=='\n') ? '\r' : c);
340 302
341 fflush(stdout); 303 if (access(bb_path_nologin_file, F_OK))
342 fclose(fp); 304 return;
343 } else {
344 puts("\r\nSystem closed for routine maintenance.\r");
345 }
346 if (!amroot)
347 return 1;
348 305
349 puts("\r\n[Disconnect bypassed -- root login allowed.]\r"); 306 fp = fopen(bb_path_nologin_file, "r");
350 } 307 if (fp) {
351 return 0; 308 while ((c = getc(fp)) != EOF)
309 putchar((c=='\n') ? '\r' : c);
310 fflush(stdout);
311 fclose(fp);
312 } else
313 puts("\r\nSystem closed for routine maintenance\r");
314 if (!amroot)
315 exit(1);
316 puts("\r\n[Disconnect bypassed -- root login allowed.]\r");
352} 317}
353 318
354#ifdef CONFIG_FEATURE_SECURETTY 319#ifdef CONFIG_FEATURE_SECURETTY
355 320
356static int check_tty(const char *tty) 321static int check_securetty(void)
357{ 322{
358 FILE *fp; 323 FILE *fp;
359 int i; 324 int i;
360 char buf[BUFSIZ]; 325 char buf[BUFSIZ];
361 326
362 fp = fopen(bb_path_securetty_file, "r"); 327 fp = fopen(bb_path_securetty_file, "r");
363 if (fp) { 328 if (!fp) {
364 while (fgets(buf, sizeof(buf)-1, fp)) { 329 /* A missing securetty file is not an error. */
365 for(i = strlen(buf)-1; i>=0; --i) { 330 return 1;
366 if (!isspace(buf[i])) 331 }
367 break; 332 while (fgets(buf, sizeof(buf)-1, fp)) {
368 } 333 for(i = strlen(buf)-1; i>=0; --i) {
369 buf[++i] = '\0'; 334 if (!isspace(buf[i]))
370 if ((buf[0]=='\0') || (buf[0]=='#')) 335 break;
371 continue; 336 }
372 337 buf[++i] = '\0';
373 if (strcmp(buf, tty)== 0) { 338 if ((buf[0]=='\0') || (buf[0]=='#'))
374 fclose(fp); 339 continue;
375 return 1; 340 if (strcmp(buf, short_tty) == 0) {
376 } 341 fclose(fp);
342 return 1;
377 } 343 }
378 fclose(fp);
379 return 0;
380 } 344 }
381 /* A missing securetty file is not an error. */ 345 fclose(fp);
382 return 1; 346 return 0;
383} 347}
384 348
385#endif 349#endif
386 350
387/* returns 1 if true */ 351/* returns 1 if true */
388static int is_my_tty(const char *tty) 352static int is_my_tty(void)
389{ 353{
390 struct stat by_name, by_fd; 354 struct stat by_name, by_fd;
391 355
392 if (stat(tty, &by_name) || fstat(0, &by_fd)) 356 if (stat(full_tty, &by_name) || fstat(0, &by_fd))
393 return 0; 357 return 0;
394 358
395 if (by_name.st_rdev != by_fd.st_rdev) 359 if (by_name.st_rdev != by_fd.st_rdev)
@@ -414,15 +378,10 @@ static void motd(void)
414 378
415 379
416#ifdef CONFIG_FEATURE_UTMP 380#ifdef CONFIG_FEATURE_UTMP
417// vv Taken from tinylogin utmp.c vv 381/* vv Taken from tinylogin utmp.c vv */
418
419#define NO_UTENT \
420 "No utmp entry. You must exec \"login\" from the lowest level \"sh\""
421#define NO_TTY \
422 "Unable to determine your tty name."
423 382
424/* 383/*
425 * checkutmp - see if utmp file is correct for this process 384 * read_or_build_utent - see if utmp file is correct for this process
426 * 385 *
427 * System V is very picky about the contents of the utmp file 386 * System V is very picky about the contents of the utmp file
428 * and requires that a slot for the current process exist. 387 * and requires that a slot for the current process exist.
@@ -435,9 +394,8 @@ static void motd(void)
435 * command line flags. 394 * command line flags.
436 */ 395 */
437 396
438static void checkutmp(int picky) 397static void read_or_build_utent(int picky)
439{ 398{
440 char *line;
441 struct utmp *ut; 399 struct utmp *ut;
442 pid_t pid = getpid(); 400 pid_t pid = getpid();
443 401
@@ -446,53 +404,41 @@ static void checkutmp(int picky)
446 /* First, try to find a valid utmp entry for this process. */ 404 /* First, try to find a valid utmp entry for this process. */
447 while ((ut = getutent())) 405 while ((ut = getutent()))
448 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && 406 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
449 (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) 407 (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
450 break; 408 break;
451 409
452 /* If there is one, just use it, otherwise create a new one. */ 410 /* If there is one, just use it, otherwise create a new one. */
453 if (ut) { 411 if (ut) {
454 utent = *ut; 412 utent = *ut;
455 } else { 413 } else {
456 time_t t_tmp; 414 if (picky)
457 415 bb_error_msg_and_die("no utmp entry found");
458 if (picky) { 416
459 puts(NO_UTENT);
460 exit(1);
461 }
462 line = ttyname(0);
463 if (!line) {
464 puts(NO_TTY);
465 exit(1);
466 }
467 if (strncmp(line, "/dev/", 5) == 0)
468 line += 5;
469 memset(&utent, 0, sizeof(utent)); 417 memset(&utent, 0, sizeof(utent));
470 utent.ut_type = LOGIN_PROCESS; 418 utent.ut_type = LOGIN_PROCESS;
471 utent.ut_pid = pid; 419 utent.ut_pid = pid;
472 strncpy(utent.ut_line, line, sizeof(utent.ut_line)); 420 strncpy(utent.ut_line, short_tty, sizeof(utent.ut_line));
473 /* XXX - assumes /dev/tty?? */ 421 /* This one is only 4 chars wide. Try to fit something
474 strncpy(utent.ut_id, utent.ut_line + 3, sizeof(utent.ut_id)); 422 * remotely meaningful by skipping "tty"... */
423 strncpy(utent.ut_id, short_tty + 3, sizeof(utent.ut_id));
475 strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user)); 424 strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user));
476 t_tmp = (time_t)utent.ut_time; 425 utent.ut_time = time(NULL);
477 time(&t_tmp);
478 } 426 }
479} 427}
480 428
481/* 429/*
482 * setutmp - put a USER_PROCESS entry in the utmp file 430 * write_utent - put a USER_PROCESS entry in the utmp file
483 * 431 *
484 * setutmp changes the type of the current utmp entry to 432 * write_utent changes the type of the current utmp entry to
485 * USER_PROCESS. the wtmp file will be updated as well. 433 * USER_PROCESS. the wtmp file will be updated as well.
486 */ 434 */
487 435
488static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED) 436static void write_utent(const char *username)
489{ 437{
490 time_t t_tmp = (time_t)utent.ut_time;
491
492 utent.ut_type = USER_PROCESS; 438 utent.ut_type = USER_PROCESS;
493 strncpy(utent.ut_user, name, sizeof(utent.ut_user)); 439 strncpy(utent.ut_user, username, sizeof(utent.ut_user));
494 time(&t_tmp); 440 utent.ut_time = time(NULL);
495 /* other fields already filled in by checkutmp above */ 441 /* other fields already filled in by read_or_build_utent above */
496 setutent(); 442 setutent();
497 pututline(&utent); 443 pututline(&utent);
498 endutent(); 444 endutent();