geoff@vindaloo.East.Sun.COM (Geoff Arnold @ Sun BOS - R.H. coast near the top) (10/17/90)
Here's the repost of the latest pcnfsd that I promised. This is NOT the
pcnfsd protocol rev.: it's simply the Nth revision of the original code
with numerous cleanups, options, variants, etc. It still doesn't use
syslog(), and if anyone has a syslogging version I'd really apreciate a
copy.
A couple of comments are in order. First, I don't think that I posted
the adpcnfsd.csh script last time: for readers of this group who
probably adb kernels without symbols in their sleep :-) the script is
simplistic, but hey... Secondly, I finally got my hands on a PC running
SVR3 (SVR4 soon, honest!) and ran into some trouble with the System V
variant code which people have passed back to me. If anyone wants to
take the time to hack together the definitive System V pcnfsd, please
let me know.
Geoff
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# r_pcnfsd.c
# adpcnfsd.csh
# This archive created: Wed Oct 17 08:46:58 1990
export PATH; PATH=/bin:$PATH
if test -f 'r_pcnfsd.c'
then
echo shar: will not over-write existing file "'r_pcnfsd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'r_pcnfsd.c'
X#ifdef sccs
Xstatic char sccsid[] = "@(#)r_pcnfsd.c 1.1 9/6/90";
X#endif
X
X/*
X * Copyright (c) 1986, 1987, 1988, 1989, 1990 by Sun Microsystems, Inc.
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 * Uncomment the following #define to enable the use of a shadow password file
X */
X/* #define SHADOW_SUPPORT 1 */
X/*
X * Uncomment the following #define to conform to Interactive System's 2.0
X */
X/* #define INTERACTIVE_2POINT0 1 */
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/* #define USER_CACHE 1 */
X/*
X * Uncomment the following #define to build a System V version
X */
X/* #define SYS5 1 */
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/* #define HACK_FOR_ROTATED_TRANSCRIPT 1 */
X
X/*
X * The following definitions may be overridden is desired.
X */
X#ifndef SPOOLDIR
X#define SPOOLDIR "/usr/spool/pcnfs"
X#endif /* SPOOLDIR */
X
X#ifndef PRINT_COMMAND
X#define PRINT_COMMAND "lpr"
X#endif /* PRINT_COMMAND */
X
X
X#include <sys/types.h>
X#include <stdio.h>
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#include <sys/wait.h>
X
X
X#ifdef SHADOW_SUPPORT
X#include <shadow.h>
X#endif
X
X#ifdef INTERACTIVE_2POINT0
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 SYS5
X#define SIGCHLD SIGCLD
X#endif
X
Xextern char *crypt();
Xextern int errno;
Xint buggit = 0;
X
X/*
X * *************** RPC parameters ********************
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 * ************* Other #define's **********************
X */
X#ifndef SPOOLDIR
X#define SPOOLDIR "/usr/spool/pcnfs"
X#endif /* SPOOLDIR */
X
X#ifndef PRINT_COMMAND
X#define PRINT_COMMAND "lpr"
X#endif /* PRINT_COMMAND */
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,"rpc.pcnfsd: Assertion failed: line %d of %s: \"%s\"\n", \
X __LINE__, __FILE__, "ex"); \
X sleep (30); exit(1);}}
X
X
X/*
X * *********** XDR structures, etc. ********************
X */
Xenum arstat {
X AUTH_RES_OK, AUTH_RES_FAKE, AUTH_RES_FAIL
X};
Xenum pirstat {
X PI_RES_OK, PI_RES_NO_SUCH_PRINTER, PI_RES_FAIL
X};
Xenum psrstat {
X PS_RES_OK, PS_RES_ALREADY, PS_RES_NULL, PS_RES_NO_FILE,
X PS_RES_FAIL
X};
X
Xstruct auth_args {
X char *aa_ident;
X char *aa_password;
X};
X
Xstruct auth_results {
X enum arstat ar_stat;
X long ar_uid;
X long ar_gid;
X};
X
Xstruct pr_init_args {
X char *pia_client;
X char *pia_printername;
X};
X
Xstruct pr_init_results {
X enum pirstat pir_stat;
X char *pir_spooldir;
X};
X
Xstruct pr_start_args {
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 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 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 * ****************** Misc. ************************
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 SYS5
Xstruct passwd *getpwnam();
X
X#endif
X
X
X/*
X * ************** Support procedures ***********************
X */
Xscramble(s1, s2)
X char *s1;
X char *s2;
X{
X while (*s1) {
X *s2++ = (*s1 ^ zchar) & 0x7f;
X s1++;
X }
X *s2 = 0;
X}
X
Xvoid free_child()
X{
X int pid;
X union wait status;
X
X while((pid = wait(&status)) != -1) {
X
X if (buggit || status.w_retcode)
X (void)fprintf(stderr, "FREE_CHILD: process #%d exited with status 0X%x\n",
X pid, status.w_retcode);
X }
X return;
X}
X
Xour_rresvport()
X{
X struct sockaddr_in sin;
X int s, 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 sin.sin_port = htons((u_short) alport);
X if (bind(s, (caddr_t) & sin, sizeof(sin)) >= 0)
X return (s);
X if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
X perror("socket");
X return (-1);
X }
X (alport)--;
X if (alport == IPPORT_RESERVED / 2) {
X (void)fprintf(stderr, "socket: All ports in use\n");
X return (-1);
X }
X }
X}
X
X
X/*
X * *************** XDR procedures *****************
X */
Xbool_t
Xxdr_auth_args(xdrs, aap)
X XDR *xdrs;
X struct 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)
X XDR *xdrs;
X struct 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)
X XDR *xdrs;
X struct 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)
X XDR *xdrs;
X struct 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)
X XDR *xdrs;
X struct 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)
X XDR *xdrs;
X struct pr_start_results *arp;
X{
X return (xdr_enum(xdrs, (enum_t *)&arp->psr_stat));
X}
X
X
X
X
X/*
X * ********************** main *********************
X */
X
Xmain(Argc, Argv)
X int Argc;
X char *Argv[];
X{
X int f1, f2, f3;
X int FromInetd;
X int socknum;
X SVCXPRT *TransportHandle;
X void Dispatch();
X
X (void)strcpy(spoolname, SPOOLDIR);
X
X setbuf(stderr, (char *)NULL);
X
X if (geteuid() != 0) {
X (void)fprintf(stderr, "rpc.pcnfsd must be run by 'root'\n");
X exit(1);
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 FromInetd = issock(0);
X
X
X if (!FromInetd) {
X while (++Argv, --Argc > 0) {
X if (strcmp(*Argv, "-d") == 0) {
X ++buggit;
X continue;
X }
X if (strcmp(*Argv, "-s") == 0) {
X if (!(++Argv, --Argc > 0)) {
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 (void)strcpy(spoolname, &(*Argv)[2]);
X continue;
X }
X }
X }
X if (!FromInetd && !buggit) {
X switch (fork()) {
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 * Can't mess with STDIN if invoked from inetd, 'cause our
X * incoming RPC request datagram is passed in on STDIN.
X */
X if (!FromInetd) {
X if ((f1 = open("/dev/null", O_RDONLY)) == -1) {
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 (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 (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 (void) ioctl(f1, TIOCNOTTY, (char *) 0);
X (void) close(f1);
X }
X#endif
X }
X /*
X * Set up our RPC environment:
X */
X if (FromInetd) {
X assert((TransportHandle = svcudp_create(0)) != (SVCXPRT *)NULL);
X assert(svc_register(TransportHandle, PCNFSDPROG, PCNFSDVERS, Dispatch, 0) != 0);
X } else {
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
X (void)mkdir(spoolname, 0777); /* just in case, ignoring the result */
X if (stat(spoolname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
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 * ******************* RPC procedures **************
X */
Xvoid
XDispatch(ServiceRequest, Transport)
X struct svc_req *ServiceRequest;
X SVCXPRT *Transport;
X{
X char *outdata;
X union {
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 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)
X char *username;
X{
X struct passwd *p;
X static struct passwd localp;
X char *pswd;
X
X#ifdef SHADOW_SUPPORT
X struct spwd *sp;
X int shadowfile;
X
X#endif
X
X#ifdef SHADOW_SUPPORT
X /*
X * Check the existence of SHADOW. If it is there, then we are
X * running a two-password-file system.
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 pswd = sp->sp_pwdp;
X (void) endspent();
X } else
X pswd = p->pw_passwd;
X
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 INTERACTIVE_2POINT0
X /* We may have an 'x' in which case look in /etc/shadow .. */
X if (((strlen(pswd)) == 1) && pswd[0] == '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)
X struct auth_args *a;
X{
X static struct auth_results r;
X char username[32];
X char password[64];
X int c1, c2;
X struct passwd *p;
X
X#ifdef SHADOW_SUPPORT
X struct spwd *sp;
X int shadowfile;
X
X#endif
X#ifdef USER_CACHE
X int 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 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 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 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#ifdef USER_CACHE
X add_cache_entry(p);
X#endif
X return ((char *) &r);
X}
X
X
Xchar *
Xpr_init(pi_arg)
X struct pr_init_args *pi_arg;
X{
X int dir_mode = 0777;
X static 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 (void)strcpy(pathname, spoolname); /* first the spool area */
X (void)strcat(pathname, "/"); /* append a slash */
X (void)strcat(pathname, pi_arg->pia_client);
X /* now the host name */
X mkdir(pathname, dir_mode); /* ignore the return code */
X if (stat(pathname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
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 } else {
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)
X struct pr_start_args *ps_arg;
X{
X static struct pr_start_results ps_res;
X int pid;
X char printer_opt[64];
X char jobname_opt[64];
X char clientname_opt[64];
X char snum[20];
X#ifdef HACK_FOR_ROTATED_TRANSCRIPT
X char scratch[512];
X#endif
X
X
X
X signal(SIGCHLD, free_child); /* when child terminates it sends */
X /* a signal which we must get */
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
X if (buggit) {
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 * We can't stat the file. Let's try appending '.spl' and
X * see if it's already in progress.
X */
X
X if (buggit)
X (void)fprintf(stderr, "...can't stat it.\n");
X
X (void)strcat(pathname, ".spl");
X if (stat(pathname, &statbuf)) {
X /*
X * It really doesn't exist.
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 * It is already on the way.
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 if (statbuf.st_size == 0) {
X /*
X * Null file - don't print it, just kill it.
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 * 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 (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 * See if the new filename exists so as not to overwrite it.
X */
X
X
X if (!stat(new_pathname, &statbuf)) {
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 * CAVEAT: Microsoft changed rename for Microsoft C V3.0.
X * Check this if porting to Xenix.
X */
X /*
X * Should never happen.
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 * FLUKE jps 28-jul-86 - Invoke lpr as the requesting
X * 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 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 if (buggit)
X (void)fprintf(stderr, "uid is %d\ngid is %d\n",
X pw->pw_uid, pw->pw_gid);
X setreuid(pw->pw_uid, pw->pw_uid);
X setregid(pw->pw_gid, pw->pw_gid);
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 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 } else {
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 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#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 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 /* HACK_FOR_ROTATED_TRANSCRIPT */
X
X if (ps_arg->psa_options[1] == 'd') {
X /*
X * This is a Diablo print stream. Apply the ps630
X * filter with the appropriate arguments.
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 * New - let's close up 0, 1 and 2 to force getlogin to
X * fail in lpr
X */
X close(0);
X close(1);
X close(2);
X
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 } else if (pid == -1) {
X perror("pc-nfsd: fork failed");
X
X if (buggit)
X (void)fprintf(stderr, "...PR_START returns PS_RES_FAIL\n");
X
X ps_res.psr_stat = PS_RES_FAIL;
X } else {
X
X if (buggit)
X (void)fprintf(stderr, "...forked child #%d\n", pid);
X
X
X if (buggit)
X (void)fprintf(stderr, "...PR_START returns PS_RES_OK\n");
X
X ps_res.psr_stat = PS_RES_OK;
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 case S_IFLNK:
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
fi # end of overwriting check
if test -f 'adpcnfsd.csh'
then
echo shar: will not over-write existing file "'adpcnfsd.csh'"
else
sed 's/^X//' << \SHAR_EOF > 'adpcnfsd.csh'
X#!/bin/csh
X# @(#)adpcnfsd.csh 9.5 10/17/90
X#
X# adpcnfsd.csh
X#
X# This script will make rpc.pcnfsd, move it to the correct place on your
X# system, then edit the appropriate file to allow the daemon to start up
X# whenever you reboot your system.
X#
X# The preferred method of starting rpc.pcnfsd is from inetd. This script will
X# modify either your /etc/servers file (for SunOS 3.X) or /etc/inetd.conf
X# file (for SunOS 4.X). If you wish to instead start rpc.pcnfsd from
X# rc.local as a normal daemon, then you should refer to the section in the
X# Installing PC-NFS guide that discusses installing server software. Also
X# make sure you read the READ THIS FIRST guide.
X#
X#
X# To use this script you must first have copied the following files from the
X# PC-NFS "Server 1" diskette:
X# adpcnfsd.csh ( this file )
X# r_pcnfsd.c
X# to some place on the system you are going to perform the install. Usually
X# /usr/tmp is a good place. (Note that the file name "r_pcnfsd.c"
X# is dictated by DOS file name conventions: this script will rename
X# the file to "rpc.pcnfsd.c".)
X#
X# You then must become root on the machine you are intending to add the
X# rpc.pcnfsd to. Then run this script. There are no arguments.
X#
X
X
Xif ( $#argv > 0 ) then
X echo " "
X echo " Usage: adpcnfsd"
X echo " "
X exit (1)
Xendif
X
Xecho " "
Xecho "Add RPC.PCNFSD shell script"
Xecho " "
Xecho
X
Xecho "Renaming R_PCNFSD.C as RPC.PCNFSD.C"
Xmv r_pcnfsd.c rpc.pcnfsd.c
Xecho "Compiling RPC.PCNFSD"
Xcc -o rpc.pcnfsd rpc.pcnfsd.c
Xstrip rpc.pcnfsd
X
Xecho " "
Xecho "Compilation complete."
Xecho "Moving RPC.PCNFSD to /usr/etc directory."
X
Xmv rpc.pcnfsd /usr/etc
X
Xecho " "
X
Xif ( -f /etc/servers ) then
Xecho "Editing servers file."
Xed - /etc/servers <<EOFSTRING
Xa
Xrpc udp /usr/etc/rpc.pcnfsd 150001 1
X.
Xw
Xq
XEOFSTRING
X#
X
Xelse if ( -f /etc/inetd.conf ) then
Xecho "Editing inetd.conf file."
Xed - /etc/inetd.conf <<EOFSTRING
Xa
Xpcnfsd/1 dgram rpc/udp wait root /usr/etc/rpc.pcnfsd rpc.pcnfsd
X.
Xw
Xq
XEOFSTRING
X#
Xelse
Xecho "No /etc/servers or /etc/inetd.conf file."
Xecho "RPC.PCNFSD built - you should make sure it is started each time"
Xecho "your system is booted."
Xecho " "
Xexit(1)
Xendif
X
Xecho " "
Xecho "ADPCNFSD.CSH script completed."
Xecho "You can start the daemon now by typing /usr/etc/rpc.pcnfsd."
Xecho " "
Xecho " "
X
X
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
-- Geoff Arnold, PC-NFS architect, Sun Microsystems. (geoff@East.Sun.COM) --
*** "Now is no time to speculate or hypothecate, but rather a time ***
*** for action, or at least not a time to rule it out, though not ***
*** necessarily a time to rule it in, either." - George Bush ***