1*505d05c7Sgtb #pragma ident "%Z%%M% %I% %E% SMI" 2*505d05c7Sgtb /* 3*505d05c7Sgtb * lib/krb5/os/dnsglue.c 4*505d05c7Sgtb * 5*505d05c7Sgtb * Copyright 2004 by the Massachusetts Institute of Technology. 6*505d05c7Sgtb * All Rights Reserved. 7*505d05c7Sgtb * 8*505d05c7Sgtb * Export of this software from the United States of America may 9*505d05c7Sgtb * require a specific license from the United States Government. 10*505d05c7Sgtb * It is the responsibility of any person or organization contemplating 11*505d05c7Sgtb * export to obtain such a license before exporting. 12*505d05c7Sgtb * 13*505d05c7Sgtb * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 14*505d05c7Sgtb * distribute this software and its documentation for any purpose and 15*505d05c7Sgtb * without fee is hereby granted, provided that the above copyright 16*505d05c7Sgtb * notice appear in all copies and that both that copyright notice and 17*505d05c7Sgtb * this permission notice appear in supporting documentation, and that 18*505d05c7Sgtb * the name of M.I.T. not be used in advertising or publicity pertaining 19*505d05c7Sgtb * to distribution of the software without specific, written prior 20*505d05c7Sgtb * permission. Furthermore if you modify this software you must label 21*505d05c7Sgtb * your software as modified software and not distribute it in such a 22*505d05c7Sgtb * fashion that it might be confused with the original M.I.T. software. 23*505d05c7Sgtb * M.I.T. makes no representations about the suitability of 24*505d05c7Sgtb * this software for any purpose. It is provided "as is" without express 25*505d05c7Sgtb * or implied warranty. 26*505d05c7Sgtb * 27*505d05c7Sgtb */ 28*505d05c7Sgtb #ifdef KRB5_DNS_LOOKUP 29*505d05c7Sgtb 30*505d05c7Sgtb #include "dnsglue.h" 31*505d05c7Sgtb 32*505d05c7Sgtb /* 33*505d05c7Sgtb * Opaque handle 34*505d05c7Sgtb */ 35*505d05c7Sgtb struct krb5int_dns_state { 36*505d05c7Sgtb int nclass; 37*505d05c7Sgtb int ntype; 38*505d05c7Sgtb void *ansp; 39*505d05c7Sgtb int anslen; 40*505d05c7Sgtb int ansmax; 41*505d05c7Sgtb #if HAVE_NS_INITPARSE 42*505d05c7Sgtb int cur_ans; 43*505d05c7Sgtb ns_msg msg; 44*505d05c7Sgtb #else 45*505d05c7Sgtb unsigned char *ptr; 46*505d05c7Sgtb unsigned short nanswers; 47*505d05c7Sgtb #endif 48*505d05c7Sgtb }; 49*505d05c7Sgtb 50*505d05c7Sgtb #if !HAVE_NS_INITPARSE 51*505d05c7Sgtb static int initparse(struct krb5int_dns_state *); 52*505d05c7Sgtb #endif 53*505d05c7Sgtb 54*505d05c7Sgtb /* 55*505d05c7Sgtb * krb5int_dns_init() 56*505d05c7Sgtb * 57*505d05c7Sgtb * Initialize an opaue handl. Do name lookup and initial parsing of 58*505d05c7Sgtb * reply, skipping question section. Prepare to iterate over answer 59*505d05c7Sgtb * section. Returns -1 on error, 0 on success. 60*505d05c7Sgtb */ 61*505d05c7Sgtb int 62*505d05c7Sgtb krb5int_dns_init(struct krb5int_dns_state **dsp, 63*505d05c7Sgtb char *host, int nclass, int ntype) 64*505d05c7Sgtb { 65*505d05c7Sgtb #if HAVE_RES_NSEARCH 66*505d05c7Sgtb struct __res_state statbuf; 67*505d05c7Sgtb #endif 68*505d05c7Sgtb struct krb5int_dns_state *ds; 69*505d05c7Sgtb int len, ret; 70*505d05c7Sgtb size_t nextincr, maxincr; 71*505d05c7Sgtb unsigned char *p; 72*505d05c7Sgtb 73*505d05c7Sgtb *dsp = ds = malloc(sizeof(*ds)); 74*505d05c7Sgtb if (ds == NULL) 75*505d05c7Sgtb return -1; 76*505d05c7Sgtb 77*505d05c7Sgtb ret = -1; 78*505d05c7Sgtb ds->nclass = nclass; 79*505d05c7Sgtb ds->ntype = ntype; 80*505d05c7Sgtb ds->ansp = NULL; 81*505d05c7Sgtb ds->anslen = 0; 82*505d05c7Sgtb ds->ansmax = 0; 83*505d05c7Sgtb nextincr = 2048; 84*505d05c7Sgtb maxincr = INT_MAX; 85*505d05c7Sgtb 86*505d05c7Sgtb #if HAVE_NS_INITPARSE 87*505d05c7Sgtb ds->cur_ans = 0; 88*505d05c7Sgtb #endif 89*505d05c7Sgtb 90*505d05c7Sgtb #if HAVE_RES_NSEARCH 91*505d05c7Sgtb ret = res_ninit(&statbuf); 92*505d05c7Sgtb if (ret < 0) 93*505d05c7Sgtb return -1; 94*505d05c7Sgtb #endif 95*505d05c7Sgtb 96*505d05c7Sgtb do { 97*505d05c7Sgtb p = (ds->ansp == NULL) 98*505d05c7Sgtb ? malloc(nextincr) : realloc(ds->ansp, nextincr); 99*505d05c7Sgtb 100*505d05c7Sgtb if (p == NULL && ds->ansp != NULL) { 101*505d05c7Sgtb ret = -1; 102*505d05c7Sgtb goto errout; 103*505d05c7Sgtb } 104*505d05c7Sgtb ds->ansp = p; 105*505d05c7Sgtb ds->ansmax = nextincr; 106*505d05c7Sgtb 107*505d05c7Sgtb #if HAVE_RES_NSEARCH 108*505d05c7Sgtb len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype, 109*505d05c7Sgtb ds->ansp, ds->ansmax); 110*505d05c7Sgtb #else 111*505d05c7Sgtb len = res_search(host, ds->nclass, ds->ntype, 112*505d05c7Sgtb ds->ansp, ds->ansmax); 113*505d05c7Sgtb #endif 114*505d05c7Sgtb if (len > maxincr) { 115*505d05c7Sgtb ret = -1; 116*505d05c7Sgtb goto errout; 117*505d05c7Sgtb } 118*505d05c7Sgtb while (nextincr < len) 119*505d05c7Sgtb nextincr *= 2; 120*505d05c7Sgtb if (len < 0 || nextincr > maxincr) { 121*505d05c7Sgtb ret = -1; 122*505d05c7Sgtb goto errout; 123*505d05c7Sgtb } 124*505d05c7Sgtb } while (len > ds->ansmax); 125*505d05c7Sgtb 126*505d05c7Sgtb ds->anslen = len; 127*505d05c7Sgtb #if HAVE_NS_INITPARSE 128*505d05c7Sgtb ret = ns_initparse(ds->ansp, ds->anslen, &ds->msg); 129*505d05c7Sgtb #else 130*505d05c7Sgtb ret = initparse(ds); 131*505d05c7Sgtb #endif 132*505d05c7Sgtb if (ret < 0) 133*505d05c7Sgtb goto errout; 134*505d05c7Sgtb 135*505d05c7Sgtb ret = 0; 136*505d05c7Sgtb 137*505d05c7Sgtb errout: 138*505d05c7Sgtb #if HAVE_RES_NSEARCH 139*505d05c7Sgtb #if HAVE_RES_NDESTROY 140*505d05c7Sgtb res_ndestroy(&statbuf); 141*505d05c7Sgtb #else 142*505d05c7Sgtb res_nclose(&statbuf); 143*505d05c7Sgtb #endif 144*505d05c7Sgtb #endif 145*505d05c7Sgtb if (ret < 0) { 146*505d05c7Sgtb if (ds->ansp != NULL) { 147*505d05c7Sgtb free(ds->ansp); 148*505d05c7Sgtb ds->ansp = NULL; 149*505d05c7Sgtb } 150*505d05c7Sgtb } 151*505d05c7Sgtb 152*505d05c7Sgtb return ret; 153*505d05c7Sgtb } 154*505d05c7Sgtb 155*505d05c7Sgtb #if HAVE_NS_INITPARSE 156*505d05c7Sgtb /* 157*505d05c7Sgtb * krb5int_dns_nextans - get next matching answer record 158*505d05c7Sgtb * 159*505d05c7Sgtb * Sets pp to NULL if no more records. Returns -1 on error, 0 on 160*505d05c7Sgtb * success. 161*505d05c7Sgtb */ 162*505d05c7Sgtb int 163*505d05c7Sgtb krb5int_dns_nextans(struct krb5int_dns_state *ds, 164*505d05c7Sgtb const unsigned char **pp, int *lenp) 165*505d05c7Sgtb { 166*505d05c7Sgtb int len; 167*505d05c7Sgtb ns_rr rr; 168*505d05c7Sgtb 169*505d05c7Sgtb *pp = NULL; 170*505d05c7Sgtb *lenp = 0; 171*505d05c7Sgtb while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) { 172*505d05c7Sgtb len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr); 173*505d05c7Sgtb if (len < 0) 174*505d05c7Sgtb return -1; 175*505d05c7Sgtb ds->cur_ans++; 176*505d05c7Sgtb if (ds->nclass == ns_rr_class(rr) 177*505d05c7Sgtb && ds->ntype == ns_rr_type(rr)) { 178*505d05c7Sgtb *pp = ns_rr_rdata(rr); 179*505d05c7Sgtb *lenp = ns_rr_rdlen(rr); 180*505d05c7Sgtb return 0; 181*505d05c7Sgtb } 182*505d05c7Sgtb } 183*505d05c7Sgtb return 0; 184*505d05c7Sgtb } 185*505d05c7Sgtb #endif 186*505d05c7Sgtb 187*505d05c7Sgtb /* 188*505d05c7Sgtb * krb5int_dns_expand - wrapper for dn_expand() 189*505d05c7Sgtb */ 190*505d05c7Sgtb int krb5int_dns_expand(struct krb5int_dns_state *ds, 191*505d05c7Sgtb const unsigned char *p, 192*505d05c7Sgtb char *buf, int len) 193*505d05c7Sgtb { 194*505d05c7Sgtb 195*505d05c7Sgtb #if HAVE_NS_NAME_UNCOMPRESS 196*505d05c7Sgtb return ns_name_uncompress(ds->ansp, 197*505d05c7Sgtb (unsigned char *)ds->ansp + ds->anslen, 198*505d05c7Sgtb p, buf, (size_t)len); 199*505d05c7Sgtb #else 200*505d05c7Sgtb return dn_expand(ds->ansp, 201*505d05c7Sgtb (unsigned char *)ds->ansp + ds->anslen, 202*505d05c7Sgtb p, buf, len); 203*505d05c7Sgtb #endif 204*505d05c7Sgtb } 205*505d05c7Sgtb 206*505d05c7Sgtb /* 207*505d05c7Sgtb * Free stuff. 208*505d05c7Sgtb */ 209*505d05c7Sgtb void 210*505d05c7Sgtb krb5int_dns_fini(struct krb5int_dns_state *ds) 211*505d05c7Sgtb { 212*505d05c7Sgtb if (ds == NULL) 213*505d05c7Sgtb return; 214*505d05c7Sgtb if (ds->ansp != NULL) 215*505d05c7Sgtb free(ds->ansp); 216*505d05c7Sgtb free(ds); 217*505d05c7Sgtb } 218*505d05c7Sgtb 219*505d05c7Sgtb /* 220*505d05c7Sgtb * Compat routines for BIND 4 221*505d05c7Sgtb */ 222*505d05c7Sgtb #if !HAVE_NS_INITPARSE 223*505d05c7Sgtb 224*505d05c7Sgtb /* 225*505d05c7Sgtb * initparse 226*505d05c7Sgtb * 227*505d05c7Sgtb * Skip header and question section of reply. Set a pointer to the 228*505d05c7Sgtb * beginning of the answer section, and prepare to iterate over 229*505d05c7Sgtb * answer records. 230*505d05c7Sgtb */ 231*505d05c7Sgtb static int 232*505d05c7Sgtb initparse(struct krb5int_dns_state *ds) 233*505d05c7Sgtb { 234*505d05c7Sgtb HEADER *hdr; 235*505d05c7Sgtb unsigned char *p; 236*505d05c7Sgtb unsigned short nqueries, nanswers; 237*505d05c7Sgtb int len; 238*505d05c7Sgtb #if !HAVE_DN_SKIPNAME 239*505d05c7Sgtb char host[MAXDNAME]; 240*505d05c7Sgtb #endif 241*505d05c7Sgtb 242*505d05c7Sgtb if (ds->anslen < sizeof(HEADER)) 243*505d05c7Sgtb return -1; 244*505d05c7Sgtb 245*505d05c7Sgtb hdr = (HEADER *)ds->ansp; 246*505d05c7Sgtb p = ds->ansp; 247*505d05c7Sgtb nqueries = ntohs((unsigned short)hdr->qdcount); 248*505d05c7Sgtb nanswers = ntohs((unsigned short)hdr->ancount); 249*505d05c7Sgtb p += sizeof(HEADER); 250*505d05c7Sgtb 251*505d05c7Sgtb /* 252*505d05c7Sgtb * Skip query records. 253*505d05c7Sgtb */ 254*505d05c7Sgtb while (nqueries--) { 255*505d05c7Sgtb #if HAVE_DN_SKIPNAME 256*505d05c7Sgtb len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen); 257*505d05c7Sgtb #else 258*505d05c7Sgtb len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, 259*505d05c7Sgtb p, host, sizeof(host)); 260*505d05c7Sgtb #endif 261*505d05c7Sgtb if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4)) 262*505d05c7Sgtb return -1; 263*505d05c7Sgtb p += len + 4; 264*505d05c7Sgtb } 265*505d05c7Sgtb ds->ptr = p; 266*505d05c7Sgtb ds->nanswers = nanswers; 267*505d05c7Sgtb return 0; 268*505d05c7Sgtb } 269*505d05c7Sgtb 270*505d05c7Sgtb /* 271*505d05c7Sgtb * krb5int_dns_nextans() - get next answer record 272*505d05c7Sgtb * 273*505d05c7Sgtb * Sets pp to NULL if no more records. 274*505d05c7Sgtb */ 275*505d05c7Sgtb int 276*505d05c7Sgtb krb5int_dns_nextans(struct krb5int_dns_state *ds, 277*505d05c7Sgtb const unsigned char **pp, int *lenp) 278*505d05c7Sgtb { 279*505d05c7Sgtb int len; 280*505d05c7Sgtb unsigned char *p; 281*505d05c7Sgtb unsigned short ntype, nclass, rdlen; 282*505d05c7Sgtb #if !HAVE_DN_SKIPNAME 283*505d05c7Sgtb char host[MAXDNAME]; 284*505d05c7Sgtb #endif 285*505d05c7Sgtb 286*505d05c7Sgtb *pp = NULL; 287*505d05c7Sgtb *lenp = 0; 288*505d05c7Sgtb p = ds->ptr; 289*505d05c7Sgtb 290*505d05c7Sgtb while (ds->nanswers--) { 291*505d05c7Sgtb #if HAVE_DN_SKIPNAME 292*505d05c7Sgtb len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen); 293*505d05c7Sgtb #else 294*505d05c7Sgtb len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, 295*505d05c7Sgtb p, host, sizeof(host)); 296*505d05c7Sgtb #endif 297*505d05c7Sgtb if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len)) 298*505d05c7Sgtb return -1; 299*505d05c7Sgtb p += len; 300*505d05c7Sgtb SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out); 301*505d05c7Sgtb /* Also skip 4 bytes of TTL */ 302*505d05c7Sgtb SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out); 303*505d05c7Sgtb SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out); 304*505d05c7Sgtb 305*505d05c7Sgtb if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen)) 306*505d05c7Sgtb return -1; 307*505d05c7Sgtb if (rdlen > INT_MAX) 308*505d05c7Sgtb return -1; 309*505d05c7Sgtb if (nclass == ds->nclass && ntype == ds->ntype) { 310*505d05c7Sgtb *pp = p; 311*505d05c7Sgtb *lenp = rdlen; 312*505d05c7Sgtb ds->ptr = p + rdlen; 313*505d05c7Sgtb return 0; 314*505d05c7Sgtb } 315*505d05c7Sgtb p += rdlen; 316*505d05c7Sgtb } 317*505d05c7Sgtb return 0; 318*505d05c7Sgtb out: 319*505d05c7Sgtb return -1; 320*505d05c7Sgtb } 321*505d05c7Sgtb 322*505d05c7Sgtb #endif 323*505d05c7Sgtb 324*505d05c7Sgtb #endif /* KRB5_DNS_LOOKUP */ 325