home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / named / db_dump.c next >
Encoding:
C/C++ Source or Header  |  1991-04-24  |  19.2 KB  |  783 lines

  1. /*
  2.  * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)db_dump.c    4.33 (Berkeley) 3/3/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/time.h>
  40. #include <sys/stat.h>
  41. #include <netinet/in.h>
  42. #include <netdb.h>
  43. #include <stdio.h>
  44. #include <syslog.h>
  45. #include <arpa/nameser.h>
  46. #include <resolv.h>
  47. #include "ns.h"
  48. #include "db.h"
  49. #include "pathnames.h"
  50.  
  51. #ifdef DUMPFILE
  52. char    *dumpfile = DUMPFILE;
  53. #else
  54. char    *dumpfile = _PATH_DUMPFILE;
  55. #endif
  56.  
  57. extern char *cache_file;
  58.  
  59. /*
  60.  * Dump current cache in a format similar to RFC 883.
  61.  *
  62.  * We try to be careful and determine whether the operation succeeded
  63.  * so that the new cache file can be installed.
  64.  */
  65.  
  66. #define DB_ROOT_TIMBUF 3600
  67.  
  68. doachkpt()
  69. {
  70.     extern int errno;
  71.     FILE *fp;
  72.     char tmpcheckfile[256];
  73.  
  74.     /* nowhere to checkpoint cache... */
  75.     if (cache_file == NULL) {
  76. #ifdef DEBUG
  77.         if (debug >= 3)
  78.             fprintf(ddt,"doachkpt(to where?)\n");
  79. #endif
  80.         return;
  81.     }
  82.  
  83. #ifdef DEBUG
  84.     if (debug >= 3)
  85.         fprintf(ddt,"doachkpt()\n");
  86. #endif
  87.  
  88.     (void) sprintf(tmpcheckfile, "%s.chk", cache_file);
  89.     if ((fp = fopen(tmpcheckfile, "w")) == NULL) {
  90. #ifdef DEBUG
  91.         if (debug >= 3)
  92.             fprintf(ddt,"doachkpt(can't open %s for write)\n", tmpcheckfile);
  93. #endif
  94.         return;
  95.     }
  96.  
  97.     (void) gettime(&tt);
  98.     fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
  99.     fflush(fp);
  100.     if (ferror(fp)) {
  101. #ifdef DEBUG
  102.         if (debug >= 3)
  103.             fprintf(ddt,"doachkpt(write to checkpoint file failed)\n");
  104. #endif
  105.         return;
  106.     }
  107.  
  108.     if (fcachetab != NULL) {
  109.     int n;
  110.     if ((n = scan_root(hashtab)) < MINROOTS) {
  111.         syslog(LOG_ERR, "%d root hints... (too low)", n);
  112.         fprintf(fp, "; ---- Root hint cache dump ----\n");
  113.         (void) db_dump(fcachetab, fp, DB_Z_CACHE, "");
  114.     }
  115.     }
  116.  
  117.     if (hashtab != NULL) {
  118.         fprintf(fp, "; ---- Cache dump ----\n");
  119.         if (db_dump(hashtab, fp, DB_Z_CACHE, "") == NODBFILE) {
  120. #ifdef DEBUG
  121.             if (debug >= 3)
  122.                 fprintf(ddt,"doachkpt(checkpoint failed)\n");
  123. #endif
  124.             (void) fclose(fp);
  125.             return;
  126.         }
  127.     }
  128.  
  129.     (void) fsync(fileno(fp));
  130.     if (fclose(fp) == EOF) {
  131. #ifdef DEBUG
  132.         if (debug >= 3)
  133.             fprintf(ddt,"doachkpt(close failed)\n");
  134. #endif
  135.         return;
  136.     }
  137.  
  138.     if (rename(tmpcheckfile, cache_file)) {
  139. #ifdef DEBUG
  140.         if (debug >= 3)
  141.             fprintf(ddt,"doachkpt(install %s to %s failed, %d)\n",
  142.                     tmpcheckfile,cache_file, errno);
  143. #endif
  144.     }
  145. }
  146.  
  147. /*
  148.  * What we do is scan the root hint cache to make sure there are at least
  149.  * MINROOTS root pointers with non-0 TTL's so that the checkpoint will not
  150.  * lose the root.  Failing this, all pointers are written out w/ TTL ~0
  151.  * (root pointers timed out and prime_cache() not done or failed).
  152.  */
  153. #define TIMBUF 300
  154.  
  155. int
  156. scan_root(htp)
  157.     struct hashbuf *htp;
  158. {
  159.     register struct databuf *dp;
  160.     register struct namebuf *np;
  161.     struct timeval soon;
  162.     int roots = 0;
  163.  
  164. #ifdef DEBUG
  165.     if (debug)
  166.         fprintf(ddt,"scan_root(0x%x)\n", htp);
  167. #endif
  168.  
  169.     /* metric by which we determine whether a root NS pointer is still */
  170.     /* valid (will be written out if we do a dump).  we also add some */
  171.     /* time buffer for safety... */
  172.     (void) gettime(&soon);
  173.     soon.tv_sec += TIMBUF;
  174.  
  175.     for (np = htp->h_tab[0]; np != NULL; np = np->n_next) {
  176.         if (np->n_dname[0] == '\0') {
  177.             dp = np->n_data;
  178.             while (dp != NULL) {
  179.                 if (dp->d_type == T_NS &&
  180.                     dp->d_ttl > soon.tv_sec) {
  181.                     roots++;
  182.                     if (roots >= MINROOTS)
  183.                         return (roots);
  184.                 }
  185.                 dp = dp->d_next;
  186.             }
  187.         }
  188.     }
  189.     return (roots);
  190. }
  191.  
  192. #ifdef notdef
  193. mark_cache(htp, ttl)
  194.     struct hashbuf *htp;
  195.     int ttl;
  196. {
  197.     register struct databuf *dp;
  198.     register struct namebuf *np;
  199.     struct namebuf **npp, **nppend;
  200.     struct timeval soon;
  201.  
  202. #ifdef DEBUG
  203.     if (debug)
  204.         fprintf(ddt,"mark_cache()\n");
  205. #endif
  206.  
  207.     (void) gettime(&soon);
  208.     soon.tv_sec += TIMBUF;
  209.  
  210.     npp = htp->h_tab;
  211.     nppend = npp + htp->h_size;
  212.     while (npp < nppend) {
  213.         for (np = *npp++; np != NULL; np = np->n_next) {
  214.             if (np->n_data == NULL)
  215.                 continue;
  216.             for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  217.                 if (dp->d_ttl < soon.tv_sec)
  218.                     dp->d_ttl = ttl;
  219.             }
  220.         }
  221.     }
  222.  
  223.     npp = htp->h_tab;
  224.     nppend = npp + htp->h_size;
  225.     while (npp < nppend) {
  226.         for (np = *npp++; np != NULL; np = np->n_next) {
  227.             if (np->n_hash == NULL)
  228.                 continue;
  229.             mark_cache(np->n_hash, ttl);
  230.         }
  231.     }
  232. }
  233. #endif notdef
  234.  
  235. /*
  236.  * Dump current data base in a format similar to RFC 883.
  237.  */
  238.  
  239. doadump()
  240. {
  241.     FILE    *fp;
  242.  
  243. #ifdef DEBUG
  244.     if (debug >= 3)
  245.         fprintf(ddt,"doadump()\n");
  246. #endif
  247.  
  248.     if ((fp = fopen(dumpfile, "w")) == NULL)
  249.         return;
  250.     gettime(&tt);
  251.     fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
  252.     fprintf(fp, "; --- Cache & Data ---\n");
  253.     if (hashtab != NULL)
  254.         (void) db_dump(hashtab, fp, DB_Z_ALL, "");
  255.     fprintf(fp, "; --- Hints ---\n");
  256.     if (fcachetab != NULL)
  257.         (void) db_dump(fcachetab, fp, DB_Z_ALL, "");
  258.     (void) fclose(fp);
  259. }
  260.  
  261. #ifdef ALLOW_UPDATES
  262. /* Create a disk database to back up zones 
  263.  */
  264. zonedump(zp)
  265.     register struct zoneinfo *zp;
  266. {
  267.     FILE    *fp;
  268.     char *fname;
  269.     struct hashbuf *htp;
  270.     char *op;
  271.     struct stat st;
  272.  
  273.     /* Only dump zone if there is a cache specified */
  274.     if (zp->z_source && *(zp->z_source)) {
  275. #ifdef DEBUG
  276.         if (debug)
  277.             fprintf(ddt, "zonedump(%s)\n", zp->z_source);
  278. #endif
  279.  
  280.         if ((fp = fopen(zp->z_source, "w")) == NULL)
  281.             return;
  282.         if (op = index(zp->z_origin, '.'))
  283.         op++;
  284.         gettime(&tt);
  285.         htp = hashtab;
  286.         if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) {
  287.             db_dump(htp, fp, zp-zones, (op == NULL ? "" : op));
  288. #ifdef ALLOW_UPDATES
  289.             zp->hasChanged = 0;        /* Checkpointed */
  290. #endif ALLOW_UPDATES
  291.         }
  292.         (void) fclose(fp);
  293.         if (stat(zp->z_source, &st) == 0)
  294.             zp->z_ftime = st.st_mtime;
  295.     }
  296. #ifdef DEBUG
  297.         else if (debug)
  298.         fprintf(ddt, "zonedump: no zone to dump\n");
  299. #endif
  300. }
  301. #endif
  302.  
  303. int
  304. db_dump(htp, fp, zone, origin)
  305.     int zone;
  306.     struct hashbuf *htp;
  307.     FILE *fp;
  308.     char *origin;
  309. {
  310.     register struct databuf *dp;
  311.     register struct namebuf *np;
  312.     struct namebuf **npp, **nppend;
  313.     char dname[MAXDNAME];
  314.     u_long n;
  315.     u_long addr;
  316.     u_short i;
  317.     int j;
  318.     register u_char *cp;
  319.     u_char *end;
  320.     char *proto;
  321.     extern char *inet_ntoa(), *protocolname(), *servicename();
  322.     int found_data, tab, printed_origin = 0;
  323.  
  324.     npp = htp->h_tab;
  325.     nppend = npp + htp->h_size;
  326.     while (npp < nppend) {
  327.         for (np = *npp++; np != NULL; np = np->n_next) {
  328.         if (np->n_data == NULL)
  329.             continue;
  330.         /* Blecch - can't tell if there is data here for the
  331.          * right zone, so can't print name yet
  332.          */
  333.         found_data = 0;
  334.         /* we want a snapshot in time... */
  335.         for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  336.             /* Is the data for this zone? */
  337.             if (zone != DB_Z_ALL && dp->d_zone != zone)
  338.                 continue;
  339.             if (dp->d_zone == DB_Z_CACHE &&
  340.                 dp->d_ttl <= tt.tv_sec &&
  341.                 (dp->d_flags & DB_F_HINT) == 0)
  342.                 continue;
  343.             if (!printed_origin) {
  344.                 fprintf(fp, "$ORIGIN %s.\n", origin);
  345.                 printed_origin++;
  346.             }
  347.             tab = 0;
  348.             if (!found_data) {
  349.                 if (np->n_dname[0] == 0) {
  350.                 if (origin[0] == 0)
  351.                     fprintf(fp, ".\t");
  352.                 else
  353.                     fprintf(fp, ".%s.\t", origin); /* ??? */
  354.                 } else
  355.                 fprintf(fp, "%s\t", np->n_dname);
  356.                 if (strlen(np->n_dname) < 8)
  357.                 tab = 1;
  358.                 found_data++;
  359.             } else {
  360.                 (void) putc('\t', fp);
  361.                 tab = 1;
  362.             }
  363.             if (dp->d_zone == DB_Z_CACHE) {
  364.                 if (dp->d_flags & DB_F_HINT &&
  365.                     (long)(dp->d_ttl - tt.tv_sec) < DB_ROOT_TIMBUF)
  366.                     fprintf(fp, "%d\t", DB_ROOT_TIMBUF);
  367.                 else
  368.                     fprintf(fp, "%d\t",
  369.                         (int)(dp->d_ttl - tt.tv_sec));
  370.             } else if (dp->d_ttl != 0 &&
  371.                 dp->d_ttl != zones[dp->d_zone].z_minimum)
  372.                 fprintf(fp, "%d\t", (int)dp->d_ttl);
  373.             else if (tab)
  374.                 (void) putc('\t', fp);
  375.             fprintf(fp, "%s\t%s\t", p_class(dp->d_class),
  376.                 p_type(dp->d_type));
  377.             cp = (u_char *)dp->d_data;
  378.             /*
  379.              * Print type specific data
  380.              */
  381.             switch (dp->d_type) {
  382.             case T_A:
  383.                 switch (dp->d_class) {
  384.                 case C_IN:
  385.                 case C_HS:
  386.                     GETLONG(n, cp);
  387.                     n = htonl(n);
  388.                     fprintf(fp, "%s",
  389.                        inet_ntoa(*(struct in_addr *)&n));
  390.                     break;
  391.                 }
  392.                 if (dp->d_nstime)
  393.                     fprintf(fp, "\t; %d", dp->d_nstime);
  394.                 fprintf(fp, "\n");
  395.                 break;
  396.             case T_CNAME:
  397.             case T_MB:
  398.             case T_MG:
  399.             case T_MR:
  400.             case T_PTR:
  401.                 if (cp[0] == '\0')
  402.                     fprintf(fp, ".\n");
  403.                 else
  404.                     fprintf(fp, "%s.\n", cp);
  405.                 break;
  406.  
  407.             case T_NS:
  408.                 cp = (u_char *)dp->d_data;
  409.                 if (cp[0] == '\0')
  410.                     fprintf(fp, ".\t");
  411.                 else
  412.                     fprintf(fp, "%s.", cp);
  413.                 if (dp->d_nstime)
  414.                     fprintf(fp, "\t; %d???", dp->d_nstime);
  415.                 fprintf(fp, "\n");
  416.                 break;
  417.  
  418.             case T_HINFO:
  419.                 if (n = *cp++) {
  420.                     fprintf(fp, "\"%.*s\"", (int)n, cp);
  421.                     cp += n;
  422.                 } else
  423.                     fprintf(fp, "\"\"");
  424.                 if (n = *cp++)
  425.                     fprintf(fp, " \"%.*s\"", (int)n, cp);
  426.                 else
  427.                     fprintf(fp, " \"\"");
  428.                 (void) putc('\n', fp);
  429.                 break;
  430.  
  431.             case T_SOA:
  432.                 fprintf(fp, "%s.", cp);
  433.                 cp += strlen((char *)cp) + 1;
  434.                 fprintf(fp, " %s. (\n", cp);
  435.                 cp += strlen((char *)cp) + 1;
  436.                 GETLONG(n, cp);
  437.                 fprintf(fp, "\t\t%lu", n);
  438.                 GETLONG(n, cp);
  439.                 fprintf(fp, " %lu", n);
  440.                 GETLONG(n, cp);
  441.                 fprintf(fp, " %lu", n);
  442.                 GETLONG(n, cp);
  443.                 fprintf(fp, " %lu", n);
  444.                 GETLONG(n, cp);
  445.                 fprintf(fp, " %lu )\n", n);
  446.                 break;
  447.  
  448.             case T_MX:
  449.                 GETSHORT(n, cp);
  450.                 fprintf(fp,"%lu", n);
  451.                 fprintf(fp," %s.\n", cp);
  452.                 break;
  453.  
  454.             case T_TXT:
  455.                 end = (u_char *)dp->d_data + dp->d_size;
  456.                 (void) putc('"', fp);
  457.                 while (cp < end) {
  458.                     if (n = *cp++) {
  459.                     for (j = n ; j > 0 && cp < end ; j--)
  460.                         if (*cp == '\n') {
  461.                         (void) putc('\\', fp);
  462.                         (void) putc(*cp++, fp);
  463.                         } else
  464.                         (void) putc(*cp++, fp);
  465.                     }
  466.                 }
  467.                 (void) fputs("\"\n", fp);
  468.                 break;
  469.  
  470.             case T_UINFO:
  471.                 fprintf(fp, "\"%s\"\n", cp);
  472.                 break;
  473.  
  474.             case T_UID:
  475.             case T_GID:
  476.                 if (dp->d_size == sizeof(u_long)) {
  477.                     GETLONG(n, cp);
  478.                     fprintf(fp, "%lu\n", n);
  479.                 }
  480.                 break;
  481.  
  482.             case T_WKS:
  483.                 GETLONG(addr, cp);    
  484.                 addr = htonl(addr);    
  485.                 fprintf(fp,"%s ",
  486.                     inet_ntoa(*(struct in_addr *)&addr));
  487.                 proto = protocolname(*cp);
  488.                 cp += sizeof(char); 
  489.                 fprintf(fp, "%s ", proto);
  490.                 i = 0;
  491.                 while(cp < (u_char *)dp->d_data + dp->d_size) {
  492.                     j = *cp++;
  493.                     do {
  494.                         if (j & 0200)
  495.                         fprintf(fp," %s",
  496.                            servicename(i, proto));
  497.                         j <<= 1;
  498.                     } while(++i & 07);
  499.                 } 
  500.                 fprintf(fp,"\n");
  501.                 break;
  502.  
  503.             case T_MINFO:
  504.                 fprintf(fp, "%s.", cp);
  505.                 cp += strlen((char *)cp) + 1;
  506.                 fprintf(fp, " %s.\n", cp);
  507.                 break;
  508. #ifdef ALLOW_T_UNSPEC
  509.             case T_UNSPEC:
  510.                 /* Dump binary data out in an ASCII-encoded
  511.                    format */
  512.                 {
  513.                     /* Allocate more than enough space:
  514.                      *  actually need 5/4 size + 20 or so
  515.                      */
  516.                     int TmpSize = 2 * dp->d_size + 30;
  517.                     char *TmpBuf = (char *) malloc(TmpSize);
  518.                     if (TmpBuf == NULL) {
  519. #ifdef DEBUG
  520.                         if (debug)
  521.                         fprintf(ddt, "Dump T_UNSPEC: malloc returned NULL\n");
  522. #endif DEBUG
  523.                         syslog(LOG_ERR, "Dump T_UNSPEC: malloc: %m");
  524.                     }
  525.                     if (btoa(cp, dp->d_size, TmpBuf,
  526.                          TmpSize) == CONV_OVERFLOW) {
  527. #ifdef DEBUG
  528.                         if (debug)
  529.                             fprintf(ddt, "Dump T_UNSPEC: Output buffer overflow\n");
  530. #endif DEBUG
  531.                             syslog(LOG_ERR, "Dump T_UNSPEC: Output buffer overflow\n");
  532.                     } else
  533.                         fprintf(fp, "%s\n", TmpBuf);
  534.                 }
  535.                 break;
  536. #endif ALLOW_T_UNSPEC
  537.             default:
  538.                 fprintf(fp, "???\n");
  539.             }
  540.         }
  541.         }
  542.     }
  543.         if (ferror(fp))
  544.             return(NODBFILE);
  545.  
  546.     npp = htp->h_tab;
  547.     nppend = npp + htp->h_size;
  548.     while (npp < nppend) {
  549.         for (np = *npp++; np != NULL; np = np->n_next) {
  550.         if (np->n_hash == NULL)
  551.             continue;
  552.         getname(np, dname, sizeof(dname));
  553.         if (db_dump(np->n_hash, fp, zone, dname) == NODBFILE)
  554.             return(NODBFILE);
  555.         }
  556.     }
  557.     return(OK);
  558. }
  559.  
  560. #ifdef ALLOW_T_UNSPEC
  561. /*
  562.  * Subroutines to convert between 8 bit binary bytes and printable ASCII.
  563.  * Computes the number of bytes, and three kinds of simple checksums.
  564.  * Incoming bytes are collected into 32-bit words, then printed in base 85:
  565.  *    exp(85,5) > exp(2,32)
  566.  * The ASCII characters used are between '!' and 'u';
  567.  * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
  568.  *
  569.  * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for
  570.  * the atob/btoa programs, released with the compress program, in mod.sources.
  571.  * Modified by Mike Schwartz 8/19/86 for use in BIND.
  572.  */
  573.  
  574. /* Make sure global variable names are unique */
  575. #define Ceor T_UNSPEC_Ceor
  576. #define Csum T_UNSPEC_Csum
  577. #define Crot T_UNSPEC_Crot
  578. #define word T_UNSPEC_word
  579. #define bcount T_UNSPEC_bcount
  580.  
  581. static long int Ceor, Csum, Crot, word, bcount;
  582.  
  583. #define EN(c)    ((int) ((c) + '!'))
  584. #define DE(c) ((c) - '!')
  585. #define AddToBuf(bufp, c) **bufp = c; (*bufp)++;
  586. #define streq(s0, s1)    strcmp(s0, s1) == 0
  587. #define times85(x)    ((((((x<<2)+x)<<2)+x)<<2)+x)
  588.  
  589.  
  590. /* Decode ASCII-encoded byte c into binary representation and 
  591.  * place into *bufp, advancing bufp 
  592.  */
  593. static int
  594. byte_atob(c, bufp)
  595.     register c;
  596.     char **bufp;
  597. {
  598.     if (c == 'z') {
  599.         if (bcount != 0)
  600.             return(CONV_BADFMT);
  601.         else {
  602.             putbyte(0, bufp);
  603.             putbyte(0, bufp);
  604.             putbyte(0, bufp);
  605.             putbyte(0, bufp);
  606.         }
  607.     } else if ((c >= '!') && (c < ('!' + 85))) {
  608.         if (bcount == 0) {
  609.             word = DE(c);
  610.             ++bcount;
  611.         } else if (bcount < 4) {
  612.             word = times85(word);
  613.             word += DE(c);
  614.             ++bcount;
  615.         } else {
  616.             word = times85(word) + DE(c);
  617.             putbyte((int)((word >> 24) & 255), bufp);
  618.             putbyte((int)((word >> 16) & 255), bufp);
  619.             putbyte((int)((word >> 8) & 255), bufp);
  620.             putbyte((int)(word & 255), bufp);
  621.             word = 0;
  622.             bcount = 0;
  623.         }
  624.     } else
  625.         return(CONV_BADFMT);
  626.     return(CONV_SUCCESS);
  627. }
  628.  
  629. /* Compute checksum info and place c into *bufp, advancing bufp */
  630. static
  631. putbyte(c, bufp)
  632.     register c;
  633.     char **bufp;
  634. {
  635.     Ceor ^= c;
  636.     Csum += c;
  637.     Csum += 1;
  638.     if ((Crot & 0x80000000)) {
  639.         Crot <<= 1;
  640.         Crot += 1;
  641.     } else {
  642.         Crot <<= 1;
  643.     }
  644.     Crot += c;
  645.     AddToBuf(bufp, c);
  646. }
  647.  
  648. /* Read the ASCII-encoded data from inbuf, of length inbuflen, and convert
  649.    it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes;
  650.    outbuflen must be divisible by 4.  (Note: this is because outbuf is filled
  651.    in 4 bytes at a time.  If the actual data doesn't end on an even 4-byte
  652.    boundary, there will be no problem...it will be padded with 0 bytes, and
  653.    numbytes will indicate the correct number of bytes.  The main point is
  654.    that since the buffer is filled in 4 bytes at a time, even if there is
  655.    not a full 4 bytes of data at the end, there has to be room to 0-pad the
  656.    data, so the buffer must be of size divisible by 4).  Place the number of
  657.    output bytes in numbytes, and return a failure/success status  */
  658. int
  659. atob(inbuf, inbuflen, outbuf, outbuflen, numbytes)
  660.     char *inbuf;
  661.     int inbuflen;
  662.     char *outbuf;
  663.     int outbuflen;
  664.     int *numbytes;
  665. {
  666.     int inc, nb;
  667.     long int oeor, osum, orot;
  668.     char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen];
  669.  
  670.     if ( (outbuflen % 4) != 0)
  671.         return(CONV_BADBUFLEN);
  672.     Ceor = Csum = Crot = word = bcount = 0;
  673.     for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) {
  674.         if (outp > endoutp)
  675.             return(CONV_OVERFLOW);
  676.         if (*inp == 'x') {
  677.             inp +=2;
  678.             break;
  679.         } else {
  680.             if (byte_atob(*inp, &outp) == CONV_BADFMT)
  681.                 return(CONV_BADFMT);
  682.         }
  683.     }
  684.  
  685.     /* Get byte count and checksum information from end of buffer */
  686.     if(sscanf(inp, "%ld %lx %lx %lx", numbytes, &oeor, &osum, &orot) != 4)
  687.         return(CONV_BADFMT);
  688.     if ((oeor != Ceor) || (osum != Csum) || (orot != Crot))
  689.         return(CONV_BADCKSUM);
  690.     return(CONV_SUCCESS);
  691. }
  692.  
  693. /* Encode binary byte c into ASCII representation and place into *bufp,
  694.    advancing bufp */
  695. static
  696. byte_btoa(c, bufp)
  697.     register c;
  698.     char **bufp;
  699. {
  700.     Ceor ^= c;
  701.     Csum += c;
  702.     Csum += 1;
  703.     if ((Crot & 0x80000000)) {
  704.         Crot <<= 1;
  705.         Crot += 1;
  706.     } else {
  707.         Crot <<= 1;
  708.     }
  709.     Crot += c;
  710.  
  711.     word <<= 8;
  712.     word |= c;
  713.     if (bcount == 3) {
  714.         if (word == 0) {
  715.             AddToBuf(bufp, 'z');
  716.         } else {
  717.             register int tmp = 0;
  718.             register long int tmpword = word;
  719.             
  720.             if (tmpword < 0) {    
  721.                /* Because some don't support unsigned long */
  722.                 tmp = 32;
  723.                 tmpword -= (long)(85 * 85 * 85 * 85 * 32);
  724.             }
  725.             if (tmpword < 0) {
  726.                 tmp = 64;
  727.                 tmpword -= (long)(85 * 85 * 85 * 85 * 32);
  728.             }
  729.             AddToBuf(bufp,
  730.                  EN((tmpword / (long)(85 * 85 * 85 * 85)) + tmp));
  731.             tmpword %= (long)(85 * 85 * 85 * 85);
  732.             AddToBuf(bufp, EN(tmpword / (85 * 85 * 85)));
  733.             tmpword %= (85 * 85 * 85);
  734.             AddToBuf(bufp, EN(tmpword / (85 * 85)));
  735.             tmpword %= (85 * 85);
  736.             AddToBuf(bufp, EN(tmpword / 85));
  737.             tmpword %= 85;
  738.             AddToBuf(bufp, EN(tmpword));
  739.         }
  740.         bcount = 0;
  741.     } else {
  742.         bcount += 1;
  743.     }
  744. }
  745.  
  746.  
  747. /*
  748.  * Encode the binary data from inbuf, of length inbuflen, into a
  749.  * null-terminated ASCII representation in outbuf, not to exceed outbuflen
  750.  * bytes. Return success/failure status
  751.  */
  752. int
  753. btoa(inbuf, inbuflen, outbuf, outbuflen)
  754.     char *inbuf;
  755.     int inbuflen;
  756.     char *outbuf;
  757.     int outbuflen;
  758. {
  759.     long int inc, nb;
  760.     long int oeor, osum, orot;
  761.     char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen -1];
  762.  
  763.     Ceor = Csum = Crot = word = bcount = 0;
  764.     for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) {
  765.         byte_btoa((unsigned char) (*inp), &outp);
  766.         if (outp >= endoutp)
  767.             return(CONV_OVERFLOW);
  768.     }
  769.     while (bcount != 0) {
  770.         byte_btoa(0, &outp);
  771.         if (outp >= endoutp)
  772.             return(CONV_OVERFLOW);
  773.     }
  774.     /* Put byte count and checksum information at end of buffer, delimited
  775.        by 'x' */
  776.     (void) sprintf(outp, "x %ld %lx %lx %lx", inbuflen, Ceor, Csum, Crot);
  777.     if (&outp[strlen(outp) - 1] >= endoutp)
  778.         return(CONV_OVERFLOW);
  779.     else
  780.         return(CONV_SUCCESS);
  781. }
  782. #endif ALLOW_T_UNSPEC
  783.