home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 11 / 11.iso / n / n003 / 8.ddi / R_PCNFSD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-13  |  24.5 KB  |  1,050 lines

  1. #ifdef sccs
  2. static char     sccsid[] = "@(#)r_pcnfsd.c    1.3 2/8/91";
  3. #endif
  4.  
  5. /*
  6.  * Copyright (c) 1986, 1987, 1988, 1989, 1990 by Sun Microsystems, Inc.
  7.  */
  8.  
  9. /**********************************************************************
  10.  *             C U S T O M I Z A T I O N   S E C T I O N              *
  11.  *                                                                    *
  12.  * You may change the following #defines to build different versions  *
  13.  * of rpc.pcnfsd. Note that this version _must_ be run by the         *
  14.  * super-user (either from inetd or at system start-up). Future       *
  15.  * clients may elect to verify that the service is provided on a      *
  16.  * reserved port for added security.                                  *
  17.  *                                                                    *
  18.  **********************************************************************
  19.  */
  20.  
  21. /*
  22.  * Uncomment the following #define to enable the use of a shadow password file
  23.  */
  24. /* #define SHADOW_SUPPORT 1 */
  25. /*
  26.  * Uncomment the following #define to conform to Interactive System's 2.0
  27.  */
  28. /* #define INTERACTIVE_2POINT0 1 */
  29. /*
  30.  * Uncomment the following #define to use a cache of recently-used
  31.  * user names. This has certain uses in university and other settings
  32.  * where (1) the pasword file is very large, and (2) a group of users
  33.  * frequently logs in together using the same account (for example,
  34.  * a class userid).
  35.  */
  36. /* #define USER_CACHE 1 */
  37. /*
  38.  * Uncomment the following #define to build a System V version
  39.  */
  40. /* #define SYS5 1 */
  41. /*
  42.  * Uncomment the following #define to build a typical "local feature":
  43.  * in this case recognizing the special printer names "rotated"
  44.  * and "2column" and using the Adobe "enscript" command to
  45.  * format the output appropriately.
  46.  */
  47. /* #define HACK_FOR_ROTATED_TRANSCRIPT 1 */
  48.  
  49. /*
  50.  * The following definitions may be overridden is desired.
  51.  */
  52. #ifndef SPOOLDIR
  53. #define SPOOLDIR    "/usr/spool/pcnfs"
  54. #endif    /* SPOOLDIR */
  55.  
  56. #ifndef PRINT_COMMAND
  57. #define PRINT_COMMAND    "lpr"
  58. #endif    /* PRINT_COMMAND */
  59.  
  60.  
  61. #include <sys/types.h>
  62. #include <stdio.h>
  63. #include <rpc/rpc.h>
  64. #include <pwd.h>
  65. #include <sys/file.h>
  66. #include <signal.h>
  67. #include <sys/stat.h>
  68. #include <sys/ioctl.h>
  69. #include <sys/socket.h>
  70. #include <netdb.h>
  71. #include <errno.h>
  72. #include <sys/wait.h>
  73.  
  74.  
  75. #ifdef SHADOW_SUPPORT
  76. #include <shadow.h>
  77. #endif
  78.  
  79. #ifdef INTERACTIVE_2POINT0
  80. #include <sys/fcntl.h>
  81. #include <shadow.h>
  82. #endif
  83.  
  84. #ifdef USER_CACHE
  85. #include <string.h>
  86. #endif
  87.  
  88. #ifdef SYS5
  89. #define SIGCHLD SIGCLD
  90. #endif
  91.  
  92. extern char *crypt();
  93. extern int errno;
  94. int             buggit = 0;
  95.  
  96. /*
  97.  * *************** RPC parameters ********************
  98.  */
  99. #define    PCNFSDPROG    (long)150001
  100. #define    PCNFSDVERS    (long)1
  101. #define    PCNFSD_AUTH    (long)1
  102. #define    PCNFSD_PR_INIT    (long)2
  103. #define    PCNFSD_PR_START    (long)3
  104.  
  105. /*
  106.  * ************* Other #define's **********************
  107.  */
  108. #ifndef SPOOLDIR
  109. #define SPOOLDIR    "/usr/spool/pcnfs"
  110. #endif    /* SPOOLDIR */
  111.  
  112. #ifndef PRINT_COMMAND
  113. #define PRINT_COMMAND    "lpr"
  114. #endif    /* PRINT_COMMAND */
  115.  
  116. #ifndef MAXPATHLEN
  117. #define MAXPATHLEN 1024
  118. #endif
  119. #define    SCRAMBLE_CHAR        0x5b
  120.  
  121. #define assert(ex) {if (!(ex)) \
  122.     {(void)fprintf(stderr,"rpc.pcnfsd: Assertion failed: line %d of %s: \"%s\"\n", \
  123.     __LINE__, __FILE__, "ex"); \
  124.     sleep (30); exit(1);}}
  125.  
  126.  
  127. /*
  128.  * *********** XDR structures, etc. ********************
  129.  */
  130. enum arstat {
  131.     AUTH_RES_OK, AUTH_RES_FAKE, AUTH_RES_FAIL
  132. };
  133. enum pirstat {
  134.     PI_RES_OK, PI_RES_NO_SUCH_PRINTER, PI_RES_FAIL
  135. };
  136. enum psrstat {
  137.     PS_RES_OK, PS_RES_ALREADY, PS_RES_NULL, PS_RES_NO_FILE,
  138.     PS_RES_FAIL
  139. };
  140.  
  141. struct auth_args {
  142.     char           *aa_ident;
  143.     char           *aa_password;
  144. };
  145.  
  146. struct auth_results {
  147.     enum arstat     ar_stat;
  148.     long            ar_uid;
  149.     long            ar_gid;
  150. };
  151.  
  152. struct pr_init_args {
  153.     char           *pia_client;
  154.     char           *pia_printername;
  155. };
  156.  
  157. struct pr_init_results {
  158.     enum pirstat    pir_stat;
  159.     char           *pir_spooldir;
  160. };
  161.  
  162. struct pr_start_args {
  163.     char           *psa_client;
  164.     char           *psa_printername;
  165.     char           *psa_username;
  166.     char           *psa_filename;    /* within the spooldir */
  167.     char           *psa_options;
  168. };
  169.  
  170. struct pr_start_results {
  171.     enum psrstat    psr_stat;
  172. };
  173.  
  174. #ifdef USER_CACHE
  175. #define CACHE_SIZE 16        /* keep it small, as linear searches are
  176.                  * done */
  177. struct cache {
  178.     int             uid;
  179.     int             gid;
  180.     char            passwd[32];
  181.     char            username[10];    /* keep this even for machines
  182.                      * with alignment problems */
  183. }               User_cache[CACHE_SIZE];
  184.  
  185. #endif /* ifdef USER_CACHE */
  186.  
  187. /*
  188.  * ****************** Misc. ************************
  189.  */
  190.  
  191. char           *authproc();
  192. char           *pr_start();
  193. char           *pr_init();
  194. struct stat     statbuf;
  195.  
  196. char            pathname[MAXPATHLEN];
  197. char            new_pathname[MAXPATHLEN];
  198. char            spoolname[MAXPATHLEN];
  199.  
  200.  
  201. #ifdef SYS5
  202. struct passwd  *getpwnam();
  203.  
  204. #endif
  205.  
  206.  
  207. /*
  208.  * ************** Support procedures ***********************
  209.  */
  210. scramble(s1, s2)
  211.     char           *s1;
  212.     char           *s2;
  213. {
  214.     while (*s1) {
  215.         *s2++ = (*s1 ^ SCRAMBLE_CHAR) & 0x7f;
  216.         s1++;
  217.     }
  218.     *s2 = 0;
  219. }
  220.  
  221. void free_child()
  222. {
  223.     int             pid;
  224.     union wait status;
  225.  
  226.     while((pid = wait(&status)) != -1) {
  227.  
  228.         if (buggit || status.w_retcode)
  229.         (void)fprintf(stderr, "FREE_CHILD: process #%d exited with status 0X%x\n",
  230.             pid, status.w_retcode);
  231.     }
  232.     return;
  233. }
  234.  
  235. our_rresvport()
  236. {
  237.     struct sockaddr_in sin;
  238.     int             s, alport = IPPORT_RESERVED - 1;
  239.  
  240.     sin.sin_family = AF_INET;
  241.     sin.sin_addr.s_addr = 0;
  242.     s = socket(AF_INET, SOCK_DGRAM, 0);
  243.     if (s < 0)
  244.         return (-1);
  245.     for (;;) {
  246.         sin.sin_port = htons((u_short) alport);
  247.         if (bind(s, (caddr_t) & sin, sizeof(sin)) >= 0)
  248.             return (s);
  249.         if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
  250.             perror("socket");
  251.             return (-1);
  252.         }
  253.         (alport)--;
  254.         if (alport == IPPORT_RESERVED / 2) {
  255.             (void)fprintf(stderr, "socket: All ports in use\n");
  256.             return (-1);
  257.         }
  258.     }
  259. }
  260.  
  261.  
  262. /*
  263.  * *************** XDR procedures *****************
  264.  */
  265. bool_t
  266. xdr_auth_args(xdrs, aap)
  267.     XDR            *xdrs;
  268.     struct auth_args *aap;
  269. {
  270.     return (xdr_string(xdrs, &aap->aa_ident, 32) &&
  271.         xdr_string(xdrs, &aap->aa_password, 64));
  272. }
  273.  
  274. bool_t
  275. xdr_auth_results(xdrs, arp)
  276.     XDR            *xdrs;
  277.     struct auth_results *arp;
  278. {
  279.     return (xdr_enum(xdrs, (enum_t *)&arp->ar_stat) &&
  280.         xdr_long(xdrs, &arp->ar_uid) &&
  281.         xdr_long(xdrs, &arp->ar_gid));
  282. }
  283.  
  284. bool_t
  285. xdr_pr_init_args(xdrs, aap)
  286.     XDR            *xdrs;
  287.     struct pr_init_args *aap;
  288. {
  289.     return (xdr_string(xdrs, &aap->pia_client, 64) &&
  290.         xdr_string(xdrs, &aap->pia_printername, 64));
  291. }
  292.  
  293. bool_t
  294. xdr_pr_init_results(xdrs, arp)
  295.     XDR            *xdrs;
  296.     struct pr_init_results *arp;
  297. {
  298.     return (xdr_enum(xdrs, (enum_t *)&arp->pir_stat) &&
  299.         xdr_string(xdrs, &arp->pir_spooldir, 255));
  300. }
  301.  
  302. bool_t
  303. xdr_pr_start_args(xdrs, aap)
  304.     XDR            *xdrs;
  305.     struct pr_start_args *aap;
  306. {
  307.     return (xdr_string(xdrs, &aap->psa_client, 64) &&
  308.         xdr_string(xdrs, &aap->psa_printername, 64) &&
  309.         xdr_string(xdrs, &aap->psa_username, 64) &&
  310.         xdr_string(xdrs, &aap->psa_filename, 64) &&
  311.         xdr_string(xdrs, &aap->psa_options, 64));
  312. }
  313.  
  314. bool_t
  315. xdr_pr_start_results(xdrs, arp)
  316.     XDR            *xdrs;
  317.     struct pr_start_results *arp;
  318. {
  319.     return (xdr_enum(xdrs, (enum_t *)&arp->psr_stat));
  320. }
  321.  
  322.  
  323. int    FromInetd = 0;
  324.  
  325. /*
  326.  * ********************** main *********************
  327.  */
  328.  
  329. main(Argc, Argv)
  330.     int             Argc;
  331.     char           *Argv[];
  332. {
  333.     int             f1, f2, f3;
  334.     int             socknum;
  335.     SVCXPRT        *TransportHandle;
  336.     void            Dispatch();
  337.  
  338.     (void)strcpy(spoolname, SPOOLDIR);
  339.  
  340.     setbuf(stderr, (char *)NULL);
  341.  
  342.     if (geteuid() != 0) {
  343.         (void)fprintf(stderr, "rpc.pcnfsd must be run by 'root'\n");
  344.         exit(1);
  345.     }
  346.     /*
  347.      * If we're called from inetd: - an open RPC socket is passed as
  348.      * fd 0. and note that we are already registered with the
  349.      * portmapper. Otherwise: - we must parse any command-line
  350.      * arguments which may be present. - we must create an RPC socket
  351.      * (svcudp_create will do this). - we are not yet registered with
  352.      * the portmapper, and must do so.
  353.      */
  354.     FromInetd = issock(0);
  355.  
  356.  
  357.     if (!FromInetd) {
  358.         while (++Argv, --Argc > 0) {
  359.             if (strcmp(*Argv, "-d") == 0) {
  360.                 ++buggit;
  361.                 continue;
  362.             }
  363.             if (strcmp(*Argv, "-s") == 0) {
  364.                 if (!(++Argv, --Argc > 0)) {
  365.                     (void)fprintf(stderr,
  366.                         "pc-nfsd error: -s option must be followed by a spooling directory path\n");
  367.                     exit(1);
  368.                 }
  369.                 (void)strcpy(spoolname, *Argv);
  370.                 continue;
  371.             }
  372.             if (strncmp(*Argv, "-s", 2) == 0) {
  373.                 (void)strcpy(spoolname, &(*Argv)[2]);
  374.                 continue;
  375.             }
  376.         }
  377.     }
  378.     if (!FromInetd && !buggit) {
  379.         switch (fork()) {
  380.         case 0:
  381.             break;
  382.         case -1:
  383.             perror("pc-nfsd: fork failed");
  384.             exit(1);
  385.         default:
  386.             exit(0);
  387.         }
  388.     }
  389.     if (!buggit) {
  390.         /*
  391.          * Can't mess with STDIN if invoked from inetd, 'cause our
  392.          * incoming RPC request datagram is passed in on STDIN.
  393.          */
  394.         if (!FromInetd) {
  395.             if ((f1 = open("/dev/null", O_RDONLY)) == -1) {
  396.                 (void)fprintf(stderr, "pc-nfsd: couldn't open /dev/null\n");
  397.                 exit(1);
  398.             }
  399.             (void) dup2(f1, 0);
  400.             (void) close(f1);
  401.         }
  402.         if ((f2 = open("/dev/console", O_WRONLY)) == -1) {
  403.             (void)fprintf(stderr, "pc-nfsd: couldn't open /dev/console\n");
  404.             exit(1);
  405.         }
  406.         (void) dup2(f2, 1);
  407.         (void) close(f2);
  408.  
  409.         if ((f3 = open("/dev/console", O_WRONLY)) == -1) {
  410.             (void)fprintf(stderr, "pc-nfsd: couldn't open /dev/console\n");
  411.             exit(1);
  412.         }
  413.         (void) dup2(f3, 2);
  414.         (void) close(f3);
  415.  
  416. #ifdef TIOCNOTTY
  417.         /*
  418.          * Disconnect ourself from the control tty:
  419.          */
  420.         if ((f1 = open("/dev/tty", O_RDONLY)) >= 0) {
  421.             (void) ioctl(f1, TIOCNOTTY, (char *) 0);
  422.             (void) close(f1);
  423.         }
  424. #endif
  425.     }
  426.     /*
  427.      * Set up our RPC environment:
  428.      */
  429.     if (FromInetd) {
  430.         assert((TransportHandle = svcudp_create(0)) != (SVCXPRT *)NULL);
  431.         assert(svc_register(TransportHandle, PCNFSDPROG, PCNFSDVERS, Dispatch, 0) != 0);
  432.     } else {
  433.         assert((socknum = our_rresvport()) >= 0);
  434.         assert((TransportHandle = svcudp_create(socknum)) != (SVCXPRT *)NULL);
  435.         pmap_unset(PCNFSDPROG, PCNFSDVERS);
  436.         assert(svc_register(TransportHandle, PCNFSDPROG, PCNFSDVERS, Dispatch, IPPROTO_UDP) != 0);
  437.     }
  438.  
  439.     (void)mkdir(spoolname, 0777);    /* just in case, ignoring the result */
  440.     if (stat(spoolname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
  441.         (void)fprintf(stderr, "pc-nfsd: invalid spool directory %s\n", spoolname);
  442.         exit(1);
  443.     }
  444.     svc_run();
  445.     (void)fprintf(stderr, "pc-nfsd: error: svc_run returned\n");
  446.     sleep(30);        /* just in case inetd wants to fork us
  447.                  * again */
  448.     exit(1);
  449. /*NOTREACHED*/
  450.  
  451.     return(0);
  452. }
  453.  
  454.  
  455. /*
  456.  * ******************* RPC procedures **************
  457.  */
  458. void 
  459. Dispatch(ServiceRequest, Transport)
  460.     struct svc_req *ServiceRequest;
  461.     SVCXPRT        *Transport;
  462. {
  463.     char           *outdata;
  464.      union {
  465.          struct auth_args xdrb_aa;
  466.          struct pr_init_args xdrb_pia;
  467.          struct pr_start_args xdrb_psa;
  468.          char    xdrb_buf[UDPMSGSIZE];
  469.      } xdrbuf;
  470.  
  471.  
  472.     bzero(xdrbuf.xdrb_buf, sizeof(xdrbuf));    /* said to be required... */
  473.  
  474.     switch (ServiceRequest->rq_proc) {
  475.     case 0:
  476.         assert(svc_sendreply(Transport, xdr_void, (caddr_t)NULL));
  477.         break;
  478.     case PCNFSD_AUTH:
  479.         assert(svc_getargs(Transport, xdr_auth_args, xdrbuf.xdrb_buf));
  480.         outdata = authproc(&xdrbuf.xdrb_aa);
  481.         assert(svc_sendreply(Transport, xdr_auth_results, outdata));
  482.         break;
  483.     case PCNFSD_PR_INIT:
  484.         assert(svc_getargs(Transport, xdr_pr_init_args, xdrbuf.xdrb_buf));
  485.         outdata = pr_init(&xdrbuf.xdrb_pia);
  486.         assert(svc_sendreply(Transport, xdr_pr_init_results, outdata));
  487.         break;
  488.     case PCNFSD_PR_START:
  489.         assert(svc_getargs(Transport, xdr_pr_start_args, xdrbuf.xdrb_buf));
  490.         outdata = pr_start(&xdrbuf.xdrb_psa);
  491.         assert(svc_sendreply(Transport, xdr_pr_start_results, outdata));
  492.         break;
  493.     default:
  494.         (void)fprintf(stderr,
  495.             "pc-nfsd error: unknown function %d called in Dispatch()\n",
  496.             ServiceRequest->rq_proc);
  497.         break;
  498.     }
  499.     if(FromInetd) 
  500.         exit(0);
  501.     return;
  502. }
  503.  
  504.  
  505. struct passwd  *
  506. get_password(username)
  507.     char           *username;
  508. {
  509.     struct passwd  *p;
  510.     static struct passwd localp;
  511.     char           *pswd;
  512.  
  513. #ifdef SHADOW_SUPPORT
  514.     struct spwd    *sp;
  515.     int             shadowfile;
  516.  
  517. #endif
  518.  
  519. #ifdef SHADOW_SUPPORT
  520.     /*
  521.      * Check the existence of SHADOW.  If it is there, then we are
  522.      * running a two-password-file system.
  523.      */
  524.     if (access(SHADOW, 0))
  525.         shadowfile = 0;    /* SHADOW is not there */
  526.     else
  527.         shadowfile = 1;
  528.  
  529.     setpwent();
  530.     if (shadowfile)
  531.         (void) setspent();    /* Setting the shadow password
  532.                      * file */
  533.     if ((p = getpwnam(username)) == (struct passwd *)NULL ||
  534.         (shadowfile && (sp = getspnam(username)) == (struct spwd *)NULL))
  535.         return ((struct passwd *)NULL);
  536.  
  537.     if (shadowfile) {
  538.         pswd = sp->sp_pwdp;
  539.         (void) endspent();
  540.     } else
  541.         pswd = p->pw_passwd;
  542.  
  543.  
  544. #else
  545.     p = getpwnam(username);
  546.     if (p == (struct passwd *)NULL)
  547.         return ((struct passwd *)NULL);
  548.     pswd = p->pw_passwd;
  549. #endif
  550.  
  551. #ifdef INTERACTIVE_2POINT0
  552.     /* We may have an 'x' in which case look in /etc/shadow .. */
  553.     if (((strlen(pswd)) == 1) && pswd[0] == 'x') {
  554.         struct spwd    *shadow = getspnam(username);
  555.  
  556.         if (!shadow)
  557.             return ((struct passwd *)NULL);
  558.         pswd = shadow->sp_pwdp;
  559.     }
  560. #endif /* ifdef INTERACTIVE_2POINT0 */
  561.  
  562.     localp = *p;
  563.     localp.pw_passwd = pswd;
  564.     return (&localp);
  565. }
  566.  
  567.  
  568. char           *
  569. authproc(a)
  570.     struct auth_args *a;
  571. {
  572.     static struct auth_results r;
  573.     char            username[32];
  574.     char            password[64];
  575.     int             c1, c2;
  576.     struct passwd  *p;
  577.  
  578. #ifdef SHADOW_SUPPORT
  579.     struct spwd    *sp;
  580.     int             shadowfile;
  581.  
  582. #endif /* ifdef SHADOW_SUPPORT */
  583.  
  584. #ifdef USER_CACHE
  585.     int             cache_entry;;
  586. #endif /* ifdef USER_CACHE */
  587.  
  588.     r.ar_stat = AUTH_RES_FAIL;    /* assume failure */
  589.     r.ar_uid = -2;
  590.     r.ar_gid = -2;
  591.  
  592.     scramble(a->aa_ident, username);
  593.     scramble(a->aa_password, password);
  594.  
  595.     if (buggit)
  596.         (void)fprintf(stderr, "AUTHPROC username=%s\n", username);
  597.  
  598. #ifdef USER_CACHE
  599.     cache_entry = check_cache(username);
  600.     if (cache_entry >= 0) {
  601.         if (buggit)
  602.             (void)fprintf(stderr, "...cache hit?\n");
  603.         c1 = strlen(password);
  604.         c2 = strlen(User_cache[cache_entry].passwd);
  605.         if ((!c1 && !c2) ||
  606.             !(strcmp(User_cache[cache_entry].passwd,
  607.                     crypt(password, User_cache[cache_entry].passwd)))) {
  608.             if (buggit)
  609.                 (void)fprintf(stderr, "...cache hit\n");
  610.             r.ar_stat = AUTH_RES_OK;
  611.             r.ar_uid = User_cache[cache_entry].uid;
  612.             r.ar_gid = User_cache[cache_entry].gid;
  613.             return ((char *) &r);
  614.         }
  615.         User_cache[cache_entry].username[0] = '\0';    /* nuke entry */
  616.     }
  617.     if (buggit)
  618.         (void)fprintf(stderr, "...cache miss\n");
  619. #endif /* ifdef USER_CACHE */
  620.  
  621.     p = get_password(username);
  622.     if (p == (struct passwd *)NULL)
  623.         return ((char *) &r);
  624.  
  625.     c1 = strlen(password);
  626.     c2 = strlen(p->pw_passwd);
  627.     if ((c1 && !c2) || (c2 && !c1) ||
  628.         (strcmp(p->pw_passwd, crypt(password, p->pw_passwd)))) {
  629.         return ((char *) &r);
  630.     }
  631.     r.ar_stat = AUTH_RES_OK;
  632.     r.ar_uid = p->pw_uid;
  633.     r.ar_gid = p->pw_gid;
  634. #ifdef USER_CACHE
  635.     add_cache_entry(p);
  636. #endif /* ifdef USER_CACHE */
  637.     return ((char *) &r);
  638. }
  639.  
  640.  
  641. char           *
  642. pr_init(pi_arg)
  643.     struct pr_init_args *pi_arg;
  644. {
  645.     int             dir_mode = 0777;
  646.     static struct pr_init_results pi_res;
  647.  
  648.     mkdir(spoolname, dir_mode);    /* just in case, ignoring the result */
  649.     chmod(spoolname, dir_mode);
  650.  
  651.     /* get pathname of current directory and return to client */
  652.     (void)strcpy(pathname, spoolname);    /* first the spool area */
  653.     (void)strcat(pathname, "/");    /* append a slash */
  654.     (void)strcat(pathname, pi_arg->pia_client);
  655.     /* now the host name */
  656.     mkdir(pathname, dir_mode);    /* ignore the return code */
  657.     if (stat(pathname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
  658.         (void)fprintf(stderr,
  659.             "pc-nfsd: unable to create spool directory %s\n",
  660.             pathname);
  661.         pathname[0] = 0;/* null to tell client bad vibes */
  662.         pi_res.pir_stat = PI_RES_FAIL;
  663.     } else {
  664.         pi_res.pir_stat = PI_RES_OK;
  665.     }
  666.     pi_res.pir_spooldir = &pathname[0];
  667.     chmod(pathname, dir_mode);
  668.  
  669.     if (buggit)
  670.         (void)fprintf(stderr, "PR_INIT pathname=%s\n", pathname);
  671.  
  672.     return ((char *) &pi_res);
  673. }
  674.  
  675. char           *
  676. pr_start(ps_arg)
  677.     struct pr_start_args *ps_arg;
  678. {
  679.     static struct pr_start_results ps_res;
  680.     int             pid;
  681.     char            printer_opt[64];
  682.     char            jobname_opt[64];
  683.     char            clientname_opt[64];
  684.     char            snum[20];
  685. #ifdef HACK_FOR_ROTATED_TRANSCRIPT
  686.     char            scratch[512];
  687. #endif
  688.  
  689.  
  690.  
  691.     signal(SIGCHLD, free_child);    /* when child terminates it sends */
  692.     /* a signal which we must get */
  693.     (void)strcpy(pathname, spoolname);    /* build filename */
  694.     (void)strcat(pathname, "/");
  695.     (void)strcat(pathname, ps_arg->psa_client);    /* /spool/host */
  696.     (void)strcat(pathname, "/");    /* /spool/host/ */
  697.     (void)strcat(pathname, ps_arg->psa_filename);    /* /spool/host/file */
  698.  
  699.     if (buggit) {
  700.         (void)fprintf(stderr, "PR_START pathname=%s\n", pathname);
  701.         (void)fprintf(stderr, "PR_START username= %s\n", ps_arg->psa_username);
  702.         (void)fprintf(stderr, "PR_START client= %s\n", ps_arg->psa_client);
  703.     }
  704.     if (stat(pathname, &statbuf)) {
  705.         /*
  706.          * We can't stat the file. Let's try appending '.spl' and
  707.          * see if it's already in progress.
  708.          */
  709.  
  710.         if (buggit)
  711.             (void)fprintf(stderr, "...can't stat it.\n");
  712.  
  713.         (void)strcat(pathname, ".spl");
  714.         if (stat(pathname, &statbuf)) {
  715.             /*
  716.              * It really doesn't exist.
  717.              */
  718.  
  719.             if (buggit)
  720.                 (void)fprintf(stderr, "...PR_START returns PS_RES_NO_FILE\n");
  721.  
  722.             ps_res.psr_stat = PS_RES_NO_FILE;
  723.             return ((char *) &ps_res);
  724.         }
  725.         /*
  726.          * It is already on the way.
  727.          */
  728.  
  729.         if (buggit)
  730.             (void)fprintf(stderr, "...PR_START returns PS_RES_ALREADY\n");
  731.  
  732.         ps_res.psr_stat = PS_RES_ALREADY;
  733.         return ((char *) &ps_res);
  734.     }
  735.     if (statbuf.st_size == 0) {
  736.         /*
  737.          * Null file - don't print it, just kill it.
  738.          */
  739.         unlink(pathname);
  740.  
  741.         if (buggit)
  742.             (void)fprintf(stderr, "...PR_START returns PS_RES_NULL\n");
  743.  
  744.         ps_res.psr_stat = PS_RES_NULL;
  745.         return ((char *) &ps_res);
  746.     }
  747.     /*
  748.      * The file is real, has some data, and is not already going out.
  749.      * We rename it by appending '.spl' and exec "lpr" to do the
  750.      * actual work.
  751.      */
  752.     (void)strcpy(new_pathname, pathname);
  753.     (void)strcat(new_pathname, ".spl");
  754.  
  755.     if (buggit)
  756.         (void)fprintf(stderr, "...renaming %s -> %s\n", pathname, new_pathname);
  757.  
  758.     /*
  759.      * See if the new filename exists so as not to overwrite it.
  760.      */
  761.  
  762.  
  763.     if (!stat(new_pathname, &statbuf)) {
  764.         (void)strcpy(new_pathname, pathname);    /* rebuild a new name */
  765.         (void)sprintf(snum, "%d", rand());    /* get some number */
  766.         (void)strncat(new_pathname, snum, 3);
  767.         (void)strcat(new_pathname, ".spl");    /* new spool file */
  768.         if (buggit)
  769.             (void)fprintf(stderr, "...created new spl file -> %s\n", new_pathname);
  770.  
  771.     }
  772.     if (rename(pathname, new_pathname)) {
  773.         /*
  774.          * CAVEAT: Microsoft changed rename for Microsoft C V3.0.
  775.          * Check this if porting to Xenix.
  776.          */
  777.         /*
  778.          * Should never happen.
  779.          */
  780.         (void)fprintf(stderr, "pc-nfsd: spool file rename (%s->%s) failed.\n",
  781.             pathname, new_pathname);
  782.         ps_res.psr_stat = PS_RES_FAIL;
  783.         return ((char *) &ps_res);
  784.     }
  785.     pid = fork();
  786.     if (pid == 0) {
  787.         /*
  788.          * FLUKE jps 28-jul-86 - Invoke lpr as the requesting
  789.          * user.
  790.          * 
  791.          * If possible, invoke lpr under the user-id/group-id of the
  792.          * person (apparently) making this RPC request.  Good for
  793.          * accounting, proper banner page, etc.  It is not
  794.          * mandatory.
  795.          */
  796.         struct passwd  *pw = getpwnam(ps_arg->psa_username);
  797.  
  798.         if (buggit)
  799.             (void)fprintf(stderr, "username is %s\n", ps_arg->psa_username);
  800.         if (pw) {
  801.             if (buggit)
  802.                 (void)fprintf(stderr, "uid is %d\ngid is %d\n",
  803.                     pw->pw_uid, pw->pw_gid);
  804.             setregid(pw->pw_gid, pw->pw_gid);
  805.             setreuid(pw->pw_uid, pw->pw_uid);
  806.  
  807.             /*
  808.              * PC-NFS doesn't pass us any filename to show on
  809.              * the banner page, so we blank this field out.
  810.              * That's batter than showing the pseudo-random
  811.              * temporary file name used internally (or the
  812.              * UNIX-ism "(stdin)").
  813.              */
  814.             sprintf(printer_opt, "-P%s", ps_arg->psa_printername);
  815.             sprintf(jobname_opt, "-J ");
  816.             sprintf(clientname_opt, "-C%s", ps_arg->psa_client);
  817.         } else {
  818.             /*
  819.              * We don't know the user's identity, so the
  820.              * printout will end up being enqueued by root.
  821.              * We do want the user's name to appear on the
  822.              * banner page, so we slip it in via the -J
  823.              * option.
  824.              */
  825.             sprintf(printer_opt, "-P%s", ps_arg->psa_printername);
  826.             sprintf(jobname_opt, "-J%s", ps_arg->psa_username);
  827.             sprintf(clientname_opt, "-C%s", ps_arg->psa_client);
  828.         }
  829. #ifdef HACK_FOR_ROTATED_TRANSCRIPT
  830.         if (!strcmp(ps_arg->psa_printername, "rotated")) {
  831.             sprintf(scratch, "enscript -lrq -fCourier7  %s",
  832.                 new_pathname);
  833.             if (buggit)
  834.                 (void)fprintf(stderr, "system(%s)\n", scratch);
  835.             system(scratch);
  836.             unlink(new_pathname);
  837.             exit(0);
  838.         }
  839.         if (!strcmp(ps_arg->psa_printername, "2column")) {
  840.             sprintf(scratch, "enscript -2rqG -J\"PC-NFS spool file\" %s",
  841.                 new_pathname);
  842.             if (buggit)
  843.                 (void)fprintf(stderr, "system(%s)\n", scratch);
  844.             system(scratch);
  845.             unlink(new_pathname);
  846.             exit(0);
  847.         }
  848. #endif /* HACK_FOR_ROTATED_TRANSCRIPT */
  849.  
  850.         if (ps_arg->psa_options[1] == 'd') {
  851.             /*
  852.              * This is a Diablo print stream. Apply the ps630
  853.              * filter with the appropriate arguments.
  854.              */
  855.             if (buggit)
  856.                 (void)fprintf(stderr, "...run_ps630 invoked\n");
  857.             (void)run_ps630(new_pathname, ps_arg->psa_options);
  858.         }
  859.         /*
  860.          * New - let's close up 0, 1 and 2 to force getlogin to
  861.          * fail in lpr
  862.          */
  863.         close(0);
  864.         close(1);
  865.         close(2);
  866.  
  867.         execlp("/usr/ucb/lpr",
  868.             PRINT_COMMAND,
  869.             "-s",
  870.             "-r",
  871.             printer_opt,
  872.             jobname_opt,
  873.             clientname_opt,
  874.             new_pathname,
  875.             0);
  876.         perror("pc-nfsd: exec lpr failed");
  877.         exit(1);    /* end of child process */
  878.     } else if (pid == -1) {
  879.         perror("pc-nfsd: fork failed");
  880.  
  881.         if (buggit)
  882.             (void)fprintf(stderr, "...PR_START returns PS_RES_FAIL\n");
  883.  
  884.         ps_res.psr_stat = PS_RES_FAIL;
  885.     } else {
  886.  
  887.         if (buggit)
  888.             (void)fprintf(stderr, "...forked child #%d\n", pid);
  889.  
  890.  
  891.         if (buggit)
  892.             (void)fprintf(stderr, "...PR_START returns PS_RES_OK\n");
  893.  
  894.         ps_res.psr_stat = PS_RES_OK;
  895.     }
  896.     return ((char *) &ps_res);
  897. }
  898.  
  899.  
  900. char           *
  901. mapfont(f, i, b)
  902.     char            f;
  903.     char            i;
  904.     char            b;
  905. {
  906.     static char     fontname[64];
  907.  
  908.     fontname[0] = 0;    /* clear it out */
  909.  
  910.     switch (f) {
  911.     case 'c':
  912.         (void)strcpy(fontname, "Courier");
  913.         break;
  914.     case 'h':
  915.         (void)strcpy(fontname, "Helvetica");
  916.         break;
  917.     case 't':
  918.         (void)strcpy(fontname, "Times");
  919.         break;
  920.     default:
  921.         (void)strcpy(fontname, "Times-Roman");
  922.         goto finis ;
  923.     }
  924.     if (i != 'o' && b != 'b') {    /* no bold or oblique */
  925.         if (f == 't')    /* special case Times */
  926.             (void)strcat(fontname, "-Roman");
  927.         goto finis;
  928.     }
  929.     (void)strcat(fontname, "-");
  930.     if (b == 'b')
  931.         (void)strcat(fontname, "Bold");
  932.     if (i == 'o')        /* o-blique */
  933.         (void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
  934.  
  935. finis:    return (&fontname[0]);
  936. }
  937.  
  938. /*
  939.  * run_ps630 performs the Diablo 630 emulation filtering process. ps630
  940.  * was broken in certain Sun releases: it would not accept point size or
  941.  * font changes. If your version is fixed, undefine the symbol
  942.  * PS630_IS_BROKEN and rebuild pc-nfsd.
  943.  */
  944. /* #define PS630_IS_BROKEN 1 */
  945.  
  946. run_ps630(file, options)
  947.     char           *file;
  948.     char           *options;
  949. {
  950.     char            temp_file[256];
  951.     char            commbuf[256];
  952.     int             i;
  953.  
  954.     (void)strcpy(temp_file, file);
  955.     (void)strcat(temp_file, "X");    /* intermediate file name */
  956.  
  957. #ifndef PS630_IS_BROKEN
  958.     (void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
  959.         options[2], options[3], temp_file);
  960.     (void)strcat(commbuf, mapfont(options[4], options[5], options[6]));
  961.     (void)strcat(commbuf, " -F ");
  962.     (void)strcat(commbuf, mapfont(options[7], options[8], options[9]));
  963.     (void)strcat(commbuf, "  ");
  964.     (void)strcat(commbuf, file);
  965. #else    /* PS630_IS_BROKEN */
  966.     /*
  967.      * The pitch and font features of ps630 appear to be broken at
  968.      * this time.
  969.      */
  970.     sprintf(commbuf, "ps630 -p %s %s", temp_file, file);
  971. #endif    /* PS630_IS_BROKEN */
  972.  
  973.  
  974.     if (i = system(commbuf)) {
  975.         /*
  976.          * Under (un)certain conditions, ps630 may return -1 even
  977.          * if it worked. Hence the commenting out of this error
  978.          * report.
  979.          */
  980.          /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
  981.         /* exit(1); */
  982.     }
  983.     if (rename(temp_file, file)) {
  984.         perror("run_ps630: rename");
  985.         exit(1);
  986.     }
  987.     return(i); /* never used, but keeps lint happy */
  988. }
  989.  
  990. /*
  991.  * Determine if a descriptor belongs to a socket or not
  992.  */
  993. issock(fd)
  994.     int             fd;
  995. {
  996.     struct stat     st;
  997.  
  998.     if (fstat(fd, &st) < 0) {
  999.         return (0);
  1000.     }
  1001.     /*
  1002.      * SunOS returns S_IFIFO for sockets, while 4.3 returns 0 and does
  1003.      * not even have an S_IFIFO mode.  Since there is confusion about
  1004.      * what the mode is, we check for what it is not instead of what
  1005.      * it is.
  1006.      */
  1007.     switch (st.st_mode & S_IFMT) {
  1008.     case S_IFCHR:
  1009.     case S_IFREG:
  1010.     case S_IFLNK:
  1011.     case S_IFDIR:
  1012.     case S_IFBLK:
  1013.         return (0);
  1014.     default:
  1015.         return (1);
  1016.     }
  1017. }
  1018.  
  1019.  
  1020.  
  1021. #ifdef USER_CACHE
  1022. int
  1023. check_cache(name)
  1024.     char           *name;
  1025. {
  1026.     int             i;
  1027.  
  1028.     for (i = 0; i < CACHE_SIZE; i++) {
  1029.         if (!strcmp(User_cache[i].username, name))
  1030.             return (i);
  1031.     }
  1032.     return (-1);
  1033. }
  1034.  
  1035. add_cache_entry(p)
  1036.     struct passwd  *p;
  1037. {
  1038.     int             i;
  1039.  
  1040.     for (i = CACHE_SIZE - 1; i > 0; i--)
  1041.         User_cache[i] = User_cache[i - 1];
  1042.     User_cache[0].uid = p->pw_uid;
  1043.     User_cache[0].gid = p->pw_gid;
  1044.     (void)strcpy(User_cache[0].passwd, p->pw_passwd);
  1045.     (void)strcpy(User_cache[0].username, p->pw_name);
  1046. }
  1047.  
  1048.  
  1049. #endif /* ifdef USER_CACHE */
  1050.