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 ***