home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / chkconf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  15.7 KB  |  730 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/chkconf.c
  3.  *   Copyright (C) 1993 Darren Reed
  4.  *
  5.  *   This program is free software; you can redistribute it and/or modify
  6.  *   it under the terms of the GNU General Public License as published by
  7.  *   the Free Software Foundation; either version 1, or (at your option)
  8.  *   any later version.
  9.  *
  10.  *   This program is distributed in the hope that it will be useful,
  11.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *   GNU General Public License for more details.
  14.  *
  15.  *   You should have received a copy of the GNU General Public License
  16.  *   along with this program; if not, write to the Free Software
  17.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #ifndef lint
  21. static  char sccsid[] = "@(#)chkconf.c    1.9 1/30/94 (C) 1993 Darren Reed";
  22. #endif
  23.  
  24. #include "struct.h"
  25. #include "common.h"
  26. #include "sys.h"
  27. #include "numeric.h"
  28. #include <sys/socket.h>
  29. #include <sys/stat.h>
  30. #include <fcntl.h>
  31. #ifdef __hpux
  32. #include "inet.h"
  33. #endif
  34. #ifdef PCS
  35. #include <time.h>
  36. #endif
  37. #ifdef    R_LINES
  38. #include <signal.h>
  39. #endif
  40.  
  41. #ifdef DYNIXPTX
  42. #include <sys/types.h>
  43. #include <time.h>
  44. #endif
  45.  
  46. #undef    free
  47. #define    MyMalloc(x)    malloc(x)
  48.  
  49. static    void    new_class();
  50. static    char    *getfield(), confchar ();
  51. static    int    openconf(), validate();
  52. static    aClass    *get_class();
  53. static    aConfItem    *initconf();
  54.  
  55. static    int    numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
  56. static    char    *configfile = CONFIGFILE;
  57. static    char    nullfield[] = "";
  58. static    char    maxsendq[12];
  59.  
  60. main(argc, argv)
  61. int    argc;
  62. char    *argv[];
  63. {
  64.     new_class(0);
  65.  
  66.     if (chdir(DPATH))
  67.         {
  68.         perror("chdir");
  69.         exit(-1);
  70.         }
  71.     if (argc > 1 && !strncmp(argv[1], "-d", 2))
  72.            {
  73.         debugflag = 1;
  74.         if (argv[1][2])
  75.             debugflag = atoi(argv[1]+2);
  76.         argc--, argv++;
  77.         }
  78.     if (argc > 1)
  79.         configfile = argv[1];
  80.     return validate(initconf());
  81. }
  82.  
  83. /*
  84.  * openconf
  85.  *
  86.  * returns -1 on any error or else the fd opened from which to read the
  87.  * configuration file from.  This may either be th4 file direct or one end
  88.  * of a pipe from m4.
  89.  */
  90. static    int    openconf()
  91. {
  92. #ifdef    M4_PREPROC
  93.     int    pi[2];
  94.  
  95.     if (pipe(pi) == -1)
  96.         return -1;
  97.     switch(fork())
  98.     {
  99.     case -1 :
  100.         return -1;
  101.     case 0 :
  102.         (void)close(pi[0]);
  103.         if (pi[1] != 1)
  104.             {
  105.             (void)dup2(pi[1], 1);
  106.             (void)close(pi[1]);
  107.             }
  108.         (void)dup2(1,2);
  109.         /*
  110.          * m4 maybe anywhere, use execvp to find it.  Any error
  111.          * goes out with report_error.  Could be dangerous,
  112.          * two servers running with the same fd's >:-) -avalon
  113.          */
  114.         (void)execlp("m4", "m4", "ircd.m4", configfile, 0);
  115.         perror("m4");
  116.         exit(-1);
  117.     default :
  118.         (void)close(pi[1]);
  119.         return pi[0];
  120.     }
  121. #else
  122.     return open(configfile, O_RDONLY);
  123. #endif
  124. }
  125.  
  126. /*
  127. ** initconf() 
  128. **    Read configuration file.
  129. **
  130. **    returns -1, if file cannot be opened
  131. **             0, if file opened
  132. */
  133.  
  134. static    aConfItem     *initconf(opt)
  135. int    opt;
  136. {
  137.     int    fd;
  138.     char    line[512], *tmp, c[80], *s;
  139.     int    ccount = 0, ncount = 0, dh, flags = 0;
  140.     aConfItem *aconf = NULL, *ctop = NULL;
  141.  
  142.     (void)fprintf(stderr, "initconf(): ircd.conf = %s\n", configfile);
  143.     if ((fd = openconf()) == -1)
  144.         {
  145. #ifdef    M4_PREPROC
  146.         (void)wait(0);
  147. #endif
  148.         return NULL;
  149.         }
  150.  
  151.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  152.     while ((dh = dgets(fd, line, sizeof(line) - 1)) > 0)
  153.         {
  154.         if (aconf)
  155.             {
  156.             if (aconf->host)
  157.                 (void)free(aconf->host);
  158.             if (aconf->passwd)
  159.                 (void)free(aconf->passwd);
  160.             if (aconf->name)
  161.                 (void)free(aconf->name);
  162.             }
  163.         else
  164.             aconf = (aConfItem *)malloc(sizeof(*aconf));
  165.         aconf->host = (char *)NULL;
  166.         aconf->passwd = (char *)NULL;
  167.         aconf->name = (char *)NULL;
  168.         aconf->class = (aClass *)NULL;
  169.         if (tmp = (char *)index(line, '\n'))
  170.             *tmp = 0;
  171.         else while(dgets(fd, c, sizeof(c) - 1))
  172.             if (tmp = (char *)index(c, '\n'))
  173.                 {
  174.                 *tmp = 0;
  175.                 break;
  176.                 }
  177.         /*
  178.          * Do quoting of characters and # detection.
  179.          */
  180.         for (tmp = line; *tmp; tmp++)
  181.             {
  182.             if (*tmp == '\\')
  183.                 {
  184.                 switch (*(tmp+1))
  185.                 {
  186.                 case 'n' :
  187.                     *tmp = '\n';
  188.                     break;
  189.                 case 'r' :
  190.                     *tmp = '\r';
  191.                     break;
  192.                 case 't' :
  193.                     *tmp = '\t';
  194.                     break;
  195.                 case '0' :
  196.                     *tmp = '\0';
  197.                     break;
  198.                 default :
  199.                     *tmp = *(tmp+1);
  200.                     break;
  201.                 }
  202.                 if (!*(tmp+1))
  203.                     break;
  204.                 else
  205.                     for (s = tmp; *s = *++s; )
  206.                         ;
  207.                 tmp++;
  208.                 }
  209.             else if (*tmp == '#')
  210.                 *tmp = '\0';
  211.             }
  212.         if (!*line || *line == '#' || *line == '\n' ||
  213.             *line == ' ' || *line == '\t')
  214.             continue;
  215.  
  216.         if (line[1] != ':')
  217.             {
  218.                         (void)fprintf(stderr, "ERROR: Bad config line (%s)\n",
  219.                 line);
  220.                         continue;
  221.                     }
  222.  
  223.         if (debugflag)
  224.             (void)printf("\n%s\n",line);
  225.         (void)fflush(stdout);
  226.  
  227.         tmp = getfield(line);
  228.         if (!tmp)
  229.             {
  230.                         (void)fprintf(stderr, "\tERROR: no fields found\n");
  231.             continue;
  232.             }
  233.  
  234.         aconf->status = CONF_ILLEGAL;
  235.  
  236.         switch (*tmp)
  237.         {
  238.             case 'A': /* Name, e-mail address of administrator */
  239.             case 'a': /* of this server. */
  240.                 aconf->status = CONF_ADMIN;
  241.                 break;
  242.             case 'C': /* Server where I should try to connect */
  243.             case 'c': /* in case of lp failures             */
  244.                 ccount++;
  245.                 aconf->status = CONF_CONNECT_SERVER;
  246.                 break;
  247.             case 'H': /* Hub server line */
  248.             case 'h':
  249.                 aconf->status = CONF_HUB;
  250.                 break;
  251.             case 'I': /* Just plain normal irc client trying  */
  252.             case 'i': /* to connect me */
  253.                 aconf->status = CONF_CLIENT;
  254.                 break;
  255.             case 'K': /* Kill user line on irc.conf           */
  256.             case 'k':
  257.                 aconf->status = CONF_KILL;
  258.                 break;
  259.             /* Operator. Line should contain at least */
  260.             /* password and host where connection is  */
  261.             case 'L': /* guaranteed leaf server */
  262.             case 'l':
  263.                 aconf->status = CONF_LEAF;
  264.                 break;
  265.             /* Me. Host field is name used for this host */
  266.             /* and port number is the number of the port */
  267.             case 'M':
  268.             case 'm':
  269.                 aconf->status = CONF_ME;
  270.                 break;
  271.             case 'N': /* Server where I should NOT try to     */
  272.             case 'n': /* connect in case of lp failures     */
  273.                   /* but which tries to connect ME        */
  274.                 ++ncount;
  275.                 aconf->status = CONF_NOCONNECT_SERVER;
  276.                 break;
  277.             case 'O':
  278.                 aconf->status = CONF_OPERATOR;
  279.                 break;
  280.             /* Local Operator, (limited privs --SRB) */
  281.             case 'o':
  282.                 aconf->status = CONF_LOCOP;
  283.                 break;
  284.             case 'P': /* listen port line */
  285.             case 'p':
  286.                 aconf->status = CONF_LISTEN_PORT;
  287.                 break;
  288.             case 'Q': /* a server that you don't want in your */
  289.             case 'q': /* network. USE WITH CAUTION! */
  290.                 aconf->status = CONF_QUARANTINED_SERVER;
  291.                 break;
  292. #ifdef R_LINES
  293.             case 'R': /* extended K line */
  294.             case 'r': /* Offers more options of how to restrict */
  295.                 aconf->status = CONF_RESTRICT;
  296.                 break;
  297. #endif
  298.             case 'S': /* Service. Same semantics as   */
  299.             case 's': /* CONF_OPERATOR                */
  300.                 aconf->status = CONF_SERVICE;
  301.                 break;
  302.             case 'U': /* Uphost, ie. host where client reading */
  303.             case 'u': /* this should connect.                  */
  304.             /* This is for client only, I must ignore this */
  305.             /* ...U-line should be removed... --msa */
  306.                 break;
  307.             case 'Y':
  308.             case 'y':
  309.                     aconf->status = CONF_CLASS;
  310.                     break;
  311.             default:
  312.             (void)fprintf(stderr,
  313.                 "\tERROR: unknown conf line letter (%c)\n",
  314.                 *tmp);
  315.             break;
  316.             }
  317.  
  318.         if (IsIllegal(aconf))
  319.             continue;
  320.  
  321.         for (;;) /* Fake loop, that I can use break here --msa */
  322.             {
  323.             if ((tmp = getfield(NULL)) == NULL)
  324.                 break;
  325.             DupString(aconf->host, tmp);
  326.             if ((tmp = getfield(NULL)) == NULL)
  327.                 break;
  328.             DupString(aconf->passwd, tmp);
  329.             if ((tmp = getfield(NULL)) == NULL)
  330.                 break;
  331.             DupString(aconf->name, tmp);
  332.             if ((tmp = getfield(NULL)) == NULL)
  333.                 break;
  334.             aconf->port = atoi(tmp);
  335.             if ((tmp = getfield(NULL)) == NULL)
  336.                 break;
  337.             if (!(aconf->status & CONF_CLASS))
  338.                 aconf->class = get_class(atoi(tmp));
  339.             break;
  340.             }
  341.         if (!aconf->class && (aconf->status & (CONF_CONNECT_SERVER|
  342.              CONF_NOCONNECT_SERVER|CONF_OPS|CONF_CLIENT)))
  343.             {
  344.             (void)fprintf(stderr,
  345.                 "\tWARNING: No class.  Default 0\n");
  346.             aconf->class = get_class(0);
  347.             }
  348.         /*
  349.                 ** If conf line is a class definition, create a class entry
  350.                 ** for it and make the conf_line illegal and delete it.
  351.                 */
  352.         if (aconf->status & CONF_CLASS)
  353.             {
  354.             int    class = 0;
  355.  
  356.             if (!aconf->host)
  357.                 {
  358.                 (void)fprintf(stderr,"\tERROR: no class #\n");
  359.                 continue;
  360.                 }
  361.             if (!tmp)
  362.                 {
  363.                 (void)fprintf(stderr,
  364.                     "\tWARNING: missing sendq field\n");
  365.                 (void)fprintf(stderr, "\t\t default: %d\n",
  366.                     MAXSENDQLENGTH);
  367.                 (void)sprintf(maxsendq, "%d", MAXSENDQLENGTH);
  368.                 }
  369.             else
  370.                 (void)sprintf(maxsendq, "%d", atoi(tmp));
  371.             new_class(atoi(aconf->host));
  372.             aconf->class = get_class(atoi(aconf->host));
  373.             goto print_confline;
  374.             }
  375.  
  376.         if (aconf->status & CONF_LISTEN_PORT)
  377.             {
  378. #ifdef    UNIXPORT
  379.             struct    stat    sb;
  380.  
  381.             if (!aconf->host)
  382.                 (void)fprintf(stderr, "\tERROR: %s\n",
  383.                     "null host field in P-line");
  384.             else if (index(aconf->host, '/'))
  385.                 {
  386.                 if (stat(aconf->host, &sb) == -1)
  387.                     {
  388.                     (void)fprintf(stderr, "\tERROR: (%s) ",
  389.                         aconf->host);
  390.                     perror("stat");
  391.                     }
  392.                 else if ((sb.st_mode & S_IFMT) != S_IFDIR)
  393.                     (void)fprintf(stderr,
  394.                         "\tERROR: %s not directory\n",
  395.                         aconf->host);
  396.                 }
  397. #else
  398.             if (!aconf->host)
  399.                 (void)fprintf(stderr, "\tERROR: %s\n",
  400.                     "null host field in P-line");
  401.             else if (index(aconf->host, '/'))
  402.                 (void)fprintf(stderr, "\t%s %s\n",
  403.                     "WARNING: / present in P-line", 
  404.                     "for non-UNIXPORT configuration");
  405. #endif
  406.             aconf->class = get_class(0);
  407.             goto print_confline;
  408.             }
  409.  
  410.         if (aconf->status & CONF_SERVER_MASK &&
  411.             (!aconf->host || index(aconf->host, '*') ||
  412.              index(aconf->host, '?')))
  413.             {
  414.             (void)fprintf(stderr, "\tERROR: bad host field\n");
  415.             continue;
  416.             }
  417.  
  418.         if (aconf->status & CONF_SERVER_MASK && BadPtr(aconf->passwd))
  419.             {
  420.             (void)fprintf(stderr,
  421.                     "\tERROR: empty/no password field\n");
  422.             continue;
  423.             }
  424.  
  425.         if (aconf->status & CONF_SERVER_MASK && !aconf->name)
  426.             {
  427.             (void)fprintf(stderr, "\tERROR: bad name field\n");
  428.             continue;
  429.             }
  430.  
  431.         if (aconf->status & (CONF_SERVER_MASK|CONF_OPS))
  432.             if (!index(aconf->host, '@'))
  433.                 {
  434.                 char    *newhost;
  435.                 int    len = 3;    /* *@\0 = 3 */
  436.  
  437.                 len += strlen(aconf->host);
  438.                 newhost = (char *)MyMalloc(len);
  439.                 (void)sprintf(newhost, "*@%s", aconf->host);
  440.                 (void)free(aconf->host);
  441.                 aconf->host = newhost;
  442.                 }
  443.  
  444.         if (!aconf->class)
  445.             aconf->class = get_class(0);
  446.         (void)sprintf(maxsendq, "%d", aconf->class->class);
  447.  
  448.         if (!aconf->name)
  449.             aconf->name = nullfield;
  450.         if (!aconf->passwd)
  451.             aconf->passwd = nullfield;
  452.         if (!aconf->host)
  453.             aconf->host = nullfield;
  454.         if (aconf->status & (CONF_ME|CONF_ADMIN))
  455.             {
  456.             if (flags & aconf->status)
  457.                 (void)fprintf(stderr,
  458.                     "ERROR: multiple %c-lines\n",
  459.                     toupper(confchar(aconf->status)));
  460.             else
  461.                 flags |= aconf->status;
  462.             }
  463. print_confline:
  464.         if (debugflag > 8)
  465.             (void)printf("(%d) (%s) (%s) (%s) (%d) (%s)\n",
  466.                   aconf->status, aconf->host, aconf->passwd,
  467.                   aconf->name, aconf->port, maxsendq);
  468.         (void)fflush(stdout);
  469.         if (aconf->status & (CONF_SERVER_MASK|CONF_HUB|CONF_LEAF))
  470.             {
  471.             aconf->next = ctop;
  472.             ctop = aconf;
  473.             aconf = NULL;
  474.             }
  475.         }
  476.     (void)close(fd);
  477. #ifdef    M4_PREPROC
  478.     (void)wait(0);
  479. #endif
  480.     return ctop;
  481. }
  482.  
  483. static    aClass    *get_class(cn)
  484. int    cn;
  485. {
  486.     static    aClass    cls;
  487.     int    i = numclasses - 1;
  488.  
  489.     cls.class = -1;
  490.     for (; i >= 0; i--)
  491.         if (classarr[i] == cn)
  492.             {
  493.             cls.class = cn;
  494.             break;
  495.             }
  496.     if (i == -1)
  497.         (void)fprintf(stderr,"\tWARNING: class %d not found\n", cn);
  498.     return &cls;
  499. }
  500.  
  501. static    void    new_class(cn)
  502. int    cn;
  503. {
  504.     numclasses++;
  505.     if (classarr)
  506.         classarr = (int *)realloc(classarr, sizeof(int) * numclasses);
  507.     else
  508.         classarr = (int *)malloc(sizeof(int));
  509.     classarr[numclasses-1] = cn;
  510. }
  511.  
  512. /*
  513.  * field breakup for ircd.conf file.
  514.  */
  515. static    char    *getfield(newline)
  516. char    *newline;
  517. {
  518.     static    char *line = NULL;
  519.     char    *end, *field;
  520.     
  521.     if (newline)
  522.         line = newline;
  523.     if (line == NULL)
  524.         return(NULL);
  525.  
  526.     field = line;
  527.     if ((end = (char *)index(line,':')) == NULL)
  528.         {
  529.         line = NULL;
  530.         if ((end = (char *)index(field,'\n')) == NULL)
  531.             end = field + strlen(field);
  532.         }
  533.     else
  534.         line = end + 1;
  535.     *end = '\0';
  536.     return(field);
  537. }
  538.  
  539.  
  540. /*
  541. ** read a string terminated by \r or \n in from a fd
  542. **
  543. ** Created: Sat Dec 12 06:29:58 EST 1992 by avalon
  544. ** Returns:
  545. **    0 - EOF
  546. **    -1 - error on read
  547. **     >0 - number of bytes returned (<=num)
  548. ** After opening a fd, it is necessary to init dgets() by calling it as
  549. **    dgets(x,y,0);
  550. ** to mark the buffer as being empty.
  551. */
  552. int    dgets(fd, buf, num)
  553. int    fd, num;
  554. char    *buf;
  555. {
  556.     static    char    dgbuf[8192];
  557.     static    char    *head = dgbuf, *tail = dgbuf;
  558.     register char    *s, *t;
  559.     register int    n, nr;
  560.  
  561.     /*
  562.     ** Sanity checks.
  563.     */
  564.     if (head == tail)
  565.         *head = '\0';
  566.     if (!num)
  567.         {
  568.         head = tail = dgbuf;
  569.         *head = '\0';
  570.         return 0;
  571.         }
  572.     if (num > sizeof(dgbuf) - 1)
  573.         num = sizeof(dgbuf) - 1;
  574. dgetsagain:
  575.     if (head > dgbuf)
  576.         {
  577.         for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
  578.             *t++ = *s++;
  579.         tail = t;
  580.         head = dgbuf;
  581.         }
  582.     /*
  583.     ** check input buffer for EOL and if present return string.
  584.     */
  585.     if (head < tail &&
  586.         ((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail)
  587.         {
  588.         n = MIN(s - head + 1, num);    /* at least 1 byte */
  589. dgetsreturnbuf:
  590.         bcopy(head, buf, n);
  591.         head += n;
  592.         if (head == tail)
  593.             head = tail = dgbuf;
  594.         return n;
  595.         }
  596.  
  597.     if (tail - head >= num)        /* dgets buf is big enough */
  598.         {
  599.         n = num;
  600.         goto dgetsreturnbuf;
  601.         }
  602.  
  603.     n = sizeof(dgbuf) - (tail - dgbuf) - 1;
  604.     nr = read(fd, tail, n);
  605.     if (nr == -1)
  606.         {
  607.         head = tail = dgbuf;
  608.         return -1;
  609.         }
  610.     if (!nr)
  611.         {
  612.         if (head < tail)
  613.             {
  614.             n = MIN(head - tail, num);
  615.             goto dgetsreturnbuf;
  616.             }
  617.         head = tail = dgbuf;
  618.         return 0;
  619.         }
  620.     tail += nr;
  621.     *tail = '\0';
  622.     for (t = head; (s = index(t, '\n')); )
  623.         {
  624.         if ((s > head) && (s > dgbuf))
  625.             {
  626.             t = s-1;
  627.             for (nr = 0; *t == '\\'; nr++)
  628.                 t--;
  629.             if (nr & 1)
  630.                 {
  631.                 t = s+1;
  632.                 s--;
  633.                 nr = tail - t;
  634.                 while (nr--)
  635.                     *s++ = *t++;
  636.                 tail -= 2;
  637.                 *tail = '\0';
  638.                 }
  639.             else
  640.                 s++;
  641.             }
  642.         else
  643.             s++;
  644.         t = s;
  645.         }
  646.     *tail = '\0';
  647.     goto dgetsagain;
  648. }
  649.  
  650.  
  651. static    int    validate(top)
  652. aConfItem *top;
  653. {
  654.     Reg1    aConfItem *aconf, *bconf;
  655.     u_int    otype, valid = 0;
  656.  
  657.     if (!top)
  658.         return 0;
  659.  
  660.     for (aconf = top; aconf; aconf = aconf->next)
  661.         {
  662.         if (aconf->status & CONF_MATCH)
  663.             continue;
  664.  
  665.         if (aconf->status & CONF_SERVER_MASK)
  666.             {
  667.             if (aconf->status & CONF_CONNECT_SERVER)
  668.                 otype = CONF_NOCONNECT_SERVER;
  669.             else if (aconf->status & CONF_NOCONNECT_SERVER)
  670.                 otype = CONF_CONNECT_SERVER;
  671.  
  672.             for (bconf = top; bconf; bconf = bconf->next)
  673.                 {
  674.                 if (bconf == aconf || !(bconf->status & otype))
  675.                     continue;
  676.                 if (bconf->class == aconf->class &&
  677.                     !mycmp(bconf->name, aconf->name) &&
  678.                     !mycmp(bconf->host, aconf->host))
  679.                     {
  680.                     aconf->status |= CONF_MATCH;
  681.                     bconf->status |= CONF_MATCH;
  682.                         break;
  683.                     }
  684.                 }
  685.             }
  686.         else
  687.             for (bconf = top; bconf; bconf = bconf->next)
  688.                 {
  689.                 if ((bconf == aconf) ||
  690.                     !(bconf->status & CONF_SERVER_MASK))
  691.                     continue;
  692.                 if (!mycmp(bconf->name, aconf->name))
  693.                     {
  694.                     aconf->status |= CONF_MATCH;
  695.                     break;
  696.                     }
  697.                 }
  698.         }
  699.  
  700.     (void) fprintf(stderr, "\n");
  701.     for (aconf = top; aconf; aconf = aconf->next)
  702.         if (aconf->status & CONF_MATCH)
  703.             valid++;
  704.         else
  705.             (void)fprintf(stderr, "Unmatched %c:%s:%s:%s\n",
  706.                 confchar(aconf->status), aconf->host,
  707.                 aconf->passwd, aconf->name);
  708.     return valid ? 0 : -1;
  709. }
  710.  
  711. static    char    confchar(status)
  712. u_int    status;
  713. {
  714.     static    char    letrs[] = "QICNoOMKARYSLPH";
  715.     char    *s = letrs;
  716.  
  717.     status &= ~(CONF_MATCH|CONF_ILLEGAL);
  718.  
  719.     for (; *s; s++, status >>= 1)
  720.         if (status & 1)
  721.             return *s;
  722.     return '-';
  723. }
  724.  
  725. outofmemory()
  726. {
  727.     (void)write(2, "Out of memory\n", 14);
  728.     exit(-1);
  729. }
  730.