[comp.protocols.nfs] pcnfsd for 386/ix - It's here!

paul@sdgsun.uucp (Paul Emerson) (01/05/91)

#!/bin/sh
# This is a shell archive (shar 3.32)
# made 01/05/1991 08:36 UTC by paul@ratso
# Source directory /usr/paul/src/pcnfs/post
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   2111 -rw-r--r-- ReadMe
#  33340 -r--r--r-- pcnfsd.c
#
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= ReadMe ==============
echo "x - extracting ReadMe (Text)"
sed 's/^X//' << 'SHAR_EOF' > ReadMe &&
X
XSat Jan  5 03:14:36 EST 1991
X
XOk, here is my hacked version of Sun's rpc.pcnfsd.c, I dropped the rpc
Xand have just named it pcnfsd.c, for those of us lacking 255 bytes file
Xnames.  
X
X1. I changed the password validation to work correctly, atleast it seems 
X   to work.  I may be wrong but I don't think comparing the length of 
X   the encoded password (13) has anything to do with the length of 
X   the unencoded password.  So I hack this comparision out. 
X
X2. I added printing using SYSV lp.  Since lp doesn't off the -r option
X   of BSD's lpr.  I use the -c (copy) option to copy the spooled nfs file
X   when lp is invoked and then wait for the lp child to return and unlink 
X   the orginal nfs spooled file.  This seems to work.  Sometimes 0 lenght
X   files are left in the pcnfs spool directory.  But this also happens on
X   the sun with lpr.  Just run a nightly cron job to clean these guys out 
X   if they bother you.
X
X3. I haven't done much with the lp command.  The default print is what 
X   you get.  You can add your own flags if you want.  When I have time 
X   I will add more lp support. 
X
X4. I have only tested this code under 386/ix 2.0.2 with TCP/IP 1.2 and
X   TCP/IP 1.1.2 and NFS 2.0.  I've used both gcc 1.37.1 and cc.  Use the
X   -traditional flag with gcc.
X
X           cc -O -o pcnfsd pcnfsd.c -lsec -lrpc -linet
X                                        or
X           gcc -O -traditional -o pcnfsd pcnfsd.c -lsec -lrpc -linet
X
X5. To install just overlay Interactive's pcnfsd in /etc 
X
X6. I have no idea if this will work on other SYSV ports.  Mail me you
X   get it running on something besides 386/ix, and  your changes so
X   I can keep things uptodate. 
X
XPaul Emerson
X
X  +----------------------------------------------+------------------+
X  |Paul Emerson                                  | XY Megatron Corp.|
X  |UUCP: [ucf-cs|uunet]!tarpit!sdgsun!ratso!paul | Orlando, FL      |
X  |INTERNET: sdgsun!paul@bikini.cis.ufl.edu      |                  |
X  |CIS: 72355,171                                | (407) 295-8837   |
X  +----------------------------------------------+------------------+
X
SHAR_EOF
$TOUCH -am 0105033291 ReadMe &&
chmod 0644 ReadMe ||
echo "restore of ReadMe failed"
set `wc -c ReadMe`;Wc_c=$1
if test "$Wc_c" != "2111"; then
	echo original size 2111, current size $Wc_c
fi
# ============= pcnfsd.c ==============
echo "x - extracting pcnfsd.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > pcnfsd.c &&
X/*
X**---------------------------------------------------------------------
X** Copyright (c) 1986, 1987, 1988, 1989, 1990 by Sun Microsystems, Inc.
X**---------------------------------------------------------------------
X*/
Xchar *sccsid="@(#)pcnfsd.c	1.5 Version 1.5";
X/*
X**---------------------------------------------------------------------
X**  Changes
X**---------------------------------------------------------------------
X**
X**  Paul Emerson  - December 1990  uunet!tarpit!sdgsun!paul
X**
X**  Made pcnfsd REALLY work for Interactive 386/ix.
X**  1. Handles shadow password file correctly
X**  2. Handles printing under SysV 
X**
X**  Interactive 2.0.2 Compile with:
X**
X**  cc -O -o pcnfsd pcnfsd.c -lsec -lrpc -linet
X**
X**---------------------------------------------------------------------
X*/
X
X/*
X**---------------------------------------------------------------------
X**             C U S T O M I Z A T I O N   S E C T I O N              *
X**                                                                    *
X** You may change the following #defines to build different versions  *
X** of rpc.pcnfsd. Note that this version _must_ be run by the         *
X** super-user (either from inetd or at system start-up). Future       *
X** clients may elect to verify that the service is provided on a      *
X** reserved port for added security.                                  *
X**                                                                    *
X**---------------------------------------------------------------------
X*/
X
X/*
X**---------------------------------------------------------------------
X** Uncomment the following #define to enable the use of a 
X** shadow password file
X**---------------------------------------------------------------------
X**/
X
X#define SHADOW_SUPPORT
X
X/*
X**------------------------------------------------------------------------
X** Uncomment the following #define to conform to Interactive System's 2.0
X**------------------------------------------------------------------------
X*/
X
X#define ISC_2_0 
X
X/*
X**---------------------------------------------------------------------
X** Uncomment the following #define to use a cache of recently-used
X** user names. This has certain uses in university and other settings
X** where (1) the pasword file is very large, and (2) a group of users
X** frequently logs in together using the same account (for example,
X** a class userid).
X**---------------------------------------------------------------------
X*/
X
X/* #define USER_CACHE */
X
X/*
X**---------------------------------------------------------------------
X** Uncomment the following #define to build a System V version
X**---------------------------------------------------------------------
X*/
X
X#define SYSV 
X
X/*
X**---------------------------------------------------------------------
X** Uncomment the following #define to build a typical "local feature":
X** in this case recognizing the special printer names "rotated"
X** and "2column" and using the Adobe "enscript" command to
X** format the output appropriately.
X**---------------------------------------------------------------------
X*/
X
X/* #define HACK_FOR_ROTATED_TRANSCRIPT */
X
X/*
X**---------------------------------------------------------------------
X** The following definitions may be overridden if desired.
X**---------------------------------------------------------------------
X*/
X
X#ifndef SPOOLDIR
X#define SPOOLDIR	"/usr/spool/pcnfs"
X#endif	
X
X#ifndef PRINT_COMMAND
X/* if you have lp for SYSV uncomment this line */
X#define PRINT_COMMAND	"lp"
X/* if you have BSD lpr uncomments this line */
X/*#define PRINT_COMMAND	"lpr"*/
X#endif
X
X#include <stdio.h>
X
X#ifndef ISC_2_0 
X/* 386/ix includes sys/types in rpc/rpc.h so don't include it here */
X#include <sys/types.h>
X#endif
X
X#include <rpc/rpc.h>
X#include <pwd.h>
X#include <sys/file.h>
X#include <signal.h>
X#include <sys/stat.h>
X#include <sys/ioctl.h>
X#include <sys/socket.h>
X#include <netdb.h>
X#include <errno.h>
X
X#ifndef SYSV
X#include <sys/wait.h>
X#endif
X
X#ifdef ISC_2_0
X#include <sys/fcntl.h>
X#include <shadow.h>
X#endif
X
X#ifdef USER_CACHE
X#include <string.h>
X#endif
X
X#ifdef SYSV
X#define SIGCHLD SIGCLD
X#endif
X
Xextern char *crypt();
Xextern int errno;
Xint             buggit = 0;
X
X/*
X**---------------------------------------------------------------------
X**                              RPC Parameters 
X**---------------------------------------------------------------------
X*/
X#define	PCNFSDPROG	(long)150001
X#define	PCNFSDVERS	(long)1
X#define	PCNFSD_AUTH	(long)1
X#define	PCNFSD_PR_INIT	(long)2
X#define	PCNFSD_PR_START	(long)3
X
X/*
X**---------------------------------------------------------------------
X** Other #define's 
X**---------------------------------------------------------------------
X*/
X#ifndef MAXPATHLEN
X#define MAXPATHLEN 1024
X#endif
X#define	zchar		0x5b
X
X#define assert(ex) {if (!(ex)) \
X    {(void)fprintf(stderr,"pcnfsd: Assertion failed: line %d of %s: \"%s\"\n", \
X    __LINE__, __FILE__, "ex"); \
X    sleep (30); exit(1);}}
X
X
X/*
X**---------------------------------------------------------------------
X**                           XDR structures, etc.
X**---------------------------------------------------------------------
X*/
X
Xenum arstat 
X     {
X     AUTH_RES_OK, 
X     AUTH_RES_FAKE, 
X     AUTH_RES_FAIL
X     };
X
Xenum pirstat 
X     {
X     PI_RES_OK, 
X     PI_RES_NO_SUCH_PRINTER, 
X     PI_RES_FAIL
X     };
X
Xenum psrstat 
X     {
X     PS_RES_OK, 
X     PS_RES_ALREADY, 
X     PS_RES_NULL, 
X     PS_RES_NO_FILE,
X     PS_RES_FAIL
X     };
X
Xstruct auth_args 
X       {
X       char  *aa_ident;
X       char  *aa_password;
X       };
X
Xstruct auth_results 
X       {
X       enum arstat  ar_stat;
X       long         ar_uid;
X       long         ar_gid;
X       };
X
Xstruct pr_init_args 
X       {
X       char   *pia_client;
X       char   *pia_printername;
X       };
X
Xstruct pr_init_results 
X       {
X       enum pirstat    pir_stat;
X       char           *pir_spooldir;
X       };
X
Xstruct pr_start_args 
X       {
X       char  *psa_client;
X       char  *psa_printername;
X       char  *psa_username;
X       char  *psa_filename;	/* within the spooldir */
X       char  *psa_options;
X       };
X
Xstruct pr_start_results 
X       {
X       enum psrstat    psr_stat;
X       };
X
X#ifdef USER_CACHE
X#define CACHE_SIZE 16		/* keep it small, as linear searches are
X				 * done */
Xstruct cache 
X       {
X       int   uid;
X       int   gid;
X       char  passwd[32];
X       char  username[10];	/* keep this even for machines
X				 * with alignment problems */
X       }User_cache[CACHE_SIZE];
X
X#endif
X
X/*
X**---------------------------------------------------------------------
X**                               Misc.
X**---------------------------------------------------------------------
X*/
X
Xchar           *authproc();
Xchar           *pr_start();
Xchar           *pr_init();
Xstruct stat     statbuf;
X
Xchar            pathname[MAXPATHLEN];
Xchar            new_pathname[MAXPATHLEN];
Xchar            spoolname[MAXPATHLEN];
X
X
X#ifdef SYSV
Xstruct passwd  *getpwnam();
X#endif
X
X
X/*
X**---------------------------------------------------------------------
X**                          Support procedures 
X**---------------------------------------------------------------------
X*/
Xscramble(s1, s2)
Xchar           *s1;
Xchar           *s2;
X{
X	while (*s1) 
X	      {
X	      *s2++ = (*s1 ^ zchar) & 0x7f;
X	      s1++;
X	      }
X	*s2 = 0;
X}
X
Xvoid free_child()
X{
Xint             pid;
X
X#ifndef SYSV
Xunion wait status;
X#else
Xunsigned int status;
X#endif
X
X	while ((pid = wait(&status)) != -1) 
X	      {
X#ifndef SYSV
X	      if (buggit || status.w_retcode)
X		 (void) fprintf(stderr,
X                        "FREE_CHILD: process #%d exited with status 0X%x\n",
X	                 pid, status.w_retcode);
X#endif
X	      }
X	return;
X}
X
Xour_rresvport()
X{
Xstruct sockaddr_in sin;
Xint s, 
X    alport = IPPORT_RESERVED - 1;
X
X	sin.sin_family = AF_INET;
X	sin.sin_addr.s_addr = 0;
X	s = socket(AF_INET, SOCK_DGRAM, 0);
X	if (s < 0)
X	   return (-1);
X	for (;;) 
X	    {
X	    sin.sin_port = htons((u_short) alport);
X	    if (bind(s, (caddr_t) & sin, sizeof(sin)) >= 0)
X		return (s);
X
X#ifndef ISC_2_0
X/*
X**---------------------------------------------------------------------
X**   Interactive failed to define EADDRINUSE and EADDRNOTAVAIL in any 
X**   include file.  Although they reference them in the bind(3) man page.
X**   So what the hell skip, this test, because who knows what error value
X**   they have defined for these errors,  if any.  
X**---------------------------------------------------------------------
X*/
X	    if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) 
X               {
X	       perror("socket");
X	       return (-1);
X	       }
X#endif
X	    (alport)--;
X	    if (alport == IPPORT_RESERVED / 2) 
X	       {
X	       (void)fprintf(stderr, "socket: All ports in use\n");
X	       return (-1);
X	       }
X	    }
X}
X
X
X/*
X**---------------------------------------------------------------------
X**                          XDR procedures 
X**---------------------------------------------------------------------
X*/
Xbool_t
Xxdr_auth_args(xdrs, aap)
XXDR            *xdrs;
Xstruct auth_args *aap;
X{
X	return (xdr_string(xdrs, &aap->aa_ident, 32) &&
X		xdr_string(xdrs, &aap->aa_password, 64));
X}
X
Xbool_t
Xxdr_auth_results(xdrs, arp)
XXDR            *xdrs;
Xstruct auth_results *arp;
X{
X	return (xdr_enum(xdrs, (enum_t *)&arp->ar_stat) &&
X		xdr_long(xdrs, &arp->ar_uid) &&
X		xdr_long(xdrs, &arp->ar_gid));
X}
X
Xbool_t
Xxdr_pr_init_args(xdrs, aap)
XXDR            *xdrs;
Xstruct pr_init_args *aap;
X{
X	return (xdr_string(xdrs, &aap->pia_client, 64) &&
X		xdr_string(xdrs, &aap->pia_printername, 64));
X}
X
Xbool_t
Xxdr_pr_init_results(xdrs, arp)
XXDR            *xdrs;
Xstruct pr_init_results *arp;
X{
X	return (xdr_enum(xdrs, (enum_t *)&arp->pir_stat) &&
X		xdr_string(xdrs, &arp->pir_spooldir, 255));
X}
X
Xbool_t
Xxdr_pr_start_args(xdrs, aap)
XXDR            *xdrs;
Xstruct pr_start_args *aap;
X{
X	return (xdr_string(xdrs, &aap->psa_client, 64) &&
X		xdr_string(xdrs, &aap->psa_printername, 64) &&
X		xdr_string(xdrs, &aap->psa_username, 64) &&
X		xdr_string(xdrs, &aap->psa_filename, 64) &&
X		xdr_string(xdrs, &aap->psa_options, 64));
X}
X
Xbool_t
Xxdr_pr_start_results(xdrs, arp)
XXDR            *xdrs;
Xstruct pr_start_results *arp;
X{
X	return (xdr_enum(xdrs, (enum_t *)&arp->psr_stat));
X}
X
X/*
X**---------------------------------------------------------------------
X**                                Main 
X**---------------------------------------------------------------------
X*/
X
Xmain(argc, argv)
Xint             argc;
Xchar           *argv[];
X{
Xint f1, f2, f3;
Xint             FromInetd;
Xint             socknum;
XSVCXPRT        *TransportHandle;
Xvoid            Dispatch();
X
X
X	(void)strcpy(spoolname, SPOOLDIR);
X
X	setbuf(stderr, (char *)NULL);
X
X	if (geteuid() != 0) 
X	   {
X	   (void)fprintf(stderr, "%s must be run by 'root'\n",argv[0]);
X	   exit(1);
X	   }
X	/*
X        **-----------------------------------------------------------------
X	** If we're called from inetd: - an open RPC socket is passed as
X	** fd 0. and note that we are already registered with the
X	** portmapper. Otherwise: - we must parse any command-line
X	** arguments which may be present. - we must create an RPC socket
X	** (svcudp_create will do this). - we are not yet registered with
X	** the portmapper, and must do so.
X        **-----------------------------------------------------------------
X	*/
X	FromInetd = issock(0);
X
X
X	if (!FromInetd) 
X	   {
X	   while (++argv, --argc > 0) 
X                 {
X		 if (strcmp(*argv, "-d") == 0) 
X                    {
X	   	    ++buggit;
X		    continue;
X		    }
X		 if (strcmp(*argv, "-s") == 0) 
X	            {
X		    if (!(++argv, --argc > 0)) 
X	               {
X		       (void)fprintf(stderr,
X		       "pc-nfsd error: -s option must be followed by a spooling directory path\n");
X			exit(1);
X			}
X		     (void)strcpy(spoolname, *argv);
X		     continue;
X		     }
X		 if (strncmp(*argv, "-s", 2) == 0) 
X	            {
X		    (void)strcpy(spoolname, &(*argv)[2]);
X		    continue;
X		    }
X		}
X	}
X	if (!FromInetd && !buggit) 
X	   {
X	   switch (fork()) 
X                  {
X		  case 0:
X		       break;
X		  case -1:
X			perror("pc-nfsd: fork failed");
X			exit(1);
X		  default:
X			exit(0);
X		   }
X	    }
X	if (!buggit) 
X           {
X	   /*
X           **--------------------------------------------------------------
X	   ** Can't mess with STDIN if invoked from inetd, 'cause our
X	   ** incoming RPC request datagram is passed in on STDIN.
X           **--------------------------------------------------------------
X	   */
X	  if (!FromInetd) 
X             {
X	     if ((f1 = open("/dev/null", O_RDONLY)) == -1) 
X	        {
X		(void)fprintf(stderr, "pc-nfsd: couldn't open /dev/null\n");
X		exit(1);
X		}
X	     (void) dup2(f1, 0);
X	     (void) close(f1);
X	     }
X	  if ((f2 = open("/dev/console", O_WRONLY)) == -1) 
X             {
X	     (void)fprintf(stderr, "pc-nfsd: couldn't open /dev/console\n");
X	     exit(1);
X	     }
X	   (void) dup2(f2, 1);
X	   (void) close(f2);
X
X	  if ((f3 = open("/dev/console", O_WRONLY)) == -1) 
X             {
X	     (void)fprintf(stderr, "pc-nfsd: couldn't open /dev/console\n");
X	     exit(1);
X	     }
X	  (void) dup2(f3, 2);
X	  (void) close(f3);
X
X#ifdef TIOCNOTTY
X		/*
X		 * Disconnect ourself from the control tty:
X		 */
X	   if ((f1 = open("/dev/tty", O_RDONLY)) >= 0) 
X              {
X	      (void) ioctl(f1, TIOCNOTTY, (char *) 0);
X	      (void) close(f1);
X	      }
X#endif
X	   }
X	/*
X	 * Set up our RPC environment:
X	 */
X
X	if (FromInetd) 
X           {
X	   assert((TransportHandle = svcudp_create(0)) != (SVCXPRT *)NULL);
X	   assert(svc_register(TransportHandle, PCNFSDPROG, PCNFSDVERS, Dispatch, 0) != 0);
X	   } 
X	else 
X 	   {
X	   assert((socknum = our_rresvport()) >= 0);
X	   assert((TransportHandle = svcudp_create(socknum)) != (SVCXPRT *)NULL);
X	   pmap_unset(PCNFSDPROG, PCNFSDVERS);
X	   assert(svc_register(TransportHandle, PCNFSDPROG, PCNFSDVERS, Dispatch, IPPROTO_UDP) != 0);
X	    }
X        /* just in case, ignoring the result */
X	(void)mkdir(spoolname, 0777);	
X	if (stat(spoolname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) 
X           {
X	   (void)fprintf(stderr, "pc-nfsd: invalid spool directory %s\n", spoolname);
X	   exit(1);
X	   }
X	svc_run();
X	(void)fprintf(stderr, "pc-nfsd: error: svc_run returned\n");
X	sleep(30);		/* just in case inetd wants to fork us
X				 * again */
X	exit(1);
X/*NOTREACHED*/
X
X	return(0);
X}
X
X
X/*
X**---------------------------------------------------------------------
X**                          RPC procedures 
X**---------------------------------------------------------------------
X*/
Xvoid 
XDispatch(ServiceRequest, Transport)
Xstruct svc_req *ServiceRequest;
XSVCXPRT        *Transport;
X{
Xchar           *outdata;
Xunion 
X    {
X    struct auth_args xdrb_aa;
X    struct pr_init_args xdrb_pia;
X    struct pr_start_args xdrb_psa;
X    char	xdrb_buf[UDPMSGSIZE];
X    } xdrbuf;
X
X
X	bzero(xdrbuf.xdrb_buf, sizeof(xdrbuf));	/* said to be required... */
X
X	switch (ServiceRequest->rq_proc) 
X               {
X	    case 0:
X		assert(svc_sendreply(Transport, xdr_void, (caddr_t)NULL));
X		break;
X	   case PCNFSD_AUTH:
X		assert(svc_getargs(Transport, xdr_auth_args, xdrbuf.xdrb_buf));
X		outdata = authproc(&xdrbuf.xdrb_aa);
X		assert(svc_sendreply(Transport, xdr_auth_results, outdata));
X		break;
X	   case PCNFSD_PR_INIT:
X		assert(svc_getargs(Transport, xdr_pr_init_args, xdrbuf.xdrb_buf));
X		outdata = pr_init(&xdrbuf.xdrb_pia);
X		assert(svc_sendreply(Transport, xdr_pr_init_results, outdata));
X		break;
X	   case PCNFSD_PR_START:
X		assert(svc_getargs(Transport, xdr_pr_start_args, xdrbuf.xdrb_buf));
X		outdata = pr_start(&xdrbuf.xdrb_psa);
X		assert(svc_sendreply(Transport, xdr_pr_start_results, outdata));
X		break;
X	   default:
X		(void)fprintf(stderr,
X			"pc-nfsd error: unknown function %d called in Dispatch()\n",
X			ServiceRequest->rq_proc);
X		break;
X	   }
X	return;
X}
X
X
Xstruct passwd  *
Xget_password(username)
Xchar           *username;
X{
Xstruct passwd  *p;
Xstatic struct passwd localp;
Xchar           *pswd;
X
X#ifdef SHADOW_SUPPORT
Xstruct spwd    *sp;
Xint             shadowfile;
X#endif
X
X#ifdef SHADOW_SUPPORT
X	/*
X        **--------------------------------------------------------------
X	** Check the existence of SHADOW.  If it is there, then we are
X	** running a two-password-file system.
X        **--------------------------------------------------------------
X	*/
X	if (access(SHADOW, 0))
X	   shadowfile = 0;	/* SHADOW is not there */
X	else
X	   shadowfile = 1;
X
X	setpwent();
X	if (shadowfile)
X	   (void) setspent();	/* Setting the shadow password
X					 * file */
X	if ((p = getpwnam(username)) == (struct passwd *)NULL ||
X	   (shadowfile && (sp = getspnam(username)) == (struct spwd *)NULL))
X	return ((struct passwd *)NULL);
X
X	if (shadowfile) 
X           {
X	   pswd = sp->sp_pwdp;
X	   (void) endspent();
X	   } 
X        else
X	   pswd = p->pw_passwd;
X
X#else
X	p = getpwnam(username);
X	if (p == (struct passwd *)NULL)
X		return ((struct passwd *)NULL);
X	pswd = p->pw_passwd;
X#endif
X
X#ifdef ISC_2_0
X	/* 
X        **-----------------------------------------------------------
X	** We may have an 'x' in which case look in /etc/shadow ..
X        **-----------------------------------------------------------
X        */
X	if (((strlen(pswd)) == 1) && pswd[0] == 'x') 
X	   {
X	   struct spwd    *shadow = getspnam(username);
X
X	   if (!shadow)
X	      return ((struct passwd *)NULL);
X	   pswd = shadow->sp_pwdp;
X	   }
X#endif
X	localp = *p;
X	localp.pw_passwd = pswd;
X	return (&localp);
X}
X
X
Xchar *
Xauthproc(a)
Xstruct auth_args *a;
X{
Xstatic struct auth_results r;
Xchar            username[32];
Xchar            password[64];
Xint             c1, c2;
Xstruct passwd  *p;
X
X#ifdef SHADOW_SUPPORT
Xstruct spwd    *sp;
Xint             shadowfile;
X#endif
X
X#ifdef USER_CACHE
Xint             cache_entry;;
X#endif
X
X	r.ar_stat = AUTH_RES_FAIL;	/* assume failure */
X	r.ar_uid = -2;
X	r.ar_gid = -2;
X
X	scramble(a->aa_ident, username);
X	scramble(a->aa_password, password);
X
X	if (buggit)
X		(void)fprintf(stderr, "AUTHPROC username=%s\n", username);
X
X#ifdef USER_CACHE
X	cache_entry = check_cache(username);
X	if (cache_entry >= 0) 
X	   {
X	   if (buggit)
X	      (void)fprintf(stderr, "...cache hit?\n");
X	      c1 = strlen(password);
X	      c2 = strlen(User_cache[cache_entry].passwd);
X	      if ((!c1 && !c2) ||
X	  	 !(strcmp(User_cache[cache_entry].passwd,
X		  crypt(password, User_cache[cache_entry].passwd)))) 
X                 {
X	         if (buggit)
X	  	    (void)fprintf(stderr, "...cache hit\n");
X		 r.ar_stat = AUTH_RES_OK;
X		 r.ar_uid = User_cache[cache_entry].uid;
X		 r.ar_gid = User_cache[cache_entry].gid;
X		 return ((char *) &r);
X		 }
X		User_cache[cache_entry].username[0] = '\0'; /* nuke entry */
X	    }
X	if (buggit)
X	   (void)fprintf(stderr, "...cache miss\n");
X#endif
X	p = get_password(username);
X	if (p == (struct passwd *)NULL)
X	   return ((char *) &r);
X
X	c1 = strlen(password);
X	c2 = strlen(p->pw_passwd);
X	if ((c1 && !c2) || (c2 && !c1) ||
X	   (strcmp(p->pw_passwd, crypt(password, p->pw_passwd)))) 
X           {
X	   return ((char *) &r);
X	   }
X	r.ar_stat = AUTH_RES_OK;
X	r.ar_uid = p->pw_uid;
X	r.ar_gid = p->pw_gid;
X
X#ifdef USER_CACHE
X	add_cache_entry(p);
X#endif
X	return ((char *) &r);
X}
X
X
Xchar  *
Xpr_init(pi_arg)
Xstruct pr_init_args *pi_arg;
X{
Xint    dir_mode = 0777;
Xstatic struct pr_init_results pi_res;
X
X	mkdir(spoolname, dir_mode);	/* just in case, ignoring the result */
X	chmod(spoolname, dir_mode);
X
X	/* get pathname of current directory and return to client */
X
X	sprintf(pathname,"%s/%s",spoolname,pi_arg->pia_client);
X/*
X	(void)strcpy(pathname, spoolname);
X	(void)strcat(pathname, "/");	        
X	(void)strcat(pathname, pi_arg->pia_client);
X*/
X
X	mkdir(pathname, dir_mode);	/* ignore the return code */
X
X	if (stat(pathname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) 
X           {
X	   (void)fprintf(stderr,
X		         "pc-nfsd: unable to create spool directory %s\n",
X		 	  pathname);
X	    pathname[0] = 0;/* null to tell client bad vibes */
X	    pi_res.pir_stat = PI_RES_FAIL;
X	    } 
X	else 
X	   {
X	   pi_res.pir_stat = PI_RES_OK;
X	   }
X	pi_res.pir_spooldir = &pathname[0];
X	chmod(pathname, dir_mode);
X
X	if (buggit)
X	   (void)fprintf(stderr, "PR_INIT pathname=%s\n", pathname);
X
X	return ((char *) &pi_res);
X}
X
Xchar *
Xpr_start(ps_arg)
Xstruct pr_start_args *ps_arg;
X{
Xstatic struct pr_start_results ps_res;
Xint             pid;
Xchar            printer_opt[64];
Xchar            jobname_opt[64];
Xchar            clientname_opt[64];
Xchar            snum[20];
Xunsigned int status;
X
X#ifdef HACK_FOR_ROTATED_TRANSCRIPT
Xchar            scratch[512];
X#endif
X
X
X	/* 
X	**--------------------------------------------------------------
X	** When child terminates it sends a signal which we must catch 
X	**--------------------------------------------------------------
X	*/
X
X	signal(SIGCHLD, free_child);	
X	sprintf(pathname,"%s/%s/%s",spoolname,
X	                         ps_arg->psa_client,
X	                         ps_arg->psa_filename);	
X#ifdef STUPID
X	(void)strcpy(pathname, spoolname);	/* build filename */
X	(void)strcat(pathname, "/");
X	(void)strcat(pathname, ps_arg->psa_client);	/* /spool/host */
X	(void)strcat(pathname, "/");	/* /spool/host/ */
X	(void)strcat(pathname, ps_arg->psa_filename);	/* /spool/host/file */
X#endif
X
X	if (buggit) 
X           {
X	   (void)fprintf(stderr,"PR_START pathname=%s\n",pathname);
X	   (void)fprintf(stderr,"PR_START username= %s\n",ps_arg->psa_username);
X	   (void)fprintf(stderr,"PR_START client= %s\n",ps_arg->psa_client);
X	   }
X	if (stat(pathname, &statbuf)) 
X           {
X	   /*
X           **-----------------------------------------------------------------
X	   ** We can't stat the file. Let's try appending '.spl' and
X	   ** see if it's already in progress.
X           **-----------------------------------------------------------------
X	   */
X
X	   if (buggit)
X	      (void)fprintf(stderr, "...can't stat it.\n");
X	   (void)strcat(pathname, ".spl");
X	   if (stat(pathname, &statbuf)) 
X	      {
X	      /*
X              **----------------------------------------------------------------
X	      ** It really doesn't exist.
X              **----------------------------------------------------------------
X	      */
X
X	      if (buggit)
X		(void)fprintf(stderr, "...PR_START returns PS_RES_NO_FILE\n");
X
X	      ps_res.psr_stat = PS_RES_NO_FILE;
X	      return ((char *) &ps_res);
X	      }
X	      /*
X              **-------------------------------------------------------------
X	      ** It is already on the way.
X              **-------------------------------------------------------------
X	      */
X
X	     if (buggit)
X		(void)fprintf(stderr, "...PR_START returns PS_RES_ALREADY\n");
X
X		ps_res.psr_stat = PS_RES_ALREADY;
X		return ((char *) &ps_res);
X	     }
X
X	if (statbuf.st_size == 0) 
X	   {
X	   /*
X           **-------------------------------------------------------------
X	   ** Null file - don't print it, just kill it.
X           **-------------------------------------------------------------
X	   */
X	   unlink(pathname);
X
X	   if (buggit)
X	      (void)fprintf(stderr, "...PR_START returns PS_RES_NULL\n");
X
X	    ps_res.psr_stat = PS_RES_NULL;
X	    return ((char *) &ps_res);
X	    }
X	 /*
X         **-------------------------------------------------------------
X	 ** The file is real, has some data, and is not already going out.
X	 ** We rename it by appending '.spl' and exec "lpr" to do the
X	 ** actual work.
X         **-------------------------------------------------------------
X	 */
X	(void)strcpy(new_pathname, pathname);
X	(void)strcat(new_pathname, ".spl");
X
X	if (buggit)
X	   (void)fprintf(stderr,"...renaming %s -> %s\n",pathname,new_pathname);
X
X	/*
X        **-------------------------------------------------------------
X	** See if the new filename exists so as not to overwrite it.
X        **-------------------------------------------------------------
X	*/
X
X
X	if (!stat(new_pathname, &statbuf)) 
X	   {
X	   (void)strcpy(new_pathname, pathname);  /* rebuild a new name */
X	   (void)sprintf(snum, "%d", rand());	  /* get some number */
X	   (void)strncat(new_pathname, snum, 3);
X	   (void)strcat(new_pathname, ".spl");	  /* new spool file */
X	   if (buggit)
X	      (void)fprintf(stderr,"...created new spl file -> %s\n",new_pathname);
X
X	    }
X	if (rename(pathname, new_pathname)) 
X	   {
X	   /*
X           **---------------------------------------------------------------
X	   ** CAVEAT: Microsoft changed rename for Microsoft C V3.0.
X	   ** Check this if porting to Xenix.
X           **---------------------------------------------------------------
X	   */
X
X	   /*
X           **---------------------------------------------------------------
X	   ** Should never happen.
X           **---------------------------------------------------------------
X           */
X	   (void)fprintf(stderr, "pc-nfsd: spool file rename (%s->%s) failed.\n",
X			pathname, new_pathname);
X		ps_res.psr_stat = PS_RES_FAIL;
X		return ((char *) &ps_res);
X	    }
X	pid = fork();
X	if (pid == 0) 
X	   {
X	   /*
X           **---------------------------------------------------------------
X	   ** FLUKE jps 28-jul-86 - Invoke lpr as the requesting user.
X	   ** 
X	   ** If possible, invoke lpr under the user-id/group-id of the
X	   ** person (apparently) making this RPC request.  Good for
X	   ** accounting, proper banner page, etc.  It is not
X	   ** mandatory.
X           **---------------------------------------------------------------
X	   */
X	   struct passwd  *pw = getpwnam(ps_arg->psa_username);
X
X	   if (buggit)
X	      (void)fprintf(stderr, "username is %s\n", ps_arg->psa_username);
X	   if (pw) 
X	      {
X	      if (buggit)
X		  (void)fprintf(stderr, "uid is %d\ngid is %d\n",
X				         pw->pw_uid, 
X	                                 pw->pw_gid);
X	      setreuid(pw->pw_uid, pw->pw_uid);
X	      setregid(pw->pw_gid, pw->pw_gid);
X
X		/*
X                **-----------------------------------------------------------
X		** PC-NFS doesn't pass us any filename to show on
X		** the banner page, so we blank this field out.
X		** That's batter than showing the pseudo-random
X		** temporary file name used internally (or the
X		** UNIX-ism "(stdin)").
X                **-----------------------------------------------------------
X		*/
X		sprintf(printer_opt, "-P%s", ps_arg->psa_printername);
X		sprintf(jobname_opt, "-J ");
X		sprintf(clientname_opt, "-C%s", ps_arg->psa_client);
X		} 
X	     else 
X	        {
X		/*
X                **--------------------------------------------------------
X		** We don't know the user's identity, so the
X		** printout will end up being enqueued by root.
X		** We do want the user's name to appear on the
X		** banner page, so we slip it in via the -J
X		** option.
X                **--------------------------------------------------------
X		*/
X		sprintf(printer_opt, "-P%s", ps_arg->psa_printername);
X		sprintf(jobname_opt, "-J%s", ps_arg->psa_username);
X		sprintf(clientname_opt, "-C%s", ps_arg->psa_client);
X		}
X
X#ifdef HACK_FOR_ROTATED_TRANSCRIPT
X		if (!strcmp(ps_arg->psa_printername, "rotated")) {
X		   sprintf(scratch, "enscript -lrq -fCourier7  %s",
X		  	             new_pathname);
X		if (buggit)
X		    (void)fprintf(stderr, "system(%s)\n", scratch);
X		system(scratch);
X		unlink(new_pathname);
X		exit(0);
X		}
X		if (!strcmp(ps_arg->psa_printername, "2column")) 
X	           {
X		   sprintf(scratch, "enscript -2rqG -J\"PC-NFS spool file\" %s",
X				new_pathname);
X			if (buggit)
X			   (void)fprintf(stderr, "system(%s)\n", scratch);
X			system(scratch);
X			unlink(new_pathname);
X			exit(0);
X		    }
X#endif
X
X		if (ps_arg->psa_options[1] == 'd') 
X	           {
X		   /*
X                   **------------------------------------------------------
X		   ** This is a Diablo print stream. Apply the ps630
X		   ** filter with the appropriate arguments.
X                   **------------------------------------------------------
X		   */
X		   if (buggit)
X		      (void)fprintf(stderr, "...run_ps630 invoked\n");
X		   (void)run_ps630(new_pathname, ps_arg->psa_options);
X		   }
X		/*
X                **----------------------------------------------------------
X		** New - let's close up 0, 1 and 2 to force getlogin to
X		** fail in lpr
X                **----------------------------------------------------------
X		*/
X		close(0);
X		close(1);
X		close(2);
X
X#ifdef ISC_2_0 
X	        /*
X                **----------------------------------------------------------
X	        **  What lpr hasn't been port to SYSV ? 
X	        **  I like lpr, but I haven't got around to porting it yet
X                **  and I doubt Interactive would even have a clue.  So use
X	        **  System V lp.   Add your own options, these are the min.
X	        **  that make it work. 
X	        **  Use the copy option so we can remove the orignal spooled
X	        **  nfs file from the spool directory.
X                **----------------------------------------------------------
X	        */
X		execlp("/usr/bin/lp",
X			PRINT_COMMAND,
X	                "-c",           /* Copy the file     */
X	                "-s",           /* Suppress messages */ 
X			new_pathname,
X			0);
X		perror("pc-nfsd: exec lp failed");
X		exit(1);	
X#else
X		execlp("/usr/ucb/lpr",
X			PRINT_COMMAND,
X			"-s",
X			"-r",
X			printer_opt,
X			jobname_opt,
X			clientname_opt,
X			new_pathname,
X			0);
X		perror("pc-nfsd: exec lpr failed");
X		exit(1);	/* end of child process */
X#endif
X	   } 
X	   else 
X	      if (pid == -1) 
X	         {
X		 perror("pc-nfsd: fork failed");
X
X		 if (buggit)
X		    (void)fprintf(stderr,"...PR_START returns PS_RES_FAIL\n");
X		 ps_res.psr_stat = PS_RES_FAIL;
X	         } 
X	      else 
X	         {
X		 if (buggit)
X		   (void)fprintf(stderr, "...forked child #%d\n", pid);
X
X		 if (buggit)
X		    (void)fprintf(stderr, "...PR_START returns PS_RES_OK\n");
X		 ps_res.psr_stat = PS_RES_OK;
X#ifdef ISC_2_0 
X		 if (buggit)
X		    (void)fprintf(stderr, "...Unlinking %s\n",new_pathname);
X
X	         /* 
X                 **-------------------------------------------------------
X	         ** We must wait until the file has been copied  
X	         ** before we remove it.
X                 **-------------------------------------------------------
X	         */ 
X	         pid = wait(&status);
X	         unlink(new_pathname);
X#endif
X	         }
X	return ((char *) &ps_res);
X}
X
X
Xchar           *
Xmapfont(f, i, b)
X	char            f;
X	char            i;
X	char            b;
X{
X	static char     fontname[64];
X
X	fontname[0] = 0;	/* clear it out */
X
X	switch (f) {
X	case 'c':
X		(void)strcpy(fontname, "Courier");
X		break;
X	case 'h':
X		(void)strcpy(fontname, "Helvetica");
X		break;
X	case 't':
X		(void)strcpy(fontname, "Times");
X		break;
X	default:
X		(void)strcpy(fontname, "Times-Roman");
X		goto finis ;
X	}
X	if (i != 'o' && b != 'b') {	/* no bold or oblique */
X		if (f == 't')	/* special case Times */
X			(void)strcat(fontname, "-Roman");
X		goto finis;
X	}
X	(void)strcat(fontname, "-");
X	if (b == 'b')
X		(void)strcat(fontname, "Bold");
X	if (i == 'o')		/* o-blique */
X		(void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
X
Xfinis:	return (&fontname[0]);
X}
X
X/*
X * run_ps630 performs the Diablo 630 emulation filtering process. ps630
X * was broken in certain Sun releases: it would not accept point size or
X * font changes. If your version is fixed, undefine the symbol
X * PS630_IS_BROKEN and rebuild pc-nfsd.
X */
X/* #define PS630_IS_BROKEN 1 */
X
Xrun_ps630(file, options)
X	char           *file;
X	char           *options;
X{
X	char            temp_file[256];
X	char            commbuf[256];
X	int             i;
X
X	(void)strcpy(temp_file, file);
X	(void)strcat(temp_file, "X");	/* intermediate file name */
X
X#ifndef PS630_IS_BROKEN
X	(void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
X		options[2], options[3], temp_file);
X	(void)strcat(commbuf, mapfont(options[4], options[5], options[6]));
X	(void)strcat(commbuf, " -F ");
X	(void)strcat(commbuf, mapfont(options[7], options[8], options[9]));
X	(void)strcat(commbuf, "  ");
X	(void)strcat(commbuf, file);
X#else	/* PS630_IS_BROKEN */
X	/*
X	 * The pitch and font features of ps630 appear to be broken at
X	 * this time.
X	 */
X	sprintf(commbuf, "ps630 -p %s %s", temp_file, file);
X#endif	/* PS630_IS_BROKEN */
X
X
X	if (i = system(commbuf)) {
X		/*
X		 * Under (un)certain conditions, ps630 may return -1 even
X		 * if it worked. Hence the commenting out of this error
X		 * report.
X		 */
X		 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
X		/* exit(1); */
X	}
X	if (rename(temp_file, file)) {
X		perror("run_ps630: rename");
X		exit(1);
X	}
X	return(i); /* never used, but keeps lint happy */
X}
X
X/*
X * Determine if a descriptor belongs to a socket or not
X */
Xissock(fd)
X	int             fd;
X{
X	struct stat     st;
X
X	if (fstat(fd, &st) < 0) {
X		return (0);
X	}
X	/*
X	 * SunOS returns S_IFIFO for sockets, while 4.3 returns 0 and does
X	 * not even have an S_IFIFO mode.  Since there is confusion about
X	 * what the mode is, we check for what it is not instead of what
X	 * it is.
X	 */
X	switch (st.st_mode & S_IFMT) {
X	case S_IFCHR:
X	case S_IFREG:
X#ifndef SYSV
X	case S_IFLNK:
X#endif
X	case S_IFDIR:
X	case S_IFBLK:
X		return (0);
X	default:
X		return (1);
X	}
X}
X
X
X
X#ifdef USER_CACHE
Xint
Xcheck_cache(name)
X	char           *name;
X{
X	int             i;
X
X	for (i = 0; i < CACHE_SIZE; i++) {
X		if (!strcmp(User_cache[i].username, name))
X			return (i);
X	}
X	return (-1);
X}
X
Xadd_cache_entry(p)
X	struct passwd  *p;
X{
X	int             i;
X
X	for (i = CACHE_SIZE - 1; i > 0; i--)
X		User_cache[i] = User_cache[i - 1];
X	User_cache[0].uid = p->pw_uid;
X	User_cache[0].gid = p->pw_gid;
X	(void)strcpy(User_cache[0].passwd, p->pw_passwd);
X	(void)strcpy(User_cache[0].username, p->pw_name);
X}
X
X
X#endif				/* USER_CACHE */
SHAR_EOF
$TOUCH -am 0105033391 pcnfsd.c &&
chmod 0444 pcnfsd.c ||
echo "restore of pcnfsd.c failed"
set `wc -c pcnfsd.c`;Wc_c=$1
if test "$Wc_c" != "33340"; then
	echo original size 33340, current size $Wc_c
fi
exit 0
-- 
Paul J. Emerson                           SDG Division of SAIC 
Senior Technical Manager                  450 Lakemont Ave.
UUCP:     uunet|tarpit!sdgsun!paul        Winter Park, FL 32792
Internet: sdgsun!paul@bikini.cis.ufl.edu  (407) 657-1300