|
|
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.