Subject: bin/696: no rexec
To: None <gnats-admin@NetBSD.ORG>
From: Andrew Wheadon <andrew@wipux2.wifo.uni-mannheim.de>
List: netbsd-bugs
Date: 01/04/1995 08:05:11
>Number:         696
>Category:       bin
>Synopsis:       no rexec
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          support
>Submitter-Id:   net
>Arrival-Date:   Wed Jan  4 08:05:04 1995
>Originator:     Andrew Wheadon
>Organization:
The cost of living hasn't affected it's popularity. (unknown)
current	release=doc host=wipux2.wifo.uni-mannheim.de \ "NetBSD-current mirror"
hostbase=/mit/ftp/pub/NetBSD base=/usr prefix=/usr backup delete use-rel-suffix
>Release:        4.1.1995
>Environment:
	
System: NetBSD wipux2 1.0A NetBSD 1.0A (WIPUX) #0: Mon Jan 2 23:50:04 MET 1995 toor@wipux2.wifo.uni-mannheim.de:/src/src/sys/arch/i386/compile/WIPUX i386


>Description:
	A long time ago (0.8, or 0.9) I mentioned to Charles (I believe)
	that there was no rexec, and he said I could go ahead and try
	getting one working... which I did. 
	Anyway I just found it again while clearing up my src's (makeing
	space for X11R6-contrib) and it still works. I cleaned it a little
	and took the current src/usr.bin/ftp/ruserpass.c instead of my
	old version. I can't get rid of the warnings in lib_rexec, because
	I don't know how to use sockets (I was talking to cgd about that ;-).

	The reason a part is commented out in ruserpass.c is because 
	hostname isn't initialised by prog_rexec.c, so it seg-faults.
	It works with rexecd from NetBSD and HPUX.

	If you can get rid of those last warnings I'd be pleased
	to now how (I tried converting the structure sockaddr_in 
	to sockaddr but it doesn't seem to work ;-).
	
>How-To-Repeat:
	unshar and compile and enjoy, (and then look shocked 
	when you see the code ;-)
	If it doesn't work then send-pr will have swallowed
	some lines, in that case it's on wipux2.wifo.uni-mannheim.de
	in ~ftp/pub/NetBSD/ports/src/rexec.shar
	Cheerio

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	lib_rexec.c
#	prog_rexec.HEADER
#	prog_rexec.c
#	rexec.3
#	ruserpass.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#	from: @(#)Makefile	5.4 (Berkeley) 3/1/92
X#	Makefile,v 1.5 1993/08/07 03:56:47 mycroft Exp
X
XPROG=	rexec
XSRCS=	prog_rexec.c lib_rexec.c ruserpass.c
XFTP=/usr/src/usr.bin/ftp
XCFLAGS+= -DREXEC -I${FTP} -g
XNOMAN=true
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - lib_rexec.c
sed 's/^X//' >lib_rexec.c << 'END-of-lib_rexec.c'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)rexec.c	5.8 (Berkeley) 6/1/90";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X
X#include <netinet/in.h>
X
X#include <stdio.h>
X#include <netdb.h>
X#include <errno.h>
X
Xextern	errno;
Xchar	*index();
Xint	rexecoptions;
Xchar	*getpass(), *getlogin();
X
Xrexec(ahost, rport, name, pass, cmd, fd2p)
X	char **ahost;
X	int rport;
X	char *name, *pass, *cmd;
X	int *fd2p;
X{
X	struct sockaddr_in sin, sin2, from;
X	struct hostent *hp;
X	u_short port;
X	int s, timo = 1, s3;
X	char c;
X
X	hp = gethostbyname(*ahost);
X	if (hp == 0) {
X		herror(*ahost);
X		return (-1);
X	}
X	*ahost = hp->h_name;
X/*	host, user, password, account */
X	ruserpass(hp->h_name, &name, &pass,0);
Xretry:
X	s = socket(AF_INET, SOCK_STREAM, 0);
X	if (s < 0) {
X		perror("rexec: socket");
X		return (-1);
X	}
X	sin.sin_family = hp->h_addrtype;
X	sin.sin_port = rport;
X	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
X	if (connect(s, &sin, sizeof(sin)) < 0) {
X		if (errno == ECONNREFUSED && timo <= 16) {
X			(void) close(s);
X			sleep(timo);
X			timo *= 2;
X			goto retry;
X		}
X		perror(hp->h_name);
X		return (-1);
X	}
X	if (fd2p == 0) {
X		(void) write(s, "", 1);
X		port = 0;
X	} else {
X		char num[8];
X		int s2, sin2len;
X		
X		s2 = socket(AF_INET, SOCK_STREAM, 0);
X		if (s2 < 0) {
X			(void) close(s);
X			return (-1);
X		}
X		listen(s2, 1);
X		sin2len = sizeof (sin2);
X		if (getsockname(s2, (char *)&sin2, &sin2len) < 0 ||
X		  sin2len != sizeof (sin2)) {
X			perror("getsockname");
X			(void) close(s2);
X			goto bad;
X		}
X		port = ntohs((u_short)sin2.sin_port);
X		(void) sprintf(num, "%u", port);
X		(void) write(s, num, strlen(num)+1);
X		{ int len = sizeof (from);
X#ifdef __NetBSD__
X		  s3 = accept(s2, &from, &len);
X#else
X		  s3 = accept(s2, &from, &len, 0);
X#endif
X		  close(s2);
X		  if (s3 < 0) {
X			perror("accept");
X			port = 0;
X			goto bad;
X		  }
X		}
X		*fd2p = s3;
X	}
X	(void) write(s, name, strlen(name) + 1);
X	/* should public key encypt the password here */
X	(void) write(s, pass, strlen(pass) + 1);
X	(void) write(s, cmd, strlen(cmd) + 1);
X	if (read(s, &c, 1) != 1) {
X		perror(*ahost);
X		goto bad;
X	}
X	if (c != 0) {
X		while (read(s, &c, 1) == 1) {
X			(void) write(2, &c, 1);
X			if (c == '\n')
X				break;
X		}
X		goto bad;
X	}
X	return (s);
Xbad:
X	if (port)
X		(void) close(*fd2p);
X	(void) close(s);
X	return (-1);
X}
END-of-lib_rexec.c
echo x - prog_rexec.HEADER
sed 's/^X//' >prog_rexec.HEADER << 'END-of-prog_rexec.HEADER'
XMessage-ID: <921105-21:51:49.474@localhost.informatik.tu-muenchen.de>
XFrom: fjp@minerva.inesc.pt (Fernando Pereira)
XNewsgroups: alt.sources
XSubject: Remote execution without using the .rhosts file.
XSummary: Running commands in remote machines without using the .rhosts file.
XKeywords: UNIX, C, remote execution.
XDate: 25 Feb 92 18:42:59 GMT
XFollowup-To: alt.sources.d
XOrganization: INESC, Lisboa, Portugal
XNntp-Posting-Host: minerva.inesc.pt
X
XArchive-Name: rexec.c/release2
XSubmitted-By: fjp@minerva.inesc.pt
X
XThe old version of rexec.c had a bug: It didn't showed stderr (or stdout).
X
XBE CAREFULL: Don't use the -p option to specify passwords in the command
Xline because the UNIX utility "ps" can show command line arguments of
Xany process. In this version I try to hide the password in the argv but
Xthere is a very small time slice before the argv is replaced when ps can
Xstill read the password...
X
XI did only notice this problem after posting the first version
X( as you probably saw in alt.sources.d ).
X
XCompile with "cc rexec.c -o rexec".
X
X*********************************CUT HERE*******************************
END-of-prog_rexec.HEADER
echo x - prog_rexec.c
sed 's/^X//' >prog_rexec.c << 'END-of-prog_rexec.c'
X#include <stdio.h>
X#include <pwd.h>
X#include <netdb.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/time.h>
X
X
X
X
Xint fd1, fd2 = 1;
Xchar host[80], *hostptr = host;
Xchar password[80];
Xchar user[80];
Xchar cmd[4096] = "";
Xfd_set re, wr, aux;
Xstruct timeval tm = { 10L, 0L };
X
Xvoid send_sigs();
X
X
X
Xmain( argc, argv )
Xint argc;
Xchar **argv;
X{
X    int i, cnt = 1;
X    char line[257];
X
X    if( argc < 2 ) {
X	fprintf( stderr, "usage: rexec host [-u/l user] [-p pass] cmd\n" );
X	exit( 1 );
X    }
X
X    strcpy( host, argv[cnt++] );
X
X    if( cnt < argc && ( !strcmp(argv[cnt],"-l") || !strcmp(argv[cnt],"-u") ) ) {
X        if( cnt >= argc ) exit( 1 );
X	strcpy( user, argv[++cnt] );
X        ++cnt;
X    }
X    else strcpy( user, getpwuid( getuid() )->pw_name );
X
X    if( cnt < argc && !strcmp( argv[cnt], "-p" ) ) {
X        if( cnt >= argc ) exit( 1 );
X	strcpy( password, argv[++cnt] );
X	for( i = strlen(argv[cnt])-1; i>=0; --i ) argv[cnt][i] = '*';
X        ++cnt;
X    }
X    else strcpy( password, (const char *)getpass( "Password: " ) );
X
X    if( cnt >= argc ) strcpy( cmd, "sh" );
X    else while( 1 ) {
X	strcat( cmd, argv[cnt++] );
X        if( cnt >= argc ) break;
X	strcat( cmd, " " );
X    }
X
X    fd1 = rexec( &hostptr, getservbyname("exec","tcp")->s_port,
X		 user, password, cmd, &fd2 );
X    if( fd1 < 0 ) exit( 1 );
X
X    for( i = 0; i < SIGUSR2; ++i )
X	 if( i != SIGKILL && i != SIGSTOP ) signal( i, send_sigs );
X
X    FD_ZERO( &aux );
X    FD_ZERO( &re );
X    FD_ZERO( &wr );
X    FD_SET( 0, &re );
X    FD_SET( fd1, &re );
X    FD_SET( fd2, &re );
X
X    while( 1 ) {
X	select( fd1>fd2 ? fd1+1 : fd2+1, &re, &wr, &aux, &tm );
X        if( FD_ISSET( 0, &re ) ) {
X   	    cnt = read( 0, line, 256 );
X	    if( cnt > 0 ) write( fd1, line, cnt );
X        }
X        if( FD_ISSET( fd1, &re ) ) {
X   	    cnt = read( fd1, line, 256 );
X	    if( cnt > 0 ) write( 1, line, cnt );
X	    else exit( 0 );
X        }
X        if( FD_ISSET( fd2, &re ) ) {
X   	    cnt = read( fd2, line, 256 );
X	    if( cnt > 0 ) write( 2, line, cnt );
X        }
X	FD_SET( 0, &re );
X	FD_SET( fd1, &re );
X	FD_SET( fd2, &re );
X    }
X}
X
X
X
Xvoid send_sigs( s )
Xint s;
X{
X    char sig = s & 0xff;
X    write( fd2, &sig, 1 );
X    signal( s, send_sigs );
X}
END-of-prog_rexec.c
echo x - rexec.3
sed 's/^X//' >rexec.3 << 'END-of-rexec.3'
X.\" Copyright (c) 1983 The Regents of the University of California.
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms are permitted provided
X.\" that: (1) source distributions retain this entire copyright notice and
X.\" comment, and (2) distributions including binaries display the following
X.\" acknowledgement:  ``This product includes software developed by the
X.\" University of California, Berkeley and its contributors'' in the
X.\" documentation or other materials provided with the distribution and in
X.\" all advertising materials mentioning features or use of this software.
X.\" Neither the name of the University nor the names of its contributors may
X.\" be used to endorse or promote products derived from this software without
X.\" specific prior written permission.
X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X.\"
X.\"	@(#)rexec.3	6.8 (Berkeley) 6/23/90
X.\"
X.TH REXEC 3 "June 23, 1990"
X.UC 5
X.SH NAME
Xrexec \- return stream to a remote command
X.SH SYNOPSIS
X.nf
X.PP
X.B "rem = rexec(ahost, inport, user, passwd, cmd, fd2p);"
X.B char **ahost;
X.B int inport;
X.B "char *user, *passwd, *cmd;"
X.B int *fd2p;
X.fi
X.SH DESCRIPTION
X.ft B
XThis interface is obsoleted by krcmd(3).
X.br
XIt is available from the compatibility library, libcompat.
X.ft R
X.PP
X.I Rexec
Xlooks up the host
X.I *ahost
Xusing
X.IR gethostbyname (3),
Xreturning \-1 if the host does not exist.
XOtherwise
X.I *ahost
Xis set to the standard name of the host.
XIf a username and password are both specified, then these
Xare used to authenticate to the foreign host; otherwise
Xthe environment and then the user's
X.I .netrc
Xfile in his
Xhome directory are searched for appropriate information.
XIf all this fails, the user is prompted for the information.
X.PP
XThe port
X.I inport
Xspecifies which well-known DARPA Internet port to use for
Xthe connection; the call ``getservbyname("exec", "tcp")'' (see 
X.IR getservent (3))
Xwill return a pointer to a structure, which contains the
Xnecessary port.
XThe protocol for connection is described in detail in
X.IR rexecd (8).
X.PP
XIf the connection succeeds,
Xa socket in the Internet domain of type SOCK_STREAM is returned to
Xthe caller, and given to the remote command as
X.B stdin
Xand
X.BR stdout .
XIf
X.I fd2p
Xis non-zero, then an auxiliary channel to a control
Xprocess will be setup, and a descriptor for it will be placed
Xin
X.IR *fd2p .
XThe control process will return diagnostic
Xoutput from the command (unit 2) on this channel, and will also
Xaccept bytes on this channel as being UNIX signal numbers, to be
Xforwarded to the process group of the command.  The diagnostic
Xinformation returned does not include remote authorization failure,
Xas the secondary connection is set up after authorization has been
Xverified.
XIf
X.I fd2p
Xis 0, then the 
X.B stderr
X(unit 2 of the remote
Xcommand) will be made the same as the 
X.B stdout
Xand no
Xprovision is made for sending arbitrary signals to the remote process,
Xalthough you may be able to get its attention by using out-of-band data.
X.SH SEE ALSO
Xrcmd(3), rexecd(8)
END-of-rexec.3
echo x - ruserpass.c
sed 's/^X//' >ruserpass.c << 'END-of-ruserpass.c'
X/*
X * Copyright (c) 1985, 1993, 1994
X *	The Regents of the University of California.  All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#ifndef lint
X/*static char sccsid[] = "from: @(#)ruserpass.c	8.3 (Berkeley) 4/2/94";*/
Xstatic char *rcsid = "$Id: ruserpass.c,v 1.5 1994/09/17 00:51:10 mycroft Exp $";
X#endif /* not lint */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include <ctype.h>
X#include <err.h>
X#include <errno.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X
X#include "ftp_var.h"
X
Xstatic	int token __P((void));
Xstatic	FILE *cfile;
X
X#define	DEFAULT	1
X#define	LOGIN	2
X#define	PASSWD	3
X#define	ACCOUNT 4
X#define MACDEF  5
X#define	ID	10
X#define	MACH	11
X
Xstatic char tokval[100];
X
Xstatic struct toktab {
X	char *tokstr;
X	int tval;
X} toktab[]= {
X	{ "default",	DEFAULT },
X	{ "login",	LOGIN },
X	{ "password",	PASSWD },
X	{ "passwd",	PASSWD },
X	{ "account",	ACCOUNT },
X	{ "machine",	MACH },
X	{ "macdef",	MACDEF },
X	{ NULL,		0 }
X};
X
Xint
Xruserpass(host, aname, apass, aacct)
X	char *host, **aname, **apass, **aacct;
X{
X	char *hdir, buf[BUFSIZ], *tmp;
X	char myname[MAXHOSTNAMELEN], *mydomain;
X	int t, i, c, usedefault = 0;
X	struct stat stb;
X
X	hdir = getenv("HOME");
X	if (hdir == NULL)
X		hdir = ".";
X	(void) sprintf(buf, "%s/.netrc", hdir);
X	cfile = fopen(buf, "r");
X	if (cfile == NULL) {
X		if (errno != ENOENT)
X			warn("%s", buf);
X		return (0);
X	}
X	if (gethostname(myname, sizeof(myname)) < 0)
X		myname[0] = '\0';
X	if ((mydomain = strchr(myname, '.')) == NULL)
X		mydomain = "";
Xnext:
X	while ((t = token())) switch(t) {
X
X	case DEFAULT:
X		usedefault = 1;
X		/* FALL THROUGH */
X
X	case MACH:
X		if (!usedefault) {
X			if (token() != ID)
X				continue;
X			/*
X			 * Allow match either for user's input host name
X			 * or official hostname.  Also allow match of 
X			 * incompletely-specified host in local domain.
X			 */
X			if (strcasecmp(host, tokval) == 0)
X				goto match;
X#ifndef REXEC
X	/* ftp.c sets hostname but it's too much trouble for me 
X	   so I'll just leave it out. */
X			if (strcasecmp(hostname, tokval) == 0)
X				goto match;
X			if ((tmp = strchr(hostname, '.')) != NULL &&
X			    strcasecmp(tmp, mydomain) == 0 &&
X			    strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
X			    tokval[tmp - hostname] == '\0')
X				goto match;
X#endif
X			if ((tmp = strchr(host, '.')) != NULL &&
X			    strcasecmp(tmp, mydomain) == 0 &&
X			    strncasecmp(host, tokval, tmp - host) == 0 &&
X			    tokval[tmp - host] == '\0')
X				goto match;
X			continue;
X		}
X	match:
X		while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
X
X		case LOGIN:
X			if (token())
X				if (*aname == 0) { 
X					*aname = malloc((unsigned) strlen(tokval) + 1);
X					(void) strcpy(*aname, tokval);
X				} else {
X					if (strcmp(*aname, tokval))
X						goto next;
X				}
X			break;
X		case PASSWD:
X			if ((*aname == 0 || strcmp(*aname, "anonymous")) &&
X			    fstat(fileno(cfile), &stb) >= 0 &&
X			    (stb.st_mode & 077) != 0) {
X	warnx("Error: .netrc file is readable by others.");
X	warnx("Remove password or make file unreadable by others.");
X				goto bad;
X			}
X			if (token() && *apass == 0) {
X				*apass = malloc((unsigned) strlen(tokval) + 1);
X				(void) strcpy(*apass, tokval);
X			}
X			break;
X		case ACCOUNT:
X			if (fstat(fileno(cfile), &stb) >= 0
X			    && (stb.st_mode & 077) != 0) {
X	warnx("Error: .netrc file is readable by others.");
X	warnx("Remove account or make file unreadable by others.");
X				goto bad;
X			}
X			if (token() && *aacct == 0) {
X				*aacct = malloc((unsigned) strlen(tokval) + 1);
X				(void) strcpy(*aacct, tokval);
X			}
X			break;
X		case MACDEF:
X			if (proxy) {
X				(void) fclose(cfile);
X				return (0);
X			}
X			while ((c=getc(cfile)) != EOF && c == ' ' || c == '\t');
X			if (c == EOF || c == '\n') {
X				printf("Missing macdef name argument.\n");
X				goto bad;
X			}
X			if (macnum == 16) {
X				printf("Limit of 16 macros have already been defined\n");
X				goto bad;
X			}
X			tmp = macros[macnum].mac_name;
X			*tmp++ = c;
X			for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
X			    !isspace(c); ++i) {
X				*tmp++ = c;
X			}
X			if (c == EOF) {
X				printf("Macro definition missing null line terminator.\n");
X				goto bad;
X			}
X			*tmp = '\0';
X			if (c != '\n') {
X				while ((c=getc(cfile)) != EOF && c != '\n');
X			}
X			if (c == EOF) {
X				printf("Macro definition missing null line terminator.\n");
X				goto bad;
X			}
X			if (macnum == 0) {
X				macros[macnum].mac_start = macbuf;
X			}
X			else {
X				macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
X			}
X			tmp = macros[macnum].mac_start;
X			while (tmp != macbuf + 4096) {
X				if ((c=getc(cfile)) == EOF) {
X				printf("Macro definition missing null line terminator.\n");
X					goto bad;
X				}
X				*tmp = c;
X				if (*tmp == '\n') {
X					if (*(tmp-1) == '\0') {
X					   macros[macnum++].mac_end = tmp - 1;
X					   break;
X					}
X					*tmp = '\0';
X				}
X				tmp++;
X			}
X			if (tmp == macbuf + 4096) {
X				printf("4K macro buffer exceeded\n");
X				goto bad;
X			}
X			break;
X		default:
X			warnx("Unknown .netrc keyword %s", tokval);
X			break;
X		}
X		goto done;
X	}
Xdone:
X	(void) fclose(cfile);
X	return (0);
Xbad:
X	(void) fclose(cfile);
X	return (-1);
X}
X
Xstatic int
Xtoken()
X{
X	char *cp;
X	int c;
X	struct toktab *t;
X
X	if (feof(cfile) || ferror(cfile))
X		return (0);
X	while ((c = getc(cfile)) != EOF &&
X	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
X		continue;
X	if (c == EOF)
X		return (0);
X	cp = tokval;
X	if (c == '"') {
X		while ((c = getc(cfile)) != EOF && c != '"') {
X			if (c == '\\')
X				c = getc(cfile);
X			*cp++ = c;
X		}
X	} else {
X		*cp++ = c;
X		while ((c = getc(cfile)) != EOF
X		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
X			if (c == '\\')
X				c = getc(cfile);
X			*cp++ = c;
X		}
X	}
X	*cp = 0;
X	if (tokval[0] == 0)
X		return (0);
X	for (t = toktab; t->tokstr; t++)
X		if (!strcmp(t->tokstr, tokval))
X			return (t->tval);
X	return (ID);
X}
END-of-ruserpass.c
exit

>Fix:
	
>Audit-Trail:
>Unformatted: