1 /*
2 * Copyright (c) 1995 Danny Gasparovski.
3 *
4 * Please read the file COPYRIGHT for the
5 * terms and conditions of the copyright.
6 */
7
8 #define WANT_SYS_IOCTL_H
9 #include <stdlib.h>
10 #include "slirp.h"
11
12 u_int curtime, time_fasttimo, last_slowtimo, detach_time;
13 u_int detach_wait = 600000; /* 10 minutes */
14
15 #if 0
16 int x_port = -1;
17 int x_display = 0;
18 int x_screen = 0;
19
20 int
21 show_x(buff, inso)
22 char *buff;
23 struct socket *inso;
24 {
25 if (x_port < 0) {
26 lprint("X Redir: X not being redirected.\r\n");
27 } else {
28 lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n",
29 inet_ntoa(our_addr), x_port, x_screen);
30 lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n",
31 inet_ntoa(our_addr), x_port, x_screen);
32 if (x_display)
33 lprint("X Redir: Redirecting to display %d\r\n", x_display);
34 }
35
36 return CFG_OK;
37 }
38
39
40 /*
41 * XXX Allow more than one X redirection?
42 */
43 void
44 redir_x(inaddr, start_port, display, screen)
45 u_int32_t inaddr;
46 int start_port;
47 int display;
48 int screen;
49 {
50 int i;
51
52 if (x_port >= 0) {
53 lprint("X Redir: X already being redirected.\r\n");
54 show_x(0, 0);
55 } else {
56 for (i = 6001 + (start_port-1); i <= 6100; i++) {
57 if (solisten(htons(i), inaddr, htons(6000 + display), 0)) {
58 /* Success */
59 x_port = i - 6000;
60 x_display = display;
61 x_screen = screen;
62 show_x(0, 0);
63 return;
64 }
65 }
66 lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n");
67 }
68 }
69 #endif
70
71 #ifndef HAVE_INET_ATON
72 int
inet_aton(const char * cp,struct in_addr * ia)73 inet_aton(const char *cp, struct in_addr *ia)
74 {
75 u_int32_t addr = inet_addr(cp);
76 if (addr == 0xffffffff)
77 return 0;
78 ia->s_addr = addr;
79 return 1;
80 }
81 #endif
82
83 /*
84 * Get our IP address and put it in our_addr
85 */
86 void
getouraddr(void)87 getouraddr(void)
88 {
89 char buff[256];
90 struct hostent *he = NULL;
91
92 if (gethostname(buff,256) == 0)
93 he = gethostbyname(buff);
94 if (he)
95 our_addr = *(struct in_addr *)he->h_addr;
96 if (our_addr.s_addr == 0)
97 our_addr.s_addr = loopback_addr.s_addr;
98 }
99
100
101 struct quehead {
102 struct quehead *qh_link;
103 struct quehead *qh_rlink;
104 };
105
106 void
insque(void * a,void * b)107 insque(void *a, void *b)
108 {
109 register struct quehead *element = (struct quehead *) a;
110 register struct quehead *head = (struct quehead *) b;
111 element->qh_link = head->qh_link;
112 head->qh_link = (struct quehead *)element;
113 element->qh_rlink = (struct quehead *)head;
114 ((struct quehead *)(element->qh_link))->qh_rlink
115 = (struct quehead *)element;
116 }
117
118 void
remque(void * a)119 remque(void *a)
120 {
121 register struct quehead *element = (struct quehead *) a;
122 ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
123 ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
124 element->qh_rlink = NULL;
125 /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */
126 }
127
128 /* #endif */
129
130
131 int
add_exec(struct ex_list ** ex_ptr,int do_pty,char * exec,int addr,int port)132 add_exec(struct ex_list **ex_ptr, int do_pty, char *exec, int addr, int port)
133 {
134 struct ex_list *tmp_ptr;
135
136 /* First, check if the port is "bound" */
137 for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
138 if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
139 return -1;
140 }
141
142 tmp_ptr = *ex_ptr;
143 *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
144 (*ex_ptr)->ex_fport = port;
145 (*ex_ptr)->ex_addr = addr;
146 (*ex_ptr)->ex_pty = do_pty;
147 (*ex_ptr)->ex_exec = strdup(exec);
148 (*ex_ptr)->ex_next = tmp_ptr;
149 return 0;
150 }
151
152 #ifndef HAVE_STRERROR
153
154 /*
155 * For systems with no strerror
156 */
157
158 extern int sys_nerr;
159 extern char *sys_errlist[];
160
161 char *
162 strerror(error)
163 int error;
164 {
165 if (error < sys_nerr)
166 return sys_errlist[error];
167 else
168 return "Unknown error.";
169 }
170
171 #endif
172
173
174 #ifdef _WIN32
175
176 int
fork_exec(struct socket * so,char * ex,int do_pty)177 fork_exec(struct socket *so, char *ex, int do_pty)
178 {
179 /* not implemented */
180 return 0;
181 }
182
183 #else
184
185 int
slirp_openpty(int * amaster,int * aslave)186 slirp_openpty(int *amaster, int *aslave)
187 {
188 register int master, slave;
189
190 #ifdef HAVE_GRANTPT
191 char *ptr;
192
193 if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
194 grantpt(master) < 0 ||
195 unlockpt(master) < 0 ||
196 (ptr = ptsname(master)) == NULL) {
197 close(master);
198 return -1;
199 }
200
201 if ((slave = open(ptr, O_RDWR)) < 0 ||
202 ioctl(slave, I_PUSH, "ptem") < 0 ||
203 ioctl(slave, I_PUSH, "ldterm") < 0 ||
204 ioctl(slave, I_PUSH, "ttcompat") < 0) {
205 close(master);
206 close(slave);
207 return -1;
208 }
209
210 *amaster = master;
211 *aslave = slave;
212 return 0;
213
214 #else
215
216 static char line[] = "/dev/ptyXX";
217 register const char *cp1, *cp2;
218
219 for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
220 line[8] = *cp1;
221 for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
222 line[9] = *cp2;
223 if ((master = open(line, O_RDWR, 0)) == -1) {
224 if (errno == ENOENT)
225 return (-1); /* out of ptys */
226 } else {
227 line[5] = 't';
228 /* These will fail */
229 (void) chown(line, getuid(), 0);
230 (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
231 #ifdef HAVE_REVOKE
232 (void) revoke(line);
233 #endif
234 if ((slave = open(line, O_RDWR, 0)) != -1) {
235 *amaster = master;
236 *aslave = slave;
237 return 0;
238 }
239 (void) close(master);
240 line[5] = 'p';
241 }
242 }
243 }
244 errno = ENOENT; /* out of ptys */
245 return (-1);
246 #endif
247 }
248
249 /*
250 * XXX This is ugly
251 * We create and bind a socket, then fork off to another
252 * process, which connects to this socket, after which we
253 * exec the wanted program. If something (strange) happens,
254 * the accept() call could block us forever.
255 *
256 * do_pty = 0 Fork/exec inetd style
257 * do_pty = 1 Fork/exec using slirp.telnetd
258 * do_ptr = 2 Fork/exec using pty
259 */
260 int
fork_exec(struct socket * so,char * ex,int do_pty)261 fork_exec(struct socket *so, char *ex, int do_pty)
262 {
263 int s;
264 struct sockaddr_in addr;
265 socklen_t addrlen = sizeof(addr);
266 int opt;
267 int master;
268 char *argv[256];
269 #if 0
270 char buff[256];
271 #endif
272 /* don't want to clobber the original */
273 char *bptr;
274 char *curarg;
275 int c, i, ret;
276
277 DEBUG_CALL("fork_exec");
278 DEBUG_ARG("so = %lx", (long)so);
279 DEBUG_ARG("ex = %lx", (long)ex);
280 DEBUG_ARG("do_pty = %lx", (long)do_pty);
281
282 if (do_pty == 2) {
283 if (slirp_openpty(&master, &s) == -1) {
284 lprint("Error: openpty failed: %s\n", strerror(errno));
285 return 0;
286 }
287 } else {
288 memset(&addr, 0, sizeof(struct sockaddr_in));
289 addr.sin_family = AF_INET;
290 addr.sin_port = 0;
291 addr.sin_addr.s_addr = INADDR_ANY;
292
293 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
294 bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
295 listen(s, 1) < 0) {
296 lprint("Error: inet socket: %s\n", strerror(errno));
297 closesocket(s);
298
299 return 0;
300 }
301 }
302
303 switch(fork()) {
304 case -1:
305 lprint("Error: fork failed: %s\n", strerror(errno));
306 close(s);
307 if (do_pty == 2)
308 close(master);
309 return 0;
310
311 case 0:
312 /* Set the DISPLAY */
313 if (do_pty == 2) {
314 (void) close(master);
315 #ifdef TIOCSCTTY /* XXXXX */
316 (void) setsid();
317 ioctl(s, TIOCSCTTY, (char *)NULL);
318 #endif
319 } else {
320 getsockname(s, (struct sockaddr *)&addr, &addrlen);
321 close(s);
322 /*
323 * Connect to the socket
324 * XXX If any of these fail, we're in trouble!
325 */
326 s = socket(AF_INET, SOCK_STREAM, 0);
327 addr.sin_addr = loopback_addr;
328 do {
329 ret = connect(s, (struct sockaddr *)&addr, addrlen);
330 } while (ret < 0 && errno == EINTR);
331 }
332
333 #if 0
334 if (x_port >= 0) {
335 #ifdef HAVE_SETENV
336 sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
337 setenv("DISPLAY", buff, 1);
338 #else
339 sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
340 putenv(buff);
341 #endif
342 }
343 #endif
344 dup2(s, 0);
345 dup2(s, 1);
346 dup2(s, 2);
347 for (s = 3; s <= 255; s++)
348 close(s);
349
350 i = 0;
351 bptr = strdup(ex); /* No need to free() this */
352 if (do_pty == 1) {
353 /* Setup "slirp.telnetd -x" */
354 argv[i++] = strdup("slirp.telnetd");
355 argv[i++] = strdup("-x");
356 argv[i++] = bptr;
357 } else
358 do {
359 /* Change the string into argv[] */
360 curarg = bptr;
361 while (*bptr != ' ' && *bptr != (char)0)
362 bptr++;
363 c = *bptr;
364 *bptr++ = (char)0;
365 argv[i++] = strdup(curarg);
366 } while (c);
367
368 argv[i] = 0;
369 execvp(argv[0], argv);
370
371 /* Ooops, failed, let's tell the user why */
372 {
373 char buff[256];
374
375 sprintf(buff, "Error: execvp of %s failed: %s\n",
376 argv[0], strerror(errno));
377 write(2, buff, strlen(buff)+1);
378 }
379 close(0); close(1); close(2); /* XXX */
380 exit(1);
381
382 default:
383 if (do_pty == 2) {
384 close(s);
385 so->s = master;
386 } else {
387 /*
388 * XXX this could block us...
389 * XXX Should set a timer here, and if accept() doesn't
390 * return after X seconds, declare it a failure
391 * The only reason this will block forever is if socket()
392 * of connect() fail in the child process
393 */
394 do {
395 so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
396 } while (so->s < 0 && errno == EINTR);
397 closesocket(s);
398 opt = 1;
399 setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
400 opt = 1;
401 setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
402 }
403 fd_nonblock(so->s);
404
405 /* Append the telnet options now */
406 if (so->so_m != 0 && do_pty == 1) {
407 sbappend(so, so->so_m);
408 so->so_m = 0;
409 }
410
411 return 1;
412 }
413 }
414 #endif
415
416 #ifndef HAVE_STRDUP
417 char *
418 strdup(str)
419 const char *str;
420 {
421 char *bptr;
422
423 bptr = (char *)malloc(strlen(str)+1);
424 strcpy(bptr, str);
425
426 return bptr;
427 }
428 #endif
429
430 #if 0
431 void
432 snooze_hup(num)
433 int num;
434 {
435 int s, ret;
436 #ifndef NO_UNIX_SOCKETS
437 struct sockaddr_un sock_un;
438 #endif
439 struct sockaddr_in sock_in;
440 char buff[256];
441
442 ret = -1;
443 if (slirp_socket_passwd) {
444 s = socket(AF_INET, SOCK_STREAM, 0);
445 if (s < 0)
446 slirp_exit(1);
447 sock_in.sin_family = AF_INET;
448 sock_in.sin_addr.s_addr = slirp_socket_addr;
449 sock_in.sin_port = htons(slirp_socket_port);
450 if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
451 slirp_exit(1); /* just exit...*/
452 sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit);
453 write(s, buff, strlen(buff)+1);
454 }
455 #ifndef NO_UNIX_SOCKETS
456 else {
457 s = socket(AF_UNIX, SOCK_STREAM, 0);
458 if (s < 0)
459 slirp_exit(1);
460 sock_un.sun_family = AF_UNIX;
461 strcpy(sock_un.sun_path, socket_path);
462 if (connect(s, (struct sockaddr *)&sock_un,
463 sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0)
464 slirp_exit(1);
465 sprintf(buff, "kill none:%d", slirp_socket_unit);
466 write(s, buff, strlen(buff)+1);
467 }
468 #endif
469 slirp_exit(0);
470 }
471
472
473 void
474 snooze()
475 {
476 sigset_t s;
477 int i;
478
479 /* Don't need our data anymore */
480 /* XXX This makes SunOS barf */
481 /* brk(0); */
482
483 /* Close all fd's */
484 for (i = 255; i >= 0; i--)
485 close(i);
486
487 signal(SIGQUIT, slirp_exit);
488 signal(SIGHUP, snooze_hup);
489 sigemptyset(&s);
490
491 /* Wait for any signal */
492 sigsuspend(&s);
493
494 /* Just in case ... */
495 exit(255);
496 }
497
498 void
499 relay(s)
500 int s;
501 {
502 char buf[8192];
503 int n;
504 fd_set readfds;
505 struct ttys *ttyp;
506
507 /* Don't need our data anymore */
508 /* XXX This makes SunOS barf */
509 /* brk(0); */
510
511 signal(SIGQUIT, slirp_exit);
512 signal(SIGHUP, slirp_exit);
513 signal(SIGINT, slirp_exit);
514 signal(SIGTERM, slirp_exit);
515
516 /* Fudge to get term_raw and term_restore to work */
517 if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
518 lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
519 slirp_exit (1);
520 }
521 ttyp->fd = 0;
522 ttyp->flags |= TTY_CTTY;
523 term_raw(ttyp);
524
525 while (1) {
526 FD_ZERO(&readfds);
527
528 FD_SET(0, &readfds);
529 FD_SET(s, &readfds);
530
531 n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
532
533 if (n <= 0)
534 slirp_exit(0);
535
536 if (FD_ISSET(0, &readfds)) {
537 n = read(0, buf, 8192);
538 if (n <= 0)
539 slirp_exit(0);
540 n = writen(s, buf, n);
541 if (n <= 0)
542 slirp_exit(0);
543 }
544
545 if (FD_ISSET(s, &readfds)) {
546 n = read(s, buf, 8192);
547 if (n <= 0)
548 slirp_exit(0);
549 n = writen(0, buf, n);
550 if (n <= 0)
551 slirp_exit(0);
552 }
553 }
554
555 /* Just in case.... */
556 exit(1);
557 }
558 #endif
559
560 int (*lprint_print) _P((void *, const char *, va_list));
561 char *lprint_ptr, *lprint_ptr2, **lprint_arg;
562
563 void
564 #if defined(__STDC__) || defined(_MSC_VER)
lprint(const char * format,...)565 lprint(const char *format, ...)
566 #else
567 lprint(va_alist) va_dcl
568 #endif
569 {
570 va_list args;
571
572 #if defined(__STDC__) || defined(_MSC_VER)
573 va_start(args, format);
574 #else
575 char *format;
576 va_start(args);
577 format = va_arg(args, char *);
578 #endif
579 #if 0
580 /* If we're printing to an sbuf, make sure there's enough room */
581 /* XXX +100? */
582 if (lprint_sb) {
583 if ((lprint_ptr - lprint_sb->sb_wptr) >=
584 (lprint_sb->sb_datalen - (strlen(format) + 100))) {
585 int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
586 int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
587 int deltap = lprint_ptr - lprint_sb->sb_data;
588
589 lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
590 lprint_sb->sb_datalen + TCP_SNDSPACE);
591
592 /* Adjust all values */
593 lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
594 lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
595 lprint_ptr = lprint_sb->sb_data + deltap;
596
597 lprint_sb->sb_datalen += TCP_SNDSPACE;
598 }
599 }
600 #endif
601 if (lprint_print)
602 lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
603
604 /* Check if they want output to be logged to file as well */
605 if (lfd) {
606 /*
607 * Remove \r's
608 * otherwise you'll get ^M all over the file
609 */
610 int len = strlen(format);
611 char *bptr1, *bptr2;
612
613 bptr1 = bptr2 = strdup(format);
614
615 while (len--) {
616 if (*bptr1 == '\r')
617 memcpy(bptr1, bptr1+1, len+1);
618 else
619 bptr1++;
620 }
621 vfprintf(lfd, bptr2, args);
622 free(bptr2);
623 }
624 va_end(args);
625 }
626
627 void
add_emu(char * buff)628 add_emu(char *buff)
629 {
630 u_int lport, fport;
631 u_int8_t tos = 0, emu = 0;
632 char buff1[256], buff2[256], buff4[128];
633 char *buff3 = buff4;
634 struct emu_t *emup;
635 struct socket *so;
636
637 if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
638 lprint("Error: Bad arguments\r\n");
639 return;
640 }
641
642 if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
643 lport = 0;
644 if (sscanf(buff1, "%d", &fport) != 1) {
645 lprint("Error: Bad first argument\r\n");
646 return;
647 }
648 }
649
650 if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
651 buff3 = 0;
652 if (sscanf(buff2, "%256s", buff1) != 1) {
653 lprint("Error: Bad second argument\r\n");
654 return;
655 }
656 }
657
658 if (buff3) {
659 if (strcmp(buff3, "lowdelay") == 0)
660 tos = IPTOS_LOWDELAY;
661 else if (strcmp(buff3, "throughput") == 0)
662 tos = IPTOS_THROUGHPUT;
663 else {
664 lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n");
665 return;
666 }
667 }
668
669 if (strcmp(buff1, "ftp") == 0)
670 emu = EMU_FTP;
671 else if (strcmp(buff1, "irc") == 0)
672 emu = EMU_IRC;
673 else if (strcmp(buff1, "none") == 0)
674 emu = EMU_NONE; /* ie: no emulation */
675 else {
676 lprint("Error: Unknown service\r\n");
677 return;
678 }
679
680 /* First, check that it isn't already emulated */
681 for (emup = tcpemu; emup; emup = emup->next) {
682 if (emup->lport == lport && emup->fport == fport) {
683 lprint("Error: port already emulated\r\n");
684 return;
685 }
686 }
687
688 /* link it */
689 emup = (struct emu_t *)malloc(sizeof (struct emu_t));
690 emup->lport = (u_int16_t)lport;
691 emup->fport = (u_int16_t)fport;
692 emup->tos = tos;
693 emup->emu = emu;
694 emup->next = tcpemu;
695 tcpemu = emup;
696
697 /* And finally, mark all current sessions, if any, as being emulated */
698 for (so = tcb.so_next; so != &tcb; so = so->so_next) {
699 if ((lport && lport == ntohs(so->so_lport)) ||
700 (fport && fport == ntohs(so->so_fport))) {
701 if (emu)
702 so->so_emu = emu;
703 if (tos)
704 so->so_iptos = tos;
705 }
706 }
707
708 lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
709 }
710
711 #ifdef BAD_SPRINTF
712
713 #undef vsprintf
714 #undef sprintf
715
716 /*
717 * Some BSD-derived systems have a sprintf which returns char *
718 */
719
720 int
721 vsprintf_len(string, format, args)
722 char *string;
723 const char *format;
724 va_list args;
725 {
726 vsprintf(string, format, args);
727 return strlen(string);
728 }
729
730 int
731 #ifdef __STDC__
sprintf_len(char * string,const char * format,...)732 sprintf_len(char *string, const char *format, ...)
733 #else
734 sprintf_len(va_alist) va_dcl
735 #endif
736 {
737 va_list args;
738 #ifdef __STDC__
739 va_start(args, format);
740 #else
741 char *string;
742 char *format;
743 va_start(args);
744 string = va_arg(args, char *);
745 format = va_arg(args, char *);
746 #endif
747 vsprintf(string, format, args);
748 return strlen(string);
749 }
750
751 #endif
752
753 void
u_sleep(int usec)754 u_sleep(int usec)
755 {
756 struct timeval t;
757 fd_set fdset;
758
759 FD_ZERO(&fdset);
760
761 t.tv_sec = 0;
762 t.tv_usec = usec * 1000;
763
764 select(0, &fdset, &fdset, &fdset, &t);
765 }
766
767 /*
768 * Set fd blocking and non-blocking
769 */
770
771 void
fd_nonblock(SLIRP_SOCKET fd)772 fd_nonblock(SLIRP_SOCKET fd)
773 {
774 #if defined USE_FIONBIO && defined FIONBIO
775 ioctlsockopt_t opt = 1;
776
777 ioctlsocket(fd, FIONBIO, &opt);
778 #else
779 int opt;
780
781 opt = fcntl(fd, F_GETFL, 0);
782 opt |= O_NONBLOCK;
783 fcntl(fd, F_SETFL, opt);
784 #endif
785 }
786
787 void
fd_block(SLIRP_SOCKET fd)788 fd_block(SLIRP_SOCKET fd)
789 {
790 #if defined USE_FIONBIO && defined FIONBIO
791 ioctlsockopt_t opt = 0;
792
793 ioctlsocket(fd, FIONBIO, &opt);
794 #else
795 int opt;
796
797 opt = fcntl(fd, F_GETFL, 0);
798 opt &= ~O_NONBLOCK;
799 fcntl(fd, F_SETFL, opt);
800 #endif
801 }
802
803
804 #if 0
805 /*
806 * invoke RSH
807 */
808 int
809 rsh_exec(so,ns, user, host, args)
810 struct socket *so;
811 struct socket *ns;
812 char *user;
813 char *host;
814 char *args;
815 {
816 int fd[2];
817 int fd0[2];
818 int s;
819 char buff[256];
820
821 DEBUG_CALL("rsh_exec");
822 DEBUG_ARG("so = %lx", (long)so);
823
824 if (pipe(fd)<0) {
825 lprint("Error: pipe failed: %s\n", strerror(errno));
826 return 0;
827 }
828 /* #ifdef HAVE_SOCKETPAIR */
829 #if 1
830 if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) {
831 close(fd[0]);
832 close(fd[1]);
833 lprint("Error: openpty failed: %s\n", strerror(errno));
834 return 0;
835 }
836 #else
837 if (slirp_openpty(&fd0[0], &fd0[1]) == -1) {
838 close(fd[0]);
839 close(fd[1]);
840 lprint("Error: openpty failed: %s\n", strerror(errno));
841 return 0;
842 }
843 #endif
844
845 switch(fork()) {
846 case -1:
847 lprint("Error: fork failed: %s\n", strerror(errno));
848 close(fd[0]);
849 close(fd[1]);
850 close(fd0[0]);
851 close(fd0[1]);
852 return 0;
853
854 case 0:
855 close(fd[0]);
856 close(fd0[0]);
857
858 /* Set the DISPLAY */
859 if (x_port >= 0) {
860 #ifdef HAVE_SETENV
861 sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
862 setenv("DISPLAY", buff, 1);
863 #else
864 sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
865 putenv(buff);
866 #endif
867 }
868
869 dup2(fd0[1], 0);
870 dup2(fd0[1], 1);
871 dup2(fd[1], 2);
872 for (s = 3; s <= 255; s++)
873 close(s);
874
875 execlp("rsh","rsh","-l", user, host, args, NULL);
876
877 /* Ooops, failed, let's tell the user why */
878
879 sprintf(buff, "Error: execlp of %s failed: %s\n",
880 "rsh", strerror(errno));
881 write(2, buff, strlen(buff)+1);
882 close(0); close(1); close(2); /* XXX */
883 exit(1);
884
885 default:
886 close(fd[1]);
887 close(fd0[1]);
888 ns->s=fd[0];
889 so->s=fd0[0];
890
891 return 1;
892 }
893 }
894 #endif
895