Commit | Line | Data |
---|---|---|
8c5eec2f DF |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
8 | char copyright[] = | |
9 | "@(#) Copyright (c) 1983 Regents of the University of California.\n\ | |
10 | All rights reserved.\n"; | |
11 | #endif not lint | |
12 | ||
a10a364d | 13 | #ifndef lint |
8c5eec2f DF |
14 | static char sccsid[] = "@(#)rlogind.c 5.1 (Berkeley) %G%"; |
15 | #endif not lint | |
a10a364d | 16 | |
bb933cc2 MK |
17 | /* |
18 | * remote login server: | |
19 | * remuser\0 | |
20 | * locuser\0 | |
6632767b | 21 | * terminal info\0 |
bb933cc2 MK |
22 | * data |
23 | */ | |
24 | ||
a10a364d BJ |
25 | #include <stdio.h> |
26 | #include <sys/types.h> | |
27 | #include <sys/stat.h> | |
28 | #include <sys/socket.h> | |
560a8855 | 29 | #include <sys/wait.h> |
6632767b | 30 | #include <sys/file.h> |
c6c678f1 SL |
31 | |
32 | #include <netinet/in.h> | |
33 | ||
a10a364d BJ |
34 | #include <errno.h> |
35 | #include <pwd.h> | |
a10a364d BJ |
36 | #include <signal.h> |
37 | #include <sgtty.h> | |
38 | #include <stdio.h> | |
3f5b52bc | 39 | #include <netdb.h> |
3f99c0f7 | 40 | #include <syslog.h> |
6632767b | 41 | #include <strings.h> |
a10a364d BJ |
42 | |
43 | extern errno; | |
92e31018 | 44 | int reapchild(); |
a10a364d | 45 | struct passwd *getpwnam(); |
6632767b | 46 | char *crypt(), *malloc(); |
bb933cc2 | 47 | |
a10a364d BJ |
48 | main(argc, argv) |
49 | int argc; | |
50 | char **argv; | |
51 | { | |
bcb894cb | 52 | int on = 1, options = 0, fromlen; |
a10a364d BJ |
53 | struct sockaddr_in from; |
54 | ||
bb933cc2 MK |
55 | fromlen = sizeof (from); |
56 | if (getpeername(0, &from, &fromlen) < 0) { | |
57 | fprintf(stderr, "%s: ", argv[0]); | |
58 | perror("getpeername"); | |
59 | _exit(1); | |
92e31018 | 60 | } |
bcb894cb | 61 | if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { |
3f99c0f7 RC |
62 | openlog(argv[0], LOG_PID, 0); |
63 | syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); | |
c6c678f1 | 64 | } |
bb933cc2 | 65 | doit(0, &from); |
92e31018 SL |
66 | } |
67 | ||
a10a364d BJ |
68 | int child; |
69 | int cleanup(); | |
70 | int netf; | |
71 | extern errno; | |
72 | char *line; | |
73 | ||
74 | doit(f, fromp) | |
75 | int f; | |
76 | struct sockaddr_in *fromp; | |
77 | { | |
6632767b | 78 | int i, p, t, pid, on = 1; |
3f5b52bc | 79 | register struct hostent *hp; |
6632767b | 80 | char c; |
a10a364d BJ |
81 | |
82 | alarm(60); | |
83 | read(f, &c, 1); | |
84 | if (c != 0) | |
85 | exit(1); | |
86 | alarm(0); | |
1227078b | 87 | fromp->sin_port = ntohs((u_short)fromp->sin_port); |
3f5b52bc SL |
88 | hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), |
89 | fromp->sin_family); | |
8de87e4f | 90 | if (hp == 0) { |
1227078b | 91 | char buf[BUFSIZ]; |
8de87e4f SL |
92 | |
93 | fatal(f, sprintf(buf, "Host name for your address (%s) unknown", | |
6632767b | 94 | inet_ntoa(fromp->sin_addr))); |
8de87e4f | 95 | } |
a10a364d | 96 | if (fromp->sin_family != AF_INET || |
1227078b | 97 | fromp->sin_port >= IPPORT_RESERVED) |
82c973f2 | 98 | fatal(f, "Permission denied"); |
a10a364d BJ |
99 | write(f, "", 1); |
100 | for (c = 'p'; c <= 's'; c++) { | |
101 | struct stat stb; | |
102 | line = "/dev/ptyXX"; | |
103 | line[strlen("/dev/pty")] = c; | |
104 | line[strlen("/dev/ptyp")] = '0'; | |
105 | if (stat(line, &stb) < 0) | |
106 | break; | |
107 | for (i = 0; i < 16; i++) { | |
108 | line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; | |
109 | p = open(line, 2); | |
110 | if (p > 0) | |
111 | goto gotpty; | |
112 | } | |
113 | } | |
82c973f2 SL |
114 | fatal(f, "All network ports in use"); |
115 | /*NOTREACHED*/ | |
a10a364d | 116 | gotpty: |
1227078b | 117 | netf = f; |
a10a364d BJ |
118 | line[strlen("/dev/")] = 't'; |
119 | #ifdef DEBUG | |
120 | { int tt = open("/dev/tty", 2); | |
121 | if (tt > 0) { | |
122 | ioctl(tt, TIOCNOTTY, 0); | |
123 | close(tt); | |
124 | } | |
125 | } | |
126 | #endif | |
127 | t = open(line, 2); | |
82c973f2 SL |
128 | if (t < 0) |
129 | fatalperror(f, line, errno); | |
a10a364d BJ |
130 | { struct sgttyb b; |
131 | gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); | |
132 | } | |
82c973f2 SL |
133 | pid = fork(); |
134 | if (pid < 0) | |
135 | fatalperror(f, "", errno); | |
6632767b SL |
136 | if (pid == 0) { |
137 | close(f), close(p); | |
138 | dup2(t, 0), dup2(t, 1), dup2(t, 2); | |
1227078b | 139 | close(t); |
6632767b SL |
140 | execl("/bin/login", "login", "-r", hp->h_name, 0); |
141 | fatalperror(2, "/bin/login", errno); | |
142 | /*NOTREACHED*/ | |
143 | } | |
144 | close(t); | |
145 | ioctl(f, FIONBIO, &on); | |
146 | ioctl(p, FIONBIO, &on); | |
147 | ioctl(p, TIOCPKT, &on); | |
148 | signal(SIGTSTP, SIG_IGN); | |
149 | signal(SIGCHLD, cleanup); | |
150 | protocol(f, p); | |
151 | cleanup(); | |
152 | } | |
82c973f2 | 153 | |
6632767b SL |
154 | char magic[2] = { 0377, 0377 }; |
155 | ||
156 | /* | |
157 | * Handle a "control" request (signaled by magic being present) | |
158 | * in the data stream. For now, we are only willing to handle | |
159 | * window size changes. | |
160 | */ | |
161 | control(pty, cp, n) | |
162 | int pty; | |
163 | char *cp; | |
164 | int n; | |
165 | { | |
166 | struct winsize *wp; | |
167 | ||
168 | if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') | |
169 | return (0); | |
170 | wp = (struct winsize *)(cp+4); | |
171 | wp->ws_row = ntohs(wp->ws_row); | |
172 | wp->ws_col = ntohs(wp->ws_col); | |
173 | wp->ws_xpixel = ntohs(wp->ws_xpixel); | |
174 | wp->ws_ypixel = ntohs(wp->ws_ypixel); | |
175 | (void)ioctl(pty, TIOCSWINSZ, wp); | |
176 | return (4+sizeof (*wp)); | |
177 | } | |
178 | ||
179 | /* | |
180 | * rlogin "protocol" machine. | |
181 | */ | |
182 | protocol(f, p) | |
183 | int f, p; | |
184 | { | |
185 | char pibuf[1024], fibuf[1024], *pbp, *fbp; | |
186 | register pcc = 0, fcc = 0; | |
187 | int cc, stop = TIOCPKT_DOSTOP; | |
188 | ||
ffaf1c0b | 189 | /* |
9ee4d121 SL |
190 | * Must ignore SIGTTOU, otherwise we'll stop |
191 | * when we try and set slave pty's window shape | |
192 | * (our pgrp is that of the master pty). | |
ffaf1c0b | 193 | */ |
9ee4d121 | 194 | (void) signal(SIGTTOU, SIG_IGN); |
6632767b SL |
195 | for (;;) { |
196 | int ibits = 0, obits = 0; | |
197 | ||
198 | if (fcc) | |
199 | obits |= (1<<p); | |
200 | else | |
201 | ibits |= (1<<f); | |
202 | if (pcc >= 0) | |
203 | if (pcc) | |
204 | obits |= (1<<f); | |
82c973f2 | 205 | else |
6632767b SL |
206 | ibits |= (1<<p); |
207 | if (select(16, &ibits, &obits, 0, 0) < 0) { | |
208 | if (errno == EINTR) | |
a10a364d | 209 | continue; |
6632767b SL |
210 | fatalperror(f, "select", errno); |
211 | } | |
212 | if (ibits == 0 && obits == 0) { | |
213 | /* shouldn't happen... */ | |
214 | sleep(5); | |
215 | continue; | |
216 | } | |
217 | if (ibits & (1<<f)) { | |
218 | fcc = read(f, fibuf, sizeof (fibuf)); | |
219 | if (fcc < 0 && errno == EWOULDBLOCK) | |
220 | fcc = 0; | |
221 | else { | |
222 | register char *cp; | |
223 | int left, n; | |
224 | ||
225 | if (fcc <= 0) | |
1227078b | 226 | break; |
6632767b SL |
227 | fbp = fibuf; |
228 | top: | |
229 | for (cp = fibuf; cp < fibuf+fcc; cp++) | |
230 | if (cp[0] == magic[0] && | |
231 | cp[1] == magic[1]) { | |
232 | left = fcc - (cp-fibuf); | |
233 | n = control(p, cp, left); | |
234 | if (n) { | |
235 | left -= n; | |
236 | if (left > 0) | |
237 | bcopy(cp, cp+n, left); | |
238 | fcc -= n; | |
239 | goto top; /* n^2 */ | |
240 | } | |
a10a364d | 241 | } |
a10a364d | 242 | } |
6632767b SL |
243 | } |
244 | if (ibits & (1<<p)) { | |
245 | pcc = read(p, pibuf, sizeof (pibuf)); | |
246 | pbp = pibuf; | |
247 | if (pcc < 0 && errno == EWOULDBLOCK) | |
248 | pcc = 0; | |
249 | else if (pcc <= 0) | |
250 | break; | |
251 | else if (pibuf[0] == 0) | |
252 | pbp++, pcc--; | |
253 | else { | |
254 | #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) | |
255 | if (pkcontrol(pibuf[0])) { | |
256 | /* The following 3 lines do nothing. */ | |
257 | int nstop = pibuf[0] & | |
258 | (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); | |
259 | ||
260 | if (nstop) | |
261 | stop = nstop; | |
262 | pibuf[0] |= nstop; | |
263 | send(f, &pibuf[0], 1, MSG_OOB); | |
a10a364d | 264 | } |
6632767b | 265 | pcc = 0; |
a10a364d | 266 | } |
6632767b SL |
267 | } |
268 | if ((obits & (1<<f)) && pcc > 0) { | |
269 | cc = write(f, pbp, pcc); | |
270 | if (cc < 0 && errno == EWOULDBLOCK) { | |
271 | /* also shouldn't happen */ | |
272 | sleep(5); | |
273 | continue; | |
274 | } | |
275 | if (cc > 0) { | |
276 | pcc -= cc; | |
277 | pbp += cc; | |
278 | } | |
279 | } | |
280 | if ((obits & (1<<p)) && fcc > 0) { | |
281 | cc = write(p, fbp, fcc); | |
282 | if (cc > 0) { | |
283 | fcc -= cc; | |
284 | fbp += cc; | |
a10a364d BJ |
285 | } |
286 | } | |
a10a364d | 287 | } |
a10a364d BJ |
288 | } |
289 | ||
290 | cleanup() | |
291 | { | |
a10a364d BJ |
292 | |
293 | rmut(); | |
dd83e8ac | 294 | vhangup(); /* XXX */ |
ff24c640 | 295 | shutdown(netf, 2); |
a10a364d BJ |
296 | kill(0, SIGKILL); |
297 | exit(1); | |
298 | } | |
299 | ||
82c973f2 SL |
300 | fatal(f, msg) |
301 | int f; | |
302 | char *msg; | |
303 | { | |
304 | char buf[BUFSIZ]; | |
305 | ||
306 | buf[0] = '\01'; /* error indicator */ | |
560a8855 | 307 | (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); |
82c973f2 SL |
308 | (void) write(f, buf, strlen(buf)); |
309 | exit(1); | |
310 | } | |
311 | ||
312 | fatalperror(f, msg, errno) | |
313 | int f; | |
314 | char *msg; | |
315 | int errno; | |
316 | { | |
317 | char buf[BUFSIZ]; | |
1227078b | 318 | extern int sys_nerr; |
82c973f2 SL |
319 | extern char *sys_errlist[]; |
320 | ||
6632767b | 321 | if ((unsigned)errno < sys_nerr) |
1227078b MK |
322 | (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); |
323 | else | |
324 | (void) sprintf(buf, "%s: Error %d", msg, errno); | |
82c973f2 SL |
325 | fatal(f, buf); |
326 | } | |
327 | ||
a10a364d BJ |
328 | #include <utmp.h> |
329 | ||
330 | struct utmp wtmp; | |
331 | char wtmpf[] = "/usr/adm/wtmp"; | |
332 | char utmp[] = "/etc/utmp"; | |
333 | #define SCPYN(a, b) strncpy(a, b, sizeof(a)) | |
334 | #define SCMPN(a, b) strncmp(a, b, sizeof(a)) | |
335 | ||
336 | rmut() | |
337 | { | |
338 | register f; | |
339 | int found = 0; | |
340 | ||
6632767b | 341 | f = open(utmp, O_RDWR); |
a10a364d BJ |
342 | if (f >= 0) { |
343 | while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { | |
344 | if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) | |
345 | continue; | |
6632767b | 346 | lseek(f, -(long)sizeof(wtmp), L_INCR); |
a10a364d | 347 | SCPYN(wtmp.ut_name, ""); |
9b3ee53c | 348 | SCPYN(wtmp.ut_host, ""); |
a10a364d BJ |
349 | time(&wtmp.ut_time); |
350 | write(f, (char *)&wtmp, sizeof(wtmp)); | |
351 | found++; | |
352 | } | |
353 | close(f); | |
354 | } | |
355 | if (found) { | |
6632767b | 356 | f = open(wtmpf, O_WRONLY); |
a10a364d BJ |
357 | if (f >= 0) { |
358 | SCPYN(wtmp.ut_line, line+5); | |
359 | SCPYN(wtmp.ut_name, ""); | |
9b3ee53c | 360 | SCPYN(wtmp.ut_host, ""); |
a10a364d | 361 | time(&wtmp.ut_time); |
6632767b | 362 | lseek(f, (long)0, L_XTND); |
a10a364d BJ |
363 | write(f, (char *)&wtmp, sizeof(wtmp)); |
364 | close(f); | |
365 | } | |
366 | } | |
367 | chmod(line, 0666); | |
368 | chown(line, 0, 0); | |
369 | line[strlen("/dev/")] = 'p'; | |
370 | chmod(line, 0666); | |
371 | chown(line, 0, 0); | |
372 | } |