Windows fixes: remove unreferenced; use sizeof to compute array size
[krb5.git] / src / util / wshelper / res_quer.c
1 /*
2  *
3  *      @doc RESOLVE
4  *
5  *
6  *      @module res_quer.c | Contains the implementation of res_query,
7  *      res_search, and res_querydomain
8  *
9  * WSHelper DNS/Hesiod Library for WINSOCK
10  *
11  */
12
13 /*
14  * Copyright (c) 1988 Regents of the University of California.
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. All advertising materials mentioning features or use of this software
26  *    must display the following acknowledgement:
27  *      This product includes software developed by the University of
28  *      California, Berkeley and its contributors.
29  * 4. Neither the name of the University nor the names of its contributors
30  *    may be used to endorse or promote products derived from this software
31  *    without specific prior written permission.
32  *
33  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  */
45
46 #if defined(LIBC_SCCS) && !defined(lint)
47 static char sccsid[] = "@(#)res_query.c 5.11 (Berkeley) 3/6/91";
48 #endif /* LIBC_SCCS and not lint */
49
50 #include <windows.h>
51 #include <winsock.h>
52 #include <resolv.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <windns.h>
58
59 #define MAX_MSG_SIZE 0x8000
60
61 #define strcasecmp      stricmp
62
63 #ifdef _DEBUG
64 #define DEBUG
65 #endif
66 int
67 __hostalias(register const char *name, char* abuf);
68 DNS_STATUS do_res_search(const char *name, int qclass, int type, u_char *retanswer, int retanswerlen, int* anslen);
69 void __putshort(register u_short, register u_char *);
70 void __putlong(register u_long, u_char *);
71 int build_rr(char* p, PDNS_RECORD ptr, int qclass);
72 int put_qname(char* p, char* qname);
73
74
75
76 /*
77         a generic query interface to the DNS name space. The query is performed with the dnsapi and
78         the answer buffer is populated based on the returned RR set.
79
80         \param[in]      name    domain name
81         \param[in]      qclass  class of query(such as DNS_CLASS_INTERNET, DNS_CLASS_CSNET, DNS_CLASS_CHAOS,
82                                                 DNS_CLASS_HESIOD. Defined in windns.h)
83         \param[in]      type    type of query(such as DNS_TYPE_A, DNS_TYPE_NS, DNS_TYPE_MX, DNS_TYPE_SRV. Defined in
84                                                 windns.h)
85         \param[in]      answer  buffer to put answer in
86         \param[in]      anslen  size of the answer buffer. compare the anslen with the return value, if the return
87                                                 value is bigger than anslen, it means the answer buffer doesn't contain the complete
88                                                 response. You will need to call this function again with a bigger answer buffer if
89                                                 you care about the complete response
90
91         \retval         return the size of the response on success, -1 on error
92
93
94  */
95 int WINAPI
96 res_search(const char *name, int qclass, int type, u_char *answer, int anslen)
97     /* domain name, class and type of query, buffer to put answer, size of answer */
98 {
99     char debstr[80];
100     int n = 0;
101     DNS_STATUS status;
102     char queryname[DNS_MAX_NAME_BUFFER_LENGTH ];
103     register const char *cp;
104     int len = 0;
105
106     char** domain;
107
108     status = -1;
109     memset(answer, 0, anslen);
110     memset(queryname, 0, sizeof(queryname));
111
112     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
113         return (-1);
114
115     for (cp = name, n = 0; *cp; cp++)
116         if (*cp == '.')
117             n++;
118
119     if (n == 0 && !__hostalias(name, queryname) && strlen(queryname)>0)
120     {
121         status = do_res_search(queryname, qclass, type, answer, anslen, &len);
122         if (status == 0)
123             return len;
124     }
125
126     if ((n == 0 && _res.options & RES_DEFNAMES))
127         // (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
128     {
129         for (domain = _res.dnsrch; *domain; domain++) {
130             strcpy(queryname, name);
131             strcat(queryname, ".");
132             strcat(queryname, *domain);
133             status = do_res_search(queryname, qclass, type, answer, anslen, &len);
134             if (status == 0)
135                 return len;
136         }
137     }
138
139
140     strcpy(queryname, name);
141     status = do_res_search(queryname, qclass, type, answer, anslen, &len);
142
143
144     if (status)
145     {
146 #ifdef DEBUG
147         if (_res.options & RES_DEBUG)
148         {
149             wsprintf(debstr, "res_query failed\n");
150             OutputDebugString(debstr);
151         }
152 #endif
153         return -1;
154     }
155     return len;
156 }
157
158 int
159 put_qname(char* cp, char* qname)
160 {
161     char* p;
162     char* temp;
163     INT_PTR n = 0;
164     INT_PTR i = 0;
165     temp = qname;
166     while (p = strchr(temp, '.'))
167     {
168         n = p - temp;
169         if (n == 0)
170         {
171             temp++;
172             break;
173         }
174         cp[0] = (int)n;
175         cp++;
176         i++;
177         strncpy(cp, temp, n);
178         temp = p+1;
179         cp =  cp + n;
180         i = i + n;
181     }
182     n = strlen(temp);
183     if (n > 0)
184     {
185         cp[0] = (int)n;
186         cp++;
187         i++;
188         strcpy(cp, temp);
189         cp = cp+n;
190     }
191     cp[0] = 0;
192     i = i+n+1;
193     return (int)i;
194 }
195
196 DNS_STATUS
197 do_res_search(const char *queryname, int qclass, int type, u_char *retanswer, int retanswerlen, int* anslen)
198 {
199     PDNS_RECORD pDnsRecord;
200     PDNS_RECORD ptr;
201     DNS_STATUS status;
202     DNS_FREE_TYPE freetype ;
203     HEADER *hp;
204     char *cp;
205     int  n;
206     int i;
207     u_char  answer[MAX_MSG_SIZE];
208     DWORD options = DNS_QUERY_STANDARD;
209     freetype =  DnsFreeRecordListDeep;
210
211     memset(answer, 0, MAX_MSG_SIZE);
212     if (!(_res.options & RES_RECURSE))
213         options = options | DNS_QUERY_NO_RECURSION;
214     if (_res.options & RES_USEVC)
215         options = options | DNS_QUERY_USE_TCP_ONLY;
216     if (_res.options & RES_IGNTC)
217         options = options | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE;
218
219     status = DnsQuery_A(queryname,                 //pointer to OwnerName
220                         type,         //Type of the record to be queried
221                         options,
222                         NULL,                   //contains DNS server IP address
223                         &pDnsRecord,                //Resource record comprising the response
224                         NULL);                     //reserved for future use
225
226     if (status)
227         return  status;
228
229
230     hp = (HEADER *) answer;
231     cp = answer + sizeof(HEADER);
232
233     // populating the header
234     hp->id = htons(++_res.id); // query id
235     hp->qr = 1;  // 0 for query 1 for response
236     hp->opcode = 0; // standard query
237     hp->aa = 1; // authoritative answer
238     hp->tc = 0; // no truncation
239     hp->rd = (_res.options & RES_RECURSE) != 0; // resursion desired
240     hp->ra = 1;  // recursion available
241     hp->pr = (_res.options & RES_PRIMARY) != 0; // primary server required
242     hp->rcode = NOERROR;
243     hp->qdcount = htons(1); // number of question entries
244     i = put_qname(cp, (char*)queryname);
245     cp = cp + i;
246     __putshort(type, (u_char *)cp);
247     cp += sizeof(u_short);
248     __putshort(qclass, (u_char *)cp);
249     cp += sizeof(u_short);
250
251     // get the answer
252     for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
253     {
254         if ((ptr->Flags).S.Section == DNSREC_ANSWER ||
255              (type == DNS_TYPE_PTR && (ptr->Flags).S.Section==DNSREC_QUESTION))
256         {
257             i = build_rr(cp, ptr, qclass);
258             cp = cp + i;
259             //strcpy(cp, pDnsRecord->pName);
260             //cp += strlen(pDnsRecord->pName);
261             //cp++;
262
263             n++;
264         }
265     }
266     hp->ancount = htons(n);
267
268     // get the authority
269     for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
270     {
271         if ((ptr->Flags).S.Section == DNSREC_AUTHORITY )
272         {
273             i = build_rr(cp, ptr, qclass);
274             cp = cp + i;
275
276             n++;
277         }
278     }
279     hp->nscount = htons(n);
280
281     // get the additional resource
282     for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
283     {
284         if ((ptr->Flags).S.Section == DNSREC_ADDITIONAL)
285         {
286             i = build_rr(cp, ptr, qclass);
287             cp = cp + i;
288
289             n++;
290         }
291
292     }
293     hp->arcount = htons(n);
294
295     *anslen = (int)(cp - answer);
296     if (*anslen > retanswerlen)
297         memcpy(retanswer, answer, retanswerlen); // partial copy
298     else
299         memcpy(retanswer, answer, *anslen);
300     DnsRecordListFree(pDnsRecord, freetype);
301     return status;
302 }
303
304 int
305 build_rr(char* p, PDNS_RECORD ptr, int qclass)
306 {
307     int i = 0;
308     int n = 0;
309     char* cp = p;
310     char* temp = NULL;
311     unsigned int index = 0;
312
313     i = put_qname(cp, ptr->pName);
314     cp = p + i;
315
316     __putshort(ptr->wType, (u_char *)cp);
317     i += sizeof(u_short);
318     cp = p + i;
319     __putshort(qclass, (u_char *)cp);
320     i += sizeof(u_short);
321     cp = p + i;
322     __putlong(ptr->dwTtl, (u_char*)cp);
323     i += sizeof(u_long);
324     cp = p + i;
325     switch (ptr->wType)
326     {
327     case DNS_TYPE_A:
328         __putshort(sizeof(ptr->Data.A), (u_char*)cp); //RDLENGTH
329         i += sizeof(u_short);
330         cp = p + i;
331         memcpy(cp, &(ptr->Data.A), sizeof(ptr->Data.A));
332         i += sizeof(ptr->Data.A);
333         break;
334     case DNS_TYPE_NS:
335     case DNS_TYPE_MD:
336     case DNS_TYPE_MF:
337     case DNS_TYPE_CNAME:
338     case DNS_TYPE_MB:
339     case DNS_TYPE_MG:
340     case DNS_TYPE_MR:
341     case DNS_TYPE_PTR:
342         temp = cp;     // hold the spot for RD length
343         i += sizeof(u_short);
344         cp = p+i;
345         n = put_qname(cp, ptr->Data.Ptr.pNameHost);
346         i += n;
347         __putshort(n, (u_char*)temp); //set RDLENGTH
348         break;
349     case DNS_TYPE_TEXT:
350     case DNS_TYPE_HINFO:
351     case DNS_TYPE_ISDN:
352     case DNS_TYPE_X25:
353         temp = cp; // hold the spot for RDLENGTH
354         i += sizeof(u_short);
355         cp = p + i;
356         n = 0;
357         for (index = 0; index < ptr->Data.Txt.dwStringCount; index++)
358         {
359             *cp = (int)(strlen(ptr->Data.Txt.pStringArray[index]));
360             n += *cp;
361             n++;
362             strcpy(++cp, ptr->Data.Txt.pStringArray[index]);
363         }
364         i += n;
365         __putshort(n,(u_char*)temp); // set RDLENGTH
366         break;
367     case DNS_TYPE_SRV:
368         temp = cp; // hold the spot for RDLENGTH
369         i += sizeof(u_short);
370         cp = p + i;
371         // priority
372         __putshort(ptr->Data.Srv.wPriority, (u_char*)cp);
373         i += sizeof(u_short);
374         cp = p + i;
375         //weight
376         __putshort(ptr->Data.Srv.wWeight, (u_char*)cp);
377         i += sizeof(u_short);
378         cp = p + i;
379         //port
380         __putshort(ptr->Data.Srv.wPort, (u_char*)cp);
381         i += sizeof(u_short);
382         cp = p + i;
383
384         n = put_qname(cp, ptr->Data.Srv.pNameTarget);
385         i+=n;
386         __putshort((u_short)(n + sizeof(u_short)*3),(u_char*)temp);
387
388         break;
389     case DNS_TYPE_MX:
390     case DNS_TYPE_AFSDB:
391     case DNS_TYPE_RT:
392         temp = cp; // hold the spot for RDLENGTH
393         i += sizeof(u_short);
394         cp = p + i;
395         __putshort(ptr->Data.Mx.wPreference, (u_char*)cp); // put wPreference
396         i += sizeof(u_short);
397         cp = p + i;
398         n = put_qname(cp, ptr->Data.Mx.pNameExchange);
399         i+=n;
400         __putshort((u_short)(n+sizeof(u_short)),(u_char*)temp);
401         break;
402         case DNS_TYPE_SOA:
403         temp = cp; // hold the spot for RDLENGTH
404         i += sizeof(u_short);
405         cp = p + i;
406         // primary server name
407         n = put_qname(cp, ptr->Data.Soa.pNamePrimaryServer);
408         i+= n;
409         cp = p + i;
410         //the person responsible for this zone.
411         n += put_qname(cp, ptr->Data.Soa.pNameAdministrator);
412         i += n;
413         cp = p + i;
414         //SERIAL
415         __putlong(ptr->Data.Soa.dwSerialNo, cp);
416         n += sizeof(u_long);
417         i += sizeof(u_long);
418         cp = p + i;
419         //refresh
420         __putlong(ptr->Data.Soa.dwRefresh, cp);
421         n += sizeof(u_long);
422         i += sizeof(u_long);
423         cp = p + i;
424         //retry
425         __putlong(ptr->Data.Soa.dwRetry, cp);
426         n += sizeof(u_long);
427         i += sizeof(u_long);
428         cp = p + i;
429         // expire
430         __putlong(ptr->Data.Soa.dwExpire, cp);
431         n += sizeof(u_long);
432         i += sizeof(u_long);
433         cp = p + i;
434         // minimum TTL
435         __putlong(ptr->Data.Soa.dwDefaultTtl, cp);
436         n += sizeof(u_long);
437         i += sizeof(u_long);
438         // set RDLength
439         __putshort(n,(u_char*)temp);
440         break;
441         case DNS_TYPE_NULL:
442         __putshort((short)ptr->Data.Null.dwByteCount, (u_char*)cp); //RDLENGTH
443         i += sizeof(u_short);
444         cp = p + i;
445         memcpy(cp, ptr->Data.Null.Data, ptr->Data.Null.dwByteCount);
446         i += ptr->Data.Null.dwByteCount;
447         break;
448         case DNS_TYPE_WKS:   // needs more work
449         temp = cp; // hold the spot for RDLENGTH
450         i += sizeof(u_short);
451         cp = p + i;
452         // address
453         memcpy(cp, &(ptr->Data.Wks.IpAddress), sizeof(ptr->Data.Wks.IpAddress));
454         n = sizeof(ptr->Data.Wks.IpAddress);
455         i += sizeof(ptr->Data.Wks.IpAddress);
456         cp = p + i;
457         // protocol
458         *cp = ptr->Data.Wks.chProtocol;
459         i++;
460         n++;
461         cp = p + i;
462         //bit mask
463         memcpy(cp, &(ptr->Data.Wks.BitMask), sizeof(ptr->Data.Wks.BitMask));
464         n+=sizeof(ptr->Data.Wks.BitMask);
465         i += n;
466         // set RDLength
467         __putshort(n,(u_char*)temp);
468         break;
469         case DNS_TYPE_MINFO:
470         case DNS_TYPE_RP:
471         temp = cp; // hold the spot for RDLENGTH
472         i += sizeof(u_short);
473         cp = p + i;
474         // pNameMailbox
475         n = put_qname(cp, ptr->Data.Minfo.pNameMailbox);
476         i+= n;
477         cp = p + i;
478         // pNameErrorsMailbox;
479         n += put_qname(cp, ptr->Data.Minfo.pNameMailbox);
480         i += n;
481         // set RDLength
482         __putshort(n,(u_char*)temp);
483     break;
484         case DNS_TYPE_AAAA:
485         __putshort(sizeof(ptr->Data.AAAA), (u_char*)cp); //RDLENGTH
486         i += sizeof(u_short);
487         cp = p + i;
488         memcpy(cp, &(ptr->Data.AAAA), sizeof(ptr->Data.AAAA));
489         i += sizeof(ptr->Data.AAAA);
490
491     break;
492     }
493     return i;
494 }
495
496
497 int
498 __hostalias(register const char *name, char* abuf)
499 {
500     register char *C1, *C2;
501     FILE *fp;
502     char *file;
503 //  char *getenv(), *strcpy(), *strncpy();  // pbh XXX 11/1/96
504     char buf[BUFSIZ];
505
506
507     file = getenv("HOSTALIASES");
508     if (file == NULL || (fp = fopen(file, "r")) == NULL)
509         return -1;
510     buf[sizeof(buf) - 1] = '\0';
511     while (fgets(buf, sizeof(buf), fp)) {
512         for (C1 = buf; *C1 && !isspace(*C1); ++C1);
513         if (!*C1)
514             break;
515         *C1 = '\0';
516         if (!strcasecmp(buf, name)) {
517             while (isspace(*++C1));
518             if (!*C1)
519                 break;
520             for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
521             abuf[sizeof(abuf) - 1] = *C2 = '\0';
522             (void)strncpy(abuf, C1, sizeof(abuf) - 1);
523             fclose(fp);
524             return 0;
525         }
526     }
527     fclose(fp);
528     return -1;
529 }
530
531 int  WINAPI
532 res_mkquery(int op, const char  *dname,
533             int qclass, int type,
534             const char  *data, int datalen,
535             const struct rrec  *newrr,
536             char  *buf, int buflen)
537 {
538     return -1;
539 }
540
541 int  WINAPI
542 res_querydomain(const char  *name,
543                 const char  *domain,
544                 int qclass, int type,
545                 u_char  *answer, int anslen)
546 {
547     return -1;
548 }
549
550 int  WINAPI
551 res_send(const char  *msg, int msglen,
552          char  *answer, int anslen)
553 {
554         return -1;
555 }
556
557 int  WINAPI
558 res_query(char *name, int qclass, int type, u_char *answer, int anslen)
559 {
560     return -1;
561 }