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