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