libcli/ldap/ldap_ndr.h: fix licence/copyright
[samba.git] / 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 #include "nsswitch/winbind_nss.h"
23
24 #ifdef HAVE_NS_API_H
25
26 #include <ns_daemon.h>
27 #endif
28
29 #if HAVE_PTHREAD_H
30 #include <pthread.h>
31 #endif
32
33 #if HAVE_PTHREAD
34 static pthread_mutex_t wins_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
35 #endif
36
37 #ifndef INADDRSZ
38 #define INADDRSZ 4
39 #endif
40
41 static int initialised;
42
43 NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
44                           char *buffer, size_t buflen, int *h_errnop);
45 NSS_STATUS _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
46                            char *buffer, size_t buflen, int *h_errnop);
47
48 static void nss_wins_init(void)
49 {
50         initialised = 1;
51         load_case_tables_library();
52         lp_set_cmdline("log level", "0");
53
54         TimeInit();
55         setup_logging("nss_wins",False);
56         lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
57         load_interfaces();
58 }
59
60 static struct in_addr *lookup_byname_backend(const char *name, int *count)
61 {
62         TALLOC_CTX *frame = talloc_stackframe();
63         struct ip_service *address = NULL;
64         struct in_addr *ret = NULL;
65         int j;
66
67         if (!initialised) {
68                 nss_wins_init();
69         }
70
71         *count = 0;
72
73         /* always try with wins first */
74         if (NT_STATUS_IS_OK(resolve_wins(name,0x00,&address,count))) {
75                 if ( (ret = SMB_MALLOC_P(struct in_addr)) == NULL ) {
76                         free( address );
77                         TALLOC_FREE(frame);
78                         return NULL;
79                 }
80                 if (address[0].ss.ss_family != AF_INET) {
81                         free(address);
82                         free(ret);
83                         TALLOC_FREE(frame);
84                         return NULL;
85                 }
86                 *ret = ((struct sockaddr_in *)(void *)&address[0].ss)
87                         ->sin_addr;
88                 free( address );
89                 TALLOC_FREE(frame);
90                 return ret;
91         }
92
93         /* uggh, we have to broadcast to each interface in turn */
94         for (j=iface_count() - 1;j >= 0;j--) {
95                 const struct in_addr *bcast = iface_n_bcast_v4(j);
96                 struct sockaddr_storage ss;
97                 struct sockaddr_storage *pss;
98                 NTSTATUS status;
99
100                 if (!bcast) {
101                         continue;
102                 }
103                 in_addr_to_sockaddr_storage(&ss, *bcast);
104                 status = name_query(name, 0x00, True, True, &ss,
105                                     talloc_tos(), &pss, count, NULL);
106                 if (NT_STATUS_IS_OK(status) && (*count > 0)) {
107                         if ((ret = SMB_MALLOC_P(struct in_addr)) == NULL) {
108                                 TALLOC_FREE(frame);
109                                 return NULL;
110                         }
111                         *ret = ((struct sockaddr_in *)pss)->sin_addr;
112                         break;
113                 }
114         }
115         TALLOC_FREE(frame);
116         return ret;
117 }
118
119 #ifdef HAVE_NS_API_H
120
121 static struct node_status *lookup_byaddr_backend(char *addr, int *count)
122 {
123         struct sockaddr_storage ss;
124         struct nmb_name nname;
125         struct node_status *result;
126         NTSTATUS status;
127
128         if (!initialised) {
129                 nss_wins_init();
130         }
131
132         make_nmb_name(&nname, "*", 0);
133         if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) {
134                 return NULL;
135         }
136         status = node_status_query(NULL, &nname, &ss, &result, count, NULL);
137         if (!NT_STATUS_IS_OK(status)) {
138                 return NULL;
139         }
140
141         return result;
142 }
143
144 /* IRIX version */
145
146 int init(void)
147 {
148         nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
149         nss_wins_init();
150         return NSD_OK;
151 }
152
153 int lookup(nsd_file_t *rq)
154 {
155         char *map;
156         char *key;
157         char *addr;
158         struct in_addr *ip_list;
159         struct node_status *status;
160         int i, count, len, size;
161         char response[1024];
162         bool found = False;
163
164         nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n");
165         if (! rq)
166                 return NSD_ERROR;
167
168         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
169         if (! map) {
170                 rq->f_status = NS_FATAL;
171                 return NSD_ERROR;
172         }
173
174         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
175         if (! key || ! *key) {
176                 rq->f_status = NS_FATAL;
177                 return NSD_ERROR;
178         }
179
180         response[0] = '\0';
181         len = sizeof(response) - 2;
182
183         /*
184          * response needs to be a string of the following format
185          * ip_address[ ip_address]*\tname[ alias]*
186          */
187         if (strcasecmp_m(map,"hosts.byaddr") == 0) {
188                 if ( status = lookup_byaddr_backend(key, &count)) {
189                     size = strlen(key) + 1;
190                     if (size > len) {
191                         talloc_free(status);
192                         return NSD_ERROR;
193                     }
194                     len -= size;
195                     strncat(response,key,size);
196                     strncat(response,"\t",1);
197                     for (i = 0; i < count; i++) {
198                         /* ignore group names */
199                         if (status[i].flags & 0x80) continue;
200                         if (status[i].type == 0x20) {
201                                 size = sizeof(status[i].name) + 1;
202                                 if (size > len) {
203                                     talloc_free(status);
204                                     return NSD_ERROR;
205                                 }
206                                 len -= size;
207                                 strncat(response, status[i].name, size);
208                                 strncat(response, " ", 1);
209                                 found = True;
210                         }
211                     }
212                     response[strlen(response)-1] = '\n';
213                     talloc_free(status);
214                 }
215         } else if (strcasecmp_m(map,"hosts.byname") == 0) {
216             if (ip_list = lookup_byname_backend(key, &count)) {
217                 for (i = count; i ; i--) {
218                     addr = inet_ntoa(ip_list[i-1]);
219                     size = strlen(addr) + 1;
220                     if (size > len) {
221                         free(ip_list);
222                         return NSD_ERROR;
223                     }
224                     len -= size;
225                     if (i != 0)
226                         response[strlen(response)-1] = ' ';
227                     strncat(response,addr,size);
228                     strncat(response,"\t",1);
229                 }
230                 size = strlen(key) + 1;
231                 if (size > len) {
232                     free(ip_list);
233                     return NSD_ERROR;
234                 }
235                 strncat(response,key,size);
236                 strncat(response,"\n",1);
237                 found = True;
238                 free(ip_list);
239             }
240         }
241
242         if (found) {
243             nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response);
244             nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
245             return NSD_OK;
246         }
247         nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n");
248         rq->f_status = NS_NOTFOUND;
249         return NSD_NEXT;
250 }
251
252 #else
253
254 /* Allocate some space from the nss static buffer.  The buffer and buflen
255    are the pointers passed in by the C library to the _nss_*_*
256    functions. */
257
258 static char *get_static(char **buffer, size_t *buflen, int len)
259 {
260         char *result;
261
262         /* Error check.  We return false if things aren't set up right, or
263            there isn't enough buffer space left. */
264
265         if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
266                 return NULL;
267         }
268
269         /* Return an index into the static buffer */
270
271         result = *buffer;
272         *buffer += len;
273         *buflen -= len;
274
275         return result;
276 }
277
278 /****************************************************************************
279 gethostbyname() - we ignore any domain portion of the name and only
280 handle names that are at most 15 characters long
281   **************************************************************************/
282 NSS_STATUS
283 _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
284                           char *buffer, size_t buflen, int *h_errnop)
285 {
286         NSS_STATUS nss_status = NSS_STATUS_SUCCESS;
287         struct in_addr *ip_list;
288         int i, count;
289         fstring name;
290         size_t namelen;
291         TALLOC_CTX *frame;
292
293 #if HAVE_PTHREAD
294         pthread_mutex_lock(&wins_nss_mutex);
295 #endif
296
297         frame = talloc_stackframe();
298
299         memset(he, '\0', sizeof(*he));
300         fstrcpy(name, hostname);
301
302         /* Do lookup */
303
304         ip_list = lookup_byname_backend(name, &count);
305
306         if (!ip_list) {
307                 nss_status = NSS_STATUS_NOTFOUND;
308                 goto out;
309         }
310
311         /* Copy h_name */
312
313         namelen = strlen(name) + 1;
314
315         if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) {
316                 free(ip_list);
317                 nss_status = NSS_STATUS_TRYAGAIN;
318                 goto out;
319         }
320
321         memcpy(he->h_name, name, namelen);
322
323         /* Copy h_addr_list, align to pointer boundary first */
324
325         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
326                 i = sizeof(char*) - i;
327
328         if (get_static(&buffer, &buflen, i) == NULL) {
329                 free(ip_list);
330                 nss_status = NSS_STATUS_TRYAGAIN;
331                 goto out;
332         }
333
334         if ((he->h_addr_list = (char **)get_static(
335                      &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL) {
336                 free(ip_list);
337                 nss_status = NSS_STATUS_TRYAGAIN;
338                 goto out;
339         }
340
341         for (i = 0; i < count; i++) {
342                 if ((he->h_addr_list[i] = get_static(&buffer, &buflen,
343                                                      INADDRSZ)) == NULL) {
344                         free(ip_list);
345                         nss_status = NSS_STATUS_TRYAGAIN;
346                         goto out;
347                 }
348                 memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ);
349         }
350
351         he->h_addr_list[count] = NULL;
352
353         free(ip_list);
354
355         /* Set h_addr_type and h_length */
356
357         he->h_addrtype = AF_INET;
358         he->h_length = INADDRSZ;
359
360         /* Set h_aliases */
361
362         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
363                 i = sizeof(char*) - i;
364
365         if (get_static(&buffer, &buflen, i) == NULL) {
366                 nss_status = NSS_STATUS_TRYAGAIN;
367                 goto out;
368         }
369
370         if ((he->h_aliases = (char **)get_static(
371                      &buffer, &buflen, sizeof(char *))) == NULL) {
372                 nss_status = NSS_STATUS_TRYAGAIN;
373                 goto out;
374         }
375
376         he->h_aliases[0] = NULL;
377
378         nss_status = NSS_STATUS_SUCCESS;
379
380   out:
381
382         TALLOC_FREE(frame);
383
384 #if HAVE_PTHREAD
385         pthread_mutex_unlock(&wins_nss_mutex);
386 #endif
387         return nss_status;
388 }
389
390
391 NSS_STATUS
392 _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
393                            char *buffer, size_t buflen, int *h_errnop)
394 {
395         NSS_STATUS nss_status;
396
397         if(af!=AF_INET) {
398                 *h_errnop = NO_DATA;
399                 nss_status = NSS_STATUS_UNAVAIL;
400         } else {
401                 nss_status = _nss_wins_gethostbyname_r(
402                                 name, he, buffer, buflen, h_errnop);
403         }
404         return nss_status;
405 }
406 #endif