summaryrefslogtreecommitdiff
path: root/gnu/libexec
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1995-08-30 17:42:29 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1995-08-30 17:42:29 +0000
commit09adf59b71be5536e90072a21ff0a298de13b31e (patch)
tree5472a1168e90c3da5a19b92d4eec77fdec82325a /gnu/libexec
parent11ae5136afc310ef71c58826e0faa94cc2b415f4 (diff)
Notes
Diffstat (limited to 'gnu/libexec')
-rw-r--r--gnu/libexec/uucp/libunix/failed.c26
-rw-r--r--gnu/libexec/uucp/libunix/sync.c42
-rw-r--r--gnu/libexec/uucp/libunix/tcp.c444
-rw-r--r--gnu/libexec/uucp/libunix/tli.c628
-rw-r--r--gnu/libexec/uucp/libunix/uid.c116
-rw-r--r--gnu/libexec/uucp/libuuconf/strip.c50
-rw-r--r--gnu/libexec/uucp/uucico/proty.c660
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;
+}