home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / pcnfsd2.zip / pcnfsd.c < prev    next >
C/C++ Source or Header  |  1994-03-17  |  21KB  |  798 lines

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