1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #include <sys/types.h> 41 #include <stdio.h> 42 #include <arpa/nameser.h> 43 44 static int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, 45 u_char **lastdnptr); 46 47 48 /* 49 * Expand compressed domain name 'comp_dn' to full domain name. 50 * 'msg' is a pointer to the begining of the message, 51 * 'eomorig' points to the first location after the message, 52 * 'exp_dn' is a pointer to a buffer of size 'length' for the result. 53 * Return size of compressed name or -1 if there was an error. 54 */ 55 int 56 dn_expand(msg, eomorig, comp_dn, exp_dn, length) 57 u_char *msg, *eomorig, *comp_dn, *exp_dn; 58 int length; 59 { 60 register u_char *cp, *dn; 61 register int n, c; 62 u_char *eom; 63 int len = -1, checked = 0; 64 65 dn = exp_dn; 66 cp = comp_dn; 67 eom = exp_dn + length; 68 /* 69 * fetch next label in domain name 70 */ 71 while (n = *cp++) { 72 /* 73 * Check for indirection 74 */ 75 switch (n & INDIR_MASK) { 76 case 0: 77 if (dn != exp_dn) { 78 if (dn >= eom) 79 return (-1); 80 *dn++ = '.'; 81 } 82 if (dn+n >= eom) 83 return (-1); 84 checked += n + 1; 85 while (--n >= 0) { 86 if ((c = *cp++) == '.') { 87 if (dn + n + 2 >= eom) 88 return (-1); 89 *dn++ = '\\'; 90 } 91 *dn++ = c; 92 if (cp >= eomorig) /* out of range */ 93 return (-1); 94 } 95 break; 96 97 case INDIR_MASK: 98 if (len < 0) 99 len = cp - comp_dn + 1; 100 cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 101 if (cp < msg || cp >= eomorig) /* out of range */ 102 return (-1); 103 checked += 2; 104 /* 105 * Check for loops in the compressed name; 106 * if we've looked at the whole message, 107 * there must be a loop. 108 */ 109 if (checked >= eomorig - msg) 110 return (-1); 111 break; 112 113 default: 114 return (-1); /* flag error */ 115 } 116 } 117 *dn = '\0'; 118 if (len < 0) 119 len = cp - comp_dn; 120 return (len); 121 } 122 123 /* 124 * Compress domain name 'exp_dn' into 'comp_dn'. 125 * Return the size of the compressed name or -1. 126 * 'length' is the size of the array pointed to by 'comp_dn'. 127 * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] 128 * is a pointer to the beginning of the message. The list ends with NULL. 129 * 'lastdnptr' is a pointer to the end of the arrary pointed to 130 * by 'dnptrs'. Side effect is to update the list of pointers for 131 * labels inserted into the message as we compress the name. 132 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 133 * is NULL, we don't update the list. 134 */ 135 int 136 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 137 u_char *exp_dn, *comp_dn; 138 int length; 139 u_char **dnptrs, **lastdnptr; 140 { 141 register u_char *cp, *dn; 142 register int c, l; 143 u_char **cpp, **lpp, *sp, *eob; 144 u_char *msg; 145 146 dn = exp_dn; 147 cp = comp_dn; 148 eob = cp + length; 149 if (dnptrs != NULL) { 150 if ((msg = *dnptrs++) != NULL) { 151 for (cpp = dnptrs; *cpp != NULL; cpp++) 152 ; 153 lpp = cpp; /* end of list to search */ 154 } 155 } else 156 msg = NULL; 157 for (c = *dn++; c != '\0'; /*EMPTY*/) { 158 /* look to see if we can use pointers */ 159 if (msg != NULL) { 160 if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 161 if (cp+1 >= eob) 162 return (-1); 163 *cp++ = (l >> 8) | INDIR_MASK; 164 *cp++ = l % 256; 165 return (cp - comp_dn); 166 } 167 /* not found, save it */ 168 if (lastdnptr != NULL && cpp < lastdnptr-1) { 169 *cpp++ = cp; 170 *cpp = NULL; 171 } 172 } 173 sp = cp++; /* save ptr to length byte */ 174 do { 175 if (c == '.') { 176 c = *dn++; 177 break; 178 } 179 if (c == '\\') { 180 if ((c = *dn++) == '\0') 181 break; 182 } 183 if (cp >= eob) { 184 if (msg != NULL) 185 *lpp = NULL; 186 return (-1); 187 } 188 *cp++ = c; 189 } while ((c = *dn++) != '\0'); 190 /* catch trailing '.'s but not '..' */ 191 if ((l = cp - sp - 1) == 0 && c == '\0') { 192 cp--; 193 break; 194 } 195 if (l <= 0 || l > MAXLABEL) { 196 if (msg != NULL) 197 *lpp = NULL; 198 return (-1); 199 } 200 *sp = l; 201 } 202 if (cp >= eob) { 203 if (msg != NULL) 204 *lpp = NULL; 205 return (-1); 206 } 207 *cp++ = '\0'; 208 return (cp - comp_dn); 209 } 210 211 /* 212 * Skip over a compressed domain name. Return the size or -1. 213 */ 214 int 215 dn_skipname(comp_dn, eom) 216 u_char *comp_dn, *eom; 217 { 218 register u_char *cp; 219 register int n; 220 221 cp = comp_dn; 222 while (cp < eom && (n = *cp++)) { 223 /* 224 * check for indirection 225 */ 226 switch (n & INDIR_MASK) { 227 case 0: /* normal case, n == len */ 228 cp += n; 229 continue; 230 default: /* illegal type */ 231 return (-1); 232 case INDIR_MASK: /* indirection */ 233 cp++; 234 } 235 break; 236 } 237 return (cp - comp_dn); 238 } 239 240 /* 241 * Search for expanded name from a list of previously compressed names. 242 * Return the offset from msg if found or -1. 243 * dnptrs is the pointer to the first name on the list, 244 * not the pointer to the start of the message. 245 */ 246 static int 247 dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr) 248 { 249 register u_char *dn, *cp, **cpp; 250 register int n; 251 u_char *sp; 252 253 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 254 dn = exp_dn; 255 sp = cp = *cpp; 256 while (n = *cp++) { 257 /* 258 * check for indirection 259 */ 260 switch (n & INDIR_MASK) { 261 case 0: /* normal case, n == len */ 262 while (--n >= 0) { 263 if (*dn == '.') 264 goto next; 265 if (*dn == '\\') 266 dn++; 267 if (*dn++ != *cp++) 268 goto next; 269 } 270 if ((n = *dn++) == '\0' && *cp == '\0') 271 return (sp - msg); 272 if (n == '.') 273 continue; 274 goto next; 275 276 default: /* illegal type */ 277 return (-1); 278 279 case INDIR_MASK: /* indirection */ 280 cp = msg + (((n & 0x3f) << 8) | *cp); 281 } 282 } 283 if (*dn == '\0') 284 return (sp - msg); 285 next: /*EMPTY*/; 286 } 287 return (-1); 288 } 289 290 /* 291 * Routines to insert/extract short/long's. Must account for byte 292 * order and non-alignment problems. This code at least has the 293 * advantage of being portable. 294 * 295 * used by sendmail. 296 */ 297 298 u_short 299 _getshort(msgp) 300 u_char *msgp; 301 { 302 register u_char *p = (u_char *) msgp; 303 #ifdef vax 304 /* 305 * vax compiler doesn't put shorts in registers 306 */ 307 register u_long u; 308 #else 309 register u_short u; 310 #endif 311 312 u = *p++ << 8; 313 return ((u_short)(u | *p)); 314 } 315 316 u_long 317 _getlong(msgp) 318 u_char *msgp; 319 { 320 register u_char *p = (u_char *) msgp; 321 register u_long u; 322 323 u = *p++; u <<= 8; 324 u |= *p++; u <<= 8; 325 u |= *p++; u <<= 8; 326 return (u | *p); 327 } 328 329 void 330 putshort(s, msgp) 331 register u_short s; 332 register u_char *msgp; 333 { 334 335 msgp[1] = s; 336 msgp[0] = s >> 8; 337 } 338 339 void 340 putlong(l, msgp) 341 register u_long l; 342 register u_char *msgp; 343 { 344 345 msgp[3] = l; 346 msgp[2] = (l >>= 8); 347 msgp[1] = (l >>= 8); 348 msgp[0] = l >> 8; 349 } 350