diff options
author | pst <pst@FreeBSD.org> | 1994-09-22 19:46:15 +0000 |
---|---|---|
committer | pst <pst@FreeBSD.org> | 1994-09-22 19:46:15 +0000 |
commit | 3866fef02d12ce18b3b81e010ac2af997ce350a8 (patch) | |
tree | 34c210f7b31ea37b062599209869c309ddfca8ee /usr.sbin/named/db_dump.c | |
parent | 8b1c40bc18615379af063dfafe0085ffa594da60 (diff) | |
download | FreeBSD-src-3866fef02d12ce18b3b81e010ac2af997ce350a8.zip FreeBSD-src-3866fef02d12ce18b3b81e010ac2af997ce350a8.tar.gz |
NAMED from BIND 4.9.3 BETA9 pl1 (no local changes)
Diffstat (limited to 'usr.sbin/named/db_dump.c')
-rw-r--r-- | usr.sbin/named/db_dump.c | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/usr.sbin/named/db_dump.c b/usr.sbin/named/db_dump.c new file mode 100644 index 0000000..4a0d2c9 --- /dev/null +++ b/usr.sbin/named/db_dump.c @@ -0,0 +1,892 @@ +#if !defined(lint) && !defined(SABER) +static char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91"; +static char rcsid[] = "$Id: db_dump.c,v 4.9.1.12 1994/07/22 08:42:39 vixie Exp $"; +#endif /* not lint */ + +/* + * ++Copyright++ 1986, 1988, 1990 + * - + * Copyright (c) 1986, 1988, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <syslog.h> +#include <resolv.h> +#include <errno.h> + +#include "named.h" + +static int scan_root __P((struct hashbuf *)); +static const char *MkCredStr __P((int)); + +#ifdef ALLOW_T_UNSPEC +static void putbyte __P((int, char **)); +#endif + +/* + * Dump current cache in a format similar to RFC 883. + * + * We try to be careful and determine whether the operation succeeded + * so that the new cache file can be installed. + */ + +void +doachkpt() +{ + FILE *fp; + char tmpcheckfile[256]; + + /* nowhere to checkpoint cache... */ + if (cache_file == NULL) { + dprintf(3, (ddt, "skipping doachkpt (cache_file == NULL)\n")); + return; + } + + dprintf(3, (ddt, "doachkpt()\n")); + + (void) sprintf(tmpcheckfile, "%s.chk", cache_file); + if ((fp = fopen(tmpcheckfile, "w")) == NULL) { + dprintf(3, (ddt, + "doachkpt(can't open %s for write)\n", tmpcheckfile)); + return; + } + + (void) gettime(&tt); + fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); + fflush(fp); + if (ferror(fp)) { + dprintf(3, (ddt, "doachkpt(write to checkpoint file failed)\n")); + return; + } + + if (fcachetab != NULL) { + int n = scan_root(hashtab); + + if (n < MINROOTS) { + syslog(LOG_ERR, "%d root hints... (too low)", n); + fprintf(fp, "; ---- Root hint cache dump ----\n"); + (void) db_dump(fcachetab, fp, DB_Z_CACHE, ""); + } + } + + if (hashtab != NULL) { + fprintf(fp, "; ---- Cache dump ----\n"); + if (db_dump(hashtab, fp, DB_Z_CACHE, "") == NODBFILE) { + dprintf(3, (ddt, "doachkpt(checkpoint failed)\n")); + (void) my_fclose(fp); + return; + } + } + + (void) fsync(fileno(fp)); + if (my_fclose(fp) == EOF) { + return; + } + + if (rename(tmpcheckfile, cache_file)) { + dprintf(3, (ddt, "doachkpt(install %s to %s failed, %d)\n", + tmpcheckfile, cache_file, errno)); + } +} + +/* + * What we do is scan the root hint cache to make sure there are at least + * MINROOTS root pointers with non-0 TTL's so that the checkpoint will not + * lose the root. Failing this, all pointers are written out w/ TTL ~0 + * (root pointers timed out and prime_cache() not done or failed). + */ + +static int +scan_root(htp) + struct hashbuf *htp; +{ + register struct databuf *dp; + register struct namebuf *np; + struct timeval soon; + int roots = 0; + + dprintf(1, (ddt, "scan_root(0x%x)\n", htp)); + + /* metric by which we determine whether a root NS pointer is still */ + /* valid (will be written out if we do a dump). we also add some */ + /* time buffer for safety... */ + (void) gettime(&soon); + soon.tv_sec += TIMBUF; + + for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { + if (np->n_dname[0] == '\0') { + dp = np->n_data; + while (dp != NULL) { + if (dp->d_type == T_NS && + dp->d_ttl > soon.tv_sec) { + roots++; + if (roots >= MINROOTS) + return (roots); + } + dp = dp->d_next; + } + } + } + return (roots); +} + +#ifdef notdef +mark_cache(htp, ttl) + struct hashbuf *htp; + int ttl; +{ + register struct databuf *dp; + register struct namebuf *np; + struct namebuf **npp, **nppend; + struct timeval soon; + + dprintf(1, (ddt, "mark_cache()\n")); + + (void) gettime(&soon); + soon.tv_sec += TIMBUF; + + npp = htp->h_tab; + nppend = npp + htp->h_size; + while (npp < nppend) { + for (np = *npp++; np != NULL; np = np->n_next) { + if (np->n_data == NULL) + continue; + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_ttl < soon.tv_sec) + dp->d_ttl = ttl; + } + } + } + + npp = htp->h_tab; + nppend = npp + htp->h_size; + while (npp < nppend) { + for (np = *npp++; np != NULL; np = np->n_next) { + if (np->n_hash == NULL) + continue; + mark_cache(np->n_hash, ttl); + } + } +} +#endif /* notdef */ + +/* + * Dump current data base in a format similar to RFC 883. + */ + +void +doadump() +{ + FILE *fp; + + dprintf(3, (ddt, "doadump()\n")); + + if ((fp = fopen(dumpfile, "w")) == NULL) + return; + gettime(&tt); + fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); + if (zones && nzones) + zt_dump(fp); + fputs( +"; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n", + fp); + fputs( +"; Note: NT=milliseconds for any A RR which we've used as a nameserver\n", + fp); + fprintf(fp, "; --- Cache & Data ---\n"); + if (hashtab != NULL) + (void) db_dump(hashtab, fp, DB_Z_ALL, ""); + fprintf(fp, "; --- Hints ---\n"); + if (fcachetab != NULL) + (void) db_dump(fcachetab, fp, DB_Z_ALL, ""); + (void) my_fclose(fp); +} + +#ifdef ALLOW_UPDATES +/* Create a disk database to back up zones + */ +void +zonedump(zp) + register struct zoneinfo *zp; +{ + FILE *fp; + char *fname; + struct hashbuf *htp; + char *op; + struct stat st; + + /* Only dump zone if there is a cache specified */ + if (zp->z_source && *(zp->z_source)) { + dprintf(1, (ddt, "zonedump(%s)\n", zp->z_source)); + + if ((fp = fopen(zp->z_source, "w")) == NULL) + return; + if (op = strchr(zp->z_origin, '.')) + op++; + gettime(&tt); + htp = hashtab; + if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) { + db_dump(htp, fp, zp-zones, (op == NULL ? "" : op)); + zp->z_flags &= ~Z_CHANGED; /* Checkpointed */ + } + (void) my_fclose(fp); + if (stat(zp->z_source, &st) == 0) + zp->z_ftime = st.st_mtime; + } else { + dprintf(1, (ddt, "zonedump: no zone to dump\n")); + } +} +#endif + +int +zt_dump(fp) + FILE *fp; +{ + register struct zoneinfo *zp; + + fprintf(fp, ";; ++zone table++\n"); + for (zp = &zones[1]; zp < &zones[nzones]; zp++) { + char *pre, buf[64]; + u_int cnt; + + fprintf(fp, "; %s (type %d, class %d, source %s)\n", + zp->z_origin, zp->z_type, zp->z_class, + zp->z_source ? zp->z_source : "Nil"); + fprintf(fp, ";\ttime=%ld, lastupdate=%ld, serial=%u,\n", + zp->z_time, zp->z_lastupdate, zp->z_serial); + fprintf(fp, ";\trefresh=%u, retry=%u, expire=%u, minimum=%u\n", + zp->z_refresh, zp->z_retry, + zp->z_expire, zp->z_minimum); + fprintf(fp, ";\tftime=%ld, xaddr=[%s], state=%04x, pid=%d\n", + zp->z_ftime, inet_ntoa(zp->z_xaddr), + zp->z_flags, zp->z_xferpid); + sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt); + pre = buf; + for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + fprintf(fp, "%s[%s]", pre, inet_ntoa(zp->z_addr[cnt])); + pre = ", "; + } + if (zp->z_addrcnt) + fputc('\n', fp); + } + fprintf(fp, ";; --zone table--\n"); +} + +int +db_dump(htp, fp, zone, origin) + struct hashbuf *htp; + FILE *fp; + int zone; + char *origin; +{ + register struct databuf *dp = NULL; + register struct namebuf *np; + struct namebuf **npp, **nppend; + char dname[MAXDNAME]; + u_int32_t n; + u_int32_t addr; + int j, i; + register u_char *cp; + u_char *end; + char *proto, *sep; + int found_data = 0, tab, printed_origin = 0; + + npp = htp->h_tab; + nppend = npp + htp->h_size; + while (npp < nppend) { + for (np = *npp++; np != NULL; np = np->n_next) { + if (np->n_data == NULL) + continue; + /* Blecch - can't tell if there is data here for the + * right zone, so can't print name yet + */ + found_data = 0; + /* we want a snapshot in time... */ + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + /* Is the data for this zone? */ + if (zone != DB_Z_ALL && dp->d_zone != zone) + continue; + if (dp->d_zone == DB_Z_CACHE && + dp->d_ttl <= tt.tv_sec && + (dp->d_flags & DB_F_HINT) == 0) + continue; + if (!printed_origin) { + fprintf(fp, "$ORIGIN %s.\n", origin); + printed_origin++; + } + tab = 0; +#ifdef NCACHE + if (dp->d_rcode == NXDOMAIN || + dp->d_rcode == NOERROR_NODATA) { + fputc(';', fp); + } else if (found_data == 0 || found_data == 1) { + found_data = 2; + } +#endif /*NCACHE*/ + if (found_data == 0 || found_data == 2) { + if (np->n_dname[0] == 0) { + if (origin[0] == 0) + fprintf(fp, ".\t"); + else + fprintf(fp, ".%s.\t", origin); /* ??? */ + } else + fprintf(fp, "%s\t", np->n_dname); + if (strlen(np->n_dname) < 8) + tab = 1; + found_data++; + } else { + (void) putc('\t', fp); + tab = 1; + } + if (dp->d_zone == DB_Z_CACHE) { + if (dp->d_flags & DB_F_HINT + && (int32_t)(dp->d_ttl - tt.tv_sec) + < DB_ROOT_TIMBUF) + fprintf(fp, "%d\t", DB_ROOT_TIMBUF); + else + fprintf(fp, "%d\t", + (int)(dp->d_ttl - tt.tv_sec)); + } else if (dp->d_ttl != 0 && + dp->d_ttl != zones[dp->d_zone].z_minimum) + fprintf(fp, "%d\t", (int)dp->d_ttl); + else if (tab) + (void) putc('\t', fp); + fprintf(fp, "%s\t%s\t", + p_class(dp->d_class), + p_type(dp->d_type)); + cp = (u_char *)dp->d_data; + sep = "\t;"; +#ifdef NCACHE +#ifdef RETURNSOA + if (dp->d_rcode == NOERROR_NODATA) { + fprintf(fp, "NODATA%s-$", sep); + goto eoln; + } +#else + if (dp->d_rcode == NXDOMAIN || + dp->d_rcode == NOERROR_NODATA) { + fprintf(fp, "%s%s-$", + (dp->d_rcode == NXDOMAIN) + ?"NXDOMAIN" :"NODATA", + sep); + goto eoln; + } +#endif +#endif + /* + * Print type specific data + */ + switch (dp->d_type) { + case T_A: + switch (dp->d_class) { + case C_IN: + case C_HS: + GETLONG(n, cp); + n = htonl(n); + fprintf(fp, "%s", + inet_ntoa(*(struct in_addr *)&n)); + break; + } + if (dp->d_nstime) { + fprintf(fp, "%sNT=%d", + sep, dp->d_nstime); + sep = " "; + } + break; + case T_CNAME: + case T_MB: + case T_MG: + case T_MR: + case T_PTR: + fprintf(fp, "%s.", cp); + break; + + case T_NS: + cp = (u_char *)dp->d_data; + if (cp[0] == '\0') + fprintf(fp, ".\t"); + else + fprintf(fp, "%s.", cp); + break; + + case T_HINFO: + case T_ISDN: + if (n = *cp++) { + fprintf(fp, "\"%.*s\"", (int)n, cp); + cp += n; + } else + fprintf(fp, "\"\""); + if (n = *cp++) + fprintf(fp, " \"%.*s\"", (int)n, cp); + else + fprintf(fp, " \"\""); + break; + + case T_SOA: + fprintf(fp, "%s.", cp); + cp += strlen((char *)cp) + 1; + fprintf(fp, " %s. (\n", cp); +#if defined(RETURNSOA) && defined(NCACHE) + if (dp->d_rcode == NXDOMAIN) + fputs(";", fp); +#endif + cp += strlen((char *)cp) + 1; + GETLONG(n, cp); + fprintf(fp, "\t\t%lu", n); + GETLONG(n, cp); + fprintf(fp, " %lu", n); + GETLONG(n, cp); + fprintf(fp, " %lu", n); + GETLONG(n, cp); + fprintf(fp, " %lu", n); + GETLONG(n, cp); + fprintf(fp, " %lu )", n); +#if defined(RETURNSOA) && defined(NCACHE) + if (dp->d_rcode == NXDOMAIN) { + fprintf(fp,";%s.;NXDOMAIN%s-$",cp,sep); + } +#endif + break; + + case T_MX: + case T_AFSDB: + case T_RT: + GETSHORT(n, cp); + fprintf(fp,"%lu", n); + fprintf(fp," %s.", cp); + break; + + case T_TXT: + case T_X25: + end = (u_char *)dp->d_data + dp->d_size; + (void) putc('"', fp); + while (cp < end) { + if (n = *cp++) { + for (j = n ; j > 0 && cp < end ; j--) + if (*cp == '\n') { + (void) putc('\\', fp); + (void) putc(*cp++, fp); + } else + (void) putc(*cp++, fp); + } + } + (void) fputs("\"", fp); + break; + + case T_NSAP: + (void) fputs(inet_nsap_ntoa(dp->d_size, + dp->d_data, NULL), + fp); + break; + + case T_UINFO: + fprintf(fp, "\"%s\"", cp); + break; + + case T_UID: + case T_GID: + if (dp->d_size == INT32SZ) { + GETLONG(n, cp); + } else { + n = -2; /* XXX - hack */ + } + fprintf(fp, "%u", n); + break; + + case T_WKS: + GETLONG(addr, cp); + addr = htonl(addr); + fprintf(fp, "%s ", + inet_ntoa(*(struct in_addr *)&addr)); + proto = protocolname(*cp); + cp += sizeof(char); + fprintf(fp, "%s ", proto); + i = 0; + while(cp < (u_char *)dp->d_data + dp->d_size) { + j = *cp++; + do { + if (j & 0200) + fprintf(fp, " %s", + servicename(i, proto)); + j <<= 1; + } while (++i & 07); + } + break; + + case T_MINFO: + case T_RP: + fprintf(fp, "%s.", cp); + cp += strlen((char *)cp) + 1; + fprintf(fp, " %s.", cp); + break; +#ifdef ALLOW_T_UNSPEC + case T_UNSPEC: + /* Dump binary data out in an ASCII-encoded + format */ + { + /* Allocate more than enough space: + * actually need 5/4 size + 20 or so + */ + int TmpSize = 2 * dp->d_size + 30; + char *TmpBuf = (char *) malloc(TmpSize); + if (TmpBuf == NULL) { + dprintf(1, + (ddt, + "Dump T_UNSPEC: bad malloc\n" + ) + ); + syslog(LOG_ERR, + "Dump T_UNSPEC: malloc: %m"); + TmpBuf = "BAD_MALLOC"; + } + if (btoa(cp, dp->d_size, TmpBuf, TmpSize) + == CONV_OVERFLOW) { + dprintf(1, (ddt, + "Dump T_UNSPEC: Output buffer overflow\n" + ) + ); + syslog(LOG_ERR, + "Dump T_UNSPEC: Output buffer overflow\n"); + TmpBuf = "OVERFLOW"; + } + fprintf(fp, "%s", TmpBuf); + } + break; +#endif /* ALLOW_T_UNSPEC */ + default: + fprintf(fp, "%s?d_type=%d?", + sep, dp->d_type); + sep = " "; + } + if (dp->d_cred < DB_C_ZONE) { + fprintf(fp, "%sCr=%s", + sep, MkCredStr(dp->d_cred)); + sep = " "; + } else { + fprintf(fp, "%sCl=%d", + sep, dp->d_clev); + sep = " "; + } +eoln: +#ifdef STATS + if (dp->d_ns) { + fprintf(fp, "%s[%s]", + sep, inet_ntoa(dp->d_ns->addr)); + sep = " "; + } +#endif + putc('\n', fp); + } + } + } + if (ferror(fp)) + return(NODBFILE); + + npp = htp->h_tab; + nppend = npp + htp->h_size; + while (npp < nppend) { + for (np = *npp++; np != NULL; np = np->n_next) { + if (np->n_hash == NULL) + continue; + getname(np, dname, sizeof(dname)); + if (db_dump(np->n_hash, fp, zone, dname) == NODBFILE) + return(NODBFILE); + } + } + return(OK); +} + +static const char * +MkCredStr(cred) + int cred; +{ + static char badness[20]; + + switch (cred) { + case DB_C_ZONE: return "zone"; + case DB_C_AUTH: return "auth"; + case DB_C_ANSWER: return "answer"; + case DB_C_ADDITIONAL: return "addtnl"; + case DB_C_CACHE: return "cache"; + default: break; + } + sprintf(badness, "?%d?", cred); + return (badness); +} + +#ifdef ALLOW_T_UNSPEC +/* + * Subroutines to convert between 8 bit binary bytes and printable ASCII. + * Computes the number of bytes, and three kinds of simple checksums. + * Incoming bytes are collected into 32-bit words, then printed in base 85: + * exp(85,5) > exp(2,32) + * The ASCII characters used are between '!' and 'u'; + * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data. + * + * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for + * the atob/btoa programs, released with the compress program, in mod.sources. + * Modified by Mike Schwartz 8/19/86 for use in BIND. + */ + +/* Make sure global variable names are unique */ +#define Ceor T_UNSPEC_Ceor +#define Csum T_UNSPEC_Csum +#define Crot T_UNSPEC_Crot +#define word T_UNSPEC_word +#define bcount T_UNSPEC_bcount + +static int32_t Ceor, Csum, Crot, word, bcount; + +#define EN(c) ((int) ((c) + '!')) +#define DE(c) ((c) - '!') +#define AddToBuf(bufp, c) **bufp = c; (*bufp)++; +#define times85(x) ((((((x<<2)+x)<<2)+x)<<2)+x) + +/* Decode ASCII-encoded byte c into binary representation and + * place into *bufp, advancing bufp + */ +static int +byte_atob(c, bufp) + register c; + char **bufp; +{ + if (c == 'z') { + if (bcount != 0) + return(CONV_BADFMT); + else { + putbyte(0, bufp); + putbyte(0, bufp); + putbyte(0, bufp); + putbyte(0, bufp); + } + } else if ((c >= '!') && (c < ('!' + 85))) { + if (bcount == 0) { + word = DE(c); + ++bcount; + } else if (bcount < 4) { + word = times85(word); + word += DE(c); + ++bcount; + } else { + word = times85(word) + DE(c); + putbyte((int)((word >> 24) & 255), bufp); + putbyte((int)((word >> 16) & 255), bufp); + putbyte((int)((word >> 8) & 255), bufp); + putbyte((int)(word & 255), bufp); + word = 0; + bcount = 0; + } + } else + return(CONV_BADFMT); + return(CONV_SUCCESS); +} + +/* Compute checksum info and place c into *bufp, advancing bufp */ +static void +putbyte(c, bufp) + register c; + char **bufp; +{ + Ceor ^= c; + Csum += c; + Csum += 1; + if ((Crot & 0x80000000)) { + Crot <<= 1; + Crot += 1; + } else { + Crot <<= 1; + } + Crot += c; + AddToBuf(bufp, c); +} + +/* Read the ASCII-encoded data from inbuf, of length inbuflen, and convert + it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes; + outbuflen must be divisible by 4. (Note: this is because outbuf is filled + in 4 bytes at a time. If the actual data doesn't end on an even 4-byte + boundary, there will be no problem...it will be padded with 0 bytes, and + numbytes will indicate the correct number of bytes. The main point is + that since the buffer is filled in 4 bytes at a time, even if there is + not a full 4 bytes of data at the end, there has to be room to 0-pad the + data, so the buffer must be of size divisible by 4). Place the number of + output bytes in numbytes, and return a failure/success status */ +int +atob(inbuf, inbuflen, outbuf, outbuflen, numbytes) + char *inbuf; + int inbuflen; + char *outbuf; + int outbuflen; + int *numbytes; +{ + int inc, nb; + int32_t oeor, osum, orot; + char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen]; + + if ( (outbuflen % 4) != 0) + return(CONV_BADBUFLEN); + Ceor = Csum = Crot = word = bcount = 0; + for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) { + if (outp > endoutp) + return(CONV_OVERFLOW); + if (*inp == 'x') { + inp +=2; + break; + } else { + if (byte_atob(*inp, &outp) == CONV_BADFMT) + return(CONV_BADFMT); + } + } + + /* Get byte count and checksum information from end of buffer */ + if(sscanf(inp, "%ld %lx %lx %lx", numbytes, &oeor, &osum, &orot) != 4) + return(CONV_BADFMT); + if ((oeor != Ceor) || (osum != Csum) || (orot != Crot)) + return(CONV_BADCKSUM); + return(CONV_SUCCESS); +} + +/* Encode binary byte c into ASCII representation and place into *bufp, + advancing bufp */ +static void +byte_btoa(c, bufp) + register c; + char **bufp; +{ + Ceor ^= c; + Csum += c; + Csum += 1; + if ((Crot & 0x80000000)) { + Crot <<= 1; + Crot += 1; + } else { + Crot <<= 1; + } + Crot += c; + + word <<= 8; + word |= c; + if (bcount == 3) { + if (word == 0) { + AddToBuf(bufp, 'z'); + } else { + register int tmp = 0; + register int32_t tmpword = word; + + if (tmpword < 0) { + /* Because some don't support unsigned long */ + tmp = 32; + tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32); + } + if (tmpword < 0) { + tmp = 64; + tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32); + } + AddToBuf(bufp, + EN((tmpword / (int32_t)(85 * 85 * 85 * 85)) + tmp)); + tmpword %= (int32_t)(85 * 85 * 85 * 85); + AddToBuf(bufp, EN(tmpword / (85 * 85 * 85))); + tmpword %= (85 * 85 * 85); + AddToBuf(bufp, EN(tmpword / (85 * 85))); + tmpword %= (85 * 85); + AddToBuf(bufp, EN(tmpword / 85)); + tmpword %= 85; + AddToBuf(bufp, EN(tmpword)); + } + bcount = 0; + } else { + bcount += 1; + } +} + + +/* + * Encode the binary data from inbuf, of length inbuflen, into a + * null-terminated ASCII representation in outbuf, not to exceed outbuflen + * bytes. Return success/failure status + */ +static int +btoa(inbuf, inbuflen, outbuf, outbuflen) + char *inbuf; + int inbuflen; + char *outbuf; + int outbuflen; +{ + int32_t inc, nb; + int32_t oeor, osum, orot; + char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen -1]; + + Ceor = Csum = Crot = word = bcount = 0; + for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) { + byte_btoa((unsigned char) (*inp), &outp); + if (outp >= endoutp) + return(CONV_OVERFLOW); + } + while (bcount != 0) { + byte_btoa(0, &outp); + if (outp >= endoutp) + return(CONV_OVERFLOW); + } + /* Put byte count and checksum information at end of buffer, delimited + by 'x' */ + (void) sprintf(outp, "x %ld %lx %lx %lx", inbuflen, Ceor, Csum, Crot); + if (&outp[strlen(outp) - 1] >= endoutp) + return(CONV_OVERFLOW); + else + return(CONV_SUCCESS); +} +#endif /* ALLOW_T_UNSPEC */ |