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 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <stdio.h> 44 #include <arpa/nameser.h> 45 46 static int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, 47 u_char **lastdnptr); 48 49 50 /* 51 * Expand compressed domain name 'comp_dn' to full domain name. 52 * 'msg' is a pointer to the begining of the message, 53 * 'eomorig' points to the first location after the message, 54 * 'exp_dn' is a pointer to a buffer of size 'length' for the result. 55 * Return size of compressed name or -1 if there was an error. 56 */ 57 int 58 dn_expand(msg, eomorig, comp_dn, exp_dn, length) 59 u_char *msg, *eomorig, *comp_dn, *exp_dn; 60 int length; 61 { 62 register u_char *cp, *dn; 63 register int n, c; 64 u_char *eom; 65 int len = -1, checked = 0; 66 67 dn = exp_dn; 68 cp = comp_dn; 69 eom = exp_dn + length; 70 /* 71 * fetch next label in domain name 72 */ 73 while (n = *cp++) { 74 /* 75 * Check for indirection 76 */ 77 switch (n & INDIR_MASK) { 78 case 0: 79 if (dn != exp_dn) { 80 if (dn >= eom) 81 return (-1); 82 *dn++ = '.'; 83 } 84 if (dn+n >= eom) 85 return (-1); 86 checked += n + 1; 87 while (--n >= 0) { 88 if ((c = *cp++) == '.') { 89 if (dn + n + 2 >= eom) 90 return (-1); 91 *dn++ = '\\'; 92 } 93 *dn++ = c; 94 if (cp >= eomorig) /* out of range */ 95 return (-1); 96 } 97 break; 98 99 case INDIR_MASK: 100 if (len < 0) 101 len = cp - comp_dn + 1; 102 cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); 103 if (cp < msg || cp >= eomorig) /* out of range */ 104 return (-1); 105 checked += 2; 106 /* 107 * Check for loops in the compressed name; 108 * if we've looked at the whole message, 109 * there must be a loop. 110 */ 111 if (checked >= eomorig - msg) 112 return (-1); 113 break; 114 115 default: 116 return (-1); /* flag error */ 117 } 118 } 119 *dn = '\0'; 120 if (len < 0) 121 len = cp - comp_dn; 122 return (len); 123 } 124 125 /* 126 * Compress domain name 'exp_dn' into 'comp_dn'. 127 * Return the size of the compressed name or -1. 128 * 'length' is the size of the array pointed to by 'comp_dn'. 129 * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0] 130 * is a pointer to the beginning of the message. The list ends with NULL. 131 * 'lastdnptr' is a pointer to the end of the arrary pointed to 132 * by 'dnptrs'. Side effect is to update the list of pointers for 133 * labels inserted into the message as we compress the name. 134 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 135 * is NULL, we don't update the list. 136 */ 137 int 138 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) 139 u_char *exp_dn, *comp_dn; 140 int length; 141 u_char **dnptrs, **lastdnptr; 142 { 143 register u_char *cp, *dn; 144 register int c, l; 145 u_char **cpp, **lpp, *sp, *eob; 146 u_char *msg; 147 148 dn = exp_dn; 149 cp = comp_dn; 150 eob = cp + length; 151 if (dnptrs != NULL) { 152 if ((msg = *dnptrs++) != NULL) { 153 for (cpp = dnptrs; *cpp != NULL; cpp++) 154 ; 155 lpp = cpp; /* end of list to search */ 156 } 157 } else 158 msg = NULL; 159 for (c = *dn++; c != '\0'; /*EMPTY*/) { 160 /* look to see if we can use pointers */ 161 if (msg != NULL) { 162 if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) { 163 if (cp+1 >= eob) 164 return (-1); 165 *cp++ = (l >> 8) | INDIR_MASK; 166 *cp++ = l % 256; 167 return (cp - comp_dn); 168 } 169 /* not found, save it */ 170 if (lastdnptr != NULL && cpp < lastdnptr-1) { 171 *cpp++ = cp; 172 *cpp = NULL; 173 } 174 } 175 sp = cp++; /* save ptr to length byte */ 176 do { 177 if (c == '.') { 178 c = *dn++; 179 break; 180 } 181 if (c == '\\') { 182 if ((c = *dn++) == '\0') 183 break; 184 } 185 if (cp >= eob) { 186 if (msg != NULL) 187 *lpp = NULL; 188 return (-1); 189 } 190 *cp++ = c; 191 } while ((c = *dn++) != '\0'); 192 /* catch trailing '.'s but not '..' */ 193 if ((l = cp - sp - 1) == 0 && c == '\0') { 194 cp--; 195 break; 196 } 197 if (l <= 0 || l > MAXLABEL) { 198 if (msg != NULL) 199 *lpp = NULL; 200 return (-1); 201 } 202 *sp = l; 203 } 204 if (cp >= eob) { 205 if (msg != NULL) 206 *lpp = NULL; 207 return (-1); 208 } 209 *cp++ = '\0'; 210 return (cp - comp_dn); 211 } 212 213 /* 214 * Skip over a compressed domain name. Return the size or -1. 215 */ 216 int 217 dn_skipname(comp_dn, eom) 218 u_char *comp_dn, *eom; 219 { 220 register u_char *cp; 221 register int n; 222 223 cp = comp_dn; 224 while (cp < eom && (n = *cp++)) { 225 /* 226 * check for indirection 227 */ 228 switch (n & INDIR_MASK) { 229 case 0: /* normal case, n == len */ 230 cp += n; 231 continue; 232 default: /* illegal type */ 233 return (-1); 234 case INDIR_MASK: /* indirection */ 235 cp++; 236 } 237 break; 238 } 239 return (cp - comp_dn); 240 } 241 242 /* 243 * Search for expanded name from a list of previously compressed names. 244 * Return the offset from msg if found or -1. 245 * dnptrs is the pointer to the first name on the list, 246 * not the pointer to the start of the message. 247 */ 248 static int 249 dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr) 250 { 251 register u_char *dn, *cp, **cpp; 252 register int n; 253 u_char *sp; 254 255 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 256 dn = exp_dn; 257 sp = cp = *cpp; 258 while (n = *cp++) { 259 /* 260 * check for indirection 261 */ 262 switch (n & INDIR_MASK) { 263 case 0: /* normal case, n == len */ 264 while (--n >= 0) { 265 if (*dn == '.') 266 goto next; 267 if (*dn == '\\') 268 dn++; 269 if (*dn++ != *cp++) 270 goto next; 271 } 272 if ((n = *dn++) == '\0' && *cp == '\0') 273 return (sp - msg); 274 if (n == '.') 275 continue; 276 goto next; 277 278 default: /* illegal type */ 279 return (-1); 280 281 case INDIR_MASK: /* indirection */ 282 cp = msg + (((n & 0x3f) << 8) | *cp); 283 } 284 } 285 if (*dn == '\0') 286 return (sp - msg); 287 next: /*EMPTY*/; 288 } 289 return (-1); 290 } 291 292 /* 293 * Routines to insert/extract short/long's. Must account for byte 294 * order and non-alignment problems. This code at least has the 295 * advantage of being portable. 296 * 297 * used by sendmail. 298 */ 299 300 u_short 301 _getshort(msgp) 302 u_char *msgp; 303 { 304 register u_char *p = (u_char *) msgp; 305 #ifdef vax 306 /* 307 * vax compiler doesn't put shorts in registers 308 */ 309 register u_long u; 310 #else 311 register u_short u; 312 #endif 313 314 u = *p++ << 8; 315 return ((u_short)(u | *p)); 316 } 317 318 u_long 319 _getlong(msgp) 320 u_char *msgp; 321 { 322 register u_char *p = (u_char *) msgp; 323 register u_long u; 324 325 u = *p++; u <<= 8; 326 u |= *p++; u <<= 8; 327 u |= *p++; u <<= 8; 328 return (u | *p); 329 } 330 331 void 332 putshort(s, msgp) 333 register u_short s; 334 register u_char *msgp; 335 { 336 337 msgp[1] = s; 338 msgp[0] = s >> 8; 339 } 340 341 void 342 putlong(l, msgp) 343 register u_long l; 344 register u_char *msgp; 345 { 346 347 msgp[3] = l; 348 msgp[2] = (l >>= 8); 349 msgp[1] = (l >>= 8); 350 msgp[0] = l >> 8; 351 } 352