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