diff options
-rw-r--r-- | loginutils/login.c | 357 |
1 files changed, 166 insertions, 191 deletions
diff --git a/loginutils/login.c b/loginutils/login.c index 2c23a8d50..78a2ba117 100644 --- a/loginutils/login.c +++ b/loginutils/login.c | |||
@@ -15,13 +15,6 @@ | |||
15 | #include <errno.h> | 15 | #include <errno.h> |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | /* import from utmp.c | ||
19 | * XXX: FIXME: provide empty bodies if ENABLE_FEATURE_UTMP == 0 | ||
20 | */ | ||
21 | static struct utmp utent; | ||
22 | static void read_or_build_utent(int); | ||
23 | static void write_utent(const char *); | ||
24 | |||
25 | enum { | 18 | enum { |
26 | TIMEOUT = 60, | 19 | TIMEOUT = 60, |
27 | EMPTY_USERNAME_COUNT = 10, | 20 | EMPTY_USERNAME_COUNT = 10, |
@@ -29,16 +22,176 @@ enum { | |||
29 | TTYNAME_SIZE = 32, | 22 | TTYNAME_SIZE = 32, |
30 | }; | 23 | }; |
31 | 24 | ||
32 | static void die_if_nologin_and_non_root(int amroot); | 25 | static char full_tty[TTYNAME_SIZE]; |
26 | static char* short_tty = full_tty; | ||
27 | |||
28 | #if ENABLE_FEATURE_UTMP | ||
29 | /* vv Taken from tinylogin utmp.c vv */ | ||
30 | /* | ||
31 | * read_or_build_utent - see if utmp file is correct for this process | ||
32 | * | ||
33 | * System V is very picky about the contents of the utmp file | ||
34 | * and requires that a slot for the current process exist. | ||
35 | * The utmp file is scanned for an entry with the same process | ||
36 | * ID. If no entry exists the process exits with a message. | ||
37 | * | ||
38 | * The "picky" flag is for network and other logins that may | ||
39 | * use special flags. It allows the pid checks to be overridden. | ||
40 | * This means that getty should never invoke login with any | ||
41 | * command line flags. | ||
42 | */ | ||
43 | static struct utmp utent; | ||
44 | static void read_or_build_utent(int picky) | ||
45 | { | ||
46 | struct utmp *ut; | ||
47 | pid_t pid = getpid(); | ||
48 | |||
49 | setutent(); | ||
50 | |||
51 | /* First, try to find a valid utmp entry for this process. */ | ||
52 | while ((ut = getutent())) | ||
53 | if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && | ||
54 | (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) | ||
55 | break; | ||
56 | |||
57 | /* If there is one, just use it, otherwise create a new one. */ | ||
58 | if (ut) { | ||
59 | utent = *ut; | ||
60 | } else { | ||
61 | if (picky) | ||
62 | bb_error_msg_and_die("no utmp entry found"); | ||
63 | |||
64 | memset(&utent, 0, sizeof(utent)); | ||
65 | utent.ut_type = LOGIN_PROCESS; | ||
66 | utent.ut_pid = pid; | ||
67 | strncpy(utent.ut_line, short_tty, sizeof(utent.ut_line)); | ||
68 | /* This one is only 4 chars wide. Try to fit something | ||
69 | * remotely meaningful by skipping "tty"... */ | ||
70 | strncpy(utent.ut_id, short_tty + 3, sizeof(utent.ut_id)); | ||
71 | strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user)); | ||
72 | utent.ut_time = time(NULL); | ||
73 | } | ||
74 | if (!picky) /* root login */ | ||
75 | memset(utent.ut_host, 0, sizeof(utent.ut_host)); | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * write_utent - put a USER_PROCESS entry in the utmp file | ||
80 | * | ||
81 | * write_utent changes the type of the current utmp entry to | ||
82 | * USER_PROCESS. the wtmp file will be updated as well. | ||
83 | */ | ||
84 | static void write_utent(const char *username) | ||
85 | { | ||
86 | utent.ut_type = USER_PROCESS; | ||
87 | strncpy(utent.ut_user, username, sizeof(utent.ut_user)); | ||
88 | utent.ut_time = time(NULL); | ||
89 | /* other fields already filled in by read_or_build_utent above */ | ||
90 | setutent(); | ||
91 | pututline(&utent); | ||
92 | endutent(); | ||
93 | #if ENABLE_FEATURE_WTMP | ||
94 | if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { | ||
95 | close(creat(bb_path_wtmp_file, 0664)); | ||
96 | } | ||
97 | updwtmp(bb_path_wtmp_file, &utent); | ||
98 | #endif | ||
99 | } | ||
100 | #else /* !CONFIG_FEATURE_UTMP */ | ||
101 | static inline void read_or_build_utent(int) {} | ||
102 | static inline void write_utent(const char *) {} | ||
103 | #endif /* !CONFIG_FEATURE_UTMP */ | ||
104 | |||
105 | static void die_if_nologin_and_non_root(int amroot) | ||
106 | { | ||
107 | FILE *fp; | ||
108 | int c; | ||
109 | |||
110 | if (access(bb_path_nologin_file, F_OK)) | ||
111 | return; | ||
112 | |||
113 | fp = fopen(bb_path_nologin_file, "r"); | ||
114 | if (fp) { | ||
115 | while ((c = getc(fp)) != EOF) | ||
116 | putchar((c=='\n') ? '\r' : c); | ||
117 | fflush(stdout); | ||
118 | fclose(fp); | ||
119 | } else | ||
120 | puts("\r\nSystem closed for routine maintenance\r"); | ||
121 | if (!amroot) | ||
122 | exit(1); | ||
123 | puts("\r\n[Disconnect bypassed -- root login allowed.]\r"); | ||
124 | } | ||
33 | 125 | ||
34 | #if ENABLE_FEATURE_SECURETTY | 126 | #if ENABLE_FEATURE_SECURETTY |
35 | static int check_securetty(void); | 127 | static int check_securetty(void) |
128 | { | ||
129 | FILE *fp; | ||
130 | int i; | ||
131 | char buf[BUFSIZ]; | ||
132 | |||
133 | fp = fopen(bb_path_securetty_file, "r"); | ||
134 | if (!fp) { | ||
135 | /* A missing securetty file is not an error. */ | ||
136 | return 1; | ||
137 | } | ||
138 | while (fgets(buf, sizeof(buf)-1, fp)) { | ||
139 | for(i = strlen(buf)-1; i>=0; --i) { | ||
140 | if (!isspace(buf[i])) | ||
141 | break; | ||
142 | } | ||
143 | buf[++i] = '\0'; | ||
144 | if ((buf[0]=='\0') || (buf[0]=='#')) | ||
145 | continue; | ||
146 | if (strcmp(buf, short_tty) == 0) { | ||
147 | fclose(fp); | ||
148 | return 1; | ||
149 | } | ||
150 | } | ||
151 | fclose(fp); | ||
152 | return 0; | ||
153 | } | ||
36 | #else | 154 | #else |
37 | static inline int check_securetty(void) { return 1; } | 155 | static inline int check_securetty(void) { return 1; } |
38 | #endif | 156 | #endif |
39 | 157 | ||
40 | static void get_username_or_die(char *buf, int size_buf); | 158 | static void get_username_or_die(char *buf, int size_buf) |
41 | static void motd(void); | 159 | { |
160 | int c, cntdown; | ||
161 | cntdown = EMPTY_USERNAME_COUNT; | ||
162 | prompt: | ||
163 | /* skip whitespace */ | ||
164 | print_login_prompt(); | ||
165 | do { | ||
166 | c = getchar(); | ||
167 | if (c == EOF) exit(1); | ||
168 | if (c == '\n') { | ||
169 | if (!--cntdown) exit(1); | ||
170 | goto prompt; | ||
171 | } | ||
172 | } while (isspace(c)); | ||
173 | |||
174 | *buf++ = c; | ||
175 | if (!fgets(buf, size_buf-2, stdin)) | ||
176 | exit(1); | ||
177 | if (!strchr(buf, '\n')) | ||
178 | exit(1); | ||
179 | while (isgraph(*buf)) buf++; | ||
180 | *buf = '\0'; | ||
181 | } | ||
182 | |||
183 | static void motd(void) | ||
184 | { | ||
185 | FILE *fp; | ||
186 | int c; | ||
187 | |||
188 | fp = fopen(bb_path_motd_file, "r"); | ||
189 | if (fp) { | ||
190 | while ((c = getc(fp)) != EOF) | ||
191 | putchar(c); | ||
192 | fclose(fp); | ||
193 | } | ||
194 | } | ||
42 | 195 | ||
43 | static void nonblock(int fd) | 196 | static void nonblock(int fd) |
44 | { | 197 | { |
@@ -56,11 +209,6 @@ static void alarm_handler(int sig ATTRIBUTE_UNUSED) | |||
56 | exit(EXIT_SUCCESS); | 209 | exit(EXIT_SUCCESS); |
57 | } | 210 | } |
58 | 211 | ||
59 | |||
60 | static char full_tty[TTYNAME_SIZE]; | ||
61 | static char* short_tty = full_tty; | ||
62 | |||
63 | |||
64 | int login_main(int argc, char **argv) | 212 | int login_main(int argc, char **argv) |
65 | { | 213 | { |
66 | char fromhost[512]; | 214 | char fromhost[512]; |
@@ -122,11 +270,7 @@ int login_main(int argc, char **argv) | |||
122 | short_tty = full_tty + 5; | 270 | short_tty = full_tty + 5; |
123 | } | 271 | } |
124 | 272 | ||
125 | if (ENABLE_FEATURE_UTMP) { | 273 | read_or_build_utent(!amroot); |
126 | read_or_build_utent(!amroot); | ||
127 | if (amroot) | ||
128 | memset(utent.ut_host, 0, sizeof(utent.ut_host)); | ||
129 | } | ||
130 | 274 | ||
131 | if (opt_host) { | 275 | if (opt_host) { |
132 | if (ENABLE_FEATURE_UTMP) | 276 | if (ENABLE_FEATURE_UTMP) |
@@ -183,8 +327,7 @@ auth_failed: | |||
183 | alarm(0); | 327 | alarm(0); |
184 | die_if_nologin_and_non_root(pw->pw_uid == 0); | 328 | die_if_nologin_and_non_root(pw->pw_uid == 0); |
185 | 329 | ||
186 | if (ENABLE_FEATURE_UTMP) | 330 | write_utent(username); |
187 | write_utent(username); | ||
188 | 331 | ||
189 | #ifdef CONFIG_SELINUX | 332 | #ifdef CONFIG_SELINUX |
190 | if (is_selinux_enabled()) { | 333 | if (is_selinux_enabled()) { |
@@ -255,171 +398,3 @@ auth_failed: | |||
255 | 398 | ||
256 | return EXIT_FAILURE; | 399 | return EXIT_FAILURE; |
257 | } | 400 | } |
258 | |||
259 | |||
260 | static void get_username_or_die(char *buf, int size_buf) | ||
261 | { | ||
262 | int c, cntdown; | ||
263 | cntdown = EMPTY_USERNAME_COUNT; | ||
264 | prompt: | ||
265 | /* skip whitespace */ | ||
266 | print_login_prompt(); | ||
267 | do { | ||
268 | c = getchar(); | ||
269 | if (c == EOF) exit(1); | ||
270 | if (c == '\n') { | ||
271 | if (!--cntdown) exit(1); | ||
272 | goto prompt; | ||
273 | } | ||
274 | } while (isspace(c)); | ||
275 | |||
276 | *buf++ = c; | ||
277 | if (!fgets(buf, size_buf-2, stdin)) | ||
278 | exit(1); | ||
279 | if (!strchr(buf, '\n')) | ||
280 | exit(1); | ||
281 | while (isgraph(*buf)) buf++; | ||
282 | *buf = '\0'; | ||
283 | } | ||
284 | |||
285 | |||
286 | static void die_if_nologin_and_non_root(int amroot) | ||
287 | { | ||
288 | FILE *fp; | ||
289 | int c; | ||
290 | |||
291 | if (access(bb_path_nologin_file, F_OK)) | ||
292 | return; | ||
293 | |||
294 | fp = fopen(bb_path_nologin_file, "r"); | ||
295 | if (fp) { | ||
296 | while ((c = getc(fp)) != EOF) | ||
297 | putchar((c=='\n') ? '\r' : c); | ||
298 | fflush(stdout); | ||
299 | fclose(fp); | ||
300 | } else | ||
301 | puts("\r\nSystem closed for routine maintenance\r"); | ||
302 | if (!amroot) | ||
303 | exit(1); | ||
304 | puts("\r\n[Disconnect bypassed -- root login allowed.]\r"); | ||
305 | } | ||
306 | |||
307 | #if ENABLE_FEATURE_SECURETTY | ||
308 | |||
309 | static int check_securetty(void) | ||
310 | { | ||
311 | FILE *fp; | ||
312 | int i; | ||
313 | char buf[BUFSIZ]; | ||
314 | |||
315 | fp = fopen(bb_path_securetty_file, "r"); | ||
316 | if (!fp) { | ||
317 | /* A missing securetty file is not an error. */ | ||
318 | return 1; | ||
319 | } | ||
320 | while (fgets(buf, sizeof(buf)-1, fp)) { | ||
321 | for(i = strlen(buf)-1; i>=0; --i) { | ||
322 | if (!isspace(buf[i])) | ||
323 | break; | ||
324 | } | ||
325 | buf[++i] = '\0'; | ||
326 | if ((buf[0]=='\0') || (buf[0]=='#')) | ||
327 | continue; | ||
328 | if (strcmp(buf, short_tty) == 0) { | ||
329 | fclose(fp); | ||
330 | return 1; | ||
331 | } | ||
332 | } | ||
333 | fclose(fp); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | #endif | ||
338 | |||
339 | static void motd(void) | ||
340 | { | ||
341 | FILE *fp; | ||
342 | int c; | ||
343 | |||
344 | fp = fopen(bb_path_motd_file, "r"); | ||
345 | if (fp) { | ||
346 | while ((c = getc(fp)) != EOF) | ||
347 | putchar(c); | ||
348 | fclose(fp); | ||
349 | } | ||
350 | } | ||
351 | |||
352 | |||
353 | #if ENABLE_FEATURE_UTMP | ||
354 | /* vv Taken from tinylogin utmp.c vv */ | ||
355 | |||
356 | /* | ||
357 | * read_or_build_utent - see if utmp file is correct for this process | ||
358 | * | ||
359 | * System V is very picky about the contents of the utmp file | ||
360 | * and requires that a slot for the current process exist. | ||
361 | * The utmp file is scanned for an entry with the same process | ||
362 | * ID. If no entry exists the process exits with a message. | ||
363 | * | ||
364 | * The "picky" flag is for network and other logins that may | ||
365 | * use special flags. It allows the pid checks to be overridden. | ||
366 | * This means that getty should never invoke login with any | ||
367 | * command line flags. | ||
368 | */ | ||
369 | |||
370 | static void read_or_build_utent(int picky) | ||
371 | { | ||
372 | struct utmp *ut; | ||
373 | pid_t pid = getpid(); | ||
374 | |||
375 | setutent(); | ||
376 | |||
377 | /* First, try to find a valid utmp entry for this process. */ | ||
378 | while ((ut = getutent())) | ||
379 | if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && | ||
380 | (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)) | ||
381 | break; | ||
382 | |||
383 | /* If there is one, just use it, otherwise create a new one. */ | ||
384 | if (ut) { | ||
385 | utent = *ut; | ||
386 | } else { | ||
387 | if (picky) | ||
388 | bb_error_msg_and_die("no utmp entry found"); | ||
389 | |||
390 | memset(&utent, 0, sizeof(utent)); | ||
391 | utent.ut_type = LOGIN_PROCESS; | ||
392 | utent.ut_pid = pid; | ||
393 | strncpy(utent.ut_line, short_tty, sizeof(utent.ut_line)); | ||
394 | /* This one is only 4 chars wide. Try to fit something | ||
395 | * remotely meaningful by skipping "tty"... */ | ||
396 | strncpy(utent.ut_id, short_tty + 3, sizeof(utent.ut_id)); | ||
397 | strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user)); | ||
398 | utent.ut_time = time(NULL); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * write_utent - put a USER_PROCESS entry in the utmp file | ||
404 | * | ||
405 | * write_utent changes the type of the current utmp entry to | ||
406 | * USER_PROCESS. the wtmp file will be updated as well. | ||
407 | */ | ||
408 | |||
409 | static void write_utent(const char *username) | ||
410 | { | ||
411 | utent.ut_type = USER_PROCESS; | ||
412 | strncpy(utent.ut_user, username, sizeof(utent.ut_user)); | ||
413 | utent.ut_time = time(NULL); | ||
414 | /* other fields already filled in by read_or_build_utent above */ | ||
415 | setutent(); | ||
416 | pututline(&utent); | ||
417 | endutent(); | ||
418 | #if ENABLE_FEATURE_WTMP | ||
419 | if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { | ||
420 | close(creat(bb_path_wtmp_file, 0664)); | ||
421 | } | ||
422 | updwtmp(bb_path_wtmp_file, &utent); | ||
423 | #endif | ||
424 | } | ||
425 | #endif /* CONFIG_FEATURE_UTMP */ | ||