home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / LINUX_PC.TAR / pcnfsd_linux2 / pcnfsd_misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-06  |  16.8 KB  |  806 lines

  1. /* RE_SID: @(%)/tmp_mnt/vol/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.13 93/02/08 10:18:54 SMI */
  2. /*
  3. **=====================================================================
  4. ** Copyright (c) 1986-1993 by Sun Microsystems, Inc.
  5. **    @(#)pcnfsd_misc.c    1.13    2/8/93
  6. **=====================================================================
  7. */
  8. #include "common.h"
  9. /*
  10. **=====================================================================
  11. **             I N C L U D E   F I L E   S E C T I O N                *
  12. **                                                                    *
  13. ** If your port requires different include files, add a suitable      *
  14. ** #define in the customization section, and make the inclusion or    *
  15. ** exclusion of the files conditional on this.                        *
  16. **=====================================================================
  17. */
  18. #include "pcnfsd.h"
  19.  
  20. #include <stdio.h>
  21. #include <pwd.h>
  22. #include <sys/file.h>
  23. #include <signal.h>
  24. #include <sys/time.h>
  25. #include <sys/stat.h>
  26. #include <sys/ioctl.h>
  27. #include <netdb.h>
  28. #include <errno.h>
  29. #include <string.h>
  30. #include <memory.h>
  31. #include <ctype.h>
  32.  
  33. #ifdef ISC_2_0
  34. #include <sys/fcntl.h>
  35. #endif
  36.  
  37. #ifdef SHADOW_SUPPORT
  38. #include <shadow.h>
  39. #endif
  40.  
  41. #ifdef WTMP
  42. int wtmp_enabled = 1;
  43. #endif
  44.  
  45. #ifdef USE_GETUSERSHELL
  46. extern char *getusershell();
  47. #endif
  48.  
  49. /*
  50. **---------------------------------------------------------------------
  51. ** Other #define's 
  52. **---------------------------------------------------------------------
  53. */
  54.  
  55. #define    zchar        0x5b
  56. #define NOBODY    (uid_t)(-2)
  57.  
  58. char            tempstr[256];
  59. extern char    sp_name[1024]; /* in pcnfsd_print.c */
  60.  
  61. #define    NUMUIDS    64
  62. int        uidrsize = 0;
  63. int        uidrlo[NUMUIDS];
  64. int        uidrhi[NUMUIDS];
  65. /*
  66. **=====================================================================
  67. **                      C O D E   S E C T I O N                       *                    **=====================================================================
  68. */
  69. /*
  70. **---------------------------------------------------------------------
  71. **                          Support procedures 
  72. **---------------------------------------------------------------------
  73. */
  74.  
  75. /*
  76. ** grab
  77. **
  78. ** bulletproof malloc
  79. */
  80. void *grab(n)
  81. int n;
  82. {
  83. void *p;
  84.  
  85.     p = (void *)malloc(n);
  86.     if(p == NULL) {
  87.         msg_out("rpc.pcnfsd: malloc failure");
  88.         exit(1);
  89.     }
  90.     return(p);
  91. }
  92.  
  93. char *
  94. my_strdup(s)
  95. char *s;
  96. {
  97. char *r;
  98.     r = (char *)grab(strlen(s)+1);
  99.     strcpy(r, s);
  100.     return(r);
  101. }
  102.  
  103. /*
  104. ** This is the latest word on the security check. The following
  105. ** routine "suspicious()" returns non-zero if the character string
  106. ** passed to it contains any shell metacharacters.
  107. ** Callers will typically code
  108. **
  109. **    if(suspicious(some_parameter)) reject();
  110. **
  111. ** Non-Unix-based systems: examine this carefully.
  112. **/
  113.  
  114. int suspicious (s)
  115. char *s;
  116. {
  117.     if(strpbrk(s, ";|&<>`'#!?*()[]^/") != NULL)
  118.         return 1;
  119.     return 0;
  120. }
  121.  
  122. void
  123. scramble(s1, s2)
  124. char           *s1;
  125. char           *s2;
  126. {
  127.     while (*s1) 
  128.           {
  129.           *s2++ = (*s1 ^ zchar) & 0x7f;
  130.           s1++;
  131.           }
  132.     *s2 = 0;
  133. }
  134.  
  135.  
  136. /*
  137. ** build_uid_ranges(s)
  138. */
  139. void
  140. build_uid_ranges(s)
  141. char *s;
  142. {
  143.     char *r1;
  144.     char *r2;
  145.     int v1;
  146.     int v2;
  147.  
  148.     r1 = strtok(s, " ,\t");
  149.     while(r1 && uidrsize < NUMUIDS) {
  150.         if(r2 = strchr(r1, '-')) {
  151.             *r2++ = '\0';
  152.         }
  153.         v1 = atoi(r1);
  154.         if(v1 == 0 && *r1 != '0')    /* syntax error */
  155.             continue;
  156.         if(r2) {
  157.             v2 = atoi(r2);
  158.             if(v2 == 0 && *r2 != 0)    /* syntax */
  159.                 continue;
  160.             if(v2 < v1)        /* botch */
  161.                 continue;
  162.         } else
  163.             v2 = v1;
  164.         uidrlo[uidrsize] = v1;
  165.         uidrhi[uidrsize] = v2;
  166.         uidrsize++;
  167.         r1 = strtok(NULL, " ,\t");
  168.     }
  169. }
  170. /*
  171. ** val_uid(u)
  172. **
  173. ** Return non-zero if the uid is legal - within range
  174. ** and zero otherwise.
  175. **
  176. ** If uid_range is NULL, check for 101-60002. Otherwise
  177. ** check against ranges.
  178. */
  179. int
  180. val_uid(u)
  181. int u;
  182. {
  183.     int i;
  184.  
  185.     if(uidrsize == 0)
  186.         return(u >= 101 && u <= 60002);
  187.  
  188.     for (i = 0; i < uidrsize; i++)
  189.         if (u >= uidrlo[i] && u <= uidrhi[i])
  190.             return(1);
  191.     return(0);
  192. }
  193.  
  194.  
  195. struct passwd  *
  196. get_password(usrnam, msgpp)
  197. char           *usrnam;
  198. char          **msgpp;
  199. {
  200. struct passwd  *p;
  201. static struct passwd localp;
  202. char           *pswd;
  203. char           *ushell;
  204. int        ok = 0;
  205.  
  206.  
  207. #ifdef SHADOW_SUPPORT
  208. struct spwd    *sp;
  209. int             shadowfile;
  210. long        today;
  211. long        expday;
  212. #endif
  213.  
  214. #ifdef SHADOW_SUPPORT
  215.     /*
  216.         **--------------------------------------------------------------
  217.     ** Check the existence of SHADOW.  If it is there, then we are
  218.     ** running a two-password-file system.
  219.         **--------------------------------------------------------------
  220.     */
  221.     if (access(SHADOW, 0))
  222.        shadowfile = 0;    /* SHADOW is not there */
  223.     else
  224.        shadowfile = 1;
  225.  
  226.     setpwent();
  227.     if (shadowfile)
  228.        (void) setspent();    /* Setting the shadow password
  229.                      * file */
  230.     if ((p = getpwnam(usrnam)) == (struct passwd *)NULL ||
  231.        (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *)NULL))
  232.     return ((struct passwd *)NULL);
  233.  
  234.     if (shadowfile) 
  235.            {
  236. /*
  237.  * New - check password expiry situation
  238.  *
  239.  *    compute today (as days since Jan.1 1970)
  240.  */
  241.         today = (long)time((time_t *)0)/86400;
  242. /*
  243.  *    If sp_expire is greater than zero and is less than today, the password
  244.  *    has expired.
  245.  */
  246.         if(sp->sp_expire > 0 && today > sp->sp_expire) {
  247.             *msgpp = "This account may no longer be used.";
  248.             return ((struct passwd *)NULL);
  249.         }
  250. /*
  251.  *    If sp_max is greater zero, the password will expire on
  252.  *    sp_lstchg+sp_max. If today is greater than this, it already did.
  253.  */
  254.         if(sp->sp_max > 0) {
  255.             expday = sp->sp_max+sp->sp_lstchg;
  256.             if(today > expday) {
  257.                 *msgpp = "The password for this account has expired.";
  258.                 return ((struct passwd *)NULL);
  259.             }
  260. /*
  261.  *    Next, subtract the warning period, sp_warn, from
  262.  *    expday. This is the first day on which warnings should
  263.  *    be issued. If today >= expday, set msgp, but proceed.
  264.  */
  265.             if(sp->sp_warn >= 0) {
  266.                 expday -= sp->sp_warn;
  267.                 if(today > expday) {
  268.                     *msgpp = "The password for this account will shortly expire. Please change it.";
  269.                 }
  270.             }
  271.         }
  272.        pswd = sp->sp_pwdp;
  273.        (void) endspent();
  274.        } 
  275.         else
  276.        pswd = p->pw_passwd;
  277.  
  278. #else
  279.     p = getpwnam(usrnam);
  280.     if (p == (struct passwd *)NULL)
  281.         return ((struct passwd *)NULL);
  282.     pswd = p->pw_passwd;
  283. #endif
  284.  
  285. #ifdef ISC_2_0
  286.     /* 
  287.         **-----------------------------------------------------------
  288.     ** We may have an 'x' in which case look in /etc/shadow ..
  289.         **-----------------------------------------------------------
  290.         */
  291.     if (((strlen(pswd)) == 1) && pswd[0] == 'x') 
  292.        {
  293.        struct spwd    *shadow = getspnam(usrnam);
  294.  
  295.        if (!shadow)
  296.           return ((struct passwd *)NULL);
  297.        pswd = shadow->sp_pwdp;
  298.        }
  299. #endif
  300.     localp = *p;
  301.     localp.pw_passwd = pswd;
  302. /*
  303.  * Fix SDR#pcn1857: If the shell field is null, this entry is legal
  304.  * (assuming that the default shell, "/bin/sh" is always legal).
  305.  */
  306.     if(localp.pw_shell == NULL || strlen(localp.pw_shell) == 0)
  307.         return(&localp);
  308.  
  309. #ifdef USE_GETUSERSHELL
  310.  
  311.     setusershell();
  312.     while(ushell = getusershell()){
  313.         if(!strcmp(ushell, localp.pw_shell)) {
  314.             ok = 1;
  315.             break;
  316.         }
  317.     }
  318.     endusershell();
  319.     if(!ok)
  320.         return ((struct passwd *)NULL);
  321. #else
  322. /*
  323.  * the best we can do is to ensure that the shell ends in "sh"
  324.  */
  325.     ushell = localp.pw_shell;
  326.     if((int)strlen(ushell) < 2)
  327.         return ((struct passwd *)NULL);
  328.     ushell += strlen(ushell) - 2;
  329.     if(strcmp(ushell, "sh"))
  330.         return ((struct passwd *)NULL);
  331.  
  332. #endif
  333.     if(!val_uid(localp.pw_uid)) {
  334.         *msgpp = "No access via pcnfsd to this account.";
  335.         return((struct passwd *)NULL);
  336.     }
  337.     return (&localp);
  338. }
  339.  
  340.  
  341. /*
  342. **---------------------------------------------------------------------
  343. **                      Print support procedures 
  344. **---------------------------------------------------------------------
  345. */
  346.  
  347. char           *
  348. mapfont(f, i, b)
  349.     char            f;
  350.     char            i;
  351.     char            b;
  352. {
  353.     static char     fontname[64];
  354.  
  355.     fontname[0] = 0;    /* clear it out */
  356.  
  357.     switch (f) {
  358.     case 'c':
  359.         (void)strcpy(fontname, "Courier");
  360.         break;
  361.     case 'h':
  362.         (void)strcpy(fontname, "Helvetica");
  363.         break;
  364.     case 't':
  365.         (void)strcpy(fontname, "Times");
  366.         break;
  367.     default:
  368.         (void)strcpy(fontname, "Times-Roman");
  369.         goto finis ;
  370.     }
  371.     if (i != 'o' && b != 'b') {    /* no bold or oblique */
  372.         if (f == 't')    /* special case Times */
  373.             (void)strcat(fontname, "-Roman");
  374.         goto finis;
  375.     }
  376.     (void)strcat(fontname, "-");
  377.     if (b == 'b')
  378.         (void)strcat(fontname, "Bold");
  379.     if (i == 'o')        /* o-blique */
  380.         (void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
  381.  
  382. finis:    return (&fontname[0]);
  383. }
  384.  
  385. /*
  386.  * run_ps630 performs the Diablo 630 emulation filtering process. ps630
  387.  * was broken in certain Sun releases: it would not accept point size or
  388.  * font changes. If your version is fixed, undefine the symbol
  389.  * PS630_IS_BROKEN and rebuild pc-nfsd.
  390.  */
  391. /* #define PS630_IS_BROKEN 1 */
  392.  
  393. void
  394. run_ps630(f, opts)
  395.     char           *f;
  396.     char           *opts;
  397. {
  398.     char            temp_file[256];
  399.     char            commbuf[256];
  400.     int             i;
  401.  
  402.     (void)strcpy(temp_file, f);
  403.     (void)strcat(temp_file, "X");    /* intermediate file name */
  404.  
  405. #ifndef PS630_IS_BROKEN
  406.     (void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
  407.         opts[2], opts[3], temp_file);
  408.     (void)strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
  409.     (void)strcat(commbuf, " -F ");
  410.     (void)strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
  411.     (void)strcat(commbuf, "  ");
  412.     (void)strcat(commbuf, f);
  413. #else    /* PS630_IS_BROKEN */
  414.     /*
  415.      * The pitch and font features of ps630 appear to be broken at
  416.      * this time.
  417.      */
  418.     (void)sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
  419. #endif    /* PS630_IS_BROKEN */
  420.  
  421.  
  422.     if (i = system(commbuf)) {
  423.         /*
  424.          * Under (un)certain conditions, ps630 may return -1 even
  425.          * if it worked. Hence the commenting out of this error
  426.          * report.
  427.          */
  428.          /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
  429.         /* exit(1); */
  430.     }
  431.     if (rename(temp_file, f)) {
  432.         perror("run_ps630: rename");
  433.         exit(1);
  434.     }
  435.     return;
  436. }
  437.  
  438.  
  439.  
  440.  
  441. /*
  442. **---------------------------------------------------------------------
  443. **                      WTMP update support 
  444. **---------------------------------------------------------------------
  445. */
  446.  
  447.  
  448. #ifdef WTMP
  449. #ifdef SVR4
  450.  
  451. #include <utmpx.h>
  452. #include <sac.h>
  453.  
  454. void
  455. wlogin(name)
  456.         char *name;
  457. {
  458.  
  459. extern char *getcallername();
  460.  
  461.     struct utmpx ut;
  462.  
  463.     if(!wtmp_enabled)
  464.         return;
  465.     memset((char *)&ut, 0, sizeof (ut));
  466.     ut.ut_type = USER_PROCESS;
  467.     ut.ut_id[0] = 'n';
  468.     ut.ut_id[1] = 'f';
  469.     ut.ut_id[2] = 's';
  470.     ut.ut_id[3] = SC_WILDC;
  471.         (void) strncpy(ut.ut_name,name,sizeof ut.ut_name);
  472.         (void) time (&ut.ut_tv.tv_sec);
  473.         (void) strncpy(ut.ut_host, getcallername(), sizeof ut.ut_host);
  474.     ut.ut_syslen = strlen(ut.ut_host) + 1; /* hdr file says include null */
  475.         (void) strcpy(ut.ut_line, "PC-NFS login");
  476.     (void)updwtmpx(WTMPX_FILE, &ut);
  477. }
  478.  
  479.  
  480. #else SVR4
  481.  
  482. #include <utmp.h>
  483. #define WTMP_PATH "/usr/adm/wtmp"
  484.  
  485. void
  486. wlogin(name)
  487.         char *name;
  488. {
  489.  
  490. extern char *getcallername();
  491.         struct utmp ut;
  492.  
  493.         int fd;
  494.  
  495.     if(!wtmp_enabled)
  496.         return;
  497.     memset((char *)&ut, 0, sizeof (ut));
  498.         (void) strcpy(ut.ut_line, "PC-NFS");
  499.         (void) strncpy(ut.ut_name,name,sizeof ut.ut_name);
  500.         ut.ut_time = time( (time_t *) 0);
  501.         (void) strncpy(ut.ut_host, getcallername(), sizeof ut.ut_host);
  502.         if ((fd = open(WTMP_PATH, O_WRONLY|O_APPEND, 0)) >= 0) {
  503.                 (void)write(fd, (char *)&ut, sizeof(ut));
  504.                 (void)close(fd);
  505.         }
  506. }
  507. #endif SVR4
  508. #endif WTMP
  509.  
  510. /*
  511. **---------------------------------------------------------------------
  512. **                      Run-process-as-user procedures 
  513. **---------------------------------------------------------------------
  514. */
  515.  
  516.  
  517. #define    READER_FD    0
  518. #define    WRITER_FD    1
  519.  
  520. static int      child_pid;
  521.  
  522. static char     cached_user[64] = "";
  523. static uid_t    cached_uid;
  524. static gid_t    cached_gid;
  525.  
  526. #ifndef SUNOS_403C
  527. static    struct sigaction old_action;
  528. static    struct sigaction new_action;
  529. #endif SUNOS_403C
  530. static    struct itimerval timer;
  531.  
  532. int interrupted = 0;
  533. static    FILE *pipe_handle;
  534.  
  535. static    void myhandler()
  536. {
  537.  interrupted = 1;
  538.  fclose(pipe_handle);
  539.  kill(child_pid, SIGKILL);
  540.  msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
  541. }
  542.  
  543. void start_watchdog(n)
  544. int n;
  545. {
  546.     /*
  547.      * Setup SIGALRM handler, force interrupt of ongoing syscall
  548.      */
  549.  
  550. #ifndef SUNOS_403C
  551.     new_action.sa_handler = myhandler;
  552.     sigemptyset(&(new_action.sa_mask));
  553.     new_action.sa_flags = 0;
  554. #ifdef SA_INTERRUPT
  555.     new_action.sa_flags |= SA_INTERRUPT;
  556. #endif
  557.     sigaction(SIGALRM, &new_action, &old_action);
  558. #else SUNOS_403C
  559.     signal(SIGALRM, myhandler);
  560. #endif SUNOS_403C
  561.  
  562.     /*
  563.      * Set interval timer for n seconds
  564.      */
  565.     timer.it_interval.tv_sec = 0;
  566.     timer.it_interval.tv_usec = 0;
  567.     timer.it_value.tv_sec = n;
  568.     timer.it_value.tv_usec = 0;
  569.     setitimer(ITIMER_REAL, &timer, NULL);
  570.     interrupted = 0;
  571.  
  572. }
  573.  
  574. void stop_watchdog()
  575. {
  576.     /*
  577.      * Cancel timer
  578.      */
  579.  
  580.     timer.it_interval.tv_sec = 0;
  581.     timer.it_interval.tv_usec = 0;
  582.     timer.it_value.tv_sec = 0;
  583.     timer.it_value.tv_usec = 0;
  584.     setitimer(ITIMER_REAL, &timer, NULL);
  585.  
  586.     /*
  587.       * restore old signal handling
  588.      */
  589. #ifndef SUNOS_403C
  590.     sigaction(SIGALRM, &old_action, NULL);
  591. #else SUNOS_403C
  592.     signal(SIGALRM, SIG_IGN);
  593. #endif SUNOS_403C
  594. }
  595.  
  596.  
  597.  
  598. FILE           *
  599. su_popen(user, cmd, maxtime)
  600.     char           *user;
  601.     char           *cmd;
  602.     int        maxtime;
  603. {
  604.     int             p[2];
  605.     int             parent_fd, child_fd, pid;
  606.     struct passwd *pw;
  607.     char    tmp[256];
  608.  
  609.     if (strcmp(cached_user, user)) {
  610.         pw = getpwnam(user);
  611.         if (!pw)
  612.             pw = getpwnam("nobody");
  613.         if (pw) {
  614.             cached_uid = pw->pw_uid;
  615.             cached_gid = pw->pw_gid;
  616.             strcpy(cached_user, user);
  617.         } else {
  618.             cached_uid = NOBODY;
  619.             cached_gid = (gid_t) NOBODY;
  620.             cached_user[0] = '\0';
  621.         }
  622.     }
  623.     if(cached_uid != NOBODY && !val_uid((int)cached_uid)) {
  624.         sprintf(tmp, "rpc.pcnfsd: rejecting request from user %s (uid %d)",
  625.             user, (int)cached_uid);
  626.         msg_out(tmp);
  627.         return(NULL);
  628.     };
  629.     if (pipe(p) < 0) {
  630.         msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
  631.         return (NULL);
  632.     }
  633.     parent_fd = p[READER_FD];
  634.     child_fd = p[WRITER_FD];
  635.     if ((pid = fork()) == 0) {
  636.         int             i;
  637.  
  638.         for (i = 0; i < 10; i++)
  639.             if (i != child_fd)
  640.                 (void) close(i);
  641.         if (child_fd != 1) {
  642.             (void) dup2(child_fd, 1);
  643.             (void) close(child_fd);
  644.         }
  645.         dup2(1, 2);    /* let's get stderr as well */
  646.  
  647.         (void) setgid(cached_gid);
  648.         (void) setuid(cached_uid);
  649.  
  650.         (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
  651.         _exit(255);
  652.     }
  653.     if (pid == -1) {
  654.         msg_out("rpc.pcnfsd: fork failed");
  655.         close(parent_fd);
  656.         close(child_fd);
  657.         return (NULL);
  658.     }
  659.     child_pid = pid;
  660.     close(child_fd);
  661.     start_watchdog(maxtime);
  662.     pipe_handle = fdopen(parent_fd, "r");
  663.     return (pipe_handle);
  664. }
  665.  
  666. int
  667. su_pclose(ptr)
  668.     FILE           *ptr;
  669. {
  670.     int             pid, status;
  671.  
  672.     stop_watchdog();
  673.  
  674.     fclose(ptr);
  675.     if (child_pid == -1)
  676.         return (-1);
  677.     while ((pid = wait(&status)) != child_pid && pid != -1);
  678.     return (pid == -1 ? -1 : status);
  679. }
  680.  
  681.  
  682. /*
  683. ** The following routine reads a file "/etc/pcnfsd.conf" if present,
  684. ** and uses it to replace certain builtin elements, like the
  685. ** name of the print spool directory. The configuration file
  686. ** Is the usual kind: Comments begin with '#', blank lines are ignored,
  687. ** and valid lines are of the form
  688. **
  689. **    <keyword><whitespace><value>
  690. **
  691. ** The following keywords are recognized:
  692. **
  693. **    spooldir dirname
  694. **    printer name alias-for command
  695. **    wtmp yes|no
  696. */
  697. void
  698. config_from_file()
  699. {
  700. FILE *fd;
  701. char buff[1024];
  702. char *cp;
  703. char *kw;
  704. char *val;
  705. char *arg1;
  706. char *arg2;
  707.  
  708.     if((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
  709.         return;
  710.     while(fgets(buff, 1024, fd)) {
  711.         cp = strchr(buff, '\n');
  712.         *cp = '\0';
  713.         cp = strchr(buff, '#');
  714.         if(cp)
  715.             *cp = '\0';
  716.         kw = strtok(buff, " \t");
  717.         if(kw == NULL)
  718.             continue;
  719.         val = strtok(NULL, " \t");
  720.         if(val == NULL)
  721.             continue;
  722.         if(!mystrcasecmp(kw, "spooldir")) {
  723.             strcpy(sp_name, val);
  724.             continue;
  725.         }
  726.         if(!mystrcasecmp(kw, "uidrange")) {
  727.             build_uid_ranges(val);
  728.             continue;
  729.         }
  730. #ifdef WTMP
  731.         if(!mystrcasecmp(kw, "wtmp")) {
  732.             /* assume default is YES, just look for negatives */
  733.             if(!mystrcasecmp(val, "no") ||
  734.                !mystrcasecmp(val, "off") ||
  735.                !mystrcasecmp(val, "disable") ||
  736.                !strcmp(val, "0"))
  737.                 wtmp_enabled = 0;;
  738.             continue;
  739.         }
  740. #endif    
  741.         if(!mystrcasecmp(kw, "printer")) {
  742.             arg1 = strtok(NULL, " \t");
  743.             arg2 = (arg1 == NULL ? NULL : strtok(NULL, ""));
  744.             (void)add_printer_alias(val, arg1, arg2);
  745.             continue;
  746.         }
  747. /*
  748. ** Add new cases here
  749. */
  750.     }
  751.     fclose(fd);
  752. }
  753.  
  754.  
  755. /*
  756. ** The following are replacements for the SunOS library
  757. ** routines strcasecmp and strncasecmp, which SVR4 doesn't
  758. ** include.
  759. **
  760.  * The following is introduced - regretfully - to deal with the broken
  761.  * toupper/tolower in libc
  762.  */
  763. static int ToUpper(c)
  764. char c;
  765. {
  766.     return(islower(c) ? toupper(c) : c);
  767. }
  768.  
  769. int mystrcasecmp(s1, s2)
  770.     char *s1, *s2;
  771. {
  772.  
  773.     while (ToUpper(*s1) == ToUpper(*s2++))
  774.         if (*s1++ == '\0')
  775.             return(0);
  776.     return(ToUpper(*s1) - ToUpper(*--s2));
  777. }
  778.  
  779. int mystrncasecmp(s1, s2, n)
  780.     char *s1, *s2;
  781.     int n;
  782. {
  783.  
  784.     while (--n >= 0 && ToUpper(*s1) == ToUpper(*s2++))
  785.         if (*s1++ == '\0')
  786.             return(0);
  787.     return(n <= 0 ? 0 : ToUpper(*s1) - ToUpper(*--s2));
  788. }
  789.  
  790.  
  791. /*
  792. ** strembedded - returns true if s1 is embedded (in any case) in s2
  793. */
  794.  
  795. int strembedded(s1, s2)
  796. char *s1;
  797. char *s2;
  798. {
  799.     while(*s2) {
  800.         if(!mystrcasecmp(s1, s2))
  801.             return 1;
  802.         s2++;
  803.     }
  804.     return 0;
  805. }
  806.