|
|
1.1 root 1: /* tcp.c
2: Code to handle TCP connections.
3:
4: Copyright (C) 1991, 1992 Ian Lance Taylor
5:
6: This file is part of the Taylor UUCP package.
7:
8: This program is free software; you can redistribute it and/or
9: modify it under the terms of the GNU General Public License as
10: published by the Free Software Foundation; either version 2 of the
11: License, or (at your option) any later version.
12:
13: This program is distributed in the hope that it will be useful, but
14: WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16: General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
19: along with this program; if not, write to the Free Software
20: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21:
22: The author of the program may be contacted at [email protected] or
23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24: */
25:
26: #include "uucp.h"
27:
28: #if USE_RCS_ID
29: const char tcp_rcsid[] = "$Id: tcp.c,v 1.1 93/07/30 07:54:16 bin Exp Locker: bin $";
30: #endif
31:
32: #if HAVE_TCP
33:
34: #include "uudefs.h"
35: #include "uuconf.h"
36: #include "sysdep.h"
37: #include "conn.h"
38: #include "system.h"
39:
40: #include <errno.h>
41:
42: #if HAVE_SYS_TYPES_TCP_H
43: #include <sys/types.tcp.h>
44: #endif
45: #include <sys/socket.h>
46: #include <netdb.h>
47: #include <netinet/in.h>
48:
49: #if HAVE_FCNTL_H
50: #include <fcntl.h>
51: #else
52: #if HAVE_SYS_FILE_H
53: #include <sys/file.h>
54: #endif
55: #endif
56:
57: #ifndef FD_CLOEXEC
58: #define FD_CLOEXEC 1
59: #endif
60:
61: /* This code handles TCP connections. It assumes a Berkeley socket
62: interface. */
63:
64: /* The normal "uucp" port number. */
65: #define IUUCP_PORT (540)
66:
67: /* Local functions. */
68: static void utcp_free P((struct sconnection *qconn));
69: static boolean ftcp_open P((struct sconnection *qconn, long ibaud,
70: boolean fwait));
71: static boolean ftcp_close P((struct sconnection *qconn,
72: pointer puuconf,
73: struct uuconf_dialer *qdialer,
74: boolean fsuccess));
75: static boolean ftcp_reset P((struct sconnection *qconn));
76: static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf,
77: const struct uuconf_system *qsys,
78: const char *zphone,
79: struct uuconf_dialer *qdialer,
80: enum tdialerfound *ptdialer));
81: static int itcp_port_number P((const char *zport));
82:
83: /* The command table for a TCP connection. */
84: static const struct sconncmds stcpcmds =
85: {
86: utcp_free,
87: NULL, /* pflock */
88: NULL, /* pfunlock */
89: ftcp_open,
90: ftcp_close,
91: ftcp_reset,
92: ftcp_dial,
93: fsysdep_conn_read,
94: fsysdep_conn_write,
95: fsysdep_conn_io,
96: NULL, /* pfbreak */
97: NULL, /* pfset */
98: NULL, /* pfcarrier */
99: fsysdep_conn_chat,
100: NULL /* pibaud */
101: };
102:
103: /* Initialize a TCP connection. */
104:
105: boolean
106: fsysdep_tcp_init (qconn)
107: struct sconnection *qconn;
108: {
109: struct ssysdep_conn *q;
110:
111: q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
112: q->o = -1;
113: q->zdevice = NULL;
114: q->iflags = -1;
115: q->istdout_flags = -1;
116: q->fterminal = FALSE;
117: q->ftli = FALSE;
118: q->ibaud = 0;
119:
120: qconn->psysdep = (pointer) q;
121: qconn->qcmds = &stcpcmds;
122: return TRUE;
123: }
124:
125: /* Free a TCP connection. */
126:
127: static void
128: utcp_free (qconn)
129: struct sconnection *qconn;
130: {
131: xfree (qconn->psysdep);
132: }
133:
134: /* Open a TCP connection. If the fwait argument is TRUE, we are
135: running as a server. Otherwise we are just trying to reach another
136: system. */
137:
138: static boolean
139: ftcp_open (qconn, ibaud, fwait)
140: struct sconnection *qconn;
141: long ibaud;
142: boolean fwait;
143: {
144: struct ssysdep_conn *qsysdep;
145: struct sockaddr_in s;
146: const char *zport;
147: uid_t iuid, ieuid;
148:
149: ulog_device ("TCP");
150:
151: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
152:
153: qsysdep->o = socket (AF_INET, SOCK_STREAM, 0);
154: if (qsysdep->o < 0)
155: {
156: ulog (LOG_ERROR, "socket: %s", strerror (errno));
157: return FALSE;
158: }
159:
160: if (fcntl (qsysdep->o, F_SETFD,
161: fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
162: {
163: ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
164: (void) close (qsysdep->o);
165: qsysdep->o = -1;
166: return FALSE;
167: }
168:
169: qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
170: if (qsysdep->iflags < 0)
171: {
172: ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
173: (void) close (qsysdep->o);
174: qsysdep->o = -1;
175: return FALSE;
176: }
177:
178: /* If we aren't waiting for a connection, we're done. */
179: if (! fwait)
180: return TRUE;
181:
182: /* Run as a server and wait for a new connection. The code in
183: uucico.c has already detached us from our controlling terminal.
184: From this point on if the server gets an error we exit; we only
185: return if we have received a connection. It would be more robust
186: to respawn the server if it fails; someday. */
187: bzero ((pointer) &s, sizeof s);
188: s.sin_family = AF_INET;
189: zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
190: s.sin_port = itcp_port_number (zport);
191: s.sin_addr.s_addr = htonl (INADDR_ANY);
192:
193: /* Swap to our real user ID when doing the bind call. This will
194: permit the server to use privileged TCP ports when invoked by
195: root. We only swap if our effective user ID is not root, so that
196: the program can also be made suid root in order to get privileged
197: ports when invoked by anybody. */
198: iuid = getuid ();
199: ieuid = geteuid ();
200: if (ieuid != 0)
201: {
202: #if HAVE_SETREUID
203: /* Swap the effective user id and the real user id. We can then
204: swap them back again when we want to return to the uucp
205: user's permissions. */
206: if (setreuid (ieuid, iuid) < 0)
207: {
208: ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
209: (long) ieuid, (long) iuid, strerror (errno));
210: (void) close (qsysdep->o);
211: qsysdep->o = -1;
212: return FALSE;
213: }
214: #else /* ! HAVE_SETREUID */
215: #if HAVE_SAVED_SETUID
216: /* Set the effective user id to the real user id. Since the
217: effective user id is the saved setuid we will able to set
218: back to it later. If the real user id is root we will not be
219: able to switch back and forth, but that doesn't matter since
220: we only want to switch once. */
221: if (setuid (iuid) < 0)
222: {
223: ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid,
224: strerror (errno));
225: (void) close (qsysdep->o);
226: qsysdep->o = -1;
227: return FALSE;
228: }
229: #else /* ! HAVE_SAVED_SETUID */
230: /* There's no way to switch between real permissions and
231: effective permissions. Just try the bind with the uucp
232: permissions. */
233: #endif /* ! HAVE_SAVED_SETUID */
234: #endif /* ! HAVE_SETREUID */
235: }
236:
237: if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
238: ulog (LOG_FATAL, "bind: %s", strerror (errno));
239:
240: /* Now swap back to the uucp user ID. */
241: if (ieuid != 0)
242: {
243: #if HAVE_SETREUID
244: if (setreuid (iuid, ieuid) < 0)
245: {
246: ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
247: (long) iuid, (long) ieuid, strerror (errno));
248: (void) close (qsysdep->o);
249: qsysdep->o = -1;
250: return FALSE;
251: }
252: #else /* ! HAVE_SETREUID */
253: #if HAVE_SAVED_SETUID
254: /* Set ourselves back to our original effective user id. */
255: if (setuid ((uid_t) ieuid) < 0)
256: {
257: ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid,
258: strerror (errno));
259: (void) close (qsysdep->o);
260: qsysdep->o = -1;
261: return FALSE;
262: }
263: #else /* ! HAVE_SAVED_SETUID */
264: /* We didn't switch, no need to switch back. */
265: #endif /* ! HAVE_SAVED_SETUID */
266: #endif /* ! HAVE_SETREUID */
267: }
268:
269: if (listen (qsysdep->o, 5) < 0)
270: ulog (LOG_FATAL, "listen: %s", strerror (errno));
271:
272: while (! FGOT_SIGNAL ())
273: {
274: size_t clen;
275: int onew;
276: pid_t ipid;
277:
278: DEBUG_MESSAGE0 (DEBUG_PORT,
279: "ftcp_open: Waiting for connections");
280:
281: clen = sizeof s;
282: onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen);
283: if (onew < 0)
284: ulog (LOG_FATAL, "accept: %s", strerror (errno));
285:
286: DEBUG_MESSAGE0 (DEBUG_PORT,
287: "ftcp_open: Got connection; forking");
288:
289: ipid = ixsfork ();
290: if (ipid < 0)
291: ulog (LOG_FATAL, "fork: %s", strerror (errno));
292: if (ipid == 0)
293: {
294: (void) close (qsysdep->o);
295: qsysdep->o = onew;
296:
297: /* Now we fork and let our parent die, so that we become
298: a child of init. This lets the main server code wait
299: for its child and then continue without accumulating
300: zombie children. */
301: ipid = ixsfork ();
302: if (ipid < 0)
303: {
304: ulog (LOG_ERROR, "fork: %s", strerror (errno));
305: _exit (EXIT_FAILURE);
306: }
307:
308: if (ipid != 0)
309: _exit (EXIT_SUCCESS);
310:
311: ulog_id (getpid ());
312:
313: return TRUE;
314: }
315:
316: (void) close (onew);
317:
318: /* Now wait for the child. */
319: (void) ixswait ((unsigned long) ipid, (const char *) NULL);
320: }
321:
322: /* We got a signal. */
323: usysdep_exit (FALSE);
324:
325: /* Avoid compiler warnings. */
326: return FALSE;
327: }
328:
329: /* Close the port. */
330:
331: /*ARGSUSED*/
332: static boolean
333: ftcp_close (qconn, puuconf, qdialer, fsuccess)
334: struct sconnection *qconn;
335: pointer puuconf;
336: struct uuconf_dialer *qdialer;
337: boolean fsuccess;
338: {
339: struct ssysdep_conn *qsysdep;
340: boolean fret;
341:
342: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
343: fret = TRUE;
344: if (qsysdep->o >= 0 && close (qsysdep->o) < 0)
345: {
346: ulog (LOG_ERROR, "close: %s", strerror (errno));
347: fret = FALSE;
348: }
349: qsysdep->o = -1;
350: return fret;
351: }
352:
353: /* Reset the port. This will be called by a child which was forked
354: off in ftcp_open, above. We don't want uucico to continue looping
355: and giving login prompts, so we pretend that we received a SIGINT
356: signal. This should probably be handled more cleanly. The signal
357: will not be recorded in the log file because we don't set
358: afLog_signal[INDEXSIG_SIGINT]. */
359:
360: /*ARGSUSED*/
361: static boolean
362: ftcp_reset (qconn)
363: struct sconnection *qconn;
364: {
365: afSignal[INDEXSIG_SIGINT] = TRUE;
366: return TRUE;
367: }
368:
369: /* Dial out on a TCP port, so to speak: connect to a remote computer. */
370:
371: /*ARGSUSED*/
372: static boolean
373: ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
374: struct sconnection *qconn;
375: pointer puuconf;
376: const struct uuconf_system *qsys;
377: const char *zphone;
378: struct uuconf_dialer *qdialer;
379: enum tdialerfound *ptdialer;
380: {
381: struct ssysdep_conn *qsysdep;
382: const char *zhost;
383: struct hostent *q;
384: struct sockaddr_in s;
385: const char *zport;
386:
387: qsysdep = (struct ssysdep_conn *) qconn->psysdep;
388:
389: *ptdialer = DIALERFOUND_FALSE;
390:
391: zhost = zphone;
392: if (zhost == NULL)
393: {
394: if (qsys == NULL)
395: {
396: ulog (LOG_ERROR, "No address for TCP connection");
397: return FALSE;
398: }
399: zhost = qsys->uuconf_zname;
400: }
401:
402: errno = 0;
403: q = gethostbyname ((char *) zhost);
404: if (q == NULL)
405: {
406: if (errno == 0)
407: ulog (LOG_ERROR, "%s: unknown host name", zhost);
408: else
409: ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno));
410: return FALSE;
411: }
412:
413: s.sin_family = q->h_addrtype;
414: zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
415: s.sin_port = itcp_port_number (zport);
416: memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length);
417:
418: if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
419: {
420: ulog (LOG_ERROR, "connect: %s", strerror (errno));
421: return FALSE;
422: }
423:
424: return TRUE;
425: }
426:
427: /* Get the port number given a name. The argument will almost always
428: be "uucp" so we cache that value. The return value is always in
429: network byte order. This returns -1 on error. */
430:
431: static int
432: itcp_port_number (zname)
433: const char *zname;
434: {
435: boolean fuucp;
436: static int iuucp;
437: int i;
438: char *zend;
439: struct servent *q;
440:
441: fuucp = strcmp (zname, "uucp") == 0;
442: if (fuucp && iuucp != 0)
443: return iuucp;
444:
445: /* Try it as a number first. */
446: i = strtol ((char *) zname, &zend, 10);
447: if (i != 0 && *zend == '\0')
448: return htons (i);
449:
450: q = getservbyname ((char *) zname, (char *) "tcp");
451: if (q == NULL)
452: {
453: /* We know that the "uucp" service should be 540, even if isn't
454: in /etc/services. */
455: if (fuucp)
456: {
457: iuucp = htons (IUUCP_PORT);
458: return iuucp;
459: }
460: ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno));
461: return -1;
462: }
463:
464: if (fuucp)
465: iuucp = q->s_port;
466:
467: return q->s_port;
468: }
469:
470: #endif /* HAVE_TCP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.