home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / pcnfsd2.zip / pcnfsd.c.orig < prev    next >
Text File  |  1994-02-12  |  19KB  |  734 lines

  1. #ifdef sccs
  2. static char     sccsid[] = "@(#)pcnfsd.c    1.4";
  3.  
  4. #endif
  5.  
  6. /*
  7.  * Copyright (c) 1986 by Sun Microsystems, Inc. 
  8.  */
  9.  
  10. /*
  11.  * pcnfsd.c 
  12.  *
  13.  * pcnfsd is intended to remedy the lack of certain critical generic network
  14.  * services by providing an simple, customizable set of RPC-based
  15.  * mechanisms. For this reason, Sun Microsystems Inc. is distributing it
  16.  * in source form as part of the PC-NFS release. 
  17.  *
  18.  * Background: The first NFS networks were composed of systems running
  19.  * derivatives of the 4.2BSD release of Unix (Sun's, VAXes, Goulds and
  20.  * Pyramids). The immediate utility of the resulting networks was derived
  21.  * not only from NFS but also from the availability of a number of TCP/IP
  22.  * based network services derived from 4.2BSD. Furthermore the thorny
  23.  * question of network-wide user authentication, while remaining a
  24.  * security hole, was solved at least in terms of a convenient usage model
  25.  * by the Yellow Pages distributed data base facility, which allows
  26.  * multiple Unix systems to refer to common password and group files. 
  27.  *
  28.  * The PC-NFS Dilemma: When Sun Microsystems Inc. ported NFS to PC's, two
  29.  * things became apparent. First, the memory constraints of the typical PC
  30.  * meant that it would be impossible to incorporate the pervasive TCP/IP
  31.  * based service suite in a resident fashion. Indeed it was not at all
  32.  * clear that the 4.2BSD services would prove sufficient: with the advent
  33.  * of Unix System V and (experimental) VAX-VMS NFS implementations, we had
  34.  * to consider the existence of networks with no BSD-derived Unix hosts.
  35.  * The two key types of functionality we needed to provide were remote
  36.  * login and print spooling. The second critical issue  was that of user
  37.  * authentication. Traditional time-sharing systems such as Unix and VMS
  38.  * have well- established user authentication mechanisms based upon user
  39.  * id's and passwords: by defining appropriate mappings, these could
  40.  * suffice for network-wide authentication provided that appropriate
  41.  * administrative procedures were enforced. The PC, however, is typically
  42.  * a single-user system, and the standard DOS operating environment
  43.  * provides no user authentication mechanisms. While this is acceptable
  44.  * within a single PC, it causes problems when attempting to connect to a
  45.  * heterogeneous network of systems in which access control, file space
  46.  * allocation, and print job accounting and routing may all be based upon
  47.  * a user's identity. The initial (and default) approach is to use the
  48.  * pseudo-identity 'nobody' defined as part of NFS to handle problems such
  49.  * as this. However, taking ease of use into consideration, it became
  50.  * necessary to provide a mechanism for establishing a user's identity. 
  51.  *
  52.  * Initially we felt that we needed to implement two types of functionality:
  53.  * user authentication and print spooling. (Remote login is addressed by
  54.  * the Telnet module.) Since no network services were defined within the
  55.  * NFS architecture to support these, it was decided to implement them in
  56.  * a fairly portable fashion using Sun's Remote Procedure Call protocol.
  57.  * Since these mechanisms will need to be re-implemented ion a variety of
  58.  * software environments, we have tried to define a very general model. 
  59.  *
  60.  * Authentication: NFS adopts the Unix model of using a pair of integers
  61.  * (uid, gid) to define a user's identity. This happens to map tolerably
  62.  * well onto the VMS system. 'pcnfsd' implements a Remote Procedure which
  63.  * is required to map a username and password into a (uid, gid) pair.
  64.  * Since we cannot predict what mapping is to be performed, and since we
  65.  * do not wish to pass clear-text passwords over the net, both the
  66.  * username and the password are mildly scrambled using a simple XOR
  67.  * operation. The intent is not to be secure (the present NFS architecture
  68.  * is inherently insecure) but to defeat "browsers". 
  69.  *
  70.  * The authentication RPC will be invoked when the user enters the PC-NFS
  71.  * command: 
  72.  *
  73.  * NET NAME user [password|*] 
  74.  *
  75.  *
  76.  * Printing: The availability of NFS file operations simplifies the print
  77.  * spooling mechanisms. There are two services which 'pcnfsd' has to
  78.  * provide:
  79.  *   pr_init:    given the name of the client system, return the
  80.  * name of a directory which is exported via NFS and in which the client
  81.  * may create spool files.
  82.  *  pr_start: given a file name, a user name, the printer name, the client
  83.  * system name and an option string, initiate printing of the file
  84.  * on the named printer. The file name is relative to the directory
  85.  * returned by pr_init. pr_start is to be "idempotent": a request to print
  86.  * a file which is already being printed has no effect. 
  87.  *
  88.  * Intent: The first versions of these procedures are implementations for Sun
  89.  * 2.0/3.0 software, which will also run on VAX 4.2BSD systems. The intent
  90.  * is to build up a set of implementations for different architectures
  91.  * (Unix System V, VMS, etc.). Users are encouraged to submit their own
  92.  * variations for redistribution. If you need a particular variation which
  93.  * you don't see here, either code it yourself (and, hopefully, send it to
  94.  * us at Sun) or contact your Customer Support representative. 
  95.  */
  96.  
  97. #include <sys/types.h>
  98. #include <stdio.h>
  99. #ifdef SHADOWPWD
  100. #include <shadow.h>
  101. #include <shadow/pwauth.h>
  102. #else
  103. #include <pwd.h>
  104. #endif
  105. #include <rpc/rpc.h>
  106. #include <sys/file.h>
  107. #include <signal.h>
  108. #include <sys/stat.h>
  109.  
  110. /*  #define DEBUG 1  */
  111.  
  112. #ifdef DEBUG
  113. int             buggit = 0;
  114.  
  115. #endif DEBUG
  116.  
  117. #ifdef LINUX
  118. #   define LP_SPOOL    "/usr/spool/lpd/pcnfs"
  119. #   define LP_BIN    "/usr/bin/lpr"
  120. #else
  121. #   define LP_SPOOL    "/usr/spool/lp"
  122. #   define LP_BIN    "/usr/ucb/lpr"
  123. #endif
  124.  
  125.  
  126. /*
  127.  * *************** RPC parameters ******************** 
  128.  */
  129. #define    PCNFSDPROG    (long)150001
  130. #define    PCNFSDVERS    (long)1
  131. #define    PCNFSD_AUTH    (long)1
  132. #define    PCNFSD_PR_INIT    (long)2
  133. #define    PCNFSD_PR_START    (long)3
  134.  
  135. /*
  136.  * ************* Other #define's ********************** 
  137.  */
  138. #ifndef MAXPATHLEN
  139. #define MAXPATHLEN 1024
  140. #endif
  141. #define    zchar        0x5b
  142.  
  143. /*
  144.  * *********** XDR structures, etc. ******************** 
  145.  */
  146. enum arstat {
  147.     AUTH_RES_OK, AUTH_RES_FAKE, AUTH_RES_FAIL
  148. };
  149. enum pirstat {
  150.     PI_RES_OK, PI_RES_NO_SUCH_PRINTER, PI_RES_FAIL
  151. };
  152. enum psrstat {
  153.     PS_RES_OK, PS_RES_ALREADY, PS_RES_NULL, PS_RES_NO_FILE,
  154.     PS_RES_FAIL
  155. };
  156.  
  157. struct auth_args {
  158.     char           *aa_ident;
  159.     char           *aa_password;
  160. };
  161.  
  162. struct auth_results {
  163.     enum arstat     ar_stat;
  164.     long            ar_uid;
  165.     long            ar_gid;
  166. };
  167.  
  168. struct pr_init_args {
  169.     char           *pia_client;
  170.     char           *pia_printername;
  171. };
  172.  
  173. struct pr_init_results {
  174.     enum pirstat    pir_stat;
  175.     char           *pir_spooldir;
  176. };
  177.  
  178. struct pr_start_args {
  179.     char           *psa_client;
  180.     char           *psa_printername;
  181.     char           *psa_username;
  182.     char           *psa_filename;    /* within the spooldir */
  183.     char           *psa_options;
  184. };
  185.  
  186. struct pr_start_results {
  187.     enum psrstat    psr_stat;
  188. };
  189.  
  190.  
  191. /*
  192.  * ****************** Misc. ************************ 
  193.  */
  194.  
  195. char           *authproc();
  196. char           *pr_start();
  197. char           *pr_init();
  198. struct stat     statbuf;
  199.  
  200. char            pathname[MAXPATHLEN];
  201. char            new_pathname[MAXPATHLEN];
  202. char            spoolname[MAXPATHLEN];
  203.  
  204. /*
  205.  * ************** Support procedures *********************** 
  206.  */
  207. scramble(s1, s2)
  208.     char           *s1;
  209.     char           *s2;
  210. {
  211.     while (*s1) {
  212.         *s2++ = (*s1 ^ zchar) & 0x7f;
  213.         s1++;
  214.     }
  215.     *s2 = 0;
  216. }
  217.  
  218. free_child()
  219. {
  220.     int             pid;
  221.     int             pstatus;
  222.  
  223.     pid = wait(&pstatus);    /* clear exit of child process */
  224.  
  225. #ifdef DEBUG
  226.     if (buggit || pstatus)
  227.         fprintf(stderr, "FREE_CHILD: process #%d exited with status 0X%x\r\n",
  228.             pid, pstatus);
  229. #endif DEBUG
  230.     return;
  231. }
  232.  
  233. /*
  234.  * *************** XDR procedures ***************** 
  235.  */
  236. bool_t
  237. xdr_auth_args(xdrs, aap)
  238.     XDR            *xdrs;
  239.     struct auth_args *aap;
  240. {
  241.     return (xdr_string(xdrs, &aap->aa_ident, 32) &&
  242.         xdr_string(xdrs, &aap->aa_password, 64));
  243. }
  244.  
  245. bool_t
  246. xdr_auth_results(xdrs, arp)
  247.     XDR            *xdrs;
  248.     struct auth_results *arp;
  249. {
  250.     return (xdr_enum(xdrs, &arp->ar_stat) &&
  251.         xdr_long(xdrs, &arp->ar_uid) &&
  252.         xdr_long(xdrs, &arp->ar_gid));
  253. }
  254.  
  255. bool_t
  256. xdr_pr_init_args(xdrs, aap)
  257.     XDR            *xdrs;
  258.     struct pr_init_args *aap;
  259. {
  260.     return (xdr_string(xdrs, &aap->pia_client, 64) &&
  261.         xdr_string(xdrs, &aap->pia_printername, 64));
  262. }
  263.  
  264. bool_t
  265. xdr_pr_init_results(xdrs, arp)
  266.     XDR            *xdrs;
  267.     struct pr_init_results *arp;
  268. {
  269.     return (xdr_enum(xdrs, &arp->pir_stat) &&
  270.         xdr_string(xdrs, &arp->pir_spooldir, 255));
  271. }
  272.  
  273. bool_t
  274. xdr_pr_start_args(xdrs, aap)
  275.     XDR            *xdrs;
  276.     struct pr_start_args *aap;
  277. {
  278.     return (xdr_string(xdrs, &aap->psa_client, 64) &&
  279.         xdr_string(xdrs, &aap->psa_printername, 64) &&
  280.         xdr_string(xdrs, &aap->psa_username, 64) &&
  281.         xdr_string(xdrs, &aap->psa_filename, 64) &&
  282.         xdr_string(xdrs, &aap->psa_options, 64));
  283. }
  284.  
  285. bool_t
  286. xdr_pr_start_results(xdrs, arp)
  287.     XDR            *xdrs;
  288.     struct pr_start_results *arp;
  289. {
  290.     return (xdr_enum(xdrs, &arp->psr_stat));
  291. }
  292.  
  293.  
  294.  
  295. /*
  296.  * ********************** main ********************* 
  297.  */
  298.  
  299. main(argc, argv)
  300.     int             argc;
  301.     char          **argv;
  302. {
  303.     int             f1, f2, f3;
  304.  
  305.         extern          xdr_string_array();
  306.  
  307.     if (fork() == 0) {
  308.         if (argc < 2)
  309.             strcpy(spoolname, LP_SPOOL);
  310.         else
  311.             strcpy(spoolname, argv[1]);
  312. #ifdef DEBUG
  313.         if (argc > 2)
  314.             buggit++;
  315. #endif DEBUG
  316.  
  317.         if (stat(spoolname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
  318.             fprintf(stderr,
  319.                 "pcnfsd: invalid spool directory %s\r\n", spoolname);
  320.             exit(1);
  321.         }
  322.  
  323. /*  Comment out for now
  324.  
  325.         if ((f1 = open("/dev/null", O_RDONLY)) == -1) {
  326.             fprintf(stderr, "pcnfsd: couldn't open /dev/null\r\n");
  327.             exit(1);
  328.         }
  329.         if ((f2 = open("/dev/console", O_WRONLY)) == -1) {
  330.             fprintf(stderr, "pcnfsd: couldn't open /dev/console\r\n");
  331.             exit(1);
  332.         }
  333.         if ((f3 = open("/dev/console", O_WRONLY)) == -1) {
  334.             fprintf(stderr, "pcnfsd: couldn't open /dev/console\r\n");
  335.             exit(1);
  336.         }
  337.         dup2(f1, 0);
  338.         dup2(f2, 1);
  339.         dup2(f3, 2);
  340.         
  341. end of commented out stuff */
  342.  
  343.         registerrpc(PCNFSDPROG, PCNFSDVERS, PCNFSD_AUTH, authproc,
  344.             xdr_auth_args, xdr_auth_results);
  345.         registerrpc(PCNFSDPROG, PCNFSDVERS, PCNFSD_PR_INIT, pr_init,
  346.             xdr_pr_init_args, xdr_pr_init_results);
  347.         registerrpc(PCNFSDPROG, PCNFSDVERS, PCNFSD_PR_START, pr_start,
  348.             xdr_pr_start_args, xdr_pr_start_results);
  349.         svc_run();
  350.         fprintf(stderr, "pcnfsd: error: svc_run returned\r\n");
  351.         exit(1);
  352.     }
  353.     
  354. }
  355.  
  356. /*
  357.  * ******************* RPC procedures ************** 
  358.  */
  359.  
  360. char           *
  361. authproc(a)
  362.     struct auth_args *a;
  363. {
  364.     static struct auth_results r;
  365.     char            username[32];
  366.     char            password[64];
  367.     int             c1, c2;
  368.     struct passwd  *p;
  369. #ifdef SHADOWPWD
  370.     struct spwd *spwd;
  371. #endif
  372.  
  373.     r.ar_stat = AUTH_RES_FAIL;    /* assume failure */
  374.     scramble(a->aa_ident, username);
  375.     scramble(a->aa_password, password);
  376.  
  377. #ifdef DEBUG
  378.     if (buggit)
  379.         fprintf(stderr, "AUTHPROC username=%s\r\n", username);
  380. #endif DEBUG
  381.  
  382.     p = getpwnam(username);
  383.     if (p == NULL)
  384.         return ((char *) &r);
  385. #ifdef SHADOWPWD
  386.     if (!(spwd = getspnam(username)))
  387.         return ((char *) &r);
  388.     else
  389.         p->pw_passwd = spwd->sp_pwdp;
  390.  
  391.     if (p->pw_name && p->pw_passwd[0] == '@') {
  392.         if (pw_auth(p->pw_passwd+1, username, PW_LOGIN))
  393.             return ((char *) &r);
  394.     } else {
  395.         if (!valid(password, p))
  396.             return ((char *) &r);
  397.     }
  398. #else
  399.     c1 = strlen(password);
  400.     c2 = strlen(p->pw_passwd);
  401.     if ((c1 && !c2) || (c2 && !c1) ||
  402.         (strcmp(p->pw_passwd, crypt(password, p->pw_passwd)))) {
  403.         return ((char *) &r);
  404.     }
  405. #endif
  406.     r.ar_stat = AUTH_RES_OK;
  407.     r.ar_uid = p->pw_uid;
  408.     r.ar_gid = p->pw_gid;
  409.     return ((char *) &r);
  410. }
  411.  
  412.  
  413. char           *
  414. pr_init(pi_arg)
  415.     struct pr_init_args *pi_arg;
  416. {
  417.     int             dir_mode = 0777;
  418.     static struct pr_init_results pi_res;
  419.  
  420.     /* get pathname of current directory and return to client */
  421.     strcpy(pathname, spoolname);    /* first the spool area */
  422.     strcat(pathname, "/");    /* append a slash */
  423.     strcat(pathname, pi_arg->pia_client);
  424.     /* now the host name */
  425.  
  426.     mkdir(pathname, dir_mode);    /* ignore the return code */
  427.  
  428.     if (stat(pathname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
  429.         fprintf(stderr,
  430.             "pcnfsd: unable to create spool directory %s\r\n",
  431.             pathname);
  432.         pathname[0] = 0;/* null to tell client bad vibes */
  433.         pi_res.pir_stat = PI_RES_FAIL;
  434.     } else {
  435.         pi_res.pir_stat = PI_RES_OK;
  436.     }
  437.     pi_res.pir_spooldir = &pathname[0];
  438.     chmod(pathname, dir_mode);
  439.  
  440. #ifdef DEBUG
  441.     if (buggit)
  442.         fprintf(stderr, "PR_INIT pathname=%s\r\n", pathname);
  443. #endif DEBUG
  444.  
  445.     return ((char *) &pi_res);
  446. }
  447.  
  448. char           *
  449. pr_start(ps_arg)
  450.     struct pr_start_args *ps_arg;
  451. {
  452.     static struct pr_start_results ps_res;
  453.     int             pid;
  454.     int             free_child();
  455.     char            printer_opt[64];
  456.     char            username_opt[64];
  457.     char            clientname_opt[64];
  458.     struct passwd  *p;
  459.     long        rnum;
  460.     char        snum[20];
  461.     int        z;
  462.  
  463.     strcpy(printer_opt, "-P");
  464.     strcpy(username_opt, "-J");
  465.     strcpy(clientname_opt, "-C");
  466.  
  467.     signal(SIGCHLD, free_child);    /* when child terminates it sends */
  468.     /* a signal which we must get */
  469.     strcpy(pathname, spoolname);    /* build filename */
  470.     strcat(pathname, "/");
  471.     strcat(pathname, ps_arg->psa_client);    /* /spool/host */
  472.     strcat(pathname, "/");    /* /spool/host/ */
  473.     strcat(pathname, ps_arg->psa_filename);    /* /spool/host/file */
  474.  
  475. #ifdef DEBUG
  476.     if (buggit) {
  477.         fprintf(stderr, "PR_START pathname=%s\r\n", pathname);
  478.         fprintf(stderr, "PR_START username= %s\r\n", ps_arg->psa_username);
  479.         fprintf(stderr, "PR_START client= %s\r\n", ps_arg->psa_client);
  480.     }
  481. #endif DEBUG
  482.  
  483.     strcat(printer_opt, ps_arg->psa_printername);
  484.     /* make it (e.g.) -Plw     */
  485.     strcat(username_opt, ps_arg->psa_username);
  486.     /* make it (e.g.) -Jbilly     */
  487.     strcat(clientname_opt, ps_arg->psa_client);
  488.     /* make it (e.g.) -Cmypc     */
  489.  
  490.     if (stat(pathname, &statbuf)) {
  491.         /*
  492.          * We can't stat the file. Let's try appending '.spl' and
  493.          * see if it's already in progress. 
  494.          */
  495.  
  496. #ifdef DEBUG
  497.         if (buggit)
  498.             fprintf(stderr, "...can't stat it.\r\n");
  499. #endif DEBUG
  500.  
  501.         strcat(pathname, ".spl");
  502.         if (stat(pathname, &statbuf)) {
  503.             /*
  504.              * It really doesn't exist. 
  505.              */
  506.  
  507. #ifdef DEBUG
  508.             if (buggit)
  509.                 fprintf(stderr, "...PR_START returns PS_RES_NO_FILE\r\n");
  510. #endif DEBUG
  511.  
  512.             ps_res.psr_stat = PS_RES_NO_FILE;
  513.             return ((char *) &ps_res);
  514.         }
  515.         /*
  516.          * It is already on the way. 
  517.          */
  518.  
  519. #ifdef DEBUG
  520.         if (buggit)
  521.             fprintf(stderr, "...PR_START returns PS_RES_ALREADY\r\n");
  522. #endif DEBUG
  523.  
  524.         ps_res.psr_stat = PS_RES_ALREADY;
  525.         return ((char *) &ps_res);
  526.     }
  527.     if (statbuf.st_size == 0) {
  528.         /*
  529.          * Null file - don't print it, just kill it. 
  530.          */
  531.         unlink(pathname);
  532.  
  533. #ifdef DEBUG
  534.         if (buggit)
  535.             fprintf(stderr, "...PR_START returns PS_RES_NULL\r\n");
  536. #endif DEBUG
  537.  
  538.         ps_res.psr_stat = PS_RES_NULL;
  539.         return ((char *) &ps_res);
  540.     }
  541.     /*
  542.      * The file is real, has some data, and is not already going out.
  543.      * We rename it by appending '.spl' and exec "lpr" to do the
  544.      * actual work. 
  545.      */
  546.     strcpy(new_pathname, pathname);
  547.     strcat(new_pathname, ".spl");
  548.  
  549. #ifdef DEBUG
  550.     if (buggit)
  551.         fprintf(stderr, "...renaming %s -> %s\r\n", pathname, new_pathname);
  552. #endif DEBUG
  553.  
  554.     /*
  555.      * See if the new filename exists so as not to overwrite it.
  556.      */
  557.  
  558.  
  559.     for(z = 0; z <100; z++) {
  560.         if (!stat(new_pathname, &statbuf)){
  561.             strcpy(new_pathname, pathname);  /* rebuild a new name */
  562.             sprintf(snum,"%ld",random());        /* get some number */
  563.             strncat(new_pathname, snum, 3);
  564.             strcat(new_pathname, ".spl");        /* new spool file */
  565. #ifdef DEBUG
  566.             if (buggit)
  567.                 fprintf(stderr, "...created new spl file -> %s\r\n", new_pathname);
  568.  
  569. #endif DEBUG
  570.         } else
  571.             break;
  572.     }
  573.         
  574.  
  575.     if (rename(pathname, new_pathname)) {
  576.         /*
  577.          * CAVEAT: Microsoft changed rename for Microsoft C V3.0.
  578.          * Check this if porting to Xenix. 
  579.          */
  580.         /*
  581.          * Should never happen. 
  582.          */
  583.         fprintf(stderr, "pcnfsd: spool file rename (%s->%s) failed.\r\n",
  584.             pathname, new_pathname);
  585.         ps_res.psr_stat = PS_RES_FAIL;
  586.         return ((char *) &ps_res);
  587.     }
  588.     pid = fork();
  589.     if (pid == 0) {
  590. #ifdef DEBUG
  591.         if (buggit)
  592.             fprintf(stderr, "...print options =%s\r\n", ps_arg->psa_options);
  593. #endif DEBUG
  594.         
  595.         if (ps_arg->psa_options[1] == 'd') {
  596.             /*
  597.              * This is a Diablo print stream. Apply the ps630
  598.              * filter with the appropriate arguments. 
  599.              */
  600. #ifdef DEBUG
  601.             if (buggit)
  602.                 fprintf(stderr, "...run_ps630 invoked\r\n");
  603. #endif DEBUG
  604.             run_ps630(new_pathname, ps_arg->psa_options);
  605.         }
  606.         execlp(LP_BIN,
  607.             "lpr",
  608.             "-s",
  609.             "-r",
  610.             printer_opt,
  611.             username_opt,
  612.             clientname_opt,
  613.             new_pathname,
  614.             0);
  615.         perror("pcnfsd: exec lpr failed");
  616.         exit(0);    /* end of child process */
  617.     } else if (pid == -1) {
  618.         perror("pcnfsd: fork failed");
  619.  
  620. #ifdef DEBUG
  621.         if (buggit)
  622.             fprintf(stderr, "...PR_START returns PS_RES_FAIL\r\n");
  623. #endif DEBUG
  624.  
  625.         ps_res.psr_stat = PS_RES_FAIL;
  626.         return ((char *) &ps_res);
  627.     } else {
  628.  
  629. #ifdef DEBUG
  630.         if (buggit)
  631.             fprintf(stderr, "...forked child #%d\r\n", pid);
  632. #endif DEBUG
  633.  
  634.  
  635. #ifdef DEBUG
  636.         if (buggit)
  637.             fprintf(stderr, "...PR_START returns PS_RES_OK\r\n");
  638. #endif DEBUG
  639.  
  640.         ps_res.psr_stat = PS_RES_OK;
  641.         return ((char *) &ps_res);
  642.     }
  643. }
  644.  
  645. char           *
  646. mapfont(f, i, b)
  647.     char            f;
  648.     char            i;
  649.     char            b;
  650. {
  651.     static char     fontname[64];
  652.  
  653.     fontname[0] = 0;    /* clear it out */
  654.  
  655.     switch (f) {
  656.     case 'c':
  657.         strcpy(fontname, "Courier");
  658.         break;
  659.     case 'h':
  660.         strcpy(fontname, "Helvetica");
  661.         break;
  662.     case 't':
  663.         strcpy(fontname, "Times");
  664.         break;
  665.     default:
  666.         strcpy(fontname, "Times-Roman");
  667.         goto exit;
  668.     }
  669.     if (i != 'o' && b != 'b') {    /* no bold or oblique */
  670.         if (f == 't')    /* special case Times */
  671.             strcat(fontname, "-Roman");
  672.         goto exit;
  673.     }
  674.     strcat(fontname, "-");
  675.     if (b == 'b')
  676.         strcat(fontname, "Bold");
  677.     if (i == 'o')        /* o-blique */
  678.         strcat(fontname, f == 't' ? "Italic" : "Oblique");
  679.  
  680. exit:    return (&fontname[0]);
  681. }
  682.  
  683. /*
  684.  * run_ps630 performs the Diablo 630 emulation filtering process. ps630 is
  685.  * currently broken in the Sun release: it will not accept point size or
  686.  * font changes. If your version is fixed, define the symbol
  687.  * PS630_IS_FIXED and rebuild pcnfsd. 
  688.  */
  689.  
  690.  
  691. run_ps630(file, options)
  692.     char           *file;
  693.     char           *options;
  694. {
  695.     char            tmpfile[256];
  696.     char            commbuf[256];
  697.     int             i;
  698.  
  699.     strcpy(tmpfile, file);
  700.     strcat(tmpfile, "X");    /* intermediate file name */
  701.  
  702. #ifdef PS630_IS_FIXED
  703.     sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
  704.         options[2], options[3], tmpfile);
  705.     strcat(commbuf, mapfont(options[4], options[5], options[6]));
  706.     strcat(commbuf, " -F ");
  707.     strcat(commbuf, mapfont(options[7], options[8], options[9]));
  708.     strcat(commbuf, "  ");
  709.     strcat(commbuf, file);
  710. #else PS630_IS_FIXED
  711.     /*
  712.      * The pitch and font features of ps630 appear to be broken at
  713.      * this time. If you think it's been fixed at your site, define
  714.      * the compile-time symbol `ps630_is_fixed'. 
  715.      */
  716.     sprintf(commbuf, "/usr/local/bin/ps630 -p %s %s", tmpfile, file);
  717. #endif PS630_IS_FIXED
  718.  
  719.  
  720.     if (i = system(commbuf)) {
  721.         /*
  722.          * Under (un)certain conditions, ps630 may return -1
  723.          * even if it worked. Hence the commenting out of this
  724.          * error report. 
  725.          */
  726.          /* fprintf(stderr, "\r\n\nrun_ps630 rc = %d\r\n", i) */ ;
  727.         /* exit(1); */
  728.     }
  729.     if (rename(tmpfile, file)) {
  730.         perror("run_ps630: rename");
  731.         exit(1);
  732.     }
  733. }
  734.