/* * krb5int_dns_nextans() - get next answer record * * Sets pp to NULL if no more records. */ int krb5int_dns_nextans(struct krb5int_dns_state *ds, const unsigned char **pp, int *lenp) { int len; unsigned char *p; unsigned short ntype, nclass, rdlen; #if !HAVE_DN_SKIPNAME char host[MAXDNAME]; #endif *pp = NULL; *lenp = 0; p = ds->ptr; while (ds->nanswers--) { #if HAVE_DN_SKIPNAME len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen); #else len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, p, host, sizeof(host)); #endif if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len)) return -1; p += len; SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out); /* Also skip 4 bytes of TTL */ SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out); SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out); if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen)) return -1; /* Solaris Kerberos - resync */ #if 0 if (rdlen > INT_MAX) return -1; #endif if (nclass == ds->nclass && ntype == ds->ntype) { *pp = p; *lenp = rdlen; ds->ptr = p + rdlen; return 0; } p += rdlen; } return 0; out: return -1; }
/* * initparse * * Skip header and question section of reply. Set a pointer to the * beginning of the answer section, and prepare to iterate over * answer records. */ static int initparse(struct krb5int_dns_state *ds) { HEADER *hdr; unsigned char *p; unsigned short nqueries, nanswers; int len; #if !HAVE_DN_SKIPNAME char host[MAXDNAME]; #endif if ((size_t) ds->anslen < sizeof(HEADER)) return -1; hdr = (HEADER *)ds->ansp; p = ds->ansp; nqueries = ntohs((unsigned short)hdr->qdcount); nanswers = ntohs((unsigned short)hdr->ancount); p += sizeof(HEADER); /* * Skip query records. */ while (nqueries--) { #if HAVE_DN_SKIPNAME len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen); #else len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, p, host, sizeof(host)); #endif if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4)) return -1; p += len + 4; } ds->ptr = p; ds->nanswers = nanswers; return 0; }
krb5_error_code krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm) { krb5_error_code retval = KRB5_ERR_HOST_REALM_UNKNOWN; const unsigned char *p, *base; char host[MAXDNAME]; int ret, rdlen, len; struct krb5int_dns_state *ds = NULL; struct k5buf buf; /* * Form our query, and send it via DNS */ krb5int_buf_init_fixed(&buf, host, sizeof(host)); if (name == NULL || name[0] == '\0') { krb5int_buf_add(&buf, prefix); } else { krb5int_buf_add_fmt(&buf, "%s.%s", prefix, name); /* Realm names don't (normally) end with ".", but if the query doesn't end with "." and doesn't get an answer as is, the resolv code will try appending the local domain. Since the realm names are absolutes, let's stop that. But only if a name has been specified. If we are performing a search on the prefix alone then the intention is to allow the local domain or domain search lists to be expanded. */ len = krb5int_buf_len(&buf); if (len > 0 && host[len - 1] != '.') krb5int_buf_add(&buf, "."); } if (krb5int_buf_data(&buf) == NULL) return KRB5_ERR_HOST_REALM_UNKNOWN; ret = krb5int_dns_init(&ds, host, C_IN, T_TXT); if (ret < 0) goto errout; ret = krb5int_dns_nextans(ds, &base, &rdlen); if (ret < 0 || base == NULL) goto errout; p = base; if (!INCR_OK(base, rdlen, p, 1)) goto errout; len = *p++; *realm = malloc((size_t)len + 1); if (*realm == NULL) { retval = ENOMEM; goto errout; } strncpy(*realm, (const char *)p, (size_t)len); (*realm)[len] = '\0'; /* Avoid a common error. */ if ( (*realm)[len-1] == '.' ) (*realm)[len-1] = '\0'; retval = 0; errout: if (ds != NULL) { krb5int_dns_fini(ds); ds = NULL; } return retval; }