17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*e8031f0aSraf 237c478bd9Sstevel@tonic-gate /* 24*e8031f0aSraf * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 337c478bd9Sstevel@tonic-gate * The Regents of the University of California 347c478bd9Sstevel@tonic-gate * All Rights Reserved 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 377c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 387c478bd9Sstevel@tonic-gate * contributors. 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 427c478bd9Sstevel@tonic-gate 43*e8031f0aSraf #include "c_synonyms.h" 447c478bd9Sstevel@tonic-gate #include <sys/types.h> 457c478bd9Sstevel@tonic-gate #include <stdio.h> 467c478bd9Sstevel@tonic-gate #include <arpa/nameser.h> 477c478bd9Sstevel@tonic-gate 486a1c6faaSanay static int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, 496a1c6faaSanay u_char **lastdnptr); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * Expand compressed domain name 'comp_dn' to full domain name. 547c478bd9Sstevel@tonic-gate * 'msg' is a pointer to the begining of the message, 557c478bd9Sstevel@tonic-gate * 'eomorig' points to the first location after the message, 567c478bd9Sstevel@tonic-gate * 'exp_dn' is a pointer to a buffer of size 'length' for the result. 577c478bd9Sstevel@tonic-gate * Return size of compressed name or -1 if there was an error. 587c478bd9Sstevel@tonic-gate */ 596a1c6faaSanay int 607c478bd9Sstevel@tonic-gate dn_expand(msg, eomorig, comp_dn, exp_dn, length) 617c478bd9Sstevel@tonic-gate u_char *msg, *eomorig, *comp_dn, *exp_dn; 627c478bd9Sstevel@tonic-gate int length; 637c478bd9Sstevel@tonic-gate { 647c478bd9Sstevel@tonic-gate register u_char *cp, *dn; 657c478bd9Sstevel@tonic-gate register int n, c; 667c478bd9Sstevel@tonic-gate u_char *eom; 677c478bd9Sstevel@tonic-gate int len = -1, checked = 0; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate dn = exp_dn; 707c478bd9Sstevel@tonic-gate cp = comp_dn; 717c478bd9Sstevel@tonic-gate eom = exp_dn + length; 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * fetch next label in domain name 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate while (n = *cp++) { 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * Check for indirection 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate switch (n & INDIR_MASK) { 807c478bd9Sstevel@tonic-gate case 0: 817c478bd9Sstevel@tonic-gate if (dn != exp_dn) { 827c478bd9Sstevel@tonic-gate if (dn >= eom) 837c478bd9Sstevel@tonic-gate return (-1); 847c478bd9Sstevel@tonic-gate *dn++ = '.'; 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate if (dn+n >= eom) 877c478bd9Sstevel@tonic-gate return (-1); 887c478bd9Sstevel@tonic-gate checked += n + 1; 897c478bd9Sstevel@tonic-gate while (--n >= 0) { 907c478bd9Sstevel@tonic-gate if ((c = *cp++) == '.') { 917c478bd9Sstevel@tonic-gate if (dn + n + 2 >= eom) 927c478bd9Sstevel@tonic-gate return (-1); 937c478bd9Sstevel@tonic-gate *dn++ = '\\'; 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate *dn++ = c; 967c478bd9Sstevel@tonic-gate if (cp >= eomorig) /* out of range */ 977c478bd9Sstevel@tonic-gate return (-1); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate break; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate case INDIR_MASK: 1027c478bd9Sstevel@tonic-gate if (len < 0) 1037c478bd9Sstevel@tonic-gate len = cp - comp_dn + 1; 1047c478bd9Sstevel@tonic-gate cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 1057c478bd9Sstevel@tonic-gate if (cp < msg || cp >= eomorig) /* out of range */ 1067c478bd9Sstevel@tonic-gate return (-1); 1077c478bd9Sstevel@tonic-gate checked += 2; 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * Check for loops in the compressed name; 1107c478bd9Sstevel@tonic-gate * if we've looked at the whole message, 1117c478bd9Sstevel@tonic-gate * there must be a loop. 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate if (checked >= eomorig - msg) 1147c478bd9Sstevel@tonic-gate return (-1); 1157c478bd9Sstevel@tonic-gate break; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate default: 1187c478bd9Sstevel@tonic-gate return (-1); /* flag error */ 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate *dn = '\0'; 1227c478bd9Sstevel@tonic-gate if (len < 0) 1237c478bd9Sstevel@tonic-gate len = cp - comp_dn; 1247c478bd9Sstevel@tonic-gate return (len); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Compress domain name 'exp_dn' into 'comp_dn'. 1297c478bd9Sstevel@tonic-gate * Return the size of the compressed name or -1. 1307c478bd9Sstevel@tonic-gate * 'length' is the size of the array pointed to by 'comp_dn'. 1317c478bd9Sstevel@tonic-gate * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] 1327c478bd9Sstevel@tonic-gate * is a pointer to the beginning of the message. The list ends with NULL. 1337c478bd9Sstevel@tonic-gate * 'lastdnptr' is a pointer to the end of the arrary pointed to 1347c478bd9Sstevel@tonic-gate * by 'dnptrs'. Side effect is to update the list of pointers for 1357c478bd9Sstevel@tonic-gate * labels inserted into the message as we compress the name. 1367c478bd9Sstevel@tonic-gate * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 1377c478bd9Sstevel@tonic-gate * is NULL, we don't update the list. 1387c478bd9Sstevel@tonic-gate */ 1396a1c6faaSanay int 1407c478bd9Sstevel@tonic-gate dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 1417c478bd9Sstevel@tonic-gate u_char *exp_dn, *comp_dn; 1427c478bd9Sstevel@tonic-gate int length; 1437c478bd9Sstevel@tonic-gate u_char **dnptrs, **lastdnptr; 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate register u_char *cp, *dn; 1467c478bd9Sstevel@tonic-gate register int c, l; 1477c478bd9Sstevel@tonic-gate u_char **cpp, **lpp, *sp, *eob; 1487c478bd9Sstevel@tonic-gate u_char *msg; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate dn = exp_dn; 1517c478bd9Sstevel@tonic-gate cp = comp_dn; 1527c478bd9Sstevel@tonic-gate eob = cp + length; 1537c478bd9Sstevel@tonic-gate if (dnptrs != NULL) { 1547c478bd9Sstevel@tonic-gate if ((msg = *dnptrs++) != NULL) { 1557c478bd9Sstevel@tonic-gate for (cpp = dnptrs; *cpp != NULL; cpp++) 1567c478bd9Sstevel@tonic-gate ; 1577c478bd9Sstevel@tonic-gate lpp = cpp; /* end of list to search */ 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate } else 1607c478bd9Sstevel@tonic-gate msg = NULL; 1617c478bd9Sstevel@tonic-gate for (c = *dn++; c != '\0'; /*EMPTY*/) { 1627c478bd9Sstevel@tonic-gate /* look to see if we can use pointers */ 1637c478bd9Sstevel@tonic-gate if (msg != NULL) { 1647c478bd9Sstevel@tonic-gate if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 1657c478bd9Sstevel@tonic-gate if (cp+1 >= eob) 1667c478bd9Sstevel@tonic-gate return (-1); 1677c478bd9Sstevel@tonic-gate *cp++ = (l >> 8) | INDIR_MASK; 1687c478bd9Sstevel@tonic-gate *cp++ = l % 256; 1697c478bd9Sstevel@tonic-gate return (cp - comp_dn); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate /* not found, save it */ 1727c478bd9Sstevel@tonic-gate if (lastdnptr != NULL && cpp < lastdnptr-1) { 1737c478bd9Sstevel@tonic-gate *cpp++ = cp; 1747c478bd9Sstevel@tonic-gate *cpp = NULL; 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate sp = cp++; /* save ptr to length byte */ 1787c478bd9Sstevel@tonic-gate do { 1797c478bd9Sstevel@tonic-gate if (c == '.') { 1807c478bd9Sstevel@tonic-gate c = *dn++; 1817c478bd9Sstevel@tonic-gate break; 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate if (c == '\\') { 1847c478bd9Sstevel@tonic-gate if ((c = *dn++) == '\0') 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate if (cp >= eob) { 1887c478bd9Sstevel@tonic-gate if (msg != NULL) 1897c478bd9Sstevel@tonic-gate *lpp = NULL; 1907c478bd9Sstevel@tonic-gate return (-1); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate *cp++ = c; 1937c478bd9Sstevel@tonic-gate } while ((c = *dn++) != '\0'); 1947c478bd9Sstevel@tonic-gate /* catch trailing '.'s but not '..' */ 1957c478bd9Sstevel@tonic-gate if ((l = cp - sp - 1) == 0 && c == '\0') { 1967c478bd9Sstevel@tonic-gate cp--; 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate if (l <= 0 || l > MAXLABEL) { 2007c478bd9Sstevel@tonic-gate if (msg != NULL) 2017c478bd9Sstevel@tonic-gate *lpp = NULL; 2027c478bd9Sstevel@tonic-gate return (-1); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate *sp = l; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate if (cp >= eob) { 2077c478bd9Sstevel@tonic-gate if (msg != NULL) 2087c478bd9Sstevel@tonic-gate *lpp = NULL; 2097c478bd9Sstevel@tonic-gate return (-1); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate *cp++ = '\0'; 2127c478bd9Sstevel@tonic-gate return (cp - comp_dn); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Skip over a compressed domain name. Return the size or -1. 2177c478bd9Sstevel@tonic-gate */ 2186a1c6faaSanay int 2197c478bd9Sstevel@tonic-gate dn_skipname(comp_dn, eom) 2207c478bd9Sstevel@tonic-gate u_char *comp_dn, *eom; 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate register u_char *cp; 2237c478bd9Sstevel@tonic-gate register int n; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate cp = comp_dn; 2267c478bd9Sstevel@tonic-gate while (cp < eom && (n = *cp++)) { 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * check for indirection 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate switch (n & INDIR_MASK) { 2317c478bd9Sstevel@tonic-gate case 0: /* normal case, n == len */ 2327c478bd9Sstevel@tonic-gate cp += n; 2337c478bd9Sstevel@tonic-gate continue; 2347c478bd9Sstevel@tonic-gate default: /* illegal type */ 2357c478bd9Sstevel@tonic-gate return (-1); 2367c478bd9Sstevel@tonic-gate case INDIR_MASK: /* indirection */ 2377c478bd9Sstevel@tonic-gate cp++; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate break; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate return (cp - comp_dn); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * Search for expanded name from a list of previously compressed names. 2467c478bd9Sstevel@tonic-gate * Return the offset from msg if found or -1. 2477c478bd9Sstevel@tonic-gate * dnptrs is the pointer to the first name on the list, 2487c478bd9Sstevel@tonic-gate * not the pointer to the start of the message. 2497c478bd9Sstevel@tonic-gate */ 2506a1c6faaSanay static int 2516a1c6faaSanay dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr) 2527c478bd9Sstevel@tonic-gate { 2537c478bd9Sstevel@tonic-gate register u_char *dn, *cp, **cpp; 2547c478bd9Sstevel@tonic-gate register int n; 2557c478bd9Sstevel@tonic-gate u_char *sp; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 2587c478bd9Sstevel@tonic-gate dn = exp_dn; 2597c478bd9Sstevel@tonic-gate sp = cp = *cpp; 2607c478bd9Sstevel@tonic-gate while (n = *cp++) { 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * check for indirection 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate switch (n & INDIR_MASK) { 2657c478bd9Sstevel@tonic-gate case 0: /* normal case, n == len */ 2667c478bd9Sstevel@tonic-gate while (--n >= 0) { 2677c478bd9Sstevel@tonic-gate if (*dn == '.') 2687c478bd9Sstevel@tonic-gate goto next; 2697c478bd9Sstevel@tonic-gate if (*dn == '\\') 2707c478bd9Sstevel@tonic-gate dn++; 2717c478bd9Sstevel@tonic-gate if (*dn++ != *cp++) 2727c478bd9Sstevel@tonic-gate goto next; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate if ((n = *dn++) == '\0' && *cp == '\0') 2757c478bd9Sstevel@tonic-gate return (sp - msg); 2767c478bd9Sstevel@tonic-gate if (n == '.') 2777c478bd9Sstevel@tonic-gate continue; 2787c478bd9Sstevel@tonic-gate goto next; 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate default: /* illegal type */ 2817c478bd9Sstevel@tonic-gate return (-1); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate case INDIR_MASK: /* indirection */ 2847c478bd9Sstevel@tonic-gate cp = msg + (((n & 0x3f) << 8) | *cp); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate if (*dn == '\0') 2887c478bd9Sstevel@tonic-gate return (sp - msg); 2897c478bd9Sstevel@tonic-gate next: /*EMPTY*/; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate return (-1); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * Routines to insert/extract short/long's. Must account for byte 2967c478bd9Sstevel@tonic-gate * order and non-alignment problems. This code at least has the 2977c478bd9Sstevel@tonic-gate * advantage of being portable. 2987c478bd9Sstevel@tonic-gate * 2997c478bd9Sstevel@tonic-gate * used by sendmail. 3007c478bd9Sstevel@tonic-gate */ 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate u_short 3037c478bd9Sstevel@tonic-gate _getshort(msgp) 3047c478bd9Sstevel@tonic-gate u_char *msgp; 3057c478bd9Sstevel@tonic-gate { 3067c478bd9Sstevel@tonic-gate register u_char *p = (u_char *) msgp; 3077c478bd9Sstevel@tonic-gate #ifdef vax 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * vax compiler doesn't put shorts in registers 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate register u_long u; 3127c478bd9Sstevel@tonic-gate #else 3137c478bd9Sstevel@tonic-gate register u_short u; 3147c478bd9Sstevel@tonic-gate #endif 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate u = *p++ << 8; 3177c478bd9Sstevel@tonic-gate return ((u_short)(u | *p)); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate u_long 3217c478bd9Sstevel@tonic-gate _getlong(msgp) 3227c478bd9Sstevel@tonic-gate u_char *msgp; 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate register u_char *p = (u_char *) msgp; 3257c478bd9Sstevel@tonic-gate register u_long u; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate u = *p++; u <<= 8; 3287c478bd9Sstevel@tonic-gate u |= *p++; u <<= 8; 3297c478bd9Sstevel@tonic-gate u |= *p++; u <<= 8; 3307c478bd9Sstevel@tonic-gate return (u | *p); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3336a1c6faaSanay void 3347c478bd9Sstevel@tonic-gate putshort(s, msgp) 3357c478bd9Sstevel@tonic-gate register u_short s; 3367c478bd9Sstevel@tonic-gate register u_char *msgp; 3377c478bd9Sstevel@tonic-gate { 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate msgp[1] = s; 3407c478bd9Sstevel@tonic-gate msgp[0] = s >> 8; 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3436a1c6faaSanay void 3447c478bd9Sstevel@tonic-gate putlong(l, msgp) 3457c478bd9Sstevel@tonic-gate register u_long l; 3467c478bd9Sstevel@tonic-gate register u_char *msgp; 3477c478bd9Sstevel@tonic-gate { 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate msgp[3] = l; 3507c478bd9Sstevel@tonic-gate msgp[2] = (l >>= 8); 3517c478bd9Sstevel@tonic-gate msgp[1] = (l >>= 8); 3527c478bd9Sstevel@tonic-gate msgp[0] = l >> 8; 3537c478bd9Sstevel@tonic-gate } 354