diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 1995-08-30 17:42:29 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 1995-08-30 17:42:29 +0000 |
| commit | 09adf59b71be5536e90072a21ff0a298de13b31e (patch) | |
| tree | 5472a1168e90c3da5a19b92d4eec77fdec82325a /gnu/libexec | |
| parent | 11ae5136afc310ef71c58826e0faa94cc2b415f4 (diff) | |
Notes
Diffstat (limited to 'gnu/libexec')
| -rw-r--r-- | gnu/libexec/uucp/libunix/failed.c | 26 | ||||
| -rw-r--r-- | gnu/libexec/uucp/libunix/sync.c | 42 | ||||
| -rw-r--r-- | gnu/libexec/uucp/libunix/tcp.c | 444 | ||||
| -rw-r--r-- | gnu/libexec/uucp/libunix/tli.c | 628 | ||||
| -rw-r--r-- | gnu/libexec/uucp/libunix/uid.c | 116 | ||||
| -rw-r--r-- | gnu/libexec/uucp/libuuconf/strip.c | 50 | ||||
| -rw-r--r-- | gnu/libexec/uucp/uucico/proty.c | 660 |
7 files changed, 1966 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/libunix/failed.c b/gnu/libexec/uucp/libunix/failed.c new file mode 100644 index 0000000000000..66c98a80df69e --- /dev/null +++ b/gnu/libexec/uucp/libunix/failed.c @@ -0,0 +1,26 @@ +/* failed.c + Save a file in the .Failed directory. */ + +#include "uucp.h" + +#include "sysdep.h" +#include "uudefs.h" +#include "system.h" + +char * +zsysdep_save_failed_file (zfile) + const char *zfile; +{ + char *zto; + + zto = zsappend3 (zSspooldir, FAILEDDIR, zfile); + + if (! fsysdep_move_file (zfile, zto, TRUE, FALSE, FALSE, + (const char *) NULL)) + { + ubuffree (zto); + return NULL; + } + + return zto; +} diff --git a/gnu/libexec/uucp/libunix/sync.c b/gnu/libexec/uucp/libunix/sync.c new file mode 100644 index 0000000000000..c346c58ccb7ad --- /dev/null +++ b/gnu/libexec/uucp/libunix/sync.c @@ -0,0 +1,42 @@ +/* sync.c + Sync a file to disk, if FSYNC_ON_CLOSE is set. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +boolean +fsysdep_sync (e, zmsg) + openfile_t e; + const char *zmsg; +{ + int o; + +#if USE_STDIO + if (fflush (e) == EOF) + { + ulog (LOG_ERROR, "%s: fflush: %s", zmsg, strerror (errno)); + return FALSE; + } +#endif + +#if USE_STDIO + o = fileno (e); +#else + o = e; +#endif + +#if FSYNC_ON_CLOSE + if (fsync (o) < 0) + { + ulog (LOG_ERROR, "%s: fsync: %s", zmsg, strerror (errno)); + return FALSE; + } +#endif + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/tcp.c b/gnu/libexec/uucp/libunix/tcp.c new file mode 100644 index 0000000000000..6ec39f26a63ba --- /dev/null +++ b/gnu/libexec/uucp/libunix/tcp.c @@ -0,0 +1,444 @@ +/* tcp.c + Code to handle TCP connections. + + Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char tcp_rcsid[] = "$Id: tcp.c,v 1.5 1995/06/21 19:20:46 ian Rel $"; +#endif + +#if HAVE_TCP + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "conn.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_SYS_TYPES_TCP_H +#include <sys/types.tcp.h> +#endif +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* This code handles TCP connections. It assumes a Berkeley socket + interface. */ + +/* The normal "uucp" port number. */ +#define IUUCP_PORT (540) + +/* Local functions. */ +static void utcp_free P((struct sconnection *qconn)); +static boolean ftcp_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean ftcp_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialer)); +static int itcp_port_number P((const char *zport)); + +/* The command table for a TCP connection. */ +static const struct sconncmds stcpcmds = +{ + utcp_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + ftcp_open, + ftcp_close, + ftcp_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + NULL, /* pfbreak */ + NULL, /* pfset */ + NULL, /* pfcarrier */ + fsysdep_conn_chat, + NULL /* pibaud */ +}; + +/* Initialize a TCP connection. */ + +boolean +fsysdep_tcp_init (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + q->o = -1; + q->ord = -1; + q->owr = -1; + q->zdevice = NULL; + q->iflags = -1; + q->iwr_flags = -1; + q->fterminal = FALSE; + q->ftli = FALSE; + q->ibaud = 0; + + qconn->psysdep = (pointer) q; + qconn->qcmds = &stcpcmds; + return TRUE; +} + +/* Free a TCP connection. */ + +static void +utcp_free (qconn) + struct sconnection *qconn; +{ + xfree (qconn->psysdep); +} + +/* Open a TCP connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftcp_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + struct sockaddr_in s; + const char *zport; + uid_t ieuid; + boolean fswap; + + ulog_device ("TCP"); + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + qsysdep->o = socket (AF_INET, SOCK_STREAM, 0); + if (qsysdep->o < 0) + { + ulog (LOG_ERROR, "socket: %s", strerror (errno)); + return FALSE; + } + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); + if (qsysdep->iflags < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + /* We save our process ID in the qconn structure. This is checked + in ftcp_close. */ + qsysdep->ipid = getpid (); + + /* If we aren't waiting for a connection, we're done. */ + if (! fwait) + return TRUE; + + /* Run as a server and wait for a new connection. The code in + uucico.c has already detached us from our controlling terminal. + From this point on if the server gets an error we exit; we only + return if we have received a connection. It would be more robust + to respawn the server if it fails; someday. */ + bzero ((pointer) &s, sizeof s); + s.sin_family = AF_INET; + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + s.sin_port = itcp_port_number (zport); + s.sin_addr.s_addr = htonl (INADDR_ANY); + + /* Swap to our real user ID when doing the bind call. This will + permit the server to use privileged TCP ports when invoked by + root. We only swap if our effective user ID is not root, so that + the program can also be made suid root in order to get privileged + ports when invoked by anybody. */ + fswap = geteuid () != 0; + if (fswap) + { + if (! fsuser_perms (&ieuid)) + { + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + } + + if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "bind: %s", strerror (errno)); + } + + /* Now swap back to the uucp user ID. */ + if (fswap) + { + if (! fsuucp_perms ((long) ieuid)) + ulog (LOG_FATAL, "Could not swap back to UUCP user permissions"); + } + + if (listen (qsysdep->o, 5) < 0) + ulog (LOG_FATAL, "listen: %s", strerror (errno)); + + while (! FGOT_SIGNAL ()) + { + size_t clen; + int onew; + pid_t ipid; + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftcp_open: Waiting for connections"); + + clen = sizeof s; + onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen); + if (onew < 0) + ulog (LOG_FATAL, "accept: %s", strerror (errno)); + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftcp_open: Got connection; forking"); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + if (ipid == 0) + { + (void) close (qsysdep->o); + qsysdep->o = onew; + + /* Now we fork and let our parent die, so that we become + a child of init. This lets the main server code wait + for its child and then continue without accumulating + zombie children. */ + ipid = ixsfork (); + if (ipid < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + ulog_id (getpid ()); + + return TRUE; + } + + (void) close (onew); + + /* Now wait for the child. */ + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + } + + /* We got a signal. */ + usysdep_exit (FALSE); + + /* Avoid compiler warnings. */ + return FALSE; +} + +/* Close the port. */ + +/*ARGSUSED*/ +static boolean +ftcp_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + fret = TRUE; + if (qsysdep->o >= 0 && close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + qsysdep->o = -1; + + /* If the current pid is not the one we used to open the port, then + we must have forked up above and we are now the child. In this + case, we are being called from within the fendless loop in + uucico.c. We return FALSE to force the loop to end and the child + to exit. This should be handled in a cleaner fashion. */ + if (qsysdep->ipid != getpid ()) + fret = FALSE; + + return fret; +} + +/* Dial out on a TCP port, so to speak: connect to a remote computer. */ + +/*ARGSUSED*/ +static boolean +ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialer; +{ + struct ssysdep_conn *qsysdep; + const char *zhost; + struct hostent *q; + struct sockaddr_in s; + const char *zport; + char **pzdialer; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + *ptdialer = DIALERFOUND_FALSE; + + zhost = zphone; + if (zhost == NULL) + { + if (qsys == NULL) + { + ulog (LOG_ERROR, "No address for TCP connection"); + return FALSE; + } + zhost = qsys->uuconf_zname; + } + + errno = 0; + q = gethostbyname ((char *) zhost); + if (q != NULL) + { + s.sin_family = q->h_addrtype; + memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length); + } + else + { + if (errno != 0) + { + ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno)); + return FALSE; + } + + s.sin_family = AF_INET; + s.sin_addr.s_addr = inet_addr ((char *) zhost); + if ((long) s.sin_addr.s_addr == (long) -1) + { + ulog (LOG_ERROR, "%s: unknown host name", zhost); + return FALSE; + } + } + + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + s.sin_port = itcp_port_number (zport); + + if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + { + ulog (LOG_ERROR, "connect: %s", strerror (errno)); + return FALSE; + } + + /* Handle the dialer sequence, if any. */ + pzdialer = qconn->qport->uuconf_u.uuconf_stcp.uuconf_pzdialer; + if (pzdialer != NULL && *pzdialer != NULL) + { + if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone, + qdialer, ptdialer)) + return FALSE; + } + + return TRUE; +} + +/* Get the port number given a name. The argument will almost always + be "uucp" so we cache that value. The return value is always in + network byte order. This returns -1 on error. */ + +static int +itcp_port_number (zname) + const char *zname; +{ + boolean fuucp; + static int iuucp; + int i; + char *zend; + struct servent *q; + + fuucp = strcmp (zname, "uucp") == 0; + if (fuucp && iuucp != 0) + return iuucp; + + /* Try it as a number first. */ + i = strtol ((char *) zname, &zend, 10); + if (i != 0 && *zend == '\0') + return htons (i); + + q = getservbyname ((char *) zname, (char *) "tcp"); + if (q == NULL) + { + /* We know that the "uucp" service should be 540, even if isn't + in /etc/services. */ + if (fuucp) + { + iuucp = htons (IUUCP_PORT); + return iuucp; + } + ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno)); + return -1; + } + + if (fuucp) + iuucp = q->s_port; + + return q->s_port; +} + +#endif /* HAVE_TCP */ diff --git a/gnu/libexec/uucp/libunix/tli.c b/gnu/libexec/uucp/libunix/tli.c new file mode 100644 index 0000000000000..3e546c844991b --- /dev/null +++ b/gnu/libexec/uucp/libunix/tli.c @@ -0,0 +1,628 @@ +/* tli.c + Code to handle TLI connections. + + Copyright (C) 1992, 1993, 1994 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char tli_rcsid[] = "$Id: tli.c,v 1.4 1995/06/21 19:20:50 ian Rel $"; +#endif + +#if HAVE_TLI + +#include "sysdep.h" +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if HAVE_TIUSER_H +#include <tiuser.h> +#else +#if HAVE_XTI_H +#include <xti.h> +#else +#if HAVE_SYS_TLI_H +#include <sys/tli.h> +#endif +#endif +#endif + +#if HAVE_STROPTS_H +#include <stropts.h> +#endif + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* The arguments to t_alloca have two different names. I want the + SVID ones, not the XPG3 ones. */ +#ifndef T_BIND +#define T_BIND T_BIND_STR +#endif +#ifndef T_CALL +#define T_CALL T_CALL_STR +#endif + +/* Hopefully these externs will not cause any trouble. This is how + they are shown in the SVID. */ +extern int t_errno; +extern char *t_errlist[]; +extern int t_nerr; + +#ifndef HAVE_TIUSER_H +#ifndef t_alloc +extern pointer t_alloc (); +#endif +#endif + +/* This code handles TLI connections. It's Unix specific. It's + largely based on code from Unix Network Programming, by W. Richard + Stevens. */ + +/* Local functions. */ +static const char *ztlierror P((void)); +static void utli_free P((struct sconnection *qconn)); +static boolean ftli_push P((struct sconnection *qconn)); +static boolean ftli_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean ftli_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialer)); + +/* The command table for a TLI connection. */ +static const struct sconncmds stlicmds = +{ + utli_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + ftli_open, + ftli_close, + ftli_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + NULL, /* pfbreak */ + NULL, /* pfset */ + NULL, /* pfcarrier */ + fsysdep_conn_chat, + NULL /* pibaud */ +}; + +/* Get a TLI error string. */ + +static const char * +ztlierror () +{ + if (t_errno == TSYSERR) + return strerror (errno); + if (t_errno < 0 || t_errno >= t_nerr) + return "Unknown TLI error"; + return t_errlist[t_errno]; +} + +/* Initialize a TLI connection. This may be called with qconn->qport + NULL, when opening standard input as a TLI connection. */ + +boolean +fsysdep_tli_init (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + q->o = -1; + q->ord = -1; + q->owr = -1; + q->zdevice = NULL; + q->iflags = -1; + q->iwr_flags = -1; + q->fterminal = FALSE; + q->ftli = TRUE; + q->ibaud = 0; + + qconn->psysdep = (pointer) q; + qconn->qcmds = &stlicmds; + return TRUE; +} + +/* Free a TLI connection. */ + +static void +utli_free (qconn) + struct sconnection *qconn; +{ + xfree (qconn->psysdep); +} + +/* Push all desired modules onto a TLI stream. If the user requests a + STREAMS connection without giving a list of modules, we just push + tirdwr. If the I_PUSH ioctl is not defined on this system, we just + ignore any list of modules. */ + +static boolean +ftli_push (qconn) + struct sconnection *qconn; +{ +#ifdef I_PUSH + + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL) + { + char **pz; + + for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush; + *pz != NULL; + pz++) + { + if (ioctl (qsysdep->o, I_PUSH, *pz) < 0) + { + ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz, + strerror (errno)); + return FALSE; + } + } + } + else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) + { + if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0) + { + ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s", + strerror (errno)); + return FALSE; + } + } + + /* If we have just put the connection into stream mode, we must turn + off the TLI flag to avoid using TLI calls on it. */ + if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) + qsysdep->ftli = FALSE; + +#endif /* defined (I_PUSH) */ + + return TRUE; +} + +/* Open a TLI connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftli_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + const char *zdevice; + char *zfreedev; + const char *zservaddr; + char *zfreeaddr; + uid_t ieuid; + boolean fswap; + struct t_bind *qtbind; + struct t_call *qtcall; + + /* Unlike most other device types, we don't bother to call + ulog_device here, because fconn_open calls it with the name of + the port anyhow. */ + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice; + if (zdevice == NULL) + zdevice = qconn->qport->uuconf_zname; + + zfreedev = NULL; + if (*zdevice != '/') + { + zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice)); + sprintf (zfreedev, "/dev/%s", zdevice); + zdevice = zfreedev; + } + + /* If we are acting as a server, swap to our real user ID before + calling t_open. This will permit the server to use privileged + TCP ports when invoked by root. We only swap if our effective + user ID is not root, so that the program can also be made suid + root in order to get privileged ports when invoked by anybody. */ + fswap = fwait && geteuid () != 0; + if (fswap) + { + if (! fsuser_perms (&ieuid)) + { + ubuffree (zfreedev); + return FALSE; + } + } + + qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL); + if (qsysdep->o < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ()); + ubuffree (zfreedev); + return FALSE; + } + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + ubuffree (zfreedev); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); + if (qsysdep->iflags < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + ubuffree (zfreedev); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + /* We save our process ID in the qconn structure. This is checked + in ftli_close. */ + qsysdep->ipid = getpid (); + + /* If we aren't waiting for a connection, we can bind to any local + address, and then we're finished. */ + if (! fwait) + { + /* fswap is known to be FALSE here. */ + ubuffree (zfreedev); + if (t_bind (qsysdep->o, (struct t_bind *) NULL, + (struct t_bind *) NULL) < 0) + { + ulog (LOG_ERROR, "t_bind: %s", ztlierror ()); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + return TRUE; + } + + /* Run as a server and wait for a new connection. The code in + uucico.c has already detached us from our controlling terminal. + From this point on if the server gets an error we exit; we only + return if we have received a connection. It would be more robust + to respawn the server if it fails; someday. */ + qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL); + if (qtbind == NULL) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ()); + } + + zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr; + if (zservaddr == NULL) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "Can't run as TLI server; no server address"); + } + + zfreeaddr = zbufcpy (zservaddr); + qtbind->addr.len = cescape (zfreeaddr); + if (qtbind->addr.len > qtbind->addr.maxlen) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "%s: TLI server address too long (max %d)", + zservaddr, qtbind->addr.maxlen); + } + memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len); + ubuffree (zfreeaddr); + + qtbind->qlen = 5; + + if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ()); + } + + if (fswap) + { + if (! fsuucp_perms ((long) ieuid)) + ulog (LOG_FATAL, "Could not swap back to UUCP user permissions"); + } + + (void) t_free ((pointer) qtbind, T_BIND); + + qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL); + if (qtcall == NULL) + ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ()); + + while (! FGOT_SIGNAL ()) + { + int onew; + pid_t ipid; + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftli_open: Waiting for connections"); + + if (t_listen (qsysdep->o, qtcall) < 0) + ulog (LOG_FATAL, "t_listen: %s", ztlierror ()); + + onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL); + if (onew < 0) + ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ()); + + if (fcntl (onew, F_SETFD, + fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0) + ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + + if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0) + ulog (LOG_FATAL, "t_bind: %s", ztlierror ()); + + if (t_accept (qsysdep->o, onew, qtcall) < 0) + { + /* We may have received a disconnect. */ + if (t_errno != TLOOK) + ulog (LOG_FATAL, "t_accept: %s", ztlierror ()); + if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) + ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ()); + (void) t_close (onew); + continue; + } + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftli_open: Got connection; forking"); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + if (ipid == 0) + { + ulog_close (); + + (void) t_close (qsysdep->o); + qsysdep->o = onew; + + /* Push any desired modules. */ + if (! ftli_push (qconn)) + _exit (EXIT_FAILURE); + + /* Now we fork and let our parent die, so that we become + a child of init. This lets the main server code wait + for its child and then continue without accumulating + zombie children. */ + ipid = ixsfork (); + if (ipid < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + ulog_id (getpid ()); + + return TRUE; + } + + (void) t_close (onew); + + /* Now wait for the child. */ + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + } + + /* We got a signal. */ + usysdep_exit (FALSE); + + /* Avoid compiler warnings. */ + return FALSE; +} + +/* Close the port. */ + +/*ARGSUSED*/ +static boolean +ftli_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + fret = TRUE; + if (qsysdep->o >= 0) + { + if (qsysdep->ftli) + { + if (t_close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "t_close: %s", ztlierror ()); + fret = FALSE; + } + } + else + { + if (close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + } + + qsysdep->o = -1; + } + + /* If the current pid is not the one we used to open the port, then + we must have forked up above and we are now the child. In this + case, we are being called from within the fendless loop in + uucico.c. We return FALSE to force the loop to end and the child + to exit. This should be handled in a cleaner fashion. */ + if (qsysdep->ipid != getpid ()) + fret = FALSE; + + return fret; +} + +/* Dial out on a TLI port, so to speak: connect to a remote computer. */ + +/*ARGSUSED*/ +static boolean +ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialerfound; +{ + struct ssysdep_conn *qsysdep; + char **pzdialer; + const char *zaddr; + struct t_call *qtcall; + char *zescape; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + *ptdialerfound = DIALERFOUND_FALSE; + + pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer; + if (*pzdialer == NULL) + pzdialer = NULL; + + /* If the first dialer is "TLI" or "TLIS", we use the first token + (pzdialer[1]) as the address to connect to. */ + zaddr = zphone; + if (pzdialer != NULL + && (strcmp (pzdialer[0], "TLI") == 0 + || strcmp (pzdialer[0], "TLIS") == 0)) + { + if (pzdialer[1] == NULL) + ++pzdialer; + else + { + if (strcmp (pzdialer[1], "\\D") != 0 + && strcmp (pzdialer[1], "\\T") != 0) + zaddr = pzdialer[1]; + pzdialer += 2; + } + } + + if (zaddr == NULL) + { + ulog (LOG_ERROR, "No address for TLI connection"); + return FALSE; + } + + qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR); + if (qtcall == NULL) + { + ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ()); + return FALSE; + } + + zescape = zbufcpy (zaddr); + qtcall->addr.len = cescape (zescape); + if (qtcall->addr.len > qtcall->addr.maxlen) + { + ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr, + qtcall->addr.maxlen); + ubuffree (zescape); + return FALSE; + } + memcpy (qtcall->addr.buf, zescape, qtcall->addr.len); + ubuffree (zescape); + + if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0) + { + if (t_errno != TLOOK) + ulog (LOG_ERROR, "t_connect: %s", ztlierror ()); + else + { + if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) + ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ()); + else + ulog (LOG_ERROR, "Connection refused"); + } + return FALSE; + } + + /* We've connected to the remote. Push any desired modules. */ + if (! ftli_push (qconn)) + return FALSE; + + /* Handle the rest of the dialer sequence. */ + if (pzdialer != NULL && *pzdialer != NULL) + { + if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone, + qdialer, ptdialerfound)) + return FALSE; + } + + return TRUE; +} + +#endif /* HAVE_TLI */ diff --git a/gnu/libexec/uucp/libunix/uid.c b/gnu/libexec/uucp/libunix/uid.c new file mode 100644 index 0000000000000..66b8fc70001fe --- /dev/null +++ b/gnu/libexec/uucp/libunix/uid.c @@ -0,0 +1,116 @@ +/* uid.c + Switch back and forth between UUCP and user permissions. + + Copyright (C) 1992, 1995 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +#include <errno.h> + +/* NetBSD apparently does not support setuid as required by POSIX when + using saved setuid, so use seteuid instead. */ + +#if HAVE_SETEUID +#define setuid seteuid +#endif + +/* Switch to permissions of the invoking user. */ + +boolean +fsuser_perms (pieuid) + uid_t *pieuid; +{ + uid_t ieuid, iuid; + + ieuid = geteuid (); + iuid = getuid (); + if (pieuid != NULL) + *pieuid = ieuid; + +#if HAVE_SETREUID + /* Swap the effective user id and the real user id. We can then + swap them back again when we want to return to the uucp user's + permissions. */ + if (setreuid (ieuid, iuid) < 0) + { + ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", + (long) ieuid, (long) iuid, strerror (errno)); + return FALSE; + } +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set the effective user id to the real user id. Since the + effective user id is saved (it's the saved setuid) we will able + to set back to it later. If the real user id is root we will not + be able to switch back and forth, so don't even try. */ + if (iuid != 0) + { + if (setuid (iuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno)); + return FALSE; + } + } +#else /* ! HAVE_SAVED_SETUID */ + /* There's no way to switch between real permissions and effective + permissions. Just try to open the file with the uucp + permissions. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + + return TRUE; +} + +/* Restore the uucp permissions. */ + +/*ARGSUSED*/ +boolean +fsuucp_perms (ieuid) + long ieuid; +{ +#if HAVE_SETREUID + /* Swap effective and real user id's back to what they were. */ + if (! fsuser_perms ((uid_t *) NULL)) + return FALSE; +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set ourselves back to our original effective user id. */ + if (setuid ((uid_t) ieuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno)); + /* Is this error message helpful or confusing? */ + if (errno == EPERM) + ulog (LOG_ERROR, + "Probably HAVE_SAVED_SETUID in policy.h should be set to 0"); + return FALSE; + } +#else /* ! HAVE_SAVED_SETUID */ + /* We didn't switch, no need to switch back. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + + return TRUE; +} diff --git a/gnu/libexec/uucp/libuuconf/strip.c b/gnu/libexec/uucp/libuuconf/strip.c new file mode 100644 index 0000000000000..fc314a77e939f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/strip.c @@ -0,0 +1,50 @@ +/* maxuxq.c + Get information about what things should be stripped. + + Copyright (C) 1995 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_strip_rcsid[] = "$Id: strip.c,v 1.2 1995/06/28 15:43:14 ian Rel $"; +#endif + +/* Get information about what types of global information should be + stripped. There are currently only two, which we return as a + couple of bits. We store them as two separate variables, so we + don't need to have a special function to set the values correctly. */ + +int +uuconf_strip (pglobal, pistrip) + pointer pglobal; + int *pistrip; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pistrip = 0; + if (qglobal->qprocess->fstrip_login) + *pistrip |= UUCONF_STRIP_LOGIN; + if (qglobal->qprocess->fstrip_proto) + *pistrip |= UUCONF_STRIP_PROTO; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/uucico/proty.c b/gnu/libexec/uucp/uucico/proty.c new file mode 100644 index 0000000000000..f15671e2b4d34 --- /dev/null +++ b/gnu/libexec/uucp/uucico/proty.c @@ -0,0 +1,660 @@ +/* proty.c + The 'y' protocol. + + Copyright (C) 1994, 1995 Jorge Cwik and Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char proty_id[] = "$Id: proty.c,v 1.4 1995/06/21 19:15:40 ian Rel $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* The 'y' protocol, and this implementation, was written and designed + by Jorge Cwik <jorge@satlink.net>. Some of the routines, and the + coding style in general, were taken verbatim or adapted from other + Taylor UUCP modules. Mark Delany made the initial testings and + helped in portability issues. + + This protocol does not perform any kind of error correction or flow + control. It does do error checking. It does not require an end to + end reliable link. It is recommended for error-free (also called + semi-reliable) connections as provided by error correcting modems. + It needs an eight bit clean channel and some kind of flow control + at the lower layers, typically RTS/CTS hardware flow control. + + The flow of the file transmission is completely unidirectional. + There are no ACKs or NAKs outside file boundaries. This makes it + very suitable for half duplex modulations (like PEP) and + connections with very long delays, like multihop satellite links. */ + +/* This protocol uses 16 bit little-endian ints in the packet header. */ +#define FROMLITTLE(p) (((p)[0] & 0xff) + (((p)[1] & 0xff) << 8)) +#define TOLITTLE(p, i) ((p)[0] = (i) & 0xff, (p)[1] = ((i) >> 8) & 0xff) + +/* The buffer and packet size we use. */ +#define CYBUFSIZE (1024) +#define IYPACKSIZE (1024) + +/* The offset in the buffer to the data. */ +#define CYFRAMELEN (6) + +/* Offsets in a packet header. */ +#define YFRAME_SEQ_OFF (0) +#define YFRAME_LEN_OFF (2) +#define YFRAME_CTL_OFF (2) +#define YFRAME_CHK_OFF (4) + +/* Offsets in a packet header viewed as an array of shorts. */ +#define YFRAME_SEQ (0) +#define YFRAME_LEN (1) +#define YFRAME_CTL (1) +#define YFRAME_CHK (2) + +/* The default timeout. */ +#define CYTIMEOUT (60) + +/* Control packet types. */ +#define YPKT_ACK (0xFFFE) +#define YPKT_ERR (0xFFFD) +#define YPKT_BAD (0xFFFC) + +/* The protocol version number. */ +#define Y_VERSION (1) + +/* When the protocol starts up, it transmit the following information: + 1 byte version + 1 byte packet size + 2 byte flags (none currently defined) + Future revision may expand the structure as long as these members + keep their current offset. */ +#define Y_INIT_HDR_LEN (4) +#define Y_INIT_HDR_VERSION_OFF (0) +#define Y_INIT_HDR_PKTSIZE_OFF (1) +#define Y_INIT_HDR_FLAGS_OFF (2) + +/* The initialization length of the lowest accepted version. */ +#define MIN_Y_SYNC (4) + +/* Not strictly needed, but I would not want to accept a 32k sync pkt. */ +#define MAX_Y_SYNC IYPACKSIZE + +/* Local and remote packet sizes (we actually use the same value for + both). */ +static size_t iYlocal_packsize = IYPACKSIZE; +static size_t iYremote_packsize = IYPACKSIZE; + +/* Local and remote packet sequence numbers. */ +static unsigned short iYlocal_pktnum; +static unsigned short iYremote_pktnum; + +/* The timeout. */ +static int cYtimeout = CYTIMEOUT; + +/* Transmitter buffer. */ +static char *zYbuf; + +/* Protocol parameters. */ + +struct uuconf_cmdtab asYproto_params[] = +{ + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cYtimeout, NULL }, + { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iYlocal_packsize, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Local functions. */ + +static boolean fywait_for_packet P((struct sdaemon *qdaemon, + boolean *pfexit)); +static unsigned short iychecksum P((const char *z, size_t c)); +static unsigned short iychecksum2 P((const char *zfirst, size_t cfirst, + const char *zsecond, size_t csecond)); +static boolean fywait_for_header P((struct sdaemon *qdaemon, + unsigned short header[3], int timeout)); +static boolean fysend_pkt P((struct sdaemon *qdaemon, + const void *zdata, size_t cdata)); +static boolean fysend_control P((struct sdaemon *qdaemon, + int itype)); +static boolean fyread_data P((struct sdaemon *qdaemon, size_t clen, + int timeout)); + +/* Exchange sync packets at protocol startup. */ + +static boolean +fyxchg_syncs (qdaemon) + struct sdaemon *qdaemon; +{ + char inithdr[Y_INIT_HDR_LEN]; + unsigned short header[3]; + unsigned short ichk; + size_t clen, cfirst; + int rpktsize; + + /* Send our configuration. We could use only one array (for local + and remote). But this is safer in case the code changes and + depend on separate ones. */ + + inithdr[Y_INIT_HDR_VERSION_OFF] = Y_VERSION; + inithdr[Y_INIT_HDR_PKTSIZE_OFF] = iYlocal_packsize >> 8; + TOLITTLE (inithdr + Y_INIT_HDR_FLAGS_OFF, 0); + + if (! fysend_pkt (qdaemon, inithdr, Y_INIT_HDR_LEN)) + return FALSE; + + if (! fywait_for_header (qdaemon, header, cYtimeout)) + return FALSE; + + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fyxchg_syncs: Got sync header"); + clen = header[YFRAME_LEN]; + + if (clen < MIN_Y_SYNC || clen > MAX_Y_SYNC) + { + ulog (LOG_ERROR, "Bad 'y' protocol sync packet length"); + return FALSE; + } + + /* It may be better to integrate this code with fywait_for_packet. */ + if (! fyread_data (qdaemon, clen, cYtimeout)) + return FALSE; + + cfirst = CRECBUFLEN - iPrecstart; + ichk = iychecksum2 (abPrecbuf + iPrecstart, cfirst, + abPrecbuf, clen - cfirst); + + rpktsize = BUCHAR (abPrecbuf[(iPrecstart + 1) % CRECBUFLEN]); + + /* Future versions of the protocol may need to check and react + according to the version number. */ + + if (rpktsize == 0 || header[YFRAME_CHK] != ichk) + { + ulog (LOG_ERROR, "Bad 'y' protocol sync packet"); + return FALSE; + } + + iYremote_packsize = rpktsize << 8; + + /* Some may want to do this different and in effect the protocol + support this. But I like the idea that the packet size would be + the same in both directions. This allows the caller to select + both packet sizes without changing the configuration at the + server. */ + if (iYremote_packsize > iYlocal_packsize) + iYremote_packsize = iYlocal_packsize; + + iPrecstart = (iPrecstart + clen) % CRECBUFLEN; + return TRUE; +} + +/* Start the protocol. */ + +boolean +fystart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + *pzlog = NULL; + + /* This should force, or at least enable if available, RTS/CTS + hardware flow control !! */ + + /* The 'y' protocol requires an eight bit clean link */ + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) + return FALSE; + + iYlocal_pktnum = iYremote_pktnum = 0; + + /* Only multiple of 256 sizes are allowed */ + iYlocal_packsize &= ~0xff; + if (iYlocal_packsize < 256 || iYlocal_packsize > (16*1024)) + iYlocal_packsize = IYPACKSIZE; + + /* Exhange SYNC packets */ + if (! fyxchg_syncs (qdaemon)) + { + /* Restore defaults */ + cYtimeout = CYTIMEOUT; + iYlocal_packsize = IYPACKSIZE; + return FALSE; + } + + zYbuf = (char *) xmalloc (CYBUFSIZE + CYFRAMELEN); + return TRUE; +} + +/* Shutdown the protocol. */ + +boolean +fyshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + xfree ((pointer) zYbuf); + zYbuf = NULL; + cYtimeout = CYTIMEOUT; + iYlocal_packsize = IYPACKSIZE; + return TRUE; +} + +/* Send a command string. We send packets containing the string until + the entire string has been sent, including the zero terminator. */ + +/*ARGSUSED*/ +boolean +fysendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + size_t clen; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fysendcmd: Sending command \"%s\"", z); + + clen = strlen (z) + 1; + + while (clen > 0) + { + size_t csize; + + csize = clen; + if (csize > iYremote_packsize) + csize = iYremote_packsize; + + if (! fysend_pkt (qdaemon, z, csize)) + return FALSE; + + z += csize; + clen -= csize; + } + + return TRUE; +} + +/* Get space to be filled with data. We always use zYbuf, which was + allocated from the heap. */ + +char * +zygetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = iYremote_packsize; + return zYbuf + CYFRAMELEN; +} + +/* Send out a data packet. */ + +boolean +fysenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ +#if DEBUG > 0 + if (cdata > iYremote_packsize) + ulog (LOG_FATAL, "fysend_packet: Packet size too large"); +#endif + + TOLITTLE (zYbuf + YFRAME_SEQ_OFF, iYlocal_pktnum); + ++iYlocal_pktnum; + TOLITTLE (zYbuf + YFRAME_LEN_OFF, cdata); + TOLITTLE (zYbuf + YFRAME_CHK_OFF, iychecksum (zdata, cdata)); + + /* We pass FALSE to fsend_data since we don't expect the other side + to be sending us anything just now. */ + return fsend_data (qdaemon->qconn, zYbuf, cdata + CYFRAMELEN, FALSE); +} + +/* Wait for data to come in and process it until we've finished a + command or a file. */ + +boolean +fywait (qdaemon) + struct sdaemon *qdaemon; +{ + boolean fexit = FALSE; + + while (! fexit) + { + if (! fywait_for_packet (qdaemon, &fexit)) + return FALSE; + } + return TRUE; +} + +/* File level routines + We could handle this inside the other public routines, + but this is cleaner and better for future expansions */ + +boolean +fyfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) + struct sdaemon *qdaemon; + struct stransfer *qtrans; + boolean fstart; + boolean fsend; + long cbytes; + boolean *pfhandled; +{ + unsigned short header[3]; + + *pfhandled = FALSE; + + if (! fstart) + { + if (fsend) + { + /* It is critical that the timeout here would be long + enough. We have just sent a full file without any kind + of flow control at the protocol level. The traffic may + be buffered in many places of the link, and the remote + may take a while until cathing up. */ + if (! fywait_for_header (qdaemon, header, cYtimeout * 2)) + return FALSE; + + if (header[YFRAME_CTL] != (unsigned short) YPKT_ACK) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fyfile: Error from remote: 0x%04X", header[1]); + ulog (LOG_ERROR, "Received 'y' protocol error from remote"); + return FALSE; + } + } + else + { + /* This is technically not requireed. But I've put this in + the protocol to allow easier expansions. */ + return fysend_control (qdaemon, YPKT_ACK); + } + } + + return TRUE; +} + +/* Send a control packet, not used during the normal file + transmission. */ + +static boolean +fysend_control (qdaemon, itype) + struct sdaemon *qdaemon; + int itype; +{ + char header[CYFRAMELEN]; + + TOLITTLE (header + YFRAME_SEQ_OFF, iYlocal_pktnum); + iYlocal_pktnum++; + TOLITTLE (header + YFRAME_CTL_OFF, itype); + TOLITTLE (header + YFRAME_CHK_OFF, 0); + + return fsend_data (qdaemon->qconn, header, CYFRAMELEN, FALSE); +} + +/* Private function to send a packet. This one doesn't need the data + to be in the buffer provided by zygetspace. I've found it worth + for avoiding memory copies. Somebody may want to do it otherwise */ + +static boolean +fysend_pkt (qdaemon, zdata, cdata) + struct sdaemon *qdaemon; + const void *zdata; + size_t cdata; +{ + char header[CYFRAMELEN]; + + TOLITTLE (header + YFRAME_SEQ_OFF, iYlocal_pktnum); + iYlocal_pktnum++; + TOLITTLE (header + YFRAME_LEN_OFF, cdata); + TOLITTLE (header + YFRAME_CHK_OFF, iychecksum (zdata, cdata)); + + if (! fsend_data (qdaemon->qconn, header, CYFRAMELEN, FALSE)) + return FALSE; + return fsend_data (qdaemon->qconn, zdata, cdata, FALSE); +} + +/* Wait until enough data arrived from the comm line. This protocol + doesn't need to perform any kind of action while waiting. */ + +static boolean +fyread_data (qdaemon, clen, timeout) + struct sdaemon *qdaemon; + size_t clen; + int timeout; +{ + int cinbuf; + size_t crec; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + + if (cinbuf < clen) + { + if (! freceive_data (qdaemon->qconn, clen - cinbuf, &crec, + timeout, TRUE)) + return FALSE; + cinbuf += crec; + if (cinbuf < clen) + { + if (! freceive_data (qdaemon->qconn, clen - cinbuf, &crec, + timeout, TRUE)) + return FALSE; + } + cinbuf += crec; + if (cinbuf < clen) + { + ulog (LOG_ERROR, "Timed out waiting for data"); + return FALSE; + } + } + + return TRUE; +} + +/* Receive a remote packet header, check for correct sequence number. */ + +static boolean +fywait_for_header (qdaemon, header, timeout) + struct sdaemon *qdaemon; + unsigned short header[3]; + int timeout; +{ + if (! fyread_data (qdaemon, CYFRAMELEN, timeout)) + return FALSE; + + /* Somebody may want to optimize this in a portable way. I'm not + sure it's worth, but the output by gcc for the portable construct + is so bad (even with optimization), that I couldn't resist. */ + + if (iPrecstart <= (CRECBUFLEN - CYFRAMELEN)) + { + header[0] = FROMLITTLE (abPrecbuf + iPrecstart); + header[1] = FROMLITTLE (abPrecbuf + iPrecstart + 2); + header[2] = FROMLITTLE (abPrecbuf + iPrecstart + 4); + } + else + { + register int i, j; + + for (i = j = 0; j < CYFRAMELEN; i++, j += 2) + { + header[i] = + (((abPrecbuf[(iPrecstart + j + 1) % CRECBUFLEN] & 0xff) << 8) + + (abPrecbuf[(iPrecstart + j) % CRECBUFLEN] & 0xff)); + } + } + + iPrecstart = (iPrecstart + CYFRAMELEN) % CRECBUFLEN; + + DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, + "fywait_for_header: Got header: 0x%04X, 0x%04X, 0x%04X", + header[0], header[1], header[2]); + + if (header[YFRAME_SEQ] != iYremote_pktnum++) + { + ulog (LOG_ERROR, "Incorrect 'y' packet sequence"); + fysend_control (qdaemon, YPKT_BAD); + return FALSE; + } + + return TRUE; +} + +/* Receive a remote data packet */ + +static boolean +fywait_for_packet (qdaemon, pfexit) + struct sdaemon *qdaemon; + boolean *pfexit; +{ + unsigned short header[3], ichk; + size_t clen, cfirst; + + if (! fywait_for_header (qdaemon, header, cYtimeout)) + return FALSE; + + clen = header[YFRAME_LEN]; + if (clen == 0 && pfexit != NULL) + { + /* I Suppose the pointers could be NULL ??? */ + return fgot_data (qdaemon, abPrecbuf, 0, abPrecbuf, 0, + -1, -1, (long) -1, TRUE, pfexit); + } + + if (clen & 0x8000) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fywait_for_packet: Error from remote: 0x%04X", + header[YFRAME_CTL]); + ulog (LOG_ERROR, "Remote error packet"); + return FALSE; + } + + /* This is really not neccessary. But if this check is removed, + take in mind that the packet may be up to 32k long. */ + if (clen > iYlocal_packsize) + { + ulog (LOG_ERROR, "Packet too large"); + return FALSE; + } + + if (! fyread_data (qdaemon, clen, cYtimeout)) + return FALSE; + + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst > clen) + cfirst = clen; + + if (cfirst == clen) + ichk = iychecksum (abPrecbuf + iPrecstart, clen); + else + ichk = iychecksum2 (abPrecbuf + iPrecstart, cfirst, + abPrecbuf, clen - cfirst); + if (header[YFRAME_CHK] != ichk) + { + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fywait_for_packet: Bad checksum 0x%x != 0x%x", + header[YFRAME_CHK], ichk); + fysend_control (qdaemon, YPKT_ERR); + ulog (LOG_ERROR, "Checksum error"); + return FALSE; + } + + if (pfexit != NULL + && ! fgot_data (qdaemon, abPrecbuf + iPrecstart, cfirst, + abPrecbuf, clen - cfirst, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = (iPrecstart + clen) % CRECBUFLEN; + + return TRUE; +} + +/* Compute 16 bit checksum */ + +#ifdef __GNUC__ +#ifdef __i386__ +#define I386_ASM +#endif +#endif + +#ifdef I386_ASM +#define ROTATE(i) \ + asm ("rolw $1,%0" : "=g" (i) : "g" (i)) +#else +#define ROTATE(i) i += i + ((i & 0x8000) >> 15) +#endif + +static unsigned short +iychecksum (z, c) + register const char *z; + register size_t c; +{ + register unsigned short ichk; + + ichk = 0xffff; + + while (c-- > 0) + { + ROTATE (ichk); + ichk += BUCHAR (*z++); + } + + return ichk; +} + +static unsigned short +iychecksum2 (zfirst, cfirst, zsecond, csecond) + const char *zfirst; + size_t cfirst; + const char *zsecond; + size_t csecond; +{ + register unsigned short ichk; + register const char *z; + register size_t c; + + z = zfirst; + c = cfirst + csecond; + + ichk = 0xffff; + + while (c-- > 0) + { + ROTATE (ichk); + ichk += BUCHAR (*z++); + + /* If the first buffer has been finished, switch to the second. */ + if (--cfirst == 0) + z = zsecond; + } + + return ichk; +} |
