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