Annotation of coherent/g/usr/lib/uucp/tay104/tcp.c, revision 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.