GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / lib / getaddrinfo.c
1 /*
2  * Mar  8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
3  * $Id: getaddrinfo.c,v 1.8 2003/03/19 18:25:28 rjs3 Exp $
4  *
5  * This module is based on ssh-1.2.27-IPv6-1.5 written by
6  * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
7  */
8 /* 
9  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer. 
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in
20  *    the documentation and/or other materials provided with the
21  *    distribution.
22  *
23  * 3. The name "Carnegie Mellon University" must not be used to
24  *    endorse or promote products derived from this software without
25  *    prior written permission. For permission or any other legal
26  *    details, please contact  
27  *      Office of Technology Transfer
28  *      Carnegie Mellon University
29  *      5000 Forbes Avenue
30  *      Pittsburgh, PA  15213-3890
31  *      (412) 268-4387, fax: (412) 268-7395
32  *      tech-transfer@andrew.cmu.edu
33  *
34  * 4. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by Computing Services
37  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
38  *
39  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
40  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
41  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
42  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
43  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
44  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
45  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46  */
47 /*
48  * fake library for ssh
49  *
50  * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
51  * These funtions are defined in rfc2133.
52  *
53  * But these functions are not implemented correctly. The minimum subset
54  * is implemented for ssh use only. For exapmle, this routine assumes
55  * that ai_family is AF_INET. Don't use it for another purpose.
56  * 
57  * In the case not using 'configure --enable-ipv6', this getaddrinfo.c
58  * will be used if you have broken getaddrinfo or no getaddrinfo.
59  */
60
61 #include "config.h"
62 #ifndef WIN32
63 #include <sys/param.h>
64 # ifndef macintosh\r
65 #  include <arpa/inet.h>
66 # endif /* macintosh */\r
67 #endif /* WIN32 */
68 #include <ctype.h>
69
70 #ifdef WIN32
71 /* : Windows socket library is missing inet_aton, emulate it with
72    : inet_addr. inet_aton return 0 if the address is uncorrect, a non zero
73    : value otherwise */
74 int
75 inet_aton (const char *cp, struct in_addr *inp)
76 {
77     if (cp == NULL || inp == NULL) {
78         return (0);
79     }
80
81     /* : handle special case */
82     if (strcmp (cp, "255.255.255.255") == 0) {
83         inp->s_addr = (unsigned int) 0xFFFFFFFF;
84         return (1);
85     }
86
87     inp->s_addr = inet_addr (cp);
88     return (1);
89 }
90 #endif /* WIN32 */
91
92 static struct addrinfo *
93 malloc_ai(int port, unsigned long addr, int socktype, int proto)
94 {
95     struct addrinfo *ai;
96
97     ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
98                                    sizeof(struct sockaddr_in));
99     if (ai) {
100         memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
101         ai->ai_addr = (struct sockaddr *)(ai + 1);
102         /* XXX -- ssh doesn't use sa_len */
103         ai->ai_addrlen = sizeof(struct sockaddr_in);
104 #ifdef HAVE_SOCKADDR_SA_LEN
105         ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
106 #endif
107         ai->ai_addr->sa_family = ai->ai_family = AF_INET;
108         ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
109         ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
110         ai->ai_socktype = socktype;
111         ai->ai_protocol = proto;
112         return ai;
113     } else {
114         return NULL;
115     }
116 }
117
118 char *
119 gai_strerror(int ecode)
120 {
121     switch (ecode) {
122     case EAI_NODATA:
123         return "no address associated with hostname.";
124     case EAI_MEMORY:
125         return "memory allocation failure.";
126     case EAI_FAMILY:
127         return "ai_family not supported.";
128     case EAI_SERVICE:
129         return "servname not supported for ai_socktype.";
130     default:
131         return "unknown error.";
132     }
133 }
134
135 void
136 freeaddrinfo(struct addrinfo *ai)
137 {
138     struct addrinfo *next;
139
140     if (ai->ai_canonname)
141         free(ai->ai_canonname);
142     do {
143         next = ai->ai_next;
144         free(ai);
145     } while ((ai = next) != NULL);
146 }
147
148 int
149 getaddrinfo(const char *hostname, const char *servname,
150             const struct addrinfo *hints, struct addrinfo **res)
151 {
152     struct addrinfo *cur, *prev = NULL;
153     struct hostent *hp;
154     struct in_addr in;
155     int i, port = 0, socktype, proto;
156
157     if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
158         return EAI_FAMILY;
159
160     socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
161                                              : SOCK_STREAM;
162     if (hints && hints->ai_protocol)
163         proto = hints->ai_protocol;
164     else {
165         switch (socktype) {
166         case SOCK_DGRAM:
167             proto = IPPROTO_UDP;
168             break;
169         case SOCK_STREAM:
170             proto = IPPROTO_TCP;
171             break;
172         default:
173             proto = 0;
174             break;
175         }
176     }
177     if (servname) {
178         if (isdigit((int)*servname))
179             port = htons((short) atoi(servname));
180         else {
181             struct servent *se;
182             char *pe_proto;
183
184             switch (socktype) {
185             case SOCK_DGRAM:
186                 pe_proto = "udp";
187                 break;
188             case SOCK_STREAM:
189                 pe_proto = "tcp";
190                 break;
191             default:
192                 pe_proto = NULL;
193                 break;
194             }
195             /* xxx thread safety ? */
196             if ((se = getservbyname(servname, pe_proto)) == NULL)
197                 return EAI_SERVICE;
198             port = se->s_port;
199         }
200     }
201     if (!hostname) {
202         if (hints && hints->ai_flags & AI_PASSIVE)
203             *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
204         else
205             *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
206         if (*res)
207             return 0;
208         else
209             return EAI_MEMORY;
210     }
211 #if HAVE_INET_ATON
212     if (inet_aton(hostname, &in))
213 #else
214     if ((in.s_addr = inet_addr(hostname)) != -1)
215 #endif
216     {
217         *res = malloc_ai(port, in.s_addr, socktype, proto);
218         if (*res)
219             return 0;
220         else
221             return EAI_MEMORY;
222     }
223     if (hints && hints->ai_flags & AI_NUMERICHOST)
224         return EAI_NODATA;
225 #ifndef macintosh
226     /* xxx thread safety? / gethostbyname_r */
227     if ((hp = gethostbyname(hostname)) &&
228         hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
229         for (i = 0; hp->h_addr_list[i]; i++) {
230             if ((cur = malloc_ai(port,
231                                 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
232                                 socktype, proto)) == NULL) {
233                 if (*res)
234                     freeaddrinfo(*res);
235                 return EAI_MEMORY;
236             }
237             if (prev)
238                 prev->ai_next = cur;
239             else
240                 *res = cur;
241             prev = cur;
242         }
243         if (hints && hints->ai_flags & AI_CANONNAME && *res) {
244             /* NOT sasl_strdup for compatibility */
245             if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
246                 freeaddrinfo(*res);
247                 return EAI_MEMORY;
248             }
249         }
250         return 0;
251     }
252 #endif
253     return EAI_NODATA;
254 }