source: trunk/minix/commands/simple/login.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 11.5 KB
Line 
1/* login - log into the system Author: Patrick van Kleef */
2
3/* Original version by Patrick van Kleef. History of modifications:
4 *
5 * Peter S. Housel Jan. 1988
6 * - Set up $USER, $HOME and $TERM.
7 * - Set signals to SIG_DFL.
8 *
9 * Terrence W. Holm June 1988
10 * - Allow a username as an optional argument.
11 * - Time out if a password is not typed within 60 seconds.
12 * - Perform a dummy delay after a bad username is entered.
13 * - Don't allow a login if "/etc/nologin" exists.
14 * - Cause a failure on bad "pw_shell" fields.
15 * - Record the login in "/usr/adm/wtmp".
16 *
17 * Peter S. Housel Dec. 1988
18 * - Record the login in "/etc/utmp" also.
19 *
20 * F. van Kempen June 1989
21 * - various patches for Minix V1.4a.
22 *
23 * F. van Kempen September 1989
24 * - added login-failure administration (new utmp.h needed!).
25 * - support arguments in pw_shell field
26 * - adapted source text to MINIX Style Sheet
27 *
28 * F. van Kempen October 1989
29 * - adapted to new utmp database.
30 * F. van Kempen, December 1989
31 * - fixed 'slot' assumption in wtmp()
32 * - fixed all MSS-stuff
33 * - adapted to POSIX (MINIX 1.5)
34 * F. van Kempen, January 1990
35 * - made all 'bad login accounting' optional by "#ifdef BADLOG".
36 * F. van Kempen, Februari 1990
37 * - fixed 'first argument' bug and added some casts.
38 *
39 * Andy Tanenbaum April 1990
40 * - if /bin/sh cannot be located, try /usr/bin/sh
41 *
42 * Michael A. Temari October 1990
43 * - handle more than single digit tty devices
44 *
45 * Philip Homburg - Feb 28 1992
46 * - use ttyname to get the name of a tty.
47 *
48 * Kees J. Bot - Feb 13 1993
49 * - putting out garbage.
50 * - added lastlog.
51 *
52 * Kees J. Bot - Feb 13 1993
53 * - supplementary groups.
54 *
55 * Kees J. Bot - Jan 3 1996
56 * - ported back to standard Minix.
57 */
58
59#define _MINIX_SOURCE
60#define _POSIX_C_SOURCE 2
61
62#include <sys/types.h>
63#include <ttyent.h>
64#include <sys/stat.h>
65#include <errno.h>
66#include <fcntl.h>
67#include <pwd.h>
68#include <grp.h>
69#include <signal.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74#include <utmp.h>
75#include <time.h>
76#include <sys/utsname.h>
77#include <minix/minlib.h>
78#include <minix/paths.h>
79
80char PATH_UTMP[] = _PATH_UTMP; /* current logins */
81char PATH_WTMP[] = _PATH_WTMP; /* login/logout history */
82char PATH_LASTLOG[] = _PATH_LASTLOG; /* last login history */
83char PATH_MOTD[] = _PATH_MOTD; /* message of the day */
84
85#define TTY_GID 4 /* group ID of ttys */
86
87#define EXTRA_ENV 6
88
89/* Crude indication of a tty being physically secure: */
90#define securetty(dev) ((unsigned) ((dev) - 0x0400) < (unsigned) 8)
91
92int time_out;
93char *hostname;
94char user[32];
95char logname[35];
96char home[128];
97char shell[128];
98char term[128];
99char **env;
100extern char **environ;
101
102_PROTOTYPE(int main, (int argc, char **argv));
103_PROTOTYPE(void wtmp, (char *user, int uid));
104_PROTOTYPE(void show_file, (char *nam));
105_PROTOTYPE(void Time_out, (int dummy));
106_PROTOTYPE(void usage, (void));
107_PROTOTYPE(void add2env, (char **env, char *entry, int replace));
108
109void wtmp(user, uid)
110char *user; /* user name */
111int uid; /* user id */
112{
113 /* Make entries in /usr/adm/wtmp and /etc/utmp. */
114 struct utmp entry;
115 register int fd= -1;
116 int lineno;
117 int err = 0;
118 char *what;
119
120 /* First, read the current UTMP entry. we need some of its
121 * parameters! (like PID, ID etc...).
122 */
123 what= "ttyslot()";
124 lineno= ttyslot();
125 if (lineno == 0) err= errno; /* ttyslot failed */
126
127 if (err == 0 && (fd = open(what = PATH_UTMP, O_RDONLY)) < 0) {
128 if (errno == ENOENT) return;
129 err= errno;
130 }
131 if (err == 0 && lseek(fd, (off_t) lineno * sizeof(entry), SEEK_SET) < 0)
132 err= errno;
133 if (err == 0 && read(fd, (char *) &entry, sizeof(entry)) != sizeof(entry))
134 err= errno;
135 if (fd >= 0) close(fd);
136
137 /* Enter new fields. */
138 strncpy(entry.ut_user, user, sizeof(entry.ut_user));
139 if (hostname) strncpy(entry.ut_host, hostname, sizeof(entry.ut_host));
140
141 if (entry.ut_pid == 0) entry.ut_pid = getpid();
142
143 entry.ut_type = USER_PROCESS; /* we are past login... */
144 time(&entry.ut_time);
145
146 /* Write a WTMP record. */
147 if (err == 0) {
148 if ((fd = open(what = PATH_WTMP, O_WRONLY|O_APPEND)) < 0) {
149 if (errno != ENOENT) err= errno;
150 } else {
151 if (write(fd, (char *) &entry, sizeof(entry)) < 0) err= errno;
152 close(fd);
153 }
154 }
155
156 /* Rewrite the UTMP entry. */
157 if (err == 0 && (fd = open(what = PATH_UTMP, O_WRONLY)) < 0)
158 err= errno;
159 if (err == 0 && lseek(fd, (off_t) lineno * sizeof(entry), SEEK_SET) < 0)
160 err= errno;
161 if (err == 0 && write(fd, (char *) &entry, sizeof(entry)) < 0)
162 err= errno;
163 if (fd >= 0) close(fd);
164
165 /* Write the LASTLOG entry. */
166 if (err == 0 && (fd = open(what = PATH_LASTLOG, O_WRONLY)) < 0) {
167 if (errno == ENOENT) return;
168 err= errno;
169 }
170 if (err == 0 && lseek(fd, (off_t) uid * sizeof(entry), SEEK_SET) < 0)
171 err= errno;
172 if (err == 0 && write(fd, (char *) &entry, sizeof(entry)) < 0)
173 err= errno;
174 if (fd >= 0) close(fd);
175
176 if (err != 0) {
177 fprintf(stderr, "login: %s: %s\n", what, strerror(err));
178 return;
179 }
180}
181
182
183void show_file(nam)
184char *nam;
185{
186/* Read a textfile and show it on the desired terminal. */
187 register int fd, len;
188 char buf[80];
189
190 if ((fd = open(nam, O_RDONLY)) > 0) {
191 len = 1;
192 while (len > 0) {
193 len = read(fd, buf, 80);
194 write(1, buf, len);
195 }
196 close(fd);
197 }
198}
199
200
201int main(argc, argv)
202int argc;
203char *argv[];
204{
205 char name[30];
206 char *password, *cryptedpwd;
207 char *tty_name, *p;
208 int n, ap, check_pw, bad, secure, i, envsiz, do_banner;
209 struct passwd *pwd;
210 char *bp, *argx[8], **ep; /* pw_shell arguments */
211 char argx0[64]; /* argv[0] of the shell */
212 char *sh = "/bin/sh"; /* sh/pw_shell field value */
213 char *initialname;
214 int c, b_flag, f_flag, p_flag;
215 char *h_arg;
216 int authorized, preserv_env;
217 struct ttyent *ttyp;
218 struct stat ttystat;
219 struct sigaction sa;
220 struct utsname uts;
221
222 /* Don't let QUIT dump core. */
223 sigemptyset(&sa.sa_mask);
224 sa.sa_flags = 0;
225 sa.sa_handler = exit;
226 sigaction(SIGQUIT, &sa, NULL);
227
228 /* Parse options. */
229 b_flag= 0;
230 f_flag= 0;
231 p_flag= 0;
232 h_arg= NULL;
233 while ((c= getopt(argc, argv, "?bfh:p")) != -1)
234 {
235 switch(c)
236 {
237 case 'b': b_flag= 1; break;
238 case 'f': f_flag= 1; break;
239 case 'h':
240 if (h_arg)
241 usage();
242 if (getuid() == 0)
243 h_arg= optarg;
244 break;
245 case 'p': p_flag= 1; break;
246 case '?':
247 usage();
248 default:
249 fprintf(stderr, "login: getopt failed: '%c'\n", c);
250 exit(1);
251 }
252 }
253 if (optind < argc)
254 initialname= argv[optind++];
255 else
256 initialname= NULL;
257 if (optind != argc)
258 usage();
259
260 authorized= f_flag;
261 hostname= h_arg;
262 preserv_env= p_flag;
263 do_banner= b_flag;
264
265 /* Look up /dev/tty number. */
266 tty_name= ttyname(0);
267 if (tty_name == NULL)
268 {
269 write(1, "Unable to lookup tty name\n", 26);
270 exit(1);
271 }
272
273 if (do_banner)
274 {
275 uname(&uts);
276 write(1, "\n", 1);
277 write(1, uts.sysname, strlen(uts.sysname));
278 write(1, "/", 1);
279 write(1, uts.machine, strlen(uts.machine));
280 write(1, " Release ", 9);
281 write(1, uts.release, strlen(uts.release));
282 write(1, " Version ", 9);
283 write(1, uts.version, strlen(uts.version));
284 write(1, " (", 2);
285 p= strrchr(tty_name, '/');
286 if (!p)
287 p= tty_name;
288 else
289 p++;
290 write(1, p, strlen(p));
291 write(1, ")\n\n", 3);
292 write(1, uts.nodename, strlen(uts.nodename));
293 write(1, " ", 1);
294 }
295
296 /* Get login name and passwd. */
297 for (;;initialname= NULL) {
298 if (initialname)
299 strcpy(name, initialname);
300 else {
301 do {
302 write(1, "login: ", 7);
303 n = read(0, name, 30);
304 if (n == 0) exit(1);
305 if (n < 0)
306 {
307 if (errno != EINTR)
308 fprintf(stderr,
309 "login: read failed: %s\n",
310 strerror(errno));
311 exit(1);
312 }
313 } while (n < 2);
314 name[n - 1] = 0;
315 }
316
317 /* Start timer running. */
318 time_out = 0;
319 sa.sa_handler = Time_out;
320 sigaction(SIGALRM, &sa, NULL);
321 alarm(60);
322
323
324 /* Look up login/passwd. */
325 pwd = getpwnam(name);
326
327 check_pw = 1; /* default is check password. */
328
329 /* For now, only console is secure. */
330 secure = fstat(0, &ttystat) == 0 && securetty(ttystat.st_rdev);
331
332 if (pwd && authorized && initialname
333 && (pwd->pw_uid == getuid() || getuid() == 0)) {
334 check_pw= 0; /* Don't ask a password for
335 * pre-authorized users.
336 */
337 } else
338 if (pwd && secure && strcmp(crypt("", pwd->pw_passwd),
339 pwd->pw_passwd) == 0) {
340 check_pw= 0; /* empty password */
341 }
342
343 if (check_pw) {
344 password = getpass("Password:");
345
346 if (time_out) exit(1);
347
348 bad = 0;
349 if (!pwd) bad = 1;
350 if (!password) { password = ""; bad = 1; }
351 if (!secure && pwd && strcmp(crypt("", pwd->pw_passwd),
352 pwd->pw_passwd) == 0) bad = 1;
353
354 cryptedpwd = bad ? "*" : pwd->pw_passwd;
355
356 if (strcmp(crypt(password, cryptedpwd), cryptedpwd) != 0) {
357 write(1, "Login incorrect\n", 16);
358 continue;
359 }
360 }
361 /* Check if the system is going down */
362 if (access("/etc/nologin", 0) == 0 && strcmp(name, "root") != 0) {
363 write(1, "System going down\n\n", 19);
364 continue;
365 }
366
367 /* Stop timer. */
368 alarm(0);
369
370 /* Write login record to /usr/adm/wtmp and /etc/utmp */
371 wtmp(name, pwd->pw_uid);
372
373 /* Create the argv[] array from the pw_shell field. */
374 ap = 0;
375 argx[ap++] = argx0; /* "-sh" most likely */
376 if (pwd->pw_shell[0]) {
377 sh = pwd->pw_shell;
378 bp = sh;
379 while (*bp) {
380 while (*bp && *bp != ' ' && *bp != '\t') bp++;
381 if (*bp == ' ' || *bp == '\t') {
382 *bp++ = '\0'; /* mark end of string */
383 argx[ap++] = bp;
384 }
385 }
386 } else
387 argx[ap] = NULL;
388 strcpy(argx0, "-"); /* most shells need it for their .profile */
389 if ((bp= strrchr(sh, '/')) == NULL) bp = sh; else bp++;
390 strncat(argx0, bp, sizeof(argx0) - 2);
391
392 /* Set the environment */
393 if (p_flag)
394 {
395 for (ep= environ; *ep; ep++)
396 ;
397 }
398 else
399 ep= environ;
400
401 envsiz= ep-environ;
402 env= calloc(envsiz + EXTRA_ENV, sizeof(*env));
403 if (env == NULL)
404 {
405 fprintf(stderr, "login: out of memory\n");
406 exit(1);
407 }
408 for (i= 0; i<envsiz; i++)
409 env[i]= environ[i];
410
411 strcpy(user, "USER=");
412 strcat(user, name);
413 add2env(env, user, 1);
414 strcpy(logname, "LOGNAME=");
415 strcat(logname, name);
416 add2env(env, logname, 1);
417 strcpy(home, "HOME=");
418 strcat(home, pwd->pw_dir);
419 add2env(env, home, 1);
420 strcpy(shell, "SHELL=");
421 strcat(shell, sh);
422 add2env(env, shell, 1);
423 if ((ttyp = getttynam(tty_name + 5)) != NULL) {
424 strcpy(term, "TERM=");
425 strcat(term, ttyp->ty_type);
426 add2env(env, term, 0);
427 }
428
429 /* Show the message-of-the-day. */
430 show_file(PATH_MOTD);
431
432 /* Assign the terminal to this user. */
433 chown(tty_name, pwd->pw_uid, TTY_GID);
434 chmod(tty_name, 0620);
435
436 /* Change id. */
437#if __minix_vmd
438 initgroups(pwd->pw_name, pwd->pw_gid);
439#endif
440 setgid(pwd->pw_gid);
441 setuid(pwd->pw_uid);
442
443 /* cd $HOME */
444 chdir(pwd->pw_dir);
445
446 /* Reset signals to default values. */
447 sa.sa_handler = SIG_DFL;
448 for (n = 1; n <= _NSIG; ++n) sigaction(n, &sa, NULL);
449
450 /* Execute the user's shell. */
451 execve(sh, argx, env);
452
453 if (pwd->pw_gid == 0) {
454 /* Privileged user gets /bin/sh in times of crisis. */
455 sh= "/bin/sh";
456 argx[0]= "-sh";
457 strcpy(shell, "SHELL=");
458 strcat(shell, sh);
459 execve(sh, argx, env);
460 }
461 fprintf(stderr, "login: can't execute %s: %s\n", sh, strerror(errno));
462 exit(1);
463 }
464 return(0);
465}
466
467
468void Time_out(dummy)
469int dummy; /* to keep the compiler happy */
470{
471 write(2, "\r\nLogin timed out after 60 seconds\r\n", 36);
472 time_out = 1;
473}
474
475void usage()
476{
477 fprintf(stderr,
478 "Usage: login [-h hostname] [-b] [-f] [-p] [username]\n");
479 exit(1);
480}
481
482void add2env(env, entry, replace)
483char **env;
484char *entry;
485int replace;
486{
487/* Replace an environment variable with entry or add entry if the environment
488 * variable doesn't exit yet.
489 */
490 char *cp;
491 int keylen;
492
493 cp= strchr(entry, '=');
494 keylen= cp-entry+1;
495
496 for(; *env; env++)
497 {
498 if (strncmp(*env, entry, keylen) == 0) {
499 if (!replace) return; /* Don't replace */
500 break;
501 }
502 }
503 *env= entry;
504}
505
506/*
507 * $PchId: login.c,v 1.6 2001/07/31 14:23:28 philip Exp $
508 */
Note: See TracBrowser for help on using the repository browser.