RIP BOOL. Convert BOOL -> bool. I found a few interesting
[tprouty/samba.git] / source / nsswitch / wins.c
1 /* 
2    Unix SMB/CIFS implementation.
3    a WINS nsswitch module 
4    Copyright (C) Andrew Tridgell 1999
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18    
19 */
20
21 #include "includes.h"
22 #ifdef HAVE_NS_API_H
23 #undef VOLATILE
24
25 #include <ns_daemon.h>
26 #endif
27
28 #ifndef INADDRSZ
29 #define INADDRSZ 4
30 #endif
31
32 static int initialised;
33
34 extern bool AllowDebugChange;
35
36 NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
37                           char *buffer, size_t buflen, int *h_errnop);
38 NSS_STATUS _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
39                            char *buffer, size_t buflen, int *h_errnop);
40
41 /* Use our own create socket code so we don't recurse.... */
42
43 static int wins_lookup_open_socket_in(void)
44 {
45         struct sockaddr_in sock;
46         int val=1;
47         int res;
48
49         memset((char *)&sock,'\0',sizeof(sock));
50
51 #ifdef HAVE_SOCK_SIN_LEN
52         sock.sin_len = sizeof(sock);
53 #endif
54         sock.sin_port = 0;
55         sock.sin_family = AF_INET;
56         sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
57         res = socket(AF_INET, SOCK_DGRAM, 0);
58         if (res == -1)
59                 return -1;
60
61         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
62 #ifdef SO_REUSEPORT
63         setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
64 #endif /* SO_REUSEPORT */
65
66         /* now we've got a socket - we need to bind it */
67
68         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
69                 close(res);
70                 return(-1);
71         }
72
73         set_socket_options(res,"SO_BROADCAST");
74
75         return res;
76 }
77
78
79 static void nss_wins_init(void)
80 {
81         initialised = 1;
82         DEBUGLEVEL = 0;
83         AllowDebugChange = False;
84
85         TimeInit();
86         setup_logging("nss_wins",False);
87         load_case_tables();
88         lp_load(dyn_CONFIGFILE,True,False,False,True);
89         load_interfaces();
90 }
91
92 static struct in_addr *lookup_byname_backend(const char *name, int *count)
93 {
94         int fd = -1;
95         struct ip_service *address = NULL;
96         struct in_addr *ret = NULL;
97         int j, flags = 0;
98
99         if (!initialised) {
100                 nss_wins_init();
101         }
102
103         *count = 0;
104
105         /* always try with wins first */
106         if (NT_STATUS_IS_OK(resolve_wins(name,0x00,&address,count))) {
107                 if ( (ret = SMB_MALLOC_P(struct in_addr)) == NULL ) {
108                         free( address );
109                         return NULL;
110                 }
111                 *ret = address[0].ip;
112                 free( address );
113                 return ret;
114         }
115
116         fd = wins_lookup_open_socket_in();
117         if (fd == -1) {
118                 return NULL;
119         }
120
121         /* uggh, we have to broadcast to each interface in turn */
122         for (j=iface_count() - 1;j >= 0;j--) {
123                 const struct in_addr *bcast = iface_n_bcast_v4(j);
124                 if (!bcast) {
125                         continue;
126                 }
127                 ret = name_query(fd,name,0x00,True,True,*bcast,count, &flags, NULL);
128                 if (ret) break;
129         }
130
131         close(fd);
132         return ret;
133 }
134
135 #ifdef HAVE_NS_API_H
136
137 static NODE_STATUS_STRUCT *lookup_byaddr_backend(char *addr, int *count)
138 {
139         int fd;
140         struct in_addr  ip;
141         struct nmb_name nname;
142         NODE_STATUS_STRUCT *status;
143
144         if (!initialised) {
145                 nss_wins_init();
146         }
147
148         fd = wins_lookup_open_socket_in();
149         if (fd == -1)
150                 return NULL;
151
152         make_nmb_name(&nname, "*", 0);
153         ip = *interpret_addr2(addr);
154         status = node_status_query(fd,&nname,ip, count, NULL);
155
156         close(fd);
157         return status;
158 }
159
160 /* IRIX version */
161
162 int init(void)
163 {
164         nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
165         nss_wins_init();
166         return NSD_OK;
167 }
168
169 int lookup(nsd_file_t *rq)
170 {
171         char *map;
172         char *key;
173         char *addr;
174         struct in_addr *ip_list;
175         NODE_STATUS_STRUCT *status;
176         int i, count, len, size;
177         char response[1024];
178         bool found = False;
179
180         nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n");
181         if (! rq) 
182                 return NSD_ERROR;
183
184         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
185         if (! map) {
186                 rq->f_status = NS_FATAL;
187                 return NSD_ERROR;
188         }
189
190         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
191         if (! key || ! *key) {
192                 rq->f_status = NS_FATAL;
193                 return NSD_ERROR;
194         }
195
196         response[0] = '\0';
197         len = sizeof(response) - 2;
198
199         /* 
200          * response needs to be a string of the following format
201          * ip_address[ ip_address]*\tname[ alias]*
202          */
203         if (StrCaseCmp(map,"hosts.byaddr") == 0) {
204                 if ( status = lookup_byaddr_backend(key, &count)) {
205                     size = strlen(key) + 1;
206                     if (size > len) {
207                         free(status);
208                         return NSD_ERROR;
209                     }
210                     len -= size;
211                     strncat(response,key,size);
212                     strncat(response,"\t",1);
213                     for (i = 0; i < count; i++) {
214                         /* ignore group names */
215                         if (status[i].flags & 0x80) continue;
216                         if (status[i].type == 0x20) {
217                                 size = sizeof(status[i].name) + 1;
218                                 if (size > len) {
219                                     free(status);
220                                     return NSD_ERROR;
221                                 }
222                                 len -= size;
223                                 strncat(response, status[i].name, size);
224                                 strncat(response, " ", 1);
225                                 found = True;
226                         }
227                     }
228                     response[strlen(response)-1] = '\n';
229                     free(status);
230                 }
231         } else if (StrCaseCmp(map,"hosts.byname") == 0) {
232             if (ip_list = lookup_byname_backend(key, &count)) {
233                 for (i = count; i ; i--) {
234                     addr = inet_ntoa(ip_list[i-1]);
235                     size = strlen(addr) + 1;
236                     if (size > len) {
237                         free(ip_list);
238                         return NSD_ERROR;
239                     }
240                     len -= size;
241                     if (i != 0)
242                         response[strlen(response)-1] = ' ';
243                     strncat(response,addr,size);
244                     strncat(response,"\t",1);
245                 }
246                 size = strlen(key) + 1;
247                 if (size > len) {
248                     free(ip_list);
249                     return NSD_ERROR;
250                 }   
251                 strncat(response,key,size);
252                 strncat(response,"\n",1);
253                 found = True;
254                 free(ip_list);
255             }
256         }
257
258         if (found) {
259             nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response);
260             nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
261             return NSD_OK;
262         }
263         nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n");
264         rq->f_status = NS_NOTFOUND;
265         return NSD_NEXT;
266 }
267
268 #else
269
270 /* Allocate some space from the nss static buffer.  The buffer and buflen
271    are the pointers passed in by the C library to the _nss_*_*
272    functions. */
273
274 static char *get_static(char **buffer, size_t *buflen, int len)
275 {
276         char *result;
277
278         /* Error check.  We return false if things aren't set up right, or
279            there isn't enough buffer space left. */
280         
281         if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
282                 return NULL;
283         }
284
285         /* Return an index into the static buffer */
286
287         result = *buffer;
288         *buffer += len;
289         *buflen -= len;
290
291         return result;
292 }
293
294 /****************************************************************************
295 gethostbyname() - we ignore any domain portion of the name and only
296 handle names that are at most 15 characters long
297   **************************************************************************/
298 NSS_STATUS
299 _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
300                           char *buffer, size_t buflen, int *h_errnop)
301 {
302         struct in_addr *ip_list;
303         int i, count;
304         fstring name;
305         size_t namelen;
306                 
307         memset(he, '\0', sizeof(*he));
308         fstrcpy(name, hostname);
309
310         /* Do lookup */
311
312         ip_list = lookup_byname_backend(name, &count);
313
314         if (!ip_list)
315                 return NSS_STATUS_NOTFOUND;
316
317         /* Copy h_name */
318
319         namelen = strlen(name) + 1;
320
321         if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) {
322                 free(ip_list);
323                 return NSS_STATUS_TRYAGAIN;
324         }
325
326         memcpy(he->h_name, name, namelen);
327
328         /* Copy h_addr_list, align to pointer boundary first */
329
330         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
331                 i = sizeof(char*) - i;
332
333         if (get_static(&buffer, &buflen, i) == NULL) {
334                 free(ip_list);
335                 return NSS_STATUS_TRYAGAIN;
336         }
337
338         if ((he->h_addr_list = (char **)get_static(
339                      &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL) {
340                 free(ip_list);
341                 return NSS_STATUS_TRYAGAIN;
342         }
343
344         for (i = 0; i < count; i++) {
345                 if ((he->h_addr_list[i] = get_static(&buffer, &buflen,
346                                                      INADDRSZ)) == NULL) {
347                         free(ip_list);
348                         return NSS_STATUS_TRYAGAIN;
349                 }
350                 memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ);
351         }
352
353         he->h_addr_list[count] = NULL;
354
355         free(ip_list);
356
357         /* Set h_addr_type and h_length */
358
359         he->h_addrtype = AF_INET;
360         he->h_length = INADDRSZ;
361
362         /* Set h_aliases */
363
364         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
365                 i = sizeof(char*) - i;
366
367         if (get_static(&buffer, &buflen, i) == NULL)
368                 return NSS_STATUS_TRYAGAIN;
369
370         if ((he->h_aliases = (char **)get_static(
371                      &buffer, &buflen, sizeof(char *))) == NULL)
372                 return NSS_STATUS_TRYAGAIN;
373
374         he->h_aliases[0] = NULL;
375
376         return NSS_STATUS_SUCCESS;
377 }
378
379
380 NSS_STATUS
381 _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
382                            char *buffer, size_t buflen, int *h_errnop)
383 {
384         if(af!=AF_INET) {
385                 *h_errnop = NO_DATA;
386                 return NSS_STATUS_UNAVAIL;
387         }
388
389         return _nss_wins_gethostbyname_r(
390                 name, he, buffer, buflen, h_errnop);
391 }
392 #endif