1 /*
2 
3     encapsulate.c, part of
4     netpipes: network pipe utilities
5     Copyright (C) 1996 Robert Forsman
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21     */
22 
23 static char info[] = "encapsulate: a  utility for sockets\nWritten 1996 by Robert Forsman <thoth@purplefrog.com>\n";
24 
25 /*
26    Encapsulate
27 
28    encapsulate is designed to be used in a script spawned as the child
29    of a faucet or hose.
30 
31   ============================================================
32 
33   NEW version of encapsulate now.  It uses the Session Control
34   Protocol described in http://sunsite.unc.edu/ses/scp.html .
35 
36   ARGS:
37 
38   If they don't specify --client or --server, compare your socket ID
39   (IP first, then port if IPs match) to the other end.  The
40   numerically lower one is the server.  The MSB is the first octet of
41   the IP.  If they're identical, you have bigger problems >:)
42 
43   For each --outfd on the subprocess, send a SYN packet with a new
44   session ID.  For each --infd on the subprocess, set aside a
45   structure to wait for a SYN packet from the other end.  Each SYN
46   packet will be associated with a file descriptor in the order they
47   were specified on the command line.
48 
49   The --duplex descriptors are trickier.  They need one session ID,
50   but who gets to allocate it?  With --Duplex the "client" (which
51   could be local or remote) allocates the session ID and sends the SYN
52   packet.  The "server" then sends a SYN packet for the same session
53   ID causing the connection to become two-way.
54 
55   With --duplex, the local program waits for a SYN from the other side
56   and responds with a SYN of its own to duplex the session.  With
57   --DUPLEX the local program sends the SYN packet and the remote side
58   is expected to duplex the session.  The short flags correspond to
59   the long like so:
60 
61   --Duplex n		-dn
62   --duplex n		-ion
63   --DUPLEX n		-oin
64 
65   Notice how the order of the i and o correspond to the order in which
66   the SYN packets are sent.
67 
68   INTEROPERABILITY
69 
70   This program is immensely complicated by the fact that I want it to
71   interoperate with a server that could also be speaking SCP (with
72   some theoretical restrictions to prevent the following problems).
73 
74   1) SYN packets to associate with input descriptors could come
75   arbitrarily late in the conversaion.
76 
77   2) The remote program might not be obeying our rules for the
78   --Duplex family of directives (this particular problem, and others,
79   could also be caused by command line mismatches on either side of
80   the link).
81 
82   3) In my reading I haven't found any restrictions on bouncing the
83   connection between RO, RW and WO, which would wreak havoc on the
84   file-descriptor model `encapsulate' is based on.
85 
86   For #1, I plan to just cope.  As long as the SYNs eventually arrive,
87   things should work.  #2 is stickier, and I want to figure out an
88   appropriate way to give a warning that a deadlock might be
89   occurring.  #3 I will handle by ruthless application of RESET
90   packets and messages to stderr.
91 
92 
93   INCOMING BUFFER: store data from socket before it is sent to the
94   subprocess.
95 
96   HEADER BUFFER: store headers from new SCP packets.
97 
98   OUTGOING BUFFER 1: store data from subprocess before it is
99   encapsulated in an SCP packet.  NOTE: once data from a subprocess
100   descriptor is stored in here, no other outgoing (subprocess-
101   writeable) descriptors should be polled.  There is only one of these
102   buffers.  This might result in a kind of starvation, so consider
103   doing a round-robin thing with the outgoing subprocess descriptors
104   that have data available.
105 
106   OUTGOING BUFFER 2: store the SCP packet while it's being written to
107   the socket.  While this buffer is in use, no packets can be
108   encapsulated, so data can accumulate in outgoing buffer 1.  This is
109   good because then we have a bigger packet for next time.
110 
111   Note: we'll be able to read arbitrarily-sized SCP packets due to the
112   design of the state machine.  We'll be limited in the size of
113   packets we send by the size of outgoing buffer 1.  I can hear you
114   saying "so what".
115 
116  */
117 
118 #include <stdio.h>
119 #include	<errno.h>
120 extern int errno;		/* I hate the errno header file */
121 #include <stdlib.h>
122 #include <unistd.h>
123 #include <signal.h>
124 #include <sys/socket.h>
125 #include <netinet/in.h>
126 #include <sys/time.h>
127 #include <sys/types.h>
128 #include <sys/wait.h>
129 #include <sys/un.h>
130 
131 #include "common.h"
132 #include "memmove.h"
133 
134 #define EXITCODE_ARGS		127
135 #define EXITCODE_SYSCALLFAILED	126
136 #define EXITCODE_EXECFAILED	125
137 #define EXITCODE_SIGNAL		124
138 #define EXITCODE_PROTOCOL	123
139 #define EXITCODE_GOT_RESET	122
140 
141 #define PACKETCODE_EOF		0
142 #define PACKETCODE_EOF_WAITING	1
143 #define PACKETCODE_EXITSTATUS	2
144 
145 /*typedef	short Nshort;*/
146 
147 #define SCP_SYN		0x80
148 #define SCP_FIN		0x40
149 #define SCP_PUSH	0x20
150 #define SCP_RESET	0x10
151 
152 #define SESSION_ENCAP	70
153 
154 /* encapsulate Control Protocol */
155 #define ECP_EOF		0
156 #define ECP_EXITCODE	1
157 
158 /********************************************************************/
159 
160 static int subproc=0;
161 static int verbose=0;
162 
163 /********************************************************************/
164 
usage()165 static void usage()
166 {
167     fprintf(stderr,"Usage : %s --fd n [ --verbose ] [ --subproc [ --infd n ] [ --outfd n ] [ --Duplex n ] [ --duplex n ] [ --DUPLEX n ] [ --prefer-local ] [ --prefer-remote ] [ --local-only ] [ --remote-only ] [ --client ] [ --server ] -[#n][v][s[in][on][dn][ion][oin][l][r][L][R]] <command> <args>  ]\n",
168 	    progname);
169 }
170 
171 /********************************************************************/
172 
173 static int remote_return_code = 0;
174 static int local_return_code = 0;
175 static int exitcode_warnings = 0;
176 
177 static int	child_unreaped = 0;
178 static int	child_running = 0;
179 static void probe_child();
180 
Im_server_p(sock_fd)181 static int Im_server_p(sock_fd)
182      int	sock_fd;
183 {
184     struct sockaddr_in	me, him;
185     int	len, i;
186 
187     len = sizeof(me);
188     getsockname(sock_fd, (struct sockaddr*)&me, &len);
189 
190     len = sizeof(him);
191     getpeername(sock_fd, (struct sockaddr*)&him, &len);
192 
193     i = memcmp(&me.sin_addr, &him.sin_addr, 4);
194     if (i<0)
195 	return 1;
196     else if (i>0)
197 	return 0;
198 
199     if (me.sin_port<him.sin_port)
200 	return 1;
201     else
202 	return 0;
203 }
204 
205 struct pipeline {
206     int	child_fd;
207     int pipe[2]; /* [0] is for the parent.  [1] is for the child */
208     /* this is different from the pipe system call */
209     enum pipe_polarity {
210 	READABLE,
211 	DUPLEX/*conditional initiate*/,
212 	DUPLEX_IO/*they initiate*/,
213 	DUPLEX_OI/*we initiate*/,
214 	WRITEABLE
215     } code;
216 
217     /* once the connections are live we need extra info */
218     int	session_id;		/* odd for servers, even for clients */
219     int	syn_received;
220 
221     int bytes_left;		/* in the packet we've partially read */
222 
223     struct pipeline *next;	/* linked list */
224     enum special_action {
225 	NOTHING,
226 	CLOSE_TO_READ,		/* we got a FIN for this session_id */
227 	CLOSE_TO_RW,		/* we got a RESET for this session_id */
228 	CLOSE_TO_WRITE,		/* the child closed the descriptor */
229     } specact;
230 };
231 
232 struct pipeline	pl_bit_bucket;
233 struct pipeline	*pl_encapsulate_control;
234 struct pipeline *pipe_head=0;
235 
236 int	session_id_;
237 
238 /******************/
239 
add_subproc_fd(fd,code,sid)240 void add_subproc_fd(fd, code, sid)
241      int	fd;
242      enum pipe_polarity	code;
243      int	sid;
244 {
245     struct pipeline	*temp;
246     temp = malloc(sizeof(*temp));
247     temp->child_fd = fd;
248     temp->code = code;
249     temp->session_id = sid;
250     temp->syn_received = 0;
251     temp->bytes_left = 0;
252     temp->specact = NOTHING;
253     temp->next = 0;
254     /* add to tail */
255     {
256 	struct pipeline	**curr;
257 	for (curr = &pipe_head; *curr; curr = &( (*curr)->next ) )
258 	    ;
259 	*curr = temp;
260     }
261 }
262 
add_control_channel()263 void add_control_channel()
264 {
265     struct pipeline	*temp;
266     temp = malloc(sizeof(*temp));
267     temp->child_fd = -1;
268     temp->pipe[0] = -10;
269     temp->code = DUPLEX_OI;
270     temp->session_id = SESSION_ENCAP;
271     temp->syn_received = 0;
272     temp->bytes_left = 0;
273     temp->specact = NOTHING;
274     temp->next = 0;
275     /* add to tail */
276     {
277 	struct pipeline	**curr;
278 	for (curr = &pipe_head; *curr; curr = &( (*curr)->next ) )
279 	    ;
280 	*curr = temp;
281     }
282 
283     pl_encapsulate_control = temp;
284 }
285 
remove_pipeline_(pl)286 void remove_pipeline_(pl)
287      struct pipeline ** pl;
288 {
289     struct pipeline *tmp;
290     tmp = *pl;
291     *pl = tmp->next;
292     free(tmp);
293 }
294 
remove_pipeline(pl)295 void remove_pipeline(pl)
296      struct pipeline * pl;
297 {
298     struct pipeline	**curr;
299     for (curr = &pipe_head;
300 	 *curr && *curr != pl;
301 	 curr = &( (*curr)->next ) )
302 	;
303     if (0==*curr) {
304 	fprintf(stderr, "%s: greivous internal error.  attempt to delete unlisted pipeline from queue\n", progname);
305 	exit(1);
306     }
307     remove_pipeline_(curr);
308 }
309 
310 /* build a buffer full of SYN packets.  The beginning of the buffer is
311    the return value, and the length is stored into len_ret. */
prepare_SYNs(len_ret)312 static char * prepare_SYNs(len_ret)
313      int	*len_ret;
314 {
315     struct pipeline	*curr;
316     int	size = 64;
317     char *rval = (char*)malloc(size);
318     *len_ret = 0;
319 
320     for (curr = pipe_head; curr; curr = curr->next) {
321 	switch (curr->code) {
322 	case WRITEABLE:
323 	case DUPLEX_IO:
324 	    /* we need to wait for the other side to send a SYN for
325                these two */
326 	    /* curr->session_id = -1; it's already -1 */
327 	    break;
328 	case READABLE:
329 	case DUPLEX_OI:
330 	    if (*len_ret + 8 > size) {
331 		rval = (char*)realloc(rval, size *=2);
332 	    }
333 	    {
334 		char	*p = rval + *len_ret;
335 		if (curr->session_id<0) {
336 		    curr->session_id = session_id_;
337 		    /* XXX - gotta prevent stompage in later rev */
338 		    session_id_ += 2; /* odd for servers, even for clients */
339 		}
340 		p[0] = SCP_SYN;
341 		p[1] = (curr->session_id >>16 ) &0xff;
342 		p[2] = (curr->session_id >> 8 ) &0xff;
343 		p[3] = (curr->session_id >> 0 ) &0xff;
344 		p[4] = p[5] = p[6] = p[7] = 0;
345 		*len_ret += 8;
346 #ifdef DEBUG
347 		fprintf(stderr, "%s: prepared SYN for session 0x%06x\n",
348 			progname, curr->session_id);
349 #endif
350 	    }
351 	    break;
352 	case DUPLEX:		/* can't happen */
353 	    abort();
354 	    exit(1);
355 	}
356     }
357 
358     return rval;
359 }
360 
361 struct special_packet {
362     char	*buf;
363     int		len;
364 
365     struct special_packet	*next;
366 };
367 
368 struct special_packet	*special_packet_queue = 0;
369 
370 
371 /* stuffs a special packet into the special-packet-queue for sending
372    at the next possible moment.  sp and sp->buf must be heap-allocated. */
prime_packet_queue_(sp)373 void prime_packet_queue_(sp)
374      struct special_packet	*sp;
375 {
376     struct special_packet	**curr;
377 
378     /* add to tail */
379     for (curr = &special_packet_queue; *curr; curr = &(*curr)->next)
380 	;
381 
382     *curr = sp;
383     sp->next = 0;
384 }
385 
prime_packet_queue(buf,len)386 void prime_packet_queue(buf, len)
387      char	*buf;
388      int	len;
389 {
390     struct special_packet	*tmp;
391     tmp = malloc(sizeof(*tmp));
392     tmp->buf = buf;
393     tmp->len = len;
394     prime_packet_queue_(tmp);
395 }
396 
397 /********************************************************************/
398 
maybe_inject_special_packets(buf,len,size)399 void maybe_inject_special_packets(buf, len, size)
400      char	*buf;
401      int	*len;
402      int	size;
403 {
404     struct special_packet	*sp;
405     if (*len>0)
406 	return;			/* can't fit one in */
407 
408     sp = special_packet_queue;
409 
410     if (sp ==0)
411 	return;			/* no special packets */
412 
413     if (sp->len > size) {
414 	memcpy(buf, sp->buf, size);
415 	memmove(sp->buf, sp->buf + size, sp->len -size);
416 	sp->len -= size;
417 	*len = size;
418     } else {
419 	memcpy(buf, sp->buf, sp->len);
420 	*len = sp->len;
421 
422 	special_packet_queue = sp->next;
423 
424 	free(sp->buf);
425 	free(sp);
426     }
427 }
428 
build_fd_lists(readfds,writefds,curr_readable,curr_writeable,sock_fd,maxfd,ibuf_len,ibuf_size,obuf_len,obuf_size,obuf2_len,obuf2_off)429 void build_fd_lists(readfds, writefds,
430 		    curr_readable, curr_writeable,
431 		    sock_fd, maxfd,
432 		    ibuf_len, ibuf_size,
433 		    obuf_len, obuf_size,
434 		    obuf2_len, obuf2_off)
435      fd_set	*readfds, *writefds;
436      struct pipeline	*curr_readable, *curr_writeable;
437      int	sock_fd, *maxfd;
438      int	ibuf_len, ibuf_size;
439      int	obuf_len, obuf_size;
440      int	obuf2_len, obuf2_off;
441 {
442 	FD_ZERO(readfds);
443 	FD_ZERO(writefds);
444 	*maxfd = -1;
445 #define    MAX_FD(i)	if (*maxfd < (i)) *maxfd = (i)
446 
447 	/* when can we write to a child? */
448 	if (ibuf_len>0 &&
449 	    curr_writeable->pipe[0]>=0 ) {
450 	    /* curr_writeable != 0 */
451 	    FD_SET(curr_writeable->pipe[0], writefds);
452 	    MAX_FD( curr_writeable->pipe[0] );
453 	}
454 
455 	/* when can we read from the socket? */
456 	if ( curr_writeable == 0
457 	     ||
458 	     (ibuf_len<ibuf_size &&
459 	      curr_writeable &&
460 	      curr_writeable->bytes_left > 0 )
461 	    ) {
462 #if 1
463 	    FD_SET(sock_fd, readfds);
464 	    MAX_FD(sock_fd);
465 #else
466 	    struct pipeline	*curr;
467 	    for (curr = pipe_head; curr; curr = curr ? curr->next : 0) {
468 		switch(curr->code) {
469 		case DUPLEX_IO:
470 		case DUPLEX_OI:
471 		case DUPLEX:	/* DUPLEX is not really possible */
472 		case WRITEABLE:
473 		    FD_SET(sock_fd, readfds);
474 		    MAX_FD(sock_fd);
475 		    curr = 0;	/* bail from for loop */
476 		    break;
477 		case READABLE:
478 		    /* we don't write to this one */
479 		    break;
480 		}
481 	    }
482 #endif
483 	}
484 
485 	/* when can we read from a child? */
486 	if ( curr_readable == 0 ) {
487 	    /* select from ANY incoming child descriptor */
488 	    struct pipeline	*curr;
489 	    for (curr = pipe_head; curr; curr = curr->next) {
490 		if (curr->pipe[0]<0) continue;
491 		if ( curr->code == DUPLEX_IO &&
492 		     ! curr->syn_received)
493 		    continue;
494 		if ( curr->specact == CLOSE_TO_WRITE ) continue;
495 		switch(curr->code) {
496 		case READABLE:
497 		case DUPLEX_IO:
498 		case DUPLEX_OI:
499 		case DUPLEX:	/* DUPLEX is not really possible */
500 		    FD_SET(curr->pipe[0], readfds);
501 		    MAX_FD(curr->pipe[0]);
502 		    break;
503 		case WRITEABLE:
504 		    /* we don't read from this one */
505 		    break;
506 		}
507 	    }
508 	} else if (obuf_len < obuf_size &&
509 		   /* yes, the curr_readable could be WRITEABLE-only
510 		      when the child closes its descriptor, but we
511 		      haven't copied the bytes into the outgoing
512 		      socket buffer. In that case we don't want to
513 		      read from the descriptor. curr_readable will be
514 		      zeroed when the bytes get copied into the
515 		      outgoing socket buffer */
516 		   curr_readable->code != WRITEABLE &&
517 		   !( curr_readable->specact == CLOSE_TO_WRITE
518 		      || curr_readable->specact == CLOSE_TO_RW)
519 		   ) {
520 	    FD_SET(curr_readable->pipe[0], readfds);
521 	    MAX_FD(curr_readable->pipe[0]);
522 	}
523 
524 	/* when can we write to the socket? */
525 	if (obuf2_len>obuf2_off) {
526 	    FD_SET(sock_fd, writefds);
527 	    MAX_FD(sock_fd);
528 	}
529 }
530 
build_packet_header(buf,flags,session,length)531 void build_packet_header (buf, flags, session, length)
532      char	*buf;		/* length 8 */
533      int	flags, session;
534      unsigned	length;
535 {
536     buf[0] = flags;
537     buf[1] = session>>16;
538     buf[2] = session>>8;
539     buf[3] = session;
540     buf[4] = length>>24;
541     buf[5] = length>>16;
542     buf[6] = length>>8;
543     buf[7] = length;
544 }
545 
send_reset(struct pipeline * pl)546 void send_reset(struct pipeline *pl)
547 {
548     char	*buf = malloc(8);
549     build_packet_header(buf, SCP_RESET, pl->session_id, 0);
550     prime_packet_queue(buf, 8);
551 }
552 
553 /* returns number of bytes read into buf at offset *buf_len, limited by
554    buf_size.  An uncrecoverable error aborts the program */
read_from_child(pl,buf,buf_len,buf_size)555 int read_from_child(pl, buf, buf_len, buf_size)
556      struct pipeline	*pl;
557      char	*buf;
558      int	*buf_len;
559      int	buf_size;
560 {
561     int	rval;
562 
563 #if DEBUG>1
564     fprintf(stderr, "%s: read(in[c%d], buf+%d, %d-%d)",
565 	    progname, pl->child_fd, *buf_len, buf_size, *buf_len);
566 #endif
567     rval = read(pl->pipe[0], buf+*buf_len, buf_size - *buf_len);
568 #if DEBUG>1
569     fprintf(stderr, "=%d;\n", rval);
570 #endif
571     if (rval == 0) {
572 #ifdef DEBUG
573 	fprintf(stderr, "%s: closing in[%d=c%d]\n", progname, pl->pipe[0], pl->child_fd);
574 #endif
575 	pl->specact = CLOSE_TO_WRITE;
576     } else if (rval<0) {
577 	if (errno == EINTR) {
578 	    return 0;		/* no biggie, retry later */
579 	} else {
580 	    fprintf(stderr, "%s: error during read(in[%d],,).  Aborting.  ",
581 		    progname, pl->pipe[0]);
582 	    perror("");
583 	    exit(EXITCODE_SYSCALLFAILED);
584 	}
585     } else {
586 	*buf_len += rval;
587     }
588     return rval;
589 }
590 
591 /* returns number of bytes written from buf, limited by (*buf_len).
592    It takes care of moving the bytes in the buffer for the case of an
593    incomplete write.  An uncrecoverable error aborts the program */
write_to_child(pl,buf,buf_len)594 int write_to_child(pl, buf, buf_len)
595      struct pipeline	*pl;
596      char	*buf;
597      int	*buf_len;
598 {
599     int	rval;
600 
601 #if DEBUG>1
602     fprintf(stderr, "%s: write(out[%d/c%d], buf, %d)",
603 	    progname, pl->pipe[0], pl->child_fd, *buf_len);
604 #endif
605     rval = write(pl->pipe[0], buf, *buf_len);
606 #if DEBUG>1
607     fprintf(stderr, "=%d;\n", rval);
608 #endif
609     if (rval == 0) {
610 #ifdef DEBUG
611 	fprintf(stderr, "%s: Inexplicable!  write(out[%d],,%d) returns 0", progname, pl->pipe[0], *buf_len);
612 #endif
613     } else if (rval<0) {
614 	if (errno == EINTR) {
615 	    return 0;		/* no biggie, retry later */
616 	} else if (errno == EPIPE) {
617 	    /* DOH! fake it */
618 	    fprintf(stderr, "%s: EPIPE while writing to child fd %d\n", progname, pl->child_fd);
619 	    exitcode_warnings = EXITCODE_GOT_RESET;
620 	    pl->specact = CLOSE_TO_READ;
621 	    *buf_len = 0;
622 	    send_reset(pl);
623 	    return 0;		/* this is NOT a normal thing */
624 	} else {
625 	    fprintf(stderr, "%s: error during write(out[%d],,).  Aborting.  ",
626 		    progname, pl->pipe[0]);
627 	    perror("");
628 	    exit(EXITCODE_SYSCALLFAILED);
629 	}
630     } else {
631 	memmove(buf, buf+rval, *buf_len - rval);
632 	*buf_len -= rval;
633     }
634     return rval;
635 }
636 
637 /* updates obuf_off to reflect how many bytes it copied from obuf to fd */
write_to_socket(fd,obuf,obuf_off,obuf_len)638 void write_to_socket(fd, obuf, obuf_off, obuf_len)
639      int	fd;
640      char	*obuf;
641      int	*obuf_off;
642      int	obuf_len;
643 {
644     int	rval;
645 
646 #if DEBUG>1
647     fprintf(stderr, "%s: write(sock_fd, buf+%d, %d-%d)",
648 	    progname, *obuf_off, obuf_len, *obuf_off);
649 #endif
650     rval = write(fd, obuf+ *obuf_off, obuf_len-*obuf_off);
651 #if DEBUG>1
652     fprintf(stderr, "=%d;\n", rval);
653 #endif
654     if (rval==0) {
655 	fprintf(stderr, "%s: Inexplicable!  write(sock_fd,,%d) returns 0\n",
656 		progname, obuf_len-*obuf_off);
657 	exit(EXITCODE_SYSCALLFAILED);
658     } else if (rval<0) {
659 	if (errno!=EINTR) {
660 	    fprintf(stderr, "%s: error during write(sock_fd,,%d).  Aborting.  ",
661 		    progname, obuf_len-*obuf_off);
662 	    perror("");
663 	    exit(EXITCODE_SYSCALLFAILED);
664 	}
665 	/* never mind. try again later */
666     } else {
667 	*obuf_off += rval;
668     }
669 }
670 
671 /* read bytes from the socket */
672 
read_from_socket(fd,pl,buf,buf_len,buf_size)673 void read_from_socket(fd, pl, buf, buf_len, buf_size)
674      int	fd;
675      struct pipeline	*pl;
676      char	*buf;
677      int	*buf_len, buf_size;
678 {
679     int	desired_read = buf_size - *buf_len;
680     int	rval;
681 
682     if (pl && desired_read > pl->bytes_left) {
683 	desired_read = pl->bytes_left;
684     }
685 #if DEBUG>1
686     fprintf(stderr, "%s: read(sock_fd, buf+%d, %d)",
687 	    progname, *buf_len, desired_read);
688 #endif
689     rval = read(fd, buf+*buf_len, desired_read);
690 #if DEBUG>1
691     fprintf(stderr, "=%d;\n", rval);
692 #endif
693     if (rval==0) {
694 	fprintf(stderr, "%s: encapsulation protocol error reading socket.  Socket closed prematurely by remote end.\n", progname);
695 	/*sock_closed = 1;*/
696 	exit(EXITCODE_PROTOCOL);
697     } else if (rval<0) {
698 	if (errno!=EINTR) {
699 	    fprintf(stderr, "%s: error during read(sock_fd,,%d).  Aborting.  ",
700 		    progname, desired_read);
701 	    perror("");
702 	    exit(EXITCODE_SYSCALLFAILED);
703 	}
704 	/* never mind. try again later */
705     } else {
706 	*buf_len += rval;
707 
708 	if (pl) pl->bytes_left -= rval;
709     }
710 
711     if (pl == &pl_bit_bucket) {
712 	/* throw away the bytes */
713 #ifdef DEBUG
714 	fprintf(stderr, "%s: %d bytes into the bit bucket\n", progname, *buf_len);
715 #endif
716 	*buf_len = 0;
717     }
718 }
719 
interpret_scp_header(header,pl)720 void interpret_scp_header(header, pl)
721      unsigned char	*header;	/* size 8 */
722      struct pipeline	**pl;
723 {
724     int	flags, session_id;
725     unsigned int	length;
726     struct pipeline	*found = 0;
727 
728     flags = header[0];
729     session_id = ( header[1] << 16 ) | ( header[2] << 8 ) | header[3];
730     length = ( header[4] << 24 ) | ( header[5] << 16 ) | ( header[6] << 8 ) | header[7];
731 
732 #ifdef DEBUG
733     fprintf(stderr, "%s: packet. flags=0x%02x, session=0x%06x, length=%d\n",
734 	    progname, flags, session_id, length);
735 #endif
736 
737     if ( (flags & (SCP_SYN|0xf)) == SCP_SYN) {
738 	struct pipeline	*curr;
739 	found = 0;
740 	/* see if there's one descriptor that's waiting for this
741            particular session_id */
742 	for (curr = pipe_head; curr && !found; curr = curr->next ) {
743 	    if (curr->syn_received)
744 		continue;
745 	    switch(curr->code) {
746 	    case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX:
747 		/* DUPLEX not actually possible */
748 		if (curr->session_id == session_id) {
749 		    found = curr;
750 		    found->syn_received = 1;
751 		}
752 		break;
753 	    case READABLE:
754 		break;		/* like, whatever */
755 	    }
756 	}
757 	if (!found) for (curr = pipe_head; curr && !found; curr = curr->next ) {
758 	    if (curr->syn_received)
759 		continue;
760 	    switch(curr->code) {
761 	    case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI:
762 	    case DUPLEX: /* DUPLEX not actually possible */
763 		if (curr->session_id<0) {
764 		    found = curr;
765 		    found->session_id = session_id;
766 		    found->syn_received = 1;
767 		}
768 		break;
769 	    case READABLE:
770 		break;		/* like, whatever */
771 	    }
772 	}
773 	if (!found) {
774 	    fprintf(stderr, "%s: Warning! discarding SYN for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
775 	    found = &pl_bit_bucket;
776 	} else {
777 #ifdef DEBUG
778 	    fprintf(stderr, "%s: received SYN for session 0x%06x", progname, session_id);
779 #endif
780 	    if (found->code == DUPLEX_IO) {
781 		char	*buf = malloc(8);
782 		build_packet_header(buf, SCP_SYN, session_id, 0);
783 		prime_packet_queue(buf, 8);
784 #ifdef DEBUG
785 		fprintf(stderr, "; sending one back");
786 #endif
787 	    }
788 #ifdef DEBUG
789 	    putc('\n', stderr);
790 #endif
791 	}
792 	/* fall through and accept any data that might be in the packet */
793     } else if ( (flags & (SCP_FIN|0xf)) == SCP_FIN) {
794 	struct pipeline	*curr;
795 	for (curr = pipe_head; curr && !found; curr = curr->next ) {
796 	    if (! curr->syn_received)
797 		continue;
798 	    if (curr->session_id != session_id)
799 		continue;
800 
801 	    switch(curr->code) {
802 	    case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI:
803 	    case DUPLEX: /* DUPLEX not actually possible */
804 		found = curr;
805 		found->specact = CLOSE_TO_READ;
806 		break;
807 	    case READABLE:
808 		break;		/* like, whatever */
809 	    }
810 	}
811 	if (!found) {
812 	    fprintf(stderr, "%s: Warning! discarding FIN for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
813 	    found = &pl_bit_bucket;
814 	} else {
815 #ifdef DEBUG
816 	    fprintf(stderr, "%s: received FIN for session 0x%06x\n", progname, session_id);
817 #endif
818 	}
819     } else if ( (flags & (SCP_PUSH|0xf)) == SCP_PUSH) {
820 	/* like, whatever */
821     } else if ( (flags & (SCP_RESET|0xf)) == SCP_RESET) {
822 	struct pipeline	*curr;
823 	/* why are they doing this to me? */
824 	fprintf(stderr, "%s: RESET received for session_id=%d.  closing descriptor bidirectionally\n", progname, session_id);
825 	for (curr = pipe_head; curr && !found; curr = curr->next ) {
826 	    if (! curr->syn_received)
827 		continue;
828 	    if (curr->session_id != session_id)
829 		continue;
830 
831 	    switch(curr->code) {
832 	    case READABLE: case DUPLEX_IO: case DUPLEX_OI:
833 	    case DUPLEX: /* DUPLEX not actually possible */
834 	    case WRITEABLE:
835 		found = curr;
836 		found->specact = CLOSE_TO_RW;
837 		exitcode_warnings = EXITCODE_GOT_RESET;
838 		break;
839 	    }
840 	}
841 	if (!found) {
842 	    fprintf(stderr, "%s: Warning! discarding RESET for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
843 	    found = &pl_bit_bucket;
844 	}
845     } else if (flags != 0) {
846 	fprintf(stderr, "%s: Warning! funky flags 0x%02x on packet, to the bit bucket!\n", progname, flags);
847 	found = &pl_bit_bucket;
848     } else {
849 	struct pipeline	*curr;
850 	for (curr = pipe_head; curr && !found; curr = curr->next ) {
851 	    if (curr->session_id == session_id) {
852 		found = curr;
853 		break;
854 	    }
855 	}
856 	if (!found) {
857 	    fprintf(stderr, "%s: Warning! discarding data packet for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
858 	    found = &pl_bit_bucket;
859 	}
860     }
861 
862     if (length) {
863 
864 	if (found->code == READABLE) {
865 	    fprintf(stderr, "%s: Got data for session 0x%06x I can't write to.  RESETting\n", progname, session_id);
866 	    send_reset(found);
867 	    found = &pl_bit_bucket;
868 	}
869 
870 	*pl = found;
871 	(*pl)->bytes_left = length;
872     }
873 }
874 
handle_control_message(buf,len)875 void handle_control_message(buf, len)
876      char	*buf;
877      int	len;
878 {
879     if (len<1) {
880 	fprintf(stderr, "%s: Internal Error: control message length <1. \n", progname);
881 	exit(1);
882     }
883 
884     switch(buf[0]) {
885     case ECP_EOF:
886 	if (len!=1) {
887 	    fprintf(stderr, "%s: Protocol Error: control message[0] length(%d) !=1. \n", progname, len);
888 	    exit(EXITCODE_PROTOCOL);
889 	}
890 #ifdef DEBUG
891 	fprintf(stderr, "%s: Got EOF from remote.\n", progname);
892 #endif
893 
894 	if (pl_encapsulate_control->code == WRITEABLE) {
895 	    remove_pipeline(pl_encapsulate_control);
896 	    pl_encapsulate_control = 0;
897 	} else {
898 	    pl_encapsulate_control->code = READABLE;
899 	}
900 
901 	break;
902 
903     case ECP_EXITCODE:
904 	if (len!=2) {
905 	    fprintf(stderr, "%s: Protocol Error: control message[1] length(%d) !=2. \n", progname, len);
906 	    exit(EXITCODE_PROTOCOL);
907 	}
908 	remote_return_code = (unsigned char )buf[1];
909 #ifdef DEBUG
910 	fprintf(stderr, "%s: remote exit status: %d\n",
911 		progname, remote_return_code);
912 #endif
913 
914 	if (pl_encapsulate_control->code == WRITEABLE) {
915 	    remove_pipeline(pl_encapsulate_control);
916 	    pl_encapsulate_control = 0;
917 	} else {
918 	    pl_encapsulate_control->code = READABLE;
919 	}
920 
921 	break;
922 
923     default:
924 	fprintf(stderr, "%s: Protocol Error: unknown control message [%d]. \n", progname, (unsigned char)buf[0]);
925 	exit(EXITCODE_PROTOCOL);
926 	break;
927     }
928 }
929 
perform_special_actions(ibuf_len,obuf_len,curr_readable,curr_writeable)930 void perform_special_actions(ibuf_len, obuf_len, curr_readable, curr_writeable)
931      int	*ibuf_len;
932      int	*obuf_len;
933      struct pipeline	**curr_readable, **curr_writeable;
934 {
935     struct pipeline	**curr;
936     for (curr = &pipe_head;
937 	 *curr;
938 	 curr = curr ? (&(*curr)->next) : &pipe_head ) {
939 	switch ((*curr)->specact) {
940 	case NOTHING:
941 	    break;
942 	case CLOSE_TO_READ:
943 	    /* got a FIN packet */
944 	    if (*ibuf_len>0)
945 		break;		/* can't drop it yet */
946 	    if (*curr_writeable == *curr
947 		|| *curr_readable == *curr) {
948 		/* fprintf(stderr, "%s: weird, special action CLOSE_TO_READ applied to a curr_ pipeline %lx\n", progname, (long)*curr); */
949 		break;
950 	    }
951 	    switch((*curr)->code) {
952 	    case WRITEABLE:
953 #ifdef DEBUG
954 		fprintf(stderr, "%s: closing W child fd %d\n", progname, (*curr)->child_fd);
955 #endif
956 		close((*curr)->pipe[0]);
957 		remove_pipeline_(curr);
958 		curr = 0;	/* start scanning from the beginning */
959 		break;
960 	    case DUPLEX:	/* DUPLEX not actually possible */
961 	    case DUPLEX_IO:
962 	    case DUPLEX_OI:
963 #ifdef DEBUG
964 		fprintf(stderr, "%s: converting child fd %d to child-write-only\n", progname, (*curr)->child_fd);
965 #endif
966 		(*curr)->specact = NOTHING;
967 		(*curr)->code = READABLE;
968 		shutdown((*curr)->pipe[0], 1);
969 
970 		break;
971 	    case READABLE:
972 		fprintf(stderr, "%s: internal error, attempt to CLOSE_TO_READ on a READABLE descriptor\n", progname);
973 		exit(1);
974 	    }
975 	    break;
976 	case CLOSE_TO_RW:
977 	    /* got a RESET packet.  get drastic */
978 	    if ( (*curr)->bytes_left >0) {
979 		fprintf(stderr, "%s: Freaky, %d bytes_left in CLOSE_TO_RW channel\n", progname, (*curr)->bytes_left);
980 		break;		/* can't dump it without corrupting the stream */
981 	    }
982 	    if (*curr_readable == *curr) {
983 		*obuf_len = 0;
984 		*curr_readable = 0;
985 	    }
986 	    if (*curr_writeable == *curr) {
987 		*ibuf_len = 0;
988 		*curr_writeable = 0;
989 	    }
990 #ifdef DEBUG
991 	    fprintf(stderr, "%s: RESETting child fd %d\n", progname, (*curr)->child_fd);
992 #endif
993 	    {
994 		struct pipeline *temp = *curr;
995 		close(temp->pipe[0]);
996 		*curr = temp->next;
997 		free(temp);
998 	    }
999 	    curr = 0;	/* start scanning from the beginning */
1000 	    break;
1001 	case CLOSE_TO_WRITE:
1002 	    /* child closed the descriptor */
1003 	    if (*curr_writeable == *curr
1004 		|| *curr_readable == *curr) {
1005 		/*fprintf(stderr, "%s: weird, special action CLOSE_TO_WRITE applied to a curr_ pipeline %lx\n", progname, (long)*curr);*/
1006 		break;
1007 	    }
1008 
1009 	    {
1010 	      char	*buf;
1011 	      int	len;
1012 	      len = 8;
1013 	      buf = malloc(len);
1014 	      build_packet_header(buf, SCP_FIN, (*curr)->session_id, 0);
1015 	      prime_packet_queue(buf, len);
1016 #ifdef DEBUG
1017 	      fprintf(stderr, "%s: sending FIN for session 0x%06x\n", progname, (*curr)->session_id);
1018 #endif
1019 	    }
1020 
1021 	    switch((*curr)->code) {
1022 	    case READABLE:
1023 #ifdef DEBUG
1024 		fprintf(stderr, "%s: closing R child fd %d\n", progname, (*curr)->child_fd);
1025 #endif
1026 		{
1027 		    struct pipeline *temp = *curr;
1028 		    temp = *curr;
1029 		    close(temp->pipe[0]);
1030 		    *curr = temp->next;
1031 		    free(temp);
1032 		}
1033 		curr = 0;	/* start scanning from the beginning */
1034 		break;
1035 	    case DUPLEX:	/* DUPLEX not actually possible */
1036 	    case DUPLEX_IO:
1037 	    case DUPLEX_OI:
1038 #ifdef DEBUG
1039 		fprintf(stderr, "%s: converting child fd %d to child-read-only\n", progname, (*curr)->child_fd);
1040 #endif
1041 		(*curr)->specact = NOTHING;
1042 		(*curr)->code = WRITEABLE;
1043 		shutdown((*curr)->pipe[0], 0);
1044 
1045 		break;
1046 	    case WRITEABLE:
1047 		fprintf(stderr, "%s: internal error, attempt to CLOSE_TO_WRITE on a WRITEABLE descriptor\n", progname);
1048 		exit(1);
1049 	    }
1050 
1051 	    break;
1052 	}
1053     }
1054 }
1055 
1056 #define BUF_SIZE	4096
1057 
main_io_loop(sock_fd)1058 static void main_io_loop(sock_fd)
1059      int	sock_fd;
1060 {
1061     char incoming_buf[BUF_SIZE]; /* read from socket, will write to child */
1062     char outgoing_buf[BUF_SIZE]; /* read from child, will packetize into : */
1063     char outgoing2_buf[BUF_SIZE+8]; /* packet buf, will write to socket */
1064 
1065     /* bytes in the buffer to child */
1066     /* this is nonzero only if curr_writeable is nonNULL */
1067     int	incoming_len=0;
1068 
1069     /* this is nonzero only if curr_readable is nonNULL */
1070     /* bytes in the buffer from child */
1071     int	outgoing_len=0;
1072 
1073     /* bytes in the buffer to socket */
1074     /* this is independent of the curr_ variables */
1075     int	outgoing2_len=0;
1076     int	outgoing2_off=0;
1077 
1078     /* for reading SCP headers */
1079     char	header_buf[8];
1080     int		header_len;
1081 
1082     fd_set	readfds, writefds;
1083     int	maxfd;
1084 
1085     struct pipeline	*curr_readable=0; /* child descriptor we're reading */
1086     struct pipeline	*curr_writeable=0; /* child descriptor we're writing */
1087 
1088     while (1) {
1089 	int	rval;
1090 
1091 	build_fd_lists (
1092 			&readfds, &writefds,
1093 			curr_readable, curr_writeable,
1094 			sock_fd, &maxfd,
1095 			incoming_len, sizeof(incoming_len),
1096 			outgoing_len, sizeof(outgoing_buf),
1097 			outgoing2_len, outgoing2_off);
1098 
1099 	if (
1100 #if 0
1101 	    maxfd<0
1102 	    ||
1103 #else
1104 	    (!subproc || !child_unreaped)
1105 	    &&
1106 #endif
1107 	    (0==pipe_head && 0 == outgoing2_len
1108 		&& special_packet_queue == 0)
1109 	    ) {
1110 	    if (incoming_len != 0 ||
1111 		outgoing_len != 0 ||
1112 		outgoing2_len != 0) {
1113 		fprintf(stderr, "%s: leftover bytes in buffers at end of encapsulation.  That is bad because it means Bob made a logic error in his code.\n", progname);
1114 	    }
1115 	    break;		/* run out of things to do */
1116 	}
1117 
1118 	if (maxfd>0) {
1119 	    struct timeval	tv;
1120 	    tv.tv_sec = 0;
1121 	    tv.tv_usec = 500000;
1122 	    rval = select(maxfd+1, &readfds, &writefds, (fd_set*)0, &tv);
1123 
1124 	    if (rval<0) {
1125 		if (errno == EINTR) {
1126 		    continue;
1127 		} else {
1128 		    fprintf(stderr, "%s: error during select: ", progname);
1129 		    perror("");
1130 		    exit(EXITCODE_SYSCALLFAILED);
1131 		}
1132 		/* NOTREACHED */
1133 	    } else if (rval==0) {
1134 		/* got a timeout */
1135 
1136 	    }
1137 
1138 	    /* read bytes from the child */
1139 	    {
1140 		struct pipeline	*curr;
1141 		for (curr = pipe_head; curr; curr = curr->next) {
1142 		    switch (curr->code) {
1143 		    case READABLE:
1144 		    case DUPLEX_IO:
1145 		    case DUPLEX_OI:
1146 		    case DUPLEX:
1147 			if (curr->pipe[0]>=0 &&
1148 			    FD_ISSET(curr->pipe[0], &readfds) &&
1149 			    (curr==curr_readable || 0==curr_readable)) {
1150 			    if (read_from_child(curr, outgoing_buf, &outgoing_len,
1151 						sizeof(outgoing_buf)) )
1152 				curr_readable = curr;
1153 			}
1154 			break;
1155 		    case WRITEABLE:
1156 			break;
1157 		    }
1158 		}
1159 	    }
1160 
1161 	    /* write bytes to the child */
1162 	    if (curr_writeable && incoming_len>0 &&
1163 		curr_writeable->pipe[0] >=0 &&
1164 		FD_ISSET(curr_writeable->pipe[0], &writefds) ) {
1165 		write_to_child(curr_writeable, incoming_buf, &incoming_len);
1166 		if (incoming_len<1 && curr_writeable->bytes_left <1) {
1167 		    curr_writeable = 0;
1168 		}
1169 	    }
1170 
1171 
1172 	    /* write bytes to the socket */
1173 	    if (FD_ISSET(sock_fd, &writefds)) {
1174 		write_to_socket(sock_fd, outgoing2_buf,
1175 				&outgoing2_off, outgoing2_len);
1176 		if (outgoing2_off >= outgoing2_len) {
1177 		    outgoing2_len = 0;
1178 		    outgoing2_off = 0;
1179 		}
1180 	    }
1181 
1182 	    /* read bytes from the socket */
1183 	    if (FD_ISSET(sock_fd, &readfds)) {
1184 
1185 		if (curr_writeable) {
1186 		    read_from_socket(sock_fd, curr_writeable,
1187 				     incoming_buf, &incoming_len,
1188 				     sizeof(incoming_buf) );
1189 		} else {
1190 		    read_from_socket(sock_fd, (struct pipeline *)0,
1191 				     header_buf, &header_len,
1192 				     sizeof(header_buf));
1193 
1194 		    if (header_len==sizeof(header_buf)) {
1195 			interpret_scp_header(header_buf, &curr_writeable);
1196 			header_len = 0;
1197 		    }
1198 		}
1199 	    }
1200 	}
1201 
1202 	maybe_inject_special_packets(outgoing2_buf, &outgoing2_len,
1203 				     sizeof(outgoing2_buf));
1204 
1205 	if (outgoing2_len==0 && outgoing_len>0) {
1206 	    build_packet_header(outgoing2_buf, 0, curr_readable->session_id,
1207 				outgoing_len);
1208 	    memcpy(outgoing2_buf + 8, outgoing_buf, outgoing_len);
1209 	    outgoing2_len = outgoing_len + 8;
1210 	    outgoing_len = 0;
1211 	}
1212 
1213 	if (curr_readable && outgoing_len==0) {
1214 	    curr_readable = 0;
1215 	}
1216 
1217 	if (curr_writeable
1218 	    && curr_writeable->bytes_left == 0
1219 	    && curr_writeable == pl_encapsulate_control
1220 	    && incoming_len>0) {
1221 	    handle_control_message(incoming_buf, incoming_len);
1222 	    incoming_len = 0;
1223 	    curr_writeable = 0;
1224 	}
1225 
1226 	if (subproc) {
1227 	    if (!child_running && child_unreaped) {
1228 		probe_child();
1229 	    }
1230 	} else {
1231 	    if (pipe_head != 0 &&
1232 		pipe_head == pl_encapsulate_control &&
1233 		pipe_head->next == 0 &&
1234 		pipe_head->code != WRITEABLE) {
1235 		/* all channels are closed */
1236 		char	*buf;
1237 		int	len = 1;
1238 #ifdef DEBUG
1239 		fprintf(stderr, "%s: sending EOF\n",
1240 			progname);
1241 #endif
1242 		buf = malloc(8+len);
1243 		build_packet_header(buf, 0, SESSION_ENCAP, len);
1244 		buf[8] = ECP_EOF;
1245 		prime_packet_queue(buf, 8+len);
1246 
1247 		if (pl_encapsulate_control->code == READABLE) {
1248 		    remove_pipeline(pl_encapsulate_control);
1249 		    pl_encapsulate_control = 0;
1250 		} else {
1251 		    pl_encapsulate_control->code = WRITEABLE;
1252 		}
1253 	    }
1254 	}
1255 
1256 	perform_special_actions(&incoming_len, &outgoing_len,
1257 				&curr_readable, &curr_writeable);
1258     }
1259 }
1260 
1261 /********************************************************************/
1262 
1263 static int	childpid = -1;
1264 
waitonchild()1265 static void waitonchild()
1266 {
1267     /* got a SIGCHILD.
1268        It must be that: */
1269     child_running = 0;
1270 }
1271 
probe_child()1272 static void probe_child()
1273 {
1274     if (child_running || !child_unreaped)
1275 	return;
1276 
1277     if ( 0>=wait(&local_return_code)) {
1278 	fprintf(stderr, "%s: wait returned error or zero: ", progname);
1279 	perror("");
1280 	exit(EXITCODE_SYSCALLFAILED);
1281     }
1282     if (!WIFEXITED(local_return_code))
1283 	local_return_code = EXITCODE_SIGNAL;
1284     else
1285 	local_return_code = WEXITSTATUS(local_return_code);
1286 
1287     {
1288 	char	*buf;
1289 	int	len = 2;
1290 #ifdef DEBUG
1291 	fprintf(stderr, "%s: sending exit status %d\n",
1292 		progname, local_return_code);
1293 #endif
1294 	buf = malloc(8+len);
1295 	build_packet_header(buf, 0, SESSION_ENCAP, len);
1296 	buf[8] = ECP_EXITCODE;
1297 	buf[8+1] = local_return_code;
1298 	prime_packet_queue(buf, len+8);
1299 
1300 	if (pl_encapsulate_control->code == READABLE) {
1301 	    remove_pipeline(pl_encapsulate_control);
1302 	    pl_encapsulate_control = 0;
1303 	} else {
1304 	    pl_encapsulate_control->code = WRITEABLE;
1305 	}
1306     }
1307 
1308     child_unreaped = 0;
1309 }
1310 
spawn_child(cmd,sockfd)1311 static void spawn_child(cmd, sockfd)
1312      char	**cmd;
1313      int	sockfd;
1314 {
1315     struct pipeline	*curr;
1316 
1317     signal(SIGCHLD,waitonchild);
1318     child_running = 1;		/* well, not yet. */
1319     child_unreaped = 1;
1320 
1321     /* We're about to allocate a big stack of descriptors.  Let's make
1322        sure we don't step on on our own toes.  Dup descriptor 0 onto
1323        each of the descriptors so that our allocations won't get one
1324        of them.  If you don't have a descriptor 0, then you're a FREAK! */
1325     /* Uhoh.  Some of them may already be connected to the parent.
1326        Bob attaches some funky things in funky places. */
1327     /* The way I tell if a descriptor has been allocated or not is I
1328        select() on it.  If I get EBADF, the descriptor has not been
1329        allocated and I can stomp on it before the fork.  If I don't,
1330        then I won't stomp on it till after the fork. */
1331     {
1332 	for (curr = pipe_head; curr; curr = curr->next) {
1333 	    if (curr->child_fd<0)
1334 		continue;
1335 	    if (!valid_descriptor(curr->child_fd))
1336 		dup2(0, curr->child_fd); /* "reserve" it */
1337 	}
1338     }
1339 
1340     for (curr = pipe_head; curr; curr = curr->next) {
1341 	if (curr->child_fd<0)
1342 	    continue;		/* skip this special channel */
1343 	switch (curr->code) {
1344 	case READABLE:
1345 	case WRITEABLE:
1346 	    if (pipe(curr->pipe) !=0) {
1347 		fprintf(stderr, "%s: totally failed to pipe(2): ", progname);
1348 		perror("");
1349 		exit (EXITCODE_SYSCALLFAILED);
1350 	    }
1351 	    break;
1352 	case DUPLEX:
1353 	case DUPLEX_IO:
1354 	case DUPLEX_OI:
1355 	    if (0!=socketpair(AF_UNIX, SOCK_STREAM, 0/*let it choose*/,
1356 			      curr->pipe)) {
1357 		fprintf(stderr, "%s: totally failed to socketpair(2): ",
1358 			progname);
1359 		perror("");
1360 		exit (EXITCODE_SYSCALLFAILED);
1361 	    }
1362 	}
1363 	if (curr->code == WRITEABLE) {
1364 	    /* we need to invert the polarity for this case, eh, Geordi? */
1365 	    int	t;
1366 	    t = curr->pipe[0];
1367 	    curr->pipe[0] = curr->pipe[1];
1368 	    curr->pipe[1] = t;
1369 	}
1370     }
1371 
1372     childpid = fork();
1373     if (childpid<0) {
1374 	fprintf(stderr, "%s: unable to fork: ", progname);
1375 	perror("");
1376 	/* I would clear child_running, but, look at the next line */
1377 	exit(EXITCODE_SYSCALLFAILED);
1378     }
1379 
1380     /* now there's a child running (assuming no race conditions, which
1381        is why I set it up above and not here.  I'm stupid, but
1382        paranoid). */
1383 
1384     if (childpid==0) {
1385 	/* child */
1386 	close(sockfd);		/* can't have the child accidentally
1387 				   stomping on our conversation. */
1388 	for (curr = pipe_head; curr; curr = curr->next) {
1389 	    if (curr->child_fd<0)
1390 		continue;		/* skip this special channel */
1391 	    close(curr->pipe[0]);
1392 	    dup2(curr->pipe[1], curr->child_fd);
1393 	    close(curr->pipe[1]);
1394 	}
1395 
1396 	execvp(*cmd, cmd);
1397 	fprintf(stderr, "%s: Unable to exec %s: ", progname, *cmd);
1398 	perror("");
1399 
1400 	exit(EXITCODE_EXECFAILED);
1401 
1402     } else {
1403 	/* parent */
1404 	for (curr = pipe_head; curr; curr = curr->next) {
1405 	    if (curr->child_fd<0)
1406 		continue;		/* skip this special channel */
1407 	    close(curr->pipe[1]);
1408 	}
1409     }
1410 }
1411 
rig_single()1412 static void rig_single()
1413 {
1414     struct pipeline	*curr;
1415     /* Dear mother of god.  I have to invert the polarity of all the
1416        pipes.  How the hell am I going to explain this in the manual
1417        page? */
1418 
1419     for (curr = pipe_head; curr; curr = curr->next) {
1420 	switch (curr->code) {
1421 	case READABLE:
1422 	    curr->code = WRITEABLE;
1423 	    break;
1424 	case WRITEABLE:
1425 	    curr->code = READABLE;
1426 	    break;
1427 	default:
1428 	    /* I don't need to diddle the duplex cases really */
1429 	    break;
1430 	}
1431 
1432 	/* so that select and I/O will work */
1433 	curr->pipe[0] = curr->child_fd;
1434 	curr->pipe[1] = -1;
1435     }
1436 
1437 }
1438 
1439 /********************************************************************/
1440 
scan_flag_numeric_fd(s,fdp)1441 static int scan_flag_numeric_fd(s, fdp)
1442     char *s;
1443     int	*fdp;
1444 {
1445     int	n;
1446     if (1 != sscanf(s, "%i%n", fdp, &n)) {
1447 	fprintf(stderr, "%s: parse error in file descriptor list at '%s'\n", progname, s);
1448 	exit(EXITCODE_ARGS);
1449     }
1450     return n;
1451 }
1452 
1453 /********************************************************************/
1454 
1455 enum mergereturns_ {
1456     UNINITIALIZED,
1457     PREFER_LOCAL,		/* if both local and remote processes
1458 				   error, return the local code */
1459     PREFER_REMOTE,		/* if both local and remote processes
1460 				   error, return the remote code.  */
1461     LOCAL_ONLY,			/* return the exit code of the local
1462 				   process, ignoring the return code
1463 				   of the remote process. */
1464     REMOTE_ONLY,		/* return the exit code of the remote
1465 				   process, ignoring the return code
1466 				   of the local process. */
1467 } merge_returns = UNINITIALIZED;
1468 
1469 static int	sockfd = -1;
1470 static int	im_server = -1;
1471 
main(argc,argv)1472 int main (argc,argv)
1473      int argc;
1474      char ** argv;
1475 
1476 {
1477     set_progname(argv[0]);
1478 
1479 #if 0
1480     if (sizeof(Nshort) != 2) {
1481 	fprintf(stderr, "%s: greivous porting error. sizeof(Nshort) == %d, not 2.\n",
1482 		progname, sizeof(Nshort));
1483 	exit(EXITCODE_ARGS);
1484     }
1485 #endif
1486 
1487     while (argc>1) {
1488 	char *arg = argv[1];
1489 	if (arg[0] != '-') {
1490 	    break;
1491 	}
1492 	arg++;
1493 	if (arg[0] == '-') {
1494 	    arg++;
1495 	    if (0==strcmp(arg, "verbose")) {
1496 		verbose = 1;
1497 		argv++; argc--;
1498 	    } else if (0==strcmp(arg, "fd")) {
1499 		argv++; argc--;
1500 		if (argc<2) {
1501 		    fprintf(stderr, "%s: --fd requires file number for socket.\n",
1502 			    progname);
1503 		    usage();
1504 		    exit(EXITCODE_ARGS);
1505 		} else if (sockfd>=0) {
1506 		    fprintf(stderr, "%s: --fd can only be specified once\n",
1507 			    progname);
1508 		    usage();
1509 		    exit(EXITCODE_ARGS);
1510 		} else  {
1511 		    sockfd = atoi(argv[1]);
1512 		    argv++; argc--;
1513 		}
1514 	    } else if (0==strcmp(arg, "subproc")) {
1515 		subproc = 1;
1516 		argv++; argc--;
1517 	    } else if (0==strcmp(arg, "infd") ||
1518 		       0==strcmp(arg, "outfd") ||
1519 		       0==strcmp(arg, "duplex") ||
1520 		       0==strcmp(arg, "Duplex") ||
1521 		       0==strcmp(arg, "DUPLEX")) {
1522 		long	fd, sid;
1523 		char	*p;
1524 		int	err = 0;
1525 		enum pipe_polarity	pol = -1;
1526 		argv++; argc--;
1527 		if (argc<2 || argv[1][0] == 0) {
1528 		    err = 1;
1529 		} else {
1530 		    fd = strtol(argv[1], &p, 0);
1531 		    if (*p==0) {
1532 			sid = -1;
1533 		    } else if (p[0] == '=' && p[1] != 0) {
1534 			sid = strtol(p+1, &p, 0);
1535 			if (*p != 0) {
1536 			    err = 1;
1537 			}
1538 		    } else {
1539 			err = 1;
1540 		    }
1541 		}
1542 		if (err) {
1543 		    fprintf(stderr, "%s: %s requires descriptor number as argument\n", progname, arg-2);
1544 		    usage();
1545 		    exit(EXITCODE_ARGS);
1546 		}
1547 
1548 		{
1549 		  if      (0==strcmp(arg, "infd"))   pol = WRITEABLE;
1550 		  else if (0==strcmp(arg, "outfd"))  pol = READABLE;
1551 		  else if (0==strcmp(arg, "duplex")) pol = DUPLEX_IO;
1552 		  else if (0==strcmp(arg, "Duplex")) pol = DUPLEX;
1553 		  else if (0==strcmp(arg, "DUPLEX")) pol = DUPLEX_OI;
1554 		}
1555 		if (pol == -1) {
1556 		    fprintf(stderr, "%s: code error, polarity uninitialized %s:%d\n", progname, __FILE__, __LINE__);
1557 		    abort();
1558 		}
1559 		add_subproc_fd(fd, pol, -1);
1560 		argv++; argc--;
1561 	    } else if (0==strcmp(arg, "prefer-local")||
1562 		       0==strcmp(arg, "preferlocal")) {
1563 		merge_returns = PREFER_LOCAL;
1564 		argv++; argc--;
1565 	    } else if (0==strcmp(arg, "prefer-remote")||
1566 		       0==strcmp(arg, "preferremote")) {
1567 		merge_returns = PREFER_REMOTE;
1568 		argv++; argc--;
1569 	    } else if (0==strcmp(arg, "local-only")||
1570 		       0==strcmp(arg, "localonly")) {
1571 		merge_returns = LOCAL_ONLY;
1572 		argv++; argc--;
1573 	    } else if (0==strcmp(arg, "remote-only")||
1574 		       0==strcmp(arg, "remoteonly")) {
1575 		merge_returns = REMOTE_ONLY;
1576 		argv++; argc--;
1577 	    } else if (0==strcmp(arg, "client")) {
1578 		im_server = 0;
1579 		argv++; argc--;
1580 	    } else if (0==strcmp(arg, "server")) {
1581 		im_server = 1;
1582 		argv++; argc--;
1583 	    } else {
1584 		/* unknown -- flag.  Assume it's a command :) */
1585 		break;
1586 	    }
1587 	} else {
1588 	    /* it's a set of single dash flags. */
1589 	    do { switch (arg[0]) {
1590 	    case '#':
1591 		arg += scan_flag_numeric_fd(arg+1, &sockfd);
1592 		break;
1593 	    case 'v':
1594 		verbose = 1;
1595 		break;
1596 	    case 's':
1597 		subproc=1;
1598 		break;
1599 	    case 'i':
1600 		if (arg[1] == 'o') {
1601 		    int	fd;
1602 		    arg += scan_flag_numeric_fd(arg+2, &fd);
1603 		    add_subproc_fd(fd, DUPLEX_IO, -1);
1604 		} else {
1605 		    int	fd;
1606 		    arg += scan_flag_numeric_fd(arg+1, &fd);
1607 		    add_subproc_fd(fd, WRITEABLE, -1);
1608 		}
1609 		break;
1610 	    case 'o':
1611 		if (arg[1] == 'i') {
1612 		    int	fd;
1613 		    arg += scan_flag_numeric_fd(arg+2, &fd);
1614 		    add_subproc_fd(fd, DUPLEX_OI, -1);
1615 		} else {
1616 		    int	fd;
1617 		    arg += scan_flag_numeric_fd(arg+1, &fd);
1618 		    add_subproc_fd(fd, READABLE, -1);
1619 		}
1620 		break;
1621 	    case 'd':
1622 		{
1623 		    int	fd;
1624 		    arg += scan_flag_numeric_fd(arg+1, &fd);
1625 		    add_subproc_fd(fd, DUPLEX, -1);
1626 		}
1627 		break;
1628 	    case 'l':
1629 		merge_returns = PREFER_LOCAL;
1630 		break;
1631 	    case 'r':
1632 		merge_returns = PREFER_REMOTE;
1633 		break;
1634 	    case 'L':
1635 		merge_returns = LOCAL_ONLY;
1636 		break;
1637 	    case 'R':
1638 		merge_returns = REMOTE_ONLY;
1639 		break;
1640 	    case 0:
1641 		fprintf(stderr, "%s: blank compact flag.\n", progname);
1642 		/* fall through */
1643 	    default:
1644 		fprintf(stderr, "%s: Unknown compact flag beginning %s\n", progname, arg);
1645 		usage();
1646 		exit (EXITCODE_ARGS);
1647 	    } arg++;
1648 	    } while (arg[0]);
1649 
1650 	    argv++;
1651 	    argc--;
1652 	}
1653     }
1654 
1655     /* argv+1 points to an unrecognized flag that must be the
1656        subprocess cmd and arguments. */
1657 
1658     if (argc>1 && !subproc) {
1659 	fprintf(stderr, "%s: Unknown flag %s\n", progname, argv[1]);
1660 	usage();
1661 	exit (EXITCODE_ARGS);
1662     }
1663 
1664     if (sockfd<0) {
1665 	fprintf(stderr, "%s:  I must know the file number for the socket.\n",
1666 		progname);
1667 	usage();
1668 	exit(EXITCODE_ARGS);
1669     }
1670 
1671     if (subproc) {
1672 	if (merge_returns == UNINITIALIZED)
1673 	    merge_returns = PREFER_LOCAL;
1674 	/* check to make sure at least one descriptor is rerouted */
1675 	if (pipe_head == 0) {
1676 	    fprintf(stderr, "%s: must redirect at least one descriptor of subprocess.\n", progname);
1677 	    usage();
1678 	    exit(EXITCODE_ARGS);
1679 	}
1680     } else {
1681 	if (pipe_head == 0) {
1682 	    /* rig the degenerate case */
1683 	    add_subproc_fd(0, WRITEABLE, -1);
1684 	    add_subproc_fd(1, READABLE, -1);
1685 	}
1686 	if (merge_returns == PREFER_LOCAL ||
1687 	    merge_returns == PREFER_REMOTE ||
1688 	    merge_returns == LOCAL_ONLY ||
1689 	    merge_returns == REMOTE_ONLY) {
1690 	    fprintf(stderr, "%s: no local process to get a return code from\n", progname);
1691 	    usage();
1692 	    exit (EXITCODE_ARGS);
1693 	}
1694 
1695 	merge_returns = LOCAL_ONLY;
1696     }
1697 
1698     add_control_channel();	/* for passing exit status.  Is DUPLEX_OI. */
1699 
1700     if (verbose)
1701         emit_version("encapsulate", 1996);
1702 
1703     if (im_server<0) {
1704 	im_server = Im_server_p(sockfd);
1705     }
1706 
1707     {
1708 	struct pipeline	*curr;
1709 	for (curr = pipe_head; curr; curr = curr->next) {
1710 	    if (curr->code == DUPLEX)
1711 		curr->code = im_server ? DUPLEX_IO : DUPLEX_OI;
1712 	}
1713 
1714 	/* might as well initialize our session_id counter */
1715 	session_id_ = im_server ? 1025 : 1024;
1716 	/* below 1024 is reserved */
1717     }
1718 
1719 
1720     if (subproc)
1721 	spawn_child(argv+1, sockfd);
1722     else {
1723 	/* I have to invert the polarity of writable and readable
1724 	   channels, but not duplex.  Also have to copy the child_fd
1725 	   to pipe[0].  What a hellish mess. */
1726 	rig_single(); }
1727 
1728     signal(SIGPIPE, SIG_IGN);	/* handle the error returns */
1729 
1730     {
1731 	char	*buf;
1732 	int	len;
1733 	buf = prepare_SYNs( &len);
1734 	prime_packet_queue(buf, len);
1735     }
1736 
1737     main_io_loop(sockfd);
1738 
1739 #ifdef DEBUG
1740     fprintf(stderr, "%s: end of IO loop\n", progname);
1741 #endif
1742 
1743 #if 0
1744     while (child_running) {
1745 	pause();
1746     }
1747     probe_child();
1748 #endif
1749 
1750     if (local_return_code ==0)
1751 	local_return_code = exitcode_warnings;
1752 
1753     switch (merge_returns) {
1754     case PREFER_LOCAL:
1755 	if (local_return_code!=0)
1756 	    exit (local_return_code);
1757 	else
1758 	    exit (remote_return_code);
1759 	/* NOTREACHED */
1760     case PREFER_REMOTE:
1761 	if (remote_return_code!=0)
1762 	    exit (remote_return_code);
1763 	else
1764 	    exit (local_return_code);
1765 	/* NOTREACHED */
1766     case LOCAL_ONLY:
1767 	exit(local_return_code);
1768     case REMOTE_ONLY:
1769 	exit(remote_return_code);
1770     default:
1771 	fprintf(stderr, "%s: logic error.  merge_returns has bogus value.\n",
1772 		progname);
1773 	exit(EXITCODE_ARGS);
1774     }
1775 }
1776