2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A/*
2N/A * University Copyright- Copyright (c) 1982, 1986, 1988
2N/A * The Regents of the University of California
2N/A * All Rights Reserved
2N/A *
2N/A * University Acknowledgment- Portions of this document are derived from
2N/A * software developed by the University of California, Berkeley, and its
2N/A * contributors.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <sys/types.h>
2N/A#include <stdio.h>
2N/A#include <arpa/nameser.h>
2N/A
2N/Astatic int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs,
2N/A u_char **lastdnptr);
2N/A
2N/A
2N/A/*
2N/A * Expand compressed domain name 'comp_dn' to full domain name.
2N/A * 'msg' is a pointer to the begining of the message,
2N/A * 'eomorig' points to the first location after the message,
2N/A * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2N/A * Return size of compressed name or -1 if there was an error.
2N/A */
2N/Aint
2N/Adn_expand(msg, eomorig, comp_dn, exp_dn, length)
2N/A u_char *msg, *eomorig, *comp_dn, *exp_dn;
2N/A int length;
2N/A{
2N/A register u_char *cp, *dn;
2N/A register int n, c;
2N/A u_char *eom;
2N/A int len = -1, checked = 0;
2N/A
2N/A dn = exp_dn;
2N/A cp = comp_dn;
2N/A eom = exp_dn + length;
2N/A /*
2N/A * fetch next label in domain name
2N/A */
2N/A while (n = *cp++) {
2N/A /*
2N/A * Check for indirection
2N/A */
2N/A switch (n & INDIR_MASK) {
2N/A case 0:
2N/A if (dn != exp_dn) {
2N/A if (dn >= eom)
2N/A return (-1);
2N/A *dn++ = '.';
2N/A }
2N/A if (dn+n >= eom)
2N/A return (-1);
2N/A checked += n + 1;
2N/A while (--n >= 0) {
2N/A if ((c = *cp++) == '.') {
2N/A if (dn + n + 2 >= eom)
2N/A return (-1);
2N/A *dn++ = '\\';
2N/A }
2N/A *dn++ = c;
2N/A if (cp >= eomorig) /* out of range */
2N/A return (-1);
2N/A }
2N/A break;
2N/A
2N/A case INDIR_MASK:
2N/A if (len < 0)
2N/A len = cp - comp_dn + 1;
2N/A cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
2N/A if (cp < msg || cp >= eomorig) /* out of range */
2N/A return (-1);
2N/A checked += 2;
2N/A /*
2N/A * Check for loops in the compressed name;
2N/A * if we've looked at the whole message,
2N/A * there must be a loop.
2N/A */
2N/A if (checked >= eomorig - msg)
2N/A return (-1);
2N/A break;
2N/A
2N/A default:
2N/A return (-1); /* flag error */
2N/A }
2N/A }
2N/A *dn = '\0';
2N/A if (len < 0)
2N/A len = cp - comp_dn;
2N/A return (len);
2N/A}
2N/A
2N/A/*
2N/A * Compress domain name 'exp_dn' into 'comp_dn'.
2N/A * Return the size of the compressed name or -1.
2N/A * 'length' is the size of the array pointed to by 'comp_dn'.
2N/A * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
2N/A * is a pointer to the beginning of the message. The list ends with NULL.
2N/A * 'lastdnptr' is a pointer to the end of the arrary pointed to
2N/A * by 'dnptrs'. Side effect is to update the list of pointers for
2N/A * labels inserted into the message as we compress the name.
2N/A * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
2N/A * is NULL, we don't update the list.
2N/A */
2N/Aint
2N/Adn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
2N/A u_char *exp_dn, *comp_dn;
2N/A int length;
2N/A u_char **dnptrs, **lastdnptr;
2N/A{
2N/A register u_char *cp, *dn;
2N/A register int c, l;
2N/A u_char **cpp, **lpp, *sp, *eob;
2N/A u_char *msg;
2N/A
2N/A dn = exp_dn;
2N/A cp = comp_dn;
2N/A eob = cp + length;
2N/A if (dnptrs != NULL) {
2N/A if ((msg = *dnptrs++) != NULL) {
2N/A for (cpp = dnptrs; *cpp != NULL; cpp++)
2N/A ;
2N/A lpp = cpp; /* end of list to search */
2N/A }
2N/A } else
2N/A msg = NULL;
2N/A for (c = *dn++; c != '\0'; /*EMPTY*/) {
2N/A /* look to see if we can use pointers */
2N/A if (msg != NULL) {
2N/A if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
2N/A if (cp+1 >= eob)
2N/A return (-1);
2N/A *cp++ = (l >> 8) | INDIR_MASK;
2N/A *cp++ = l % 256;
2N/A return (cp - comp_dn);
2N/A }
2N/A /* not found, save it */
2N/A if (lastdnptr != NULL && cpp < lastdnptr-1) {
2N/A *cpp++ = cp;
2N/A *cpp = NULL;
2N/A }
2N/A }
2N/A sp = cp++; /* save ptr to length byte */
2N/A do {
2N/A if (c == '.') {
2N/A c = *dn++;
2N/A break;
2N/A }
2N/A if (c == '\\') {
2N/A if ((c = *dn++) == '\0')
2N/A break;
2N/A }
2N/A if (cp >= eob) {
2N/A if (msg != NULL)
2N/A *lpp = NULL;
2N/A return (-1);
2N/A }
2N/A *cp++ = c;
2N/A } while ((c = *dn++) != '\0');
2N/A /* catch trailing '.'s but not '..' */
2N/A if ((l = cp - sp - 1) == 0 && c == '\0') {
2N/A cp--;
2N/A break;
2N/A }
2N/A if (l <= 0 || l > MAXLABEL) {
2N/A if (msg != NULL)
2N/A *lpp = NULL;
2N/A return (-1);
2N/A }
2N/A *sp = l;
2N/A }
2N/A if (cp >= eob) {
2N/A if (msg != NULL)
2N/A *lpp = NULL;
2N/A return (-1);
2N/A }
2N/A *cp++ = '\0';
2N/A return (cp - comp_dn);
2N/A}
2N/A
2N/A/*
2N/A * Skip over a compressed domain name. Return the size or -1.
2N/A */
2N/Aint
2N/Adn_skipname(comp_dn, eom)
2N/A u_char *comp_dn, *eom;
2N/A{
2N/A register u_char *cp;
2N/A register int n;
2N/A
2N/A cp = comp_dn;
2N/A while (cp < eom && (n = *cp++)) {
2N/A /*
2N/A * check for indirection
2N/A */
2N/A switch (n & INDIR_MASK) {
2N/A case 0: /* normal case, n == len */
2N/A cp += n;
2N/A continue;
2N/A default: /* illegal type */
2N/A return (-1);
2N/A case INDIR_MASK: /* indirection */
2N/A cp++;
2N/A }
2N/A break;
2N/A }
2N/A return (cp - comp_dn);
2N/A}
2N/A
2N/A/*
2N/A * Search for expanded name from a list of previously compressed names.
2N/A * Return the offset from msg if found or -1.
2N/A * dnptrs is the pointer to the first name on the list,
2N/A * not the pointer to the start of the message.
2N/A */
2N/Astatic int
2N/Adn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr)
2N/A{
2N/A register u_char *dn, *cp, **cpp;
2N/A register int n;
2N/A u_char *sp;
2N/A
2N/A for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
2N/A dn = exp_dn;
2N/A sp = cp = *cpp;
2N/A while (n = *cp++) {
2N/A /*
2N/A * check for indirection
2N/A */
2N/A switch (n & INDIR_MASK) {
2N/A case 0: /* normal case, n == len */
2N/A while (--n >= 0) {
2N/A if (*dn == '.')
2N/A goto next;
2N/A if (*dn == '\\')
2N/A dn++;
2N/A if (*dn++ != *cp++)
2N/A goto next;
2N/A }
2N/A if ((n = *dn++) == '\0' && *cp == '\0')
2N/A return (sp - msg);
2N/A if (n == '.')
2N/A continue;
2N/A goto next;
2N/A
2N/A default: /* illegal type */
2N/A return (-1);
2N/A
2N/A case INDIR_MASK: /* indirection */
2N/A cp = msg + (((n & 0x3f) << 8) | *cp);
2N/A }
2N/A }
2N/A if (*dn == '\0')
2N/A return (sp - msg);
2N/A next: /*EMPTY*/;
2N/A }
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Routines to insert/extract short/long's. Must account for byte
2N/A * order and non-alignment problems. This code at least has the
2N/A * advantage of being portable.
2N/A *
2N/A * used by sendmail.
2N/A */
2N/A
2N/Au_short
2N/A_getshort(msgp)
2N/A u_char *msgp;
2N/A{
2N/A register u_char *p = (u_char *) msgp;
2N/A#ifdef vax
2N/A /*
2N/A * vax compiler doesn't put shorts in registers
2N/A */
2N/A register u_long u;
2N/A#else
2N/A register u_short u;
2N/A#endif
2N/A
2N/A u = *p++ << 8;
2N/A return ((u_short)(u | *p));
2N/A}
2N/A
2N/Au_long
2N/A_getlong(msgp)
2N/A u_char *msgp;
2N/A{
2N/A register u_char *p = (u_char *) msgp;
2N/A register u_long u;
2N/A
2N/A u = *p++; u <<= 8;
2N/A u |= *p++; u <<= 8;
2N/A u |= *p++; u <<= 8;
2N/A return (u | *p);
2N/A}
2N/A
2N/Avoid
2N/Aputshort(s, msgp)
2N/A register u_short s;
2N/A register u_char *msgp;
2N/A{
2N/A
2N/A msgp[1] = s;
2N/A msgp[0] = s >> 8;
2N/A}
2N/A
2N/Avoid
2N/Aputlong(l, msgp)
2N/A register u_long l;
2N/A register u_char *msgp;
2N/A{
2N/A
2N/A msgp[3] = l;
2N/A msgp[2] = (l >>= 8);
2N/A msgp[1] = (l >>= 8);
2N/A msgp[0] = l >> 8;
2N/A}