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