Annotation of coherent/g/usr/lib/uucp/tay104/tcp.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.