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