comparison toys/login.c @ 642:812afb883392

Minor cleanups, mostly whitespace.
author Rob Landley <rob@landley.net>
date Tue, 24 Jul 2012 02:52:36 -0500
parents 9aeea680acc7
children
comparison
equal deleted inserted replaced
641:94f189961631 642:812afb883392
28 #define LOGIN_FAIL_TIMEOUT 3 28 #define LOGIN_FAIL_TIMEOUT 3
29 #define USER_NAME_MAX_SIZE 32 29 #define USER_NAME_MAX_SIZE 32
30 #define HOSTNAME_SIZE 32 30 #define HOSTNAME_SIZE 32
31 31
32 DEFINE_GLOBALS( 32 DEFINE_GLOBALS(
33 char * hostname; 33 char *hostname;
34 ) 34 )
35 #define TT this.login 35 #define TT this.login
36 36
37 static void login_timeout_handler(int sig __attribute__((unused))) 37 static void login_timeout_handler(int sig __attribute__((unused)))
38 { 38 {
39 printf("\nLogin timed out after %d seconds.\n", LOGIN_TIMEOUT); 39 printf("\nLogin timed out after %d seconds.\n", LOGIN_TIMEOUT);
40 exit(0); 40 exit(0);
41 } 41 }
42 42
43 static const char *forbid[] = { 43 static char *forbid[] = {
44 "BASH_ENV", 44 "BASH_ENV",
45 "ENV", 45 "ENV",
46 "HOME", 46 "HOME",
47 "IFS", 47 "IFS",
48 "LD_LIBRARY_PATH", 48 "LD_LIBRARY_PATH",
55 "LD_KEEPDIR", 55 "LD_KEEPDIR",
56 "SHELL", 56 "SHELL",
57 NULL 57 NULL
58 }; 58 };
59 59
60 // Unset dangerous environment variables.
61 void sanitize_env()
62 {
63 const char **p = forbid;
64 do {
65 unsetenv(*p);
66 p++;
67 } while (*p);
68 }
69
70 int verify_password(char * pwd) 60 int verify_password(char * pwd)
71 { 61 {
72 char * pass; 62 char *pass;
73 63
74 if (read_password(toybuf, sizeof(toybuf), "Password: ")) 64 if (read_password(toybuf, sizeof(toybuf), "Password: ")) return 1;
75 return 1; 65 if (!pwd) return 1;
76 if (!pwd) 66 if (pwd[0] == '!' || pwd[0] == '*') return 1;
77 return 1;
78 if (pwd[0] == '!' || pwd[0] == '*')
79 return 1;
80 67
81 pass = crypt(toybuf, pwd); 68 pass = crypt(toybuf, pwd);
82 if (pass != NULL && strcmp(pass, pwd)==0) 69 if (pass && !strcmp(pass, pwd)) return 0;
83 return 0;
84 70
85 return 1; 71 return 1;
86 } 72 }
87 73
88 void read_user(char * buff, int size) 74 void read_user(char * buff, int size)
89 { 75 {
90 char hostname[HOSTNAME_SIZE+1]; 76 char hostname[HOSTNAME_SIZE+1];
91 int i = 0; 77 int i = 0;
92 hostname[HOSTNAME_SIZE] = 0; 78 hostname[HOSTNAME_SIZE] = 0;
93 if(!gethostname(hostname, HOSTNAME_SIZE)) 79 if(!gethostname(hostname, HOSTNAME_SIZE)) fputs(hostname, stdout);
94 fputs(hostname, stdout);
95 80
96 fputs(" login: ", stdout); 81 fputs(" login: ", stdout);
97 fflush(stdout); 82 fflush(stdout);
98 83
99 do { 84 do {
104 89
105 if (buff[0] != '\n') 90 if (buff[0] != '\n')
106 if(!fgets(&buff[1], HOSTNAME_SIZE-1, stdin)) 91 if(!fgets(&buff[1], HOSTNAME_SIZE-1, stdin))
107 _exit(1); 92 _exit(1);
108 93
109 while(i<HOSTNAME_SIZE-1 && isgraph(buff[i])) 94 while(i<HOSTNAME_SIZE-1 && isgraph(buff[i])) i++;
110 {
111 i++;
112 }
113 buff[i] = 0; 95 buff[i] = 0;
114 } 96 }
115 97
116 void handle_nologin(void) 98 void handle_nologin(void)
117 { 99 {
118 int fd = open("/etc/nologin", O_RDONLY); 100 int fd = open("/etc/nologin", O_RDONLY);
119 int size; 101 int size;
120 if (fd == -1) 102 if (fd == -1) return;
121 return;
122 103
123 size = readall(fd, toybuf,sizeof(toybuf)-1); 104 size = readall(fd, toybuf,sizeof(toybuf)-1);
124 toybuf[size] = 0; 105 toybuf[size] = 0;
125 if (!size) 106 if (!size) puts("System closed for routine maintenance\n");
126 puts("System closed for routine maintenance\n"); 107 else puts(toybuf);
127 else
128 puts(toybuf);
129 108
130 close(fd); 109 close(fd);
131 fflush(stdout); 110 fflush(stdout);
132 exit(EXIT_FAILURE); 111 exit(EXIT_FAILURE);
133 } 112 }
134 113
135 void handle_motd(void) 114 void handle_motd(void)
136 { 115 {
137 int fd = open("/etc/motd", O_RDONLY); 116 int fd = open("/etc/motd", O_RDONLY);
138 int size; 117 int size;
139 if (fd == -1) 118 if (fd == -1) return;
140 return;
141 119
142 size = readall(fd, toybuf,sizeof(toybuf)-1); 120 size = readall(fd, toybuf,sizeof(toybuf)-1);
143 toybuf[size] = 0; 121 toybuf[size] = 0;
144 puts(toybuf); 122 puts(toybuf);
145 123
147 fflush(stdout); 125 fflush(stdout);
148 } 126 }
149 127
150 int change_identity(const struct passwd *pwd) 128 int change_identity(const struct passwd *pwd)
151 { 129 {
152 if (initgroups(pwd->pw_name,pwd->pw_gid)) 130 if (initgroups(pwd->pw_name,pwd->pw_gid)) return 1;
153 return 1; 131 if (setgid(pwd->pw_uid)) return 1;
154 if (setgid(pwd->pw_uid)) 132 if (setuid(pwd->pw_uid)) return 1;
155 return 1;
156 if (setuid(pwd->pw_uid))
157 return 1;
158 133
159 return 0; 134 return 0;
160 } 135 }
161 136
162 void spawn_shell(const char *shell) 137 void spawn_shell(const char *shell)
163 { 138 {
164 const char * exec_name = strrchr(shell,'/'); 139 const char * exec_name = strrchr(shell,'/');
165 if (exec_name) 140 if (exec_name) exec_name++;
166 exec_name++; 141 else exec_name = shell;
167 else
168 exec_name = shell;
169 142
170 snprintf(toybuf,sizeof(toybuf)-1, "-%s", shell); 143 snprintf(toybuf,sizeof(toybuf)-1, "-%s", shell);
171 execl(shell, toybuf, NULL); 144 execl(shell, toybuf, NULL);
172 error_exit("Failed to spawn shell"); 145 error_exit("Failed to spawn shell");
173 } 146 }
174 147
175 void setup_environment(const struct passwd *pwd, int clear_env) 148 void setup_environment(const struct passwd *pwd, int clear_env)
176 { 149 {
177 if (chdir(pwd->pw_dir)) 150 if (chdir(pwd->pw_dir)) printf("bad home dir: %s\n", pwd->pw_dir);
178 printf("can't chdir to home directory: %s\n", pwd->pw_dir); 151
179 152 if (clear_env) {
180 if (clear_env)
181 {
182 const char * term = getenv("TERM"); 153 const char * term = getenv("TERM");
183 clearenv(); 154 clearenv();
184 if (term) setenv("TERM", term, 1); 155 if (term) setenv("TERM", term, 1);
185 } 156 }
186 157
187 setenv("USER", pwd->pw_name, 1); 158 setenv("USER", pwd->pw_name, 1);
188 setenv("LOGNAME", pwd->pw_name, 1); 159 setenv("LOGNAME", pwd->pw_name, 1);
189 setenv("HOME", pwd->pw_dir, 1); 160 setenv("HOME", pwd->pw_dir, 1);
190 setenv("SHELL", pwd->pw_shell, 1); 161 setenv("SHELL", pwd->pw_shell, 1);
191 } 162 }
192 163
193 void login_main(void) 164 void login_main(void)
194 { 165 {
195 int f_flag = (toys.optflags & 4) >> 2; 166 int f_flag = (toys.optflags & 4) >> 2;
196 int p_flag = (toys.optflags & 2) >> 1; 167 int p_flag = (toys.optflags & 2) >> 1;
197 int h_flag = toys.optflags & 1; 168 int h_flag = toys.optflags & 1;
198 char username[USER_NAME_MAX_SIZE+1]; 169 char username[USER_NAME_MAX_SIZE+1], *pass = NULL, **ss;
199 struct passwd * pwd = NULL; 170 struct passwd * pwd = NULL;
200 struct spwd * spwd = NULL; 171 struct spwd * spwd = NULL;
201 char *pass = NULL;
202 int auth_fail_cnt = 0; 172 int auth_fail_cnt = 0;
203 173
204 if (f_flag && toys.optc != 1) 174 if (f_flag && toys.optc != 1)
205 error_exit("-f requires username"); 175 error_exit("-f requires username");
206 176
207 if (geteuid() != 0 ) 177 if (geteuid()) error_exit("not root");
208 error_exit("Cannot possibly work without effective root"); 178
209 179 if (!isatty(0) || !isatty(1) || !isatty(2)) error_exit("no tty");
210 if (!isatty(0) || !isatty(1) || !isatty(2))
211 error_exit("Not connected to a tty");
212 180
213 openlog("login", LOG_PID | LOG_CONS, LOG_AUTH); 181 openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
214 signal(SIGALRM, login_timeout_handler); 182 signal(SIGALRM, login_timeout_handler);
215 alarm(LOGIN_TIMEOUT); 183 alarm(LOGIN_TIMEOUT);
216 sanitize_env(); 184
185 for (ss = forbid; *ss; ss++) unsetenv(*ss);
217 186
218 while (1) { 187 while (1) {
219 tcflush(0, TCIFLUSH); 188 tcflush(0, TCIFLUSH);
220 189
221 username[USER_NAME_MAX_SIZE] = 0; 190 username[USER_NAME_MAX_SIZE] = 0;
222 if (toys.optargs[0]) 191 if (toys.optargs[0])
223 strncpy(username, toys.optargs[0], USER_NAME_MAX_SIZE); 192 strncpy(username, toys.optargs[0], USER_NAME_MAX_SIZE);
224 else { 193 else {
225 read_user(username, USER_NAME_MAX_SIZE+1); 194 read_user(username, USER_NAME_MAX_SIZE+1);
226 if (username[0] == 0) 195 if (username[0] == 0) continue;
227 continue;
228 } 196 }
229 197
230 pwd = getpwnam(username); 198 pwd = getpwnam(username);
231 if (!pwd) 199 if (!pwd) goto query_pass; // Non-existing user
232 goto query_pass; // Non-existing user
233 200
234 if (pwd->pw_passwd[0] == '!' || pwd->pw_passwd[0] == '*') 201 if (pwd->pw_passwd[0] == '!' || pwd->pw_passwd[0] == '*')
235 goto query_pass; // Locked account 202 goto query_pass; // Locked account
236 203
237 if (f_flag) 204 if (f_flag) break; // Pre-authenticated
238 break; // Pre-authenticated 205
239 206 if (!pwd->pw_passwd[0]) break; // Password-less account
240 if (pwd->pw_passwd[0] == '\0')
241 break; // Password-less account
242 207
243 pass = pwd->pw_passwd; 208 pass = pwd->pw_passwd;
244 if (pwd->pw_passwd[0] == 'x') { 209 if (pwd->pw_passwd[0] == 'x') {
245 spwd = getspnam (username); 210 spwd = getspnam (username);
246 if (spwd) 211 if (spwd) pass = spwd->sp_pwdp;
247 pass = spwd->sp_pwdp;
248 } 212 }
249 213
250 query_pass: 214 query_pass:
251 if (!verify_password(pass)) 215 if (!verify_password(pass)) break;
252 break;
253 216
254 f_flag = 0; 217 f_flag = 0;
255 syslog(LOG_WARNING, "invalid password for '%s' on %s %s %s", username, 218 syslog(LOG_WARNING, "invalid password for '%s' on %s %s %s", username,
256 ttyname(0), 219 ttyname(0), (h_flag)?"from":"", (h_flag)?TT.hostname:"");
257 (h_flag)?"from":"",
258 (h_flag)?TT.hostname:"");
259 220
260 sleep(LOGIN_FAIL_TIMEOUT); 221 sleep(LOGIN_FAIL_TIMEOUT);
261 puts("Login incorrect"); 222 puts("Login incorrect");
262 223
263 if (++auth_fail_cnt == 3) 224 if (++auth_fail_cnt == 3)
264 {
265 error_exit("Maximum number of tries exceeded (%d)\n", auth_fail_cnt); 225 error_exit("Maximum number of tries exceeded (%d)\n", auth_fail_cnt);
266 }
267 226
268 username[0] = 0; 227 username[0] = 0;
269 pwd = NULL; 228 pwd = NULL;
270 spwd = NULL; 229 spwd = NULL;
271 } 230 }
272 231
273 alarm(0); 232 alarm(0);
274 233
275 if (pwd->pw_uid) 234 if (pwd->pw_uid) handle_nologin();
276 handle_nologin(); 235
277 236 if (change_identity(pwd)) error_exit("Failed to change identity");
278 if (change_identity(pwd))
279 error_exit("Failed to change identity");
280 237
281 setup_environment(pwd, !p_flag); 238 setup_environment(pwd, !p_flag);
282 239
283 handle_motd(); 240 handle_motd();
284 241
285 syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name, 242 syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
286 ttyname(0), 243 ttyname(0), (h_flag)?"from":"", (h_flag)?TT.hostname:"");
287 (h_flag)?"from":"",
288 (h_flag)?TT.hostname:"");
289 244
290 spawn_shell(pwd->pw_shell); 245 spawn_shell(pwd->pw_shell);
291 } 246 }