Deleted Added
full compact
rlogind.c (51433) rlogind.c (56590)
1/*-
2 * Copyright (c) 1983, 1988, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
43#endif
44static const char rcsid[] =
1/*-
2 * Copyright (c) 1983, 1988, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
43#endif
44static const char rcsid[] =
45 "$FreeBSD: head/libexec/rlogind/rlogind.c 51433 1999-09-19 22:05:32Z markm $";
45 "$FreeBSD: head/libexec/rlogind/rlogind.c 56590 2000-01-25 14:52:10Z shin $";
46#endif /* not lint */
47
48/*
49 * remote login server:
50 * \0
51 * remuser\0
52 * locuser\0
53 * terminal_type/speed\0
54 * data
55 */
56
57#define FD_SETSIZE 16 /* don't need many bits for select */
58#include <sys/types.h>
59#include <sys/param.h>
60#include <sys/stat.h>
61#include <sys/ioctl.h>
62#include <signal.h>
63#include <termios.h>
64
65#include <sys/socket.h>
66#include <netinet/in.h>
67#include <netinet/in_systm.h>
68#include <netinet/ip.h>
69#include <netinet/tcp.h>
70#include <arpa/inet.h>
71#include <netdb.h>
72
73#include <errno.h>
74#include <libutil.h>
75#include <pwd.h>
76#include <syslog.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81#include "pathnames.h"
82
83#ifndef NO_PAM
84#include <security/pam_appl.h>
85#include <security/pam_misc.h>
86#endif
87
88#ifndef TIOCPKT_WINDOW
89#define TIOCPKT_WINDOW 0x80
90#endif
91
92#define ARGSTR "Dalnx"
93
46#endif /* not lint */
47
48/*
49 * remote login server:
50 * \0
51 * remuser\0
52 * locuser\0
53 * terminal_type/speed\0
54 * data
55 */
56
57#define FD_SETSIZE 16 /* don't need many bits for select */
58#include <sys/types.h>
59#include <sys/param.h>
60#include <sys/stat.h>
61#include <sys/ioctl.h>
62#include <signal.h>
63#include <termios.h>
64
65#include <sys/socket.h>
66#include <netinet/in.h>
67#include <netinet/in_systm.h>
68#include <netinet/ip.h>
69#include <netinet/tcp.h>
70#include <arpa/inet.h>
71#include <netdb.h>
72
73#include <errno.h>
74#include <libutil.h>
75#include <pwd.h>
76#include <syslog.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81#include "pathnames.h"
82
83#ifndef NO_PAM
84#include <security/pam_appl.h>
85#include <security/pam_misc.h>
86#endif
87
88#ifndef TIOCPKT_WINDOW
89#define TIOCPKT_WINDOW 0x80
90#endif
91
92#define ARGSTR "Dalnx"
93
94/* wrapper for KAME-special getnameinfo() */
95#ifndef NI_WITHSCOPEID
96#define NI_WITHSCOPEID 0
97#endif
98
94char *env[2];
95#define NMAX 30
96char lusername[NMAX+1], rusername[NMAX+1];
97static char term[64] = "TERM=";
98#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
99int keepalive = 1;
100int check_all = 0;
101int no_delay;
102
103struct passwd *pwd;
104
99char *env[2];
100#define NMAX 30
101char lusername[NMAX+1], rusername[NMAX+1];
102static char term[64] = "TERM=";
103#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
104int keepalive = 1;
105int check_all = 0;
106int no_delay;
107
108struct passwd *pwd;
109
105void doit __P((int, struct sockaddr_in *));
110union sockunion {
111 struct sockinet {
112 u_char si_len;
113 u_char si_family;
114 u_short si_port;
115 } su_si;
116 struct sockaddr_in su_sin;
117 struct sockaddr_in6 su_sin6;
118};
119#define su_len su_si.si_len
120#define su_family su_si.si_family
121#define su_port su_si.si_port
122
123void doit __P((int, union sockunion *));
106int control __P((int, char *, int));
107void protocol __P((int, int));
108void cleanup __P((int));
109void fatal __P((int, char *, int));
124int control __P((int, char *, int));
125void protocol __P((int, int));
126void cleanup __P((int));
127void fatal __P((int, char *, int));
110int do_rlogin __P((struct sockaddr_in *));
128int do_rlogin __P((union sockunion *));
111void getstr __P((char *, int, char *));
112void setup_term __P((int));
113int do_krb_login __P((struct sockaddr_in *));
114void usage __P((void));
115
116#ifndef NO_PAM
117extern int auth_pam __P((char *));
118#endif
119
120int
121main(argc, argv)
122 int argc;
123 char *argv[];
124{
125 extern int __check_rhosts_file;
129void getstr __P((char *, int, char *));
130void setup_term __P((int));
131int do_krb_login __P((struct sockaddr_in *));
132void usage __P((void));
133
134#ifndef NO_PAM
135extern int auth_pam __P((char *));
136#endif
137
138int
139main(argc, argv)
140 int argc;
141 char *argv[];
142{
143 extern int __check_rhosts_file;
126 struct sockaddr_in from;
144 union sockunion from;
127 int ch, fromlen, on;
128
129 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
130
131 opterr = 0;
132 while ((ch = getopt(argc, argv, ARGSTR)) != -1)
133 switch (ch) {
134 case 'D':
135 no_delay = 1;
136 break;
137 case 'a':
138 check_all = 1;
139 break;
140 case 'l':
141 __check_rhosts_file = 0;
142 break;
143 case 'n':
144 keepalive = 0;
145 break;
146#ifdef CRYPT
147 case 'x':
148 doencrypt = 1;
149 break;
150#endif
151 case '?':
152 default:
153 usage();
154 break;
155 }
156 argc -= optind;
157 argv += optind;
158
159 fromlen = sizeof (from);
160 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
161 syslog(LOG_ERR,"Can't get peer name of remote host: %m");
162 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
163 }
164 on = 1;
165 if (keepalive &&
166 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
167 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
168 if (no_delay &&
169 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
170 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
145 int ch, fromlen, on;
146
147 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
148
149 opterr = 0;
150 while ((ch = getopt(argc, argv, ARGSTR)) != -1)
151 switch (ch) {
152 case 'D':
153 no_delay = 1;
154 break;
155 case 'a':
156 check_all = 1;
157 break;
158 case 'l':
159 __check_rhosts_file = 0;
160 break;
161 case 'n':
162 keepalive = 0;
163 break;
164#ifdef CRYPT
165 case 'x':
166 doencrypt = 1;
167 break;
168#endif
169 case '?':
170 default:
171 usage();
172 break;
173 }
174 argc -= optind;
175 argv += optind;
176
177 fromlen = sizeof (from);
178 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
179 syslog(LOG_ERR,"Can't get peer name of remote host: %m");
180 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
181 }
182 on = 1;
183 if (keepalive &&
184 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
185 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
186 if (no_delay &&
187 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
188 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
189 if (from.su_family == AF_INET)
190 {
171 on = IPTOS_LOWDELAY;
172 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
173 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
191 on = IPTOS_LOWDELAY;
192 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
193 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
194 }
174
175 doit(0, &from);
176 return 0;
177}
178
179int child;
180int netf;
181char line[MAXPATHLEN];
182int confirmed;
183
184struct winsize win = { 0, 0, 0, 0 };
185
186
187void
188doit(f, fromp)
189 int f;
195
196 doit(0, &from);
197 return 0;
198}
199
200int child;
201int netf;
202char line[MAXPATHLEN];
203int confirmed;
204
205struct winsize win = { 0, 0, 0, 0 };
206
207
208void
209doit(f, fromp)
210 int f;
190 struct sockaddr_in *fromp;
211 union sockunion *fromp;
191{
192 int master, pid, on = 1;
193 int authenticated = 0;
212{
213 int master, pid, on = 1;
214 int authenticated = 0;
194 char hostname[MAXHOSTNAMELEN];
215 char hostname[2 * MAXHOSTNAMELEN + 1];
216 char nameinfo[2 * INET6_ADDRSTRLEN + 1];
195 char c;
196
197 alarm(60);
198 read(f, &c, 1);
199
200 if (c != 0)
201 exit(1);
202
203 alarm(0);
217 char c;
218
219 alarm(60);
220 read(f, &c, 1);
221
222 if (c != 0)
223 exit(1);
224
225 alarm(0);
204 fromp->sin_port = ntohs((u_short)fromp->sin_port);
205 realhostname(hostname, sizeof(hostname) - 1, &fromp->sin_addr);
226
227 realhostname_sa(hostname, sizeof(hostname) - 1,
228 (struct sockaddr *)fromp, fromp->su_len);
229 /* error check ? */
230 fromp->su_port = ntohs((u_short)fromp->su_port);
206 hostname[sizeof(hostname) - 1] = '\0';
207
208 {
231 hostname[sizeof(hostname) - 1] = '\0';
232
233 {
209 if (fromp->sin_family != AF_INET ||
210 fromp->sin_port >= IPPORT_RESERVED ||
211 fromp->sin_port < IPPORT_RESERVED/2) {
234 if ((fromp->su_family != AF_INET &&
235#ifdef INET6
236 fromp->su_family != AF_INET6
237#endif
238 ) ||
239 fromp->su_port >= IPPORT_RESERVED ||
240 fromp->su_port < IPPORT_RESERVED/2) {
241 getnameinfo((struct sockaddr *)fromp,
242 fromp->su_len,
243 nameinfo, sizeof(nameinfo), NULL, 0,
244 NI_NUMERICHOST|NI_WITHSCOPEID);
245 /* error check ? */
212 syslog(LOG_NOTICE, "Connection from %s on illegal port",
246 syslog(LOG_NOTICE, "Connection from %s on illegal port",
213 inet_ntoa(fromp->sin_addr));
247 nameinfo);
214 fatal(f, "Permission denied", 0);
215 }
216#ifdef IP_OPTIONS
248 fatal(f, "Permission denied", 0);
249 }
250#ifdef IP_OPTIONS
217 {
251 if (fromp->su_family == AF_INET)
252 {
218 u_char optbuf[BUFSIZ/3];
219 int optsize = sizeof(optbuf), ipproto, i;
220 struct protoent *ip;
221
222 if ((ip = getprotobyname("ip")) != NULL)
223 ipproto = ip->p_proto;
224 else
225 ipproto = IPPROTO_IP;
226 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
227 &optsize) == 0 && optsize != 0) {
228 for (i = 0; i < optsize; ) {
229 u_char c = optbuf[i];
230 if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
231 syslog(LOG_NOTICE,
232 "Connection refused from %s with IP option %s",
253 u_char optbuf[BUFSIZ/3];
254 int optsize = sizeof(optbuf), ipproto, i;
255 struct protoent *ip;
256
257 if ((ip = getprotobyname("ip")) != NULL)
258 ipproto = ip->p_proto;
259 else
260 ipproto = IPPROTO_IP;
261 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
262 &optsize) == 0 && optsize != 0) {
263 for (i = 0; i < optsize; ) {
264 u_char c = optbuf[i];
265 if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
266 syslog(LOG_NOTICE,
267 "Connection refused from %s with IP option %s",
233 inet_ntoa(fromp->sin_addr),
268 inet_ntoa(fromp->su_sin.sin_addr),
234 c == IPOPT_LSRR ? "LSRR" : "SSRR");
235 exit(1);
236 }
237 if (c == IPOPT_EOL)
238 break;
239 i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
240 }
241 }
269 c == IPOPT_LSRR ? "LSRR" : "SSRR");
270 exit(1);
271 }
272 if (c == IPOPT_EOL)
273 break;
274 i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
275 }
276 }
242 }
277 }
243#endif
244 if (do_rlogin(fromp) == 0)
245 authenticated++;
246 }
247 if (confirmed == 0) {
248 write(f, "", 1);
249 confirmed = 1; /* we sent the null! */
250 }
251#ifdef CRYPT
252 if (doencrypt)
253 (void) des_enc_write(f,
254 SECURE_MESSAGE,
255 strlen(SECURE_MESSAGE),
256 schedule, &kdata->session);
257#endif
258 netf = f;
259
260 pid = forkpty(&master, line, NULL, &win);
261 if (pid < 0) {
262 if (errno == ENOENT)
263 fatal(f, "Out of ptys", 0);
264 else
265 fatal(f, "Forkpty", 1);
266 }
267 if (pid == 0) {
268 if (f > 2) /* f should always be 0, but... */
269 (void) close(f);
270 setup_term(0);
271 if (*lusername=='-') {
272 syslog(LOG_ERR, "tried to pass user \"%s\" to login",
273 lusername);
274 fatal(STDERR_FILENO, "invalid user", 0);
275 }
276 if (authenticated) {
277 execl(_PATH_LOGIN, "login", "-p",
278 "-h", hostname, "-f", lusername, (char *)NULL);
279 } else
280 execl(_PATH_LOGIN, "login", "-p",
281 "-h", hostname, lusername, (char *)NULL);
282 fatal(STDERR_FILENO, _PATH_LOGIN, 1);
283 /*NOTREACHED*/
284 }
285#ifdef CRYPT
286 /*
287 * If encrypted, don't turn on NBIO or the des read/write
288 * routines will croak.
289 */
290
291 if (!doencrypt)
292#endif
293 ioctl(f, FIONBIO, &on);
294 ioctl(master, FIONBIO, &on);
295 ioctl(master, TIOCPKT, &on);
296 signal(SIGCHLD, cleanup);
297 protocol(f, master);
298 signal(SIGCHLD, SIG_IGN);
299 cleanup(0);
300}
301
302char magic[2] = { 0377, 0377 };
303char oobdata[] = {TIOCPKT_WINDOW};
304
305/*
306 * Handle a "control" request (signaled by magic being present)
307 * in the data stream. For now, we are only willing to handle
308 * window size changes.
309 */
310int
311control(pty, cp, n)
312 int pty;
313 char *cp;
314 int n;
315{
316 struct winsize w;
317
318 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
319 return (0);
320 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
321 bcopy(cp+4, (char *)&w, sizeof(w));
322 w.ws_row = ntohs(w.ws_row);
323 w.ws_col = ntohs(w.ws_col);
324 w.ws_xpixel = ntohs(w.ws_xpixel);
325 w.ws_ypixel = ntohs(w.ws_ypixel);
326 (void)ioctl(pty, TIOCSWINSZ, &w);
327 return (4+sizeof (w));
328}
329
330/*
331 * rlogin "protocol" machine.
332 */
333void
334protocol(f, p)
335 register int f, p;
336{
337 char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
338 int pcc = 0, fcc = 0;
339 int cc, nfd, n;
340 char cntl;
341
342 /*
343 * Must ignore SIGTTOU, otherwise we'll stop
344 * when we try and set slave pty's window shape
345 * (our controlling tty is the master pty).
346 */
347 (void) signal(SIGTTOU, SIG_IGN);
348 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
349 if (f > p)
350 nfd = f + 1;
351 else
352 nfd = p + 1;
353 if (nfd > FD_SETSIZE) {
354 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
355 fatal(f, "internal error (select mask too small)", 0);
356 }
357 for (;;) {
358 fd_set ibits, obits, ebits, *omask;
359
360 FD_ZERO(&ebits);
361 FD_ZERO(&ibits);
362 FD_ZERO(&obits);
363 omask = (fd_set *)NULL;
364 if (fcc) {
365 FD_SET(p, &obits);
366 omask = &obits;
367 } else
368 FD_SET(f, &ibits);
369 if (pcc >= 0) {
370 if (pcc) {
371 FD_SET(f, &obits);
372 omask = &obits;
373 } else
374 FD_SET(p, &ibits);
375 }
376 FD_SET(p, &ebits);
377 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
378 if (errno == EINTR)
379 continue;
380 fatal(f, "select", 1);
381 }
382 if (n == 0) {
383 /* shouldn't happen... */
384 sleep(5);
385 continue;
386 }
387#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
388 if (FD_ISSET(p, &ebits)) {
389 cc = read(p, &cntl, 1);
390 if (cc == 1 && pkcontrol(cntl)) {
391 cntl |= oobdata[0];
392 send(f, &cntl, 1, MSG_OOB);
393 if (cntl & TIOCPKT_FLUSHWRITE) {
394 pcc = 0;
395 FD_CLR(p, &ibits);
396 }
397 }
398 }
399 if (FD_ISSET(f, &ibits)) {
400#ifdef CRYPT
401 if (doencrypt)
402 fcc = des_enc_read(f, fibuf, sizeof(fibuf),
403 schedule, &kdata->session);
404 else
405#endif
406 fcc = read(f, fibuf, sizeof(fibuf));
407 if (fcc < 0 && errno == EWOULDBLOCK)
408 fcc = 0;
409 else {
410 register char *cp;
411 int left, n;
412
413 if (fcc <= 0)
414 break;
415 fbp = fibuf;
416
417 top:
418 for (cp = fibuf; cp < fibuf+fcc-1; cp++)
419 if (cp[0] == magic[0] &&
420 cp[1] == magic[1]) {
421 left = fcc - (cp-fibuf);
422 n = control(p, cp, left);
423 if (n) {
424 left -= n;
425 if (left > 0)
426 bcopy(cp+n, cp, left);
427 fcc -= n;
428 goto top; /* n^2 */
429 }
430 }
431 FD_SET(p, &obits); /* try write */
432 }
433 }
434
435 if (FD_ISSET(p, &obits) && fcc > 0) {
436 cc = write(p, fbp, fcc);
437 if (cc > 0) {
438 fcc -= cc;
439 fbp += cc;
440 }
441 }
442
443 if (FD_ISSET(p, &ibits)) {
444 pcc = read(p, pibuf, sizeof (pibuf));
445 pbp = pibuf;
446 if (pcc < 0 && errno == EWOULDBLOCK)
447 pcc = 0;
448 else if (pcc <= 0)
449 break;
450 else if (pibuf[0] == 0) {
451 pbp++, pcc--;
452#ifdef CRYPT
453 if (!doencrypt)
454#endif
455 FD_SET(f, &obits); /* try write */
456 } else {
457 if (pkcontrol(pibuf[0])) {
458 pibuf[0] |= oobdata[0];
459 send(f, &pibuf[0], 1, MSG_OOB);
460 }
461 pcc = 0;
462 }
463 }
464 if ((FD_ISSET(f, &obits)) && pcc > 0) {
465#ifdef CRYPT
466 if (doencrypt)
467 cc = des_enc_write(f, pbp, pcc,
468 schedule, &kdata->session);
469 else
470#endif
471 cc = write(f, pbp, pcc);
472 if (cc < 0 && errno == EWOULDBLOCK) {
473 /*
474 * This happens when we try write after read
475 * from p, but some old kernels balk at large
476 * writes even when select returns true.
477 */
478 if (!FD_ISSET(p, &ibits))
479 sleep(5);
480 continue;
481 }
482 if (cc > 0) {
483 pcc -= cc;
484 pbp += cc;
485 }
486 }
487 }
488}
489
490void
491cleanup(signo)
492 int signo;
493{
494 char *p;
495
496 p = line + sizeof(_PATH_DEV) - 1;
497 if (logout(p))
498 logwtmp(p, "", "");
499 (void)chflags(line, 0);
500 (void)chmod(line, 0666);
501 (void)chown(line, 0, 0);
502 *p = 'p';
503 (void)chflags(line, 0);
504 (void)chmod(line, 0666);
505 (void)chown(line, 0, 0);
506 shutdown(netf, 2);
507 exit(1);
508}
509
510void
511fatal(f, msg, syserr)
512 int f;
513 char *msg;
514 int syserr;
515{
516 int len;
517 char buf[BUFSIZ], *bp = buf;
518
519 /*
520 * Prepend binary one to message if we haven't sent
521 * the magic null as confirmation.
522 */
523 if (!confirmed)
524 *bp++ = '\01'; /* error indicator */
525 if (syserr)
526 len = sprintf(bp, "rlogind: %s: %s.\r\n",
527 msg, strerror(errno));
528 else
529 len = sprintf(bp, "rlogind: %s.\r\n", msg);
530 (void) write(f, buf, bp + len - buf);
531 exit(1);
532}
533
534int
535do_rlogin(dest)
278#endif
279 if (do_rlogin(fromp) == 0)
280 authenticated++;
281 }
282 if (confirmed == 0) {
283 write(f, "", 1);
284 confirmed = 1; /* we sent the null! */
285 }
286#ifdef CRYPT
287 if (doencrypt)
288 (void) des_enc_write(f,
289 SECURE_MESSAGE,
290 strlen(SECURE_MESSAGE),
291 schedule, &kdata->session);
292#endif
293 netf = f;
294
295 pid = forkpty(&master, line, NULL, &win);
296 if (pid < 0) {
297 if (errno == ENOENT)
298 fatal(f, "Out of ptys", 0);
299 else
300 fatal(f, "Forkpty", 1);
301 }
302 if (pid == 0) {
303 if (f > 2) /* f should always be 0, but... */
304 (void) close(f);
305 setup_term(0);
306 if (*lusername=='-') {
307 syslog(LOG_ERR, "tried to pass user \"%s\" to login",
308 lusername);
309 fatal(STDERR_FILENO, "invalid user", 0);
310 }
311 if (authenticated) {
312 execl(_PATH_LOGIN, "login", "-p",
313 "-h", hostname, "-f", lusername, (char *)NULL);
314 } else
315 execl(_PATH_LOGIN, "login", "-p",
316 "-h", hostname, lusername, (char *)NULL);
317 fatal(STDERR_FILENO, _PATH_LOGIN, 1);
318 /*NOTREACHED*/
319 }
320#ifdef CRYPT
321 /*
322 * If encrypted, don't turn on NBIO or the des read/write
323 * routines will croak.
324 */
325
326 if (!doencrypt)
327#endif
328 ioctl(f, FIONBIO, &on);
329 ioctl(master, FIONBIO, &on);
330 ioctl(master, TIOCPKT, &on);
331 signal(SIGCHLD, cleanup);
332 protocol(f, master);
333 signal(SIGCHLD, SIG_IGN);
334 cleanup(0);
335}
336
337char magic[2] = { 0377, 0377 };
338char oobdata[] = {TIOCPKT_WINDOW};
339
340/*
341 * Handle a "control" request (signaled by magic being present)
342 * in the data stream. For now, we are only willing to handle
343 * window size changes.
344 */
345int
346control(pty, cp, n)
347 int pty;
348 char *cp;
349 int n;
350{
351 struct winsize w;
352
353 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
354 return (0);
355 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
356 bcopy(cp+4, (char *)&w, sizeof(w));
357 w.ws_row = ntohs(w.ws_row);
358 w.ws_col = ntohs(w.ws_col);
359 w.ws_xpixel = ntohs(w.ws_xpixel);
360 w.ws_ypixel = ntohs(w.ws_ypixel);
361 (void)ioctl(pty, TIOCSWINSZ, &w);
362 return (4+sizeof (w));
363}
364
365/*
366 * rlogin "protocol" machine.
367 */
368void
369protocol(f, p)
370 register int f, p;
371{
372 char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
373 int pcc = 0, fcc = 0;
374 int cc, nfd, n;
375 char cntl;
376
377 /*
378 * Must ignore SIGTTOU, otherwise we'll stop
379 * when we try and set slave pty's window shape
380 * (our controlling tty is the master pty).
381 */
382 (void) signal(SIGTTOU, SIG_IGN);
383 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
384 if (f > p)
385 nfd = f + 1;
386 else
387 nfd = p + 1;
388 if (nfd > FD_SETSIZE) {
389 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
390 fatal(f, "internal error (select mask too small)", 0);
391 }
392 for (;;) {
393 fd_set ibits, obits, ebits, *omask;
394
395 FD_ZERO(&ebits);
396 FD_ZERO(&ibits);
397 FD_ZERO(&obits);
398 omask = (fd_set *)NULL;
399 if (fcc) {
400 FD_SET(p, &obits);
401 omask = &obits;
402 } else
403 FD_SET(f, &ibits);
404 if (pcc >= 0) {
405 if (pcc) {
406 FD_SET(f, &obits);
407 omask = &obits;
408 } else
409 FD_SET(p, &ibits);
410 }
411 FD_SET(p, &ebits);
412 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
413 if (errno == EINTR)
414 continue;
415 fatal(f, "select", 1);
416 }
417 if (n == 0) {
418 /* shouldn't happen... */
419 sleep(5);
420 continue;
421 }
422#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
423 if (FD_ISSET(p, &ebits)) {
424 cc = read(p, &cntl, 1);
425 if (cc == 1 && pkcontrol(cntl)) {
426 cntl |= oobdata[0];
427 send(f, &cntl, 1, MSG_OOB);
428 if (cntl & TIOCPKT_FLUSHWRITE) {
429 pcc = 0;
430 FD_CLR(p, &ibits);
431 }
432 }
433 }
434 if (FD_ISSET(f, &ibits)) {
435#ifdef CRYPT
436 if (doencrypt)
437 fcc = des_enc_read(f, fibuf, sizeof(fibuf),
438 schedule, &kdata->session);
439 else
440#endif
441 fcc = read(f, fibuf, sizeof(fibuf));
442 if (fcc < 0 && errno == EWOULDBLOCK)
443 fcc = 0;
444 else {
445 register char *cp;
446 int left, n;
447
448 if (fcc <= 0)
449 break;
450 fbp = fibuf;
451
452 top:
453 for (cp = fibuf; cp < fibuf+fcc-1; cp++)
454 if (cp[0] == magic[0] &&
455 cp[1] == magic[1]) {
456 left = fcc - (cp-fibuf);
457 n = control(p, cp, left);
458 if (n) {
459 left -= n;
460 if (left > 0)
461 bcopy(cp+n, cp, left);
462 fcc -= n;
463 goto top; /* n^2 */
464 }
465 }
466 FD_SET(p, &obits); /* try write */
467 }
468 }
469
470 if (FD_ISSET(p, &obits) && fcc > 0) {
471 cc = write(p, fbp, fcc);
472 if (cc > 0) {
473 fcc -= cc;
474 fbp += cc;
475 }
476 }
477
478 if (FD_ISSET(p, &ibits)) {
479 pcc = read(p, pibuf, sizeof (pibuf));
480 pbp = pibuf;
481 if (pcc < 0 && errno == EWOULDBLOCK)
482 pcc = 0;
483 else if (pcc <= 0)
484 break;
485 else if (pibuf[0] == 0) {
486 pbp++, pcc--;
487#ifdef CRYPT
488 if (!doencrypt)
489#endif
490 FD_SET(f, &obits); /* try write */
491 } else {
492 if (pkcontrol(pibuf[0])) {
493 pibuf[0] |= oobdata[0];
494 send(f, &pibuf[0], 1, MSG_OOB);
495 }
496 pcc = 0;
497 }
498 }
499 if ((FD_ISSET(f, &obits)) && pcc > 0) {
500#ifdef CRYPT
501 if (doencrypt)
502 cc = des_enc_write(f, pbp, pcc,
503 schedule, &kdata->session);
504 else
505#endif
506 cc = write(f, pbp, pcc);
507 if (cc < 0 && errno == EWOULDBLOCK) {
508 /*
509 * This happens when we try write after read
510 * from p, but some old kernels balk at large
511 * writes even when select returns true.
512 */
513 if (!FD_ISSET(p, &ibits))
514 sleep(5);
515 continue;
516 }
517 if (cc > 0) {
518 pcc -= cc;
519 pbp += cc;
520 }
521 }
522 }
523}
524
525void
526cleanup(signo)
527 int signo;
528{
529 char *p;
530
531 p = line + sizeof(_PATH_DEV) - 1;
532 if (logout(p))
533 logwtmp(p, "", "");
534 (void)chflags(line, 0);
535 (void)chmod(line, 0666);
536 (void)chown(line, 0, 0);
537 *p = 'p';
538 (void)chflags(line, 0);
539 (void)chmod(line, 0666);
540 (void)chown(line, 0, 0);
541 shutdown(netf, 2);
542 exit(1);
543}
544
545void
546fatal(f, msg, syserr)
547 int f;
548 char *msg;
549 int syserr;
550{
551 int len;
552 char buf[BUFSIZ], *bp = buf;
553
554 /*
555 * Prepend binary one to message if we haven't sent
556 * the magic null as confirmation.
557 */
558 if (!confirmed)
559 *bp++ = '\01'; /* error indicator */
560 if (syserr)
561 len = sprintf(bp, "rlogind: %s: %s.\r\n",
562 msg, strerror(errno));
563 else
564 len = sprintf(bp, "rlogind: %s.\r\n", msg);
565 (void) write(f, buf, bp + len - buf);
566 exit(1);
567}
568
569int
570do_rlogin(dest)
536 struct sockaddr_in *dest;
571 union sockunion *dest;
537{
538 int retval;
572{
573 int retval;
574 int af;
575 char *addr;
539
540 getstr(rusername, sizeof(rusername), "remuser too long");
541 getstr(lusername, sizeof(lusername), "locuser too long");
542 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
543
544#ifndef NO_PAM
545 retval = auth_pam(lusername);
546
547 if (retval) {
548 if (retval == -1) {
549 syslog(LOG_ERR, "PAM authentication failed");
550 }
551 else {
552 syslog(LOG_ERR,
553 "User %s failed PAM authentication", lusername);
554 exit(1);
555 }
556 }
557#endif
558 pwd = getpwnam(lusername);
559 if (pwd == NULL)
560 return (-1);
561 /* XXX why don't we syslog() failure? */
576
577 getstr(rusername, sizeof(rusername), "remuser too long");
578 getstr(lusername, sizeof(lusername), "locuser too long");
579 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
580
581#ifndef NO_PAM
582 retval = auth_pam(lusername);
583
584 if (retval) {
585 if (retval == -1) {
586 syslog(LOG_ERR, "PAM authentication failed");
587 }
588 else {
589 syslog(LOG_ERR,
590 "User %s failed PAM authentication", lusername);
591 exit(1);
592 }
593 }
594#endif
595 pwd = getpwnam(lusername);
596 if (pwd == NULL)
597 return (-1);
598 /* XXX why don't we syslog() failure? */
562 return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
563 rusername, lusername));
599
600 af = dest->su_family;
601 switch (af) {
602 case AF_INET:
603 addr = (char *)&dest->su_sin.sin_addr;
604 break;
605#ifdef INET6
606 case AF_INET6:
607 addr = (char *)&dest->su_sin6.sin6_addr;
608 break;
609#endif
610 default:
611 return -1; /*EAFNOSUPPORT*/
612 }
613
614 return (iruserok_af(addr, pwd->pw_uid == 0, rusername, lusername, af));
564}
565
566void
567getstr(buf, cnt, errmsg)
568 char *buf;
569 int cnt;
570 char *errmsg;
571{
572 char c;
573
574 do {
575 if (read(0, &c, 1) != 1)
576 exit(1);
577 if (--cnt < 0)
578 fatal(STDOUT_FILENO, errmsg, 0);
579 *buf++ = c;
580 } while (c != 0);
581}
582
583extern char **environ;
584
585void
586setup_term(fd)
587 int fd;
588{
589 register char *cp = index(term+ENVSIZE, '/');
590 char *speed;
591 struct termios tt;
592
593#ifndef notyet
594 tcgetattr(fd, &tt);
595 if (cp) {
596 *cp++ = '\0';
597 speed = cp;
598 cp = index(speed, '/');
599 if (cp)
600 *cp++ = '\0';
601 cfsetspeed(&tt, atoi(speed));
602 }
603
604 tt.c_iflag = TTYDEF_IFLAG;
605 tt.c_oflag = TTYDEF_OFLAG;
606 tt.c_lflag = TTYDEF_LFLAG;
607 tcsetattr(fd, TCSAFLUSH, &tt);
608#else
609 if (cp) {
610 *cp++ = '\0';
611 speed = cp;
612 cp = index(speed, '/');
613 if (cp)
614 *cp++ = '\0';
615 tcgetattr(fd, &tt);
616 cfsetspeed(&tt, atoi(speed));
617 tcsetattr(fd, TCSAFLUSH, &tt);
618 }
619#endif
620
621 env[0] = term;
622 env[1] = 0;
623 environ = env;
624}
625
626void
627usage()
628{
629 syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]");
630}
615}
616
617void
618getstr(buf, cnt, errmsg)
619 char *buf;
620 int cnt;
621 char *errmsg;
622{
623 char c;
624
625 do {
626 if (read(0, &c, 1) != 1)
627 exit(1);
628 if (--cnt < 0)
629 fatal(STDOUT_FILENO, errmsg, 0);
630 *buf++ = c;
631 } while (c != 0);
632}
633
634extern char **environ;
635
636void
637setup_term(fd)
638 int fd;
639{
640 register char *cp = index(term+ENVSIZE, '/');
641 char *speed;
642 struct termios tt;
643
644#ifndef notyet
645 tcgetattr(fd, &tt);
646 if (cp) {
647 *cp++ = '\0';
648 speed = cp;
649 cp = index(speed, '/');
650 if (cp)
651 *cp++ = '\0';
652 cfsetspeed(&tt, atoi(speed));
653 }
654
655 tt.c_iflag = TTYDEF_IFLAG;
656 tt.c_oflag = TTYDEF_OFLAG;
657 tt.c_lflag = TTYDEF_LFLAG;
658 tcsetattr(fd, TCSAFLUSH, &tt);
659#else
660 if (cp) {
661 *cp++ = '\0';
662 speed = cp;
663 cp = index(speed, '/');
664 if (cp)
665 *cp++ = '\0';
666 tcgetattr(fd, &tt);
667 cfsetspeed(&tt, atoi(speed));
668 tcsetattr(fd, TCSAFLUSH, &tt);
669 }
670#endif
671
672 env[0] = term;
673 env[1] = 0;
674 environ = env;
675}
676
677void
678usage()
679{
680 syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]");
681}