/etc/securetty is checked, even when root logins across the net.
[unix-history] / usr / src / usr.bin / login / login.c
CommitLineData
32e13142 1static char *sccsid = "@(#)login.c 4.23 83/05/19";
88a01c09
BJ
2/*
3 * login [ name ]
86eb6c9e 4 * login -r
88a01c09
BJ
5 */
6
7#include <sys/types.h>
8#include <sgtty.h>
9#include <utmp.h>
10#include <signal.h>
11#include <pwd.h>
12#include <stdio.h>
13#include <sys/stat.h>
14#include <lastlog.h>
f570e1ff
BJ
15
16#define SCPYN(a, b) strncpy(a, b, sizeof(a))
88a01c09 17
b4389814
BJ
18#define NMAX sizeof(utmp.ut_name)
19#define LMAX sizeof(utmp.ut_line)
88a01c09 20
f570e1ff
BJ
21#define FALSE 0
22#define TRUE -1
23
24char nolog[] = "/etc/nologin";
25char qlog[] = ".hushlogin";
26char securetty[] = "/etc/securetty";
88a01c09
BJ
27char maildir[30] = "/usr/spool/mail/";
28char lastlog[] = "/usr/adm/lastlog";
3479a16a 29struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" };
88a01c09
BJ
30struct sgttyb ttyb;
31struct utmp utmp;
32char minusnam[16] = "-";
86eb6c9e 33
88a01c09
BJ
34char homedir[64] = "HOME=";
35char shell[64] = "SHELL=";
36char term[64] = "TERM=";
f570e1ff 37char user[20] = "USER=";
86eb6c9e
BJ
38char *speeds[] =
39 { "0", "50", "75", "110", "134", "150", "200", "300",
40 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
41#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
42
43char *envinit[] =
44 {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0};
88a01c09 45
86eb6c9e 46struct passwd *pwd;
88a01c09 47struct passwd *getpwnam();
86eb6c9e 48char *strcat(), *rindex(), *index();
88a01c09
BJ
49int setpwent();
50char *ttyname();
51char *crypt();
52char *getpass();
88a01c09
BJ
53char *stypeof();
54extern char **environ;
55
3479a16a
SL
56struct ttychars tc = {
57 CERASE, CKILL, CINTR, CQUIT, CSTART,
58 CSTOP, CEOF, CBRK, CSUSP, CDSUSP,
59 CRPRNT, CFLUSH, CWERASE,CLNEXT
841d84b0
BJ
60};
61
86eb6c9e 62int rflag;
b4389814 63char rusername[NMAX+1], lusername[NMAX+1];
86eb6c9e 64char rpassword[NMAX+1];
e5321f7b 65char name[NMAX+1];
b4389814 66char *rhost;
86eb6c9e 67
88a01c09
BJ
68main(argc, argv)
69char **argv;
70{
71 register char *namep;
72 int t, f, c;
f570e1ff
BJ
73 int invalid;
74 int quietlog;
75 int i;
76 FILE *nlfd;
88a01c09 77 char *ttyn;
b4389814
BJ
78 int ldisc = 0, zero = 0;
79 FILE *hostf; int first = 1;
88a01c09
BJ
80
81 alarm(60);
82 signal(SIGQUIT, SIG_IGN);
83 signal(SIGINT, SIG_IGN);
84 nice(-100);
85 nice(20);
86 nice(0);
4f8d3876 87 if (argc > 1 && !strcmp(argv[1], "-r")) {
86eb6c9e 88 rflag++;
4f8d3876 89 rhost = argv[2];
b4389814 90 argc = 1;
4f8d3876
BJ
91 getstr(rusername, sizeof (rusername), "remuser");
92 getstr(lusername, sizeof (lusername), "locuser");
86eb6c9e 93 getstr(term+5, sizeof(term)-5, "Terminal type");
4f8d3876
BJ
94 if (getuid())
95 goto abnormal;
b4389814
BJ
96 setpwent();
97 pwd = getpwnam(lusername);
4f8d3876 98 endpwent();
703f91ff 99 if (pwd == NULL)
4f8d3876 100 goto abnormal;
1886582e 101 hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0;
b4389814
BJ
102 again:
103 if (hostf) {
fd29004e
CL
104 char ahost[32];
105
106 while (fgets(ahost, sizeof (ahost), hostf)) {
107 char *user;
108
32e13142
CL
109 if ((user = index(ahost, '\n')) != 0)
110 *user++ = '\0';
111 if ((user = index(ahost, ' ')) != 0)
112 *user++ = '\0';
fd29004e
CL
113 if (!strcmp(rhost, ahost) &&
114 !strcmp(rusername, user ?
115 user : lusername)) {
116 fclose(hostf);
117 goto normal;
118 }
4f8d3876 119 }
fd29004e 120 fclose(hostf);
b4389814
BJ
121 }
122 if (first == 1) {
fd29004e
CL
123 char *rhosts = ".rhosts";
124 struct stat sbuf;
125
b4389814
BJ
126 first = 0;
127 if (chdir(pwd->pw_dir) < 0)
128 goto again;
fd29004e
CL
129 if (lstat(rhosts, &sbuf) < 0)
130 goto again;
131 if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
132 printf("login: .rhosts is a soft link.\r\n");
fd29004e
CL
133 goto abnormal;
134 }
135 hostf = fopen(rhosts, "r");
136 fstat(fileno(hostf), &sbuf);
137 if ((int) sbuf.st_uid != pwd->pw_uid &&
138 (int) sbuf.st_uid != 0) {
139 printf("login: Bad .rhosts ownership.\r\n");
140 fclose(hostf);
141 goto abnormal;
142 }
143 goto again;
b4389814 144 }
4f8d3876 145abnormal:
b4389814
BJ
146 rhost = 0;
147 rflag = -1;
86eb6c9e 148 }
b4389814 149normal:
3479a16a 150 ioctl(0, TIOCLSET, &zero); /* XXX */
c95ed2b2 151 ioctl(0, TIOCNXCL, 0);
4f8d3876
BJ
152 ioctl(0, FIONBIO, &zero);
153 ioctl(0, FIOASYNC, &zero);
3479a16a 154 ioctl(0, TIOCGETP, &ttyb); /* XXX */
86eb6c9e
BJ
155 if (rflag) {
156 char *cp = index(term, '/');
157 if (cp) {
158 int i;
159 *cp++ = 0;
160 for (i = 0; i < NSPEEDS; i++)
161 if (!strcmp(speeds[i], cp)) {
162 ttyb.sg_ispeed = ttyb.sg_ospeed = i;
163 break;
164 }
165 }
166 ttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS;
167 }
3479a16a
SL
168 ioctl(0, TIOCSETP, &ttyb); /* XXX */
169 ioctl(0, TIOCCSET, &tc);
88a01c09
BJ
170 for (t=3; t<20; t++)
171 close(t);
172 ttyn = ttyname(0);
f570e1ff 173 if (ttyn==(char *)0)
88a01c09 174 ttyn = "/dev/tty??";
f570e1ff
BJ
175 do {
176 ldisc = 0;
c95ed2b2 177 ioctl(0, TIOCSETD, &ldisc);
f570e1ff
BJ
178 invalid = FALSE;
179 SCPYN(utmp.ut_name, "");
180 if (argc>1) {
181 SCPYN(utmp.ut_name, argv[1]);
182 argc = 0;
183 }
4f8d3876 184 if (rflag) {
3479a16a 185 SCPYN(utmp.ut_name, lusername);
4f8d3876
BJ
186 if (rflag == -1)
187 rflag = 0;
188 } else
b4389814
BJ
189 while (utmp.ut_name[0] == '\0') {
190 namep = utmp.ut_name;
191 { char hostname[32];
192 gethostname(hostname, sizeof (hostname));
193 printf("%s login: ", hostname); }
194 while ((c = getchar()) != '\n') {
195 if (c == ' ')
196 c = '_';
197 if (c == EOF)
198 exit(0);
199 if (namep < utmp.ut_name+NMAX)
200 *namep++ = c;
201 }
f570e1ff 202 }
b4389814
BJ
203 if (rhost == 0) {
204 setpwent();
205 if ((pwd = getpwnam(utmp.ut_name)) == NULL)
206 pwd = &nouser;
207 endpwent();
f570e1ff 208 }
f570e1ff
BJ
209 if (!strcmp(pwd->pw_shell, "/bin/csh")) {
210 ldisc = NTTYDISC;
211 ioctl(0, TIOCSETD, &ldisc);
212 }
b4389814
BJ
213 if (rhost == 0) {
214 if (*pwd->pw_passwd != '\0') {
215 char *pp;
216 nice(-4);
217 if (rflag == 0)
218 pp = getpass("Password:");
219 else
220 pp = rpassword;
221 namep = crypt(pp,pwd->pw_passwd);
222 nice(4);
223 if (strcmp(namep, pwd->pw_passwd))
224 invalid = TRUE;
225 }
f570e1ff
BJ
226 }
227 if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) {
228 /* logins are disabled except for root */
229 while ((c = getc(nlfd)) != EOF)
230 putchar(c);
231 fflush(stdout);
232 sleep(5);
233 exit(0);
234 }
235 if (!invalid && pwd->pw_uid == 0 &&
236 !rootterm(ttyn+sizeof("/dev/")-1)) {
4f8d3876
BJ
237 logerr("ROOT LOGIN REFUSED %s",
238 ttyn+sizeof("/dev/")-1);
f570e1ff
BJ
239 invalid = TRUE;
240 }
241 if (invalid) {
88a01c09 242 printf("Login incorrect\n");
4f8d3876
BJ
243 if (ttyn[sizeof("/dev/tty")-1] == 'd')
244 logerr("BADDIALUP %s %s\n",
245 ttyn+sizeof("/dev/")-1, utmp.ut_name);
88a01c09 246 }
f570e1ff
BJ
247 if (*pwd->pw_shell == '\0')
248 pwd->pw_shell = "/bin/sh";
249 i = strlen(pwd->pw_shell);
250 if (chdir(pwd->pw_dir) < 0 && !invalid ) {
251 if (chdir("/") < 0) {
252 printf("No directory!\n");
253 invalid = TRUE;
254 } else {
255 printf("No directory! Logging in with home=/\n");
256 pwd->pw_dir = "/";
257 }
88a01c09 258 }
86eb6c9e
BJ
259 if (rflag && invalid)
260 exit(1);
f570e1ff 261 } while (invalid);
88a01c09 262
86eb6c9e 263
88a01c09
BJ
264 time(&utmp.ut_time);
265 t = ttyslot();
266 if (t>0 && (f = open("/etc/utmp", 1)) >= 0) {
267 lseek(f, (long)(t*sizeof(utmp)), 0);
268 SCPYN(utmp.ut_line, rindex(ttyn, '/')+1);
269 write(f, (char *)&utmp, sizeof(utmp));
270 close(f);
271 }
272 if (t>0 && (f = open("/usr/adm/wtmp", 1)) >= 0) {
273 lseek(f, 0L, 2);
274 write(f, (char *)&utmp, sizeof(utmp));
275 close(f);
276 }
4f8d3876 277 quietlog = 0;
f570e1ff 278 if (access(qlog, 0) == 0)
4f8d3876
BJ
279 quietlog = 1;
280 if ((f = open(lastlog, 2)) >= 0) {
f570e1ff
BJ
281 struct lastlog ll;
282
283 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
284 if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
285 ll.ll_time != 0) {
4f8d3876 286 if (quietlog == 0)
f570e1ff
BJ
287 printf("Last login: %.*s on %.*s\n"
288 , 24-5
289 , (char *) ctime(&ll.ll_time)
290 , sizeof(ll.ll_line)
291 , ll.ll_line
292 );
293 }
294 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
295 time(&ll.ll_time);
296 SCPYN(ll.ll_line, rindex(ttyn, '/')+1);
297 write(f, (char *) &ll, sizeof ll);
298 close(f);
299 }
88a01c09 300 chown(ttyn, pwd->pw_uid, pwd->pw_gid);
3479a16a 301 chmod(ttyn, 0622);
88a01c09 302 setgid(pwd->pw_gid);
e5321f7b
KM
303 strncpy(name, utmp.ut_name, NMAX);
304 name[NMAX] = '\0';
b1198826 305 initgroups(name, pwd->pw_gid);
88a01c09 306 setuid(pwd->pw_uid);
88a01c09
BJ
307 environ = envinit;
308 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
309 strncat(shell, pwd->pw_shell, sizeof(shell)-7);
4f8d3876 310 if (term[strlen("TERM=")] == 0)
86eb6c9e 311 strncat(term, stypeof(ttyn), sizeof(term)-6);
f570e1ff 312 strncat(user, pwd->pw_name, sizeof(user)-6);
88a01c09
BJ
313 if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
314 namep = pwd->pw_shell;
315 else
316 namep++;
317 strcat(minusnam, namep);
318 alarm(0);
b4389814 319 umask(022);
4f8d3876
BJ
320 if (ttyn[sizeof("/dev/tty")-1] == 'd')
321 logerr("DIALUP %s %s\n", ttyn+sizeof("/dev/")-1, pwd->pw_name);
322 if (!quietlog) {
f570e1ff
BJ
323 showmotd();
324 strcat(maildir, pwd->pw_name);
325 if (access(maildir,4)==0) {
326 struct stat statb;
327 stat(maildir, &statb);
328 if (statb.st_size)
329 printf("You have mail.\n");
330 }
331 }
332
88a01c09
BJ
333 signal(SIGQUIT, SIG_DFL);
334 signal(SIGINT, SIG_DFL);
5f87416f 335 signal(SIGTSTP, SIG_IGN);
88a01c09 336 execlp(pwd->pw_shell, minusnam, 0);
f570e1ff 337 perror(pwd->pw_shell);
88a01c09
BJ
338 printf("No shell\n");
339 exit(0);
340}
341
342int stopmotd;
343catch()
344{
1886582e 345
88a01c09
BJ
346 signal(SIGINT, SIG_IGN);
347 stopmotd++;
348}
349
f570e1ff 350rootterm(tty)
1886582e 351 char *tty;
f570e1ff
BJ
352{
353 register FILE *fd;
1886582e 354 char buf[100];
f570e1ff
BJ
355
356 if ((fd = fopen(securetty, "r")) == NULL)
357 return(1);
358 while (fgets(buf, sizeof buf, fd) != NULL) {
359 buf[strlen(buf)-1] = '\0';
360 if (strcmp(tty, buf) == 0) {
361 fclose(fd);
362 return(1);
363 }
364 }
365 fclose(fd);
366 return(0);
367}
368
88a01c09
BJ
369showmotd()
370{
371 FILE *mf;
372 register c;
373
374 signal(SIGINT, catch);
f570e1ff
BJ
375 if ((mf = fopen("/etc/motd","r")) != NULL) {
376 while ((c = getc(mf)) != EOF && stopmotd == 0)
88a01c09
BJ
377 putchar(c);
378 fclose(mf);
379 }
380 signal(SIGINT, SIG_IGN);
381}
382
f570e1ff 383#undef UNKNOWN
88a01c09
BJ
384#define UNKNOWN "su"
385
386char *
387stypeof(ttyid)
388char *ttyid;
389{
390 static char typebuf[16];
391 char buf[50];
392 register FILE *f;
393 register char *p, *t, *q;
394
395 if (ttyid == NULL)
396 return (UNKNOWN);
397 f = fopen("/etc/ttytype", "r");
398 if (f == NULL)
399 return (UNKNOWN);
400 /* split off end of name */
401 for (p = q = ttyid; *p != 0; p++)
402 if (*p == '/')
403 q = p + 1;
404
405 /* scan the file */
406 while (fgets(buf, sizeof buf, f) != NULL)
407 {
f570e1ff 408 for (t=buf; *t!=' ' && *t != '\t'; t++)
88a01c09
BJ
409 ;
410 *t++ = 0;
f570e1ff
BJ
411 while (*t == ' ' || *t == '\t')
412 t++;
88a01c09
BJ
413 for (p=t; *p>' '; p++)
414 ;
415 *p = 0;
416 if (strcmp(q,t)==0) {
417 strcpy(typebuf, buf);
418 fclose(f);
419 return (typebuf);
420 }
421 }
422 fclose (f);
423 return (UNKNOWN);
424}
86eb6c9e
BJ
425
426getstr(buf, cnt, err)
427 char *buf;
428 int cnt;
429 char *err;
430{
431 char c;
432
433 do {
434 if (read(0, &c, 1) != 1)
435 exit(1);
436 if (--cnt < 0) {
437 printf("%s too long\r\n", err);
438 exit(1);
439 }
440 *buf++ = c;
441 } while (c != 0);
442}
4f8d3876
BJ
443
444logerr(fmt, a1, a2, a3)
445 char *fmt, *a1, *a2, *a3;
446{
447
448}