This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[ira/wip.git] / source3 / 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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19    
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25 #ifdef HAVE_NS_API_H
26 #undef VOLATILE
27
28 #include <ns_daemon.h>
29 #endif
30
31 #ifndef INADDRSZ
32 #define INADDRSZ 4
33 #endif
34
35 static int initialised;
36
37 extern BOOL AllowDebugChange;
38
39 /* Use our own create socket code so we don't recurse.... */
40
41 static int wins_lookup_open_socket_in(void)
42 {
43         struct sockaddr_in sock;
44         int val=1;
45         int res;
46
47         memset((char *)&sock,'\0',sizeof(sock));
48
49 #ifdef HAVE_SOCK_SIN_LEN
50         sock.sin_len = sizeof(sock);
51 #endif
52         sock.sin_port = 0;
53         sock.sin_family = AF_INET;
54         sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
55         res = socket(AF_INET, SOCK_DGRAM, 0);
56         if (res == -1)
57                 return -1;
58
59         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
60 #ifdef SO_REUSEPORT
61         setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
62 #endif /* SO_REUSEPORT */
63
64         /* now we've got a socket - we need to bind it */
65
66         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
67                 close(res);
68                 return(-1);
69         }
70
71         set_socket_options(res,"SO_BROADCAST");
72
73         return res;
74 }
75
76
77 static void nss_wins_init(void)
78 {
79         initialised = 1;
80         DEBUGLEVEL = 0;
81         AllowDebugChange = False;
82
83         /* needed for lp_xx() functions */
84         charset_initialise();
85
86         TimeInit();
87         setup_logging("nss_wins",False);
88         lp_load(dyn_CONFIGFILE,True,False,False);
89         load_interfaces();
90         codepage_initialise(lp_client_code_page());
91 }
92
93 static struct node_status *lookup_byaddr_backend(char *addr, int *count)
94 {
95         int fd;
96         struct in_addr  ip;
97         struct nmb_name nname;
98         struct node_status *status;
99
100         if (!initialised) {
101                 nss_wins_init();
102         }
103
104         fd = wins_lookup_open_socket_in();
105         if (fd == -1)
106                 return NULL;
107
108         make_nmb_name(&nname, "*", 0);
109         ip = *interpret_addr2(addr);
110         status = node_status_query(fd,&nname,ip, count);
111
112         close(fd);
113         return status;
114 }
115
116 static struct in_addr *lookup_byname_backend(const char *name, int *count)
117 {
118         int fd;
119         struct in_addr *ret = NULL;
120         struct in_addr  p;
121         int j;
122
123         if (!initialised) {
124                 nss_wins_init();
125         }
126
127         *count = 0;
128
129         fd = wins_lookup_open_socket_in();
130         if (fd == -1)
131                 return NULL;
132
133         p = wins_srv_ip();
134         if( !is_zero_ip(p) ) {
135                 ret = name_query(fd,name,0x20,False,True, p, count);
136                 goto out;
137         }
138
139         if (lp_wins_support()) {
140                 /* we are our own WINS server */
141                 ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count);
142                 goto out;
143         }
144
145         /* uggh, we have to broadcast to each interface in turn */
146         for (j=iface_count() - 1;
147              j >= 0;
148              j--) {
149                 struct in_addr *bcast = iface_n_bcast(j);
150                 ret = name_query(fd,name,0x20,True,True,*bcast,count);
151                 if (ret) break;
152         }
153
154  out:
155
156         close(fd);
157         return ret;
158 }
159
160
161 #ifdef HAVE_NS_API_H
162 /* IRIX version */
163
164 int init(void)
165 {
166         nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
167         nss_wins_init();
168         return NSD_OK;
169 }
170
171 int lookup(nsd_file_t *rq)
172 {
173         char *map;
174         char *key;
175         char *addr;
176         struct in_addr *ip_list;
177         struct node_status *status;
178         int i, count, len, size;
179         char response[1024];
180         BOOL found = False;
181
182         nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n");
183         if (! rq) 
184                 return NSD_ERROR;
185
186         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
187         if (! map) {
188                 rq->f_status = NS_FATAL;
189                 return NSD_ERROR;
190         }
191
192         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
193         if (! key || ! *key) {
194                 rq->f_status = NS_FATAL;
195                 return NSD_ERROR;
196         }
197
198         response[0] = '\0';
199         len = sizeof(response) - 2;
200
201         /* 
202          * response needs to be a string of the following format
203          * ip_address[ ip_address]*\tname[ alias]*
204          */
205         if (strcasecmp(map,"hosts.byaddr") == 0) {
206                 if ( status = lookup_byaddr_backend(key, &count)) {
207                     size = strlen(key) + 1;
208                     if (size > len) {
209                         free(status);
210                         return NSD_ERROR;
211                     }
212                     len -= size;
213                     strncat(response,key,size);
214                     strncat(response,"\t",1);
215                     for (i = 0; i < count; i++) {
216                         /* ignore group names */
217                         if (status[i].flags & 0x80) continue;
218                         if (status[i].type == 0x20) {
219                                 size = sizeof(status[i].name) + 1;
220                                 if (size > len) {
221                                     free(status);
222                                     return NSD_ERROR;
223                                 }
224                                 len -= size;
225                                 strncat(response, status[i].name, size);
226                                 strncat(response, " ", 1);
227                                 found = True;
228                         }
229                     }
230                     response[strlen(response)-1] = '\n';
231                     free(status);
232                 }
233         } else if (strcasecmp(map,"hosts.byname") == 0) {
234             if (ip_list = lookup_byname_backend(key, &count)) {
235                 for (i = count; i ; i--) {
236                     addr = inet_ntoa(ip_list[i-1]);
237                     size = strlen(addr) + 1;
238                     if (size > len) {
239                         free(ip_list);
240                         return NSD_ERROR;
241                     }
242                     len -= size;
243                     if (i != 0)
244                         response[strlen(response)-1] = ' ';
245                     strncat(response,addr,size);
246                     strncat(response,"\t",1);
247                 }
248                 size = strlen(key) + 1;
249                 if (size > len) {
250                     free(ip_list);
251                     return NSD_ERROR;
252                 }   
253                 strncat(response,key,size);
254                 strncat(response,"\n",1);
255                 found = True;
256                 free(ip_list);
257             }
258         }
259
260         if (found) {
261             nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response);
262             nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
263             return NSD_OK;
264         }
265         nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n");
266         rq->f_status = NS_NOTFOUND;
267         return NSD_NEXT;
268 }
269
270 #else
271 /****************************************************************************
272 gethostbyname() - we ignore any domain portion of the name and only
273 handle names that are at most 15 characters long
274   **************************************************************************/
275 NSS_STATUS
276 _nss_wins_gethostbyname_r(const char *name, struct hostent *he,
277                           char *buffer, size_t buflen, int *errnop,
278                           int *h_errnop)
279 {
280         char **host_addresses;
281         struct in_addr *ip_list;
282         int i, count;
283         size_t namelen = strlen(name) + 1;
284                 
285         memset(he, '\0', sizeof(*he));
286
287         ip_list = lookup_byname_backend(name, &count);
288         if (!ip_list) {
289                 return NSS_STATUS_NOTFOUND;
290         }
291
292         if (buflen < namelen + (2*count+1)*INADDRSZ) {
293                 /* no ENOMEM error type?! */
294                 return NSS_STATUS_NOTFOUND;
295         }
296
297
298         host_addresses = (char **)buffer;
299         he->h_addr_list = host_addresses;
300         host_addresses[count] = NULL;
301         buffer += (count + 1) * INADDRSZ;
302         buflen += (count + 1) * INADDRSZ;
303         he->h_addrtype = AF_INET;
304         he->h_length = INADDRSZ;
305
306         for (i=0;i<count;i++) {
307                 memcpy(buffer, &ip_list[i].s_addr, INADDRSZ);
308                 *host_addresses = buffer;
309                 buffer += INADDRSZ;
310                 buflen -= INADDRSZ;
311                 host_addresses++;
312         }
313
314         if (ip_list)
315                 free(ip_list);
316
317         memcpy(buffer, name, namelen);
318         he->h_name = buffer;
319
320         return NSS_STATUS_SUCCESS;
321 }
322 #endif
323