484b39342a629c8faf1ebcc7fdd3a1f4457ca147
[ira/wip.git] / source3 / winbindd / winbindd_wins.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - WINS related functions
5
6    Copyright (C) Andrew Tridgell 1999
7    Copyright (C) Herb Lewis 2002
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 /* Use our own create socket code so we don't recurse.... */
30
31 static int wins_lookup_open_socket_in(void)
32 {
33         struct sockaddr_in sock;
34         int val=1;
35         int res;
36
37         memset((char *)&sock,'\0',sizeof(sock));
38
39 #ifdef HAVE_SOCK_SIN_LEN
40         sock.sin_len = sizeof(sock);
41 #endif
42         sock.sin_port = 0;
43         sock.sin_family = AF_INET;
44         sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
45         res = socket(AF_INET, SOCK_DGRAM, 0);
46         if (res == -1)
47                 return -1;
48
49         if (setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))) {
50                 close(res);
51                 return -1;
52         }
53 #ifdef SO_REUSEPORT
54         if (setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val))) {
55                 close(res);
56                 return -1;
57         }
58 #endif /* SO_REUSEPORT */
59
60         /* now we've got a socket - we need to bind it */
61
62         if (bind(res, (struct sockaddr *)(void *)&sock, sizeof(sock)) < 0) {
63                 close(res);
64                 return(-1);
65         }
66
67         set_socket_options(res,"SO_BROADCAST");
68
69         return res;
70 }
71
72
73 static struct node_status *lookup_byaddr_backend(TALLOC_CTX *mem_ctx,
74                                                  const char *addr, int *count)
75 {
76         int fd;
77         struct sockaddr_storage ss;
78         struct nmb_name nname;
79         struct node_status *result;
80         NTSTATUS status;
81
82         fd = wins_lookup_open_socket_in();
83         if (fd == -1)
84                 return NULL;
85
86         make_nmb_name(&nname, "*", 0);
87         if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) {
88                 return NULL;
89         }
90         status = node_status_query(fd, &nname, &ss, mem_ctx,
91                                    &result, count, NULL);
92         close(fd);
93         if (!NT_STATUS_IS_OK(status)) {
94                 return NULL;
95         }
96         return result;
97 }
98
99 static struct sockaddr_storage *lookup_byname_backend(const char *name,
100                                         int *count)
101 {
102         int fd;
103         struct ip_service *ret = NULL;
104         struct sockaddr_storage *return_ss = NULL;
105         int j, i, flags = 0;
106
107         *count = 0;
108
109         /* always try with wins first */
110         if (NT_STATUS_IS_OK(resolve_wins(name,0x20,&ret,count))) {
111                 if ( *count == 0 )
112                         return NULL;
113                 if ( (return_ss = SMB_MALLOC_ARRAY(struct sockaddr_storage, *count)) == NULL ) {
114                         free( ret );
115                         return NULL;
116                 }
117
118                 /* copy the IP addresses */
119                 for ( i=0; i<(*count); i++ )
120                         return_ss[i] = ret[i].ss;
121
122                 free( ret );
123                 return return_ss;
124         }
125
126         fd = wins_lookup_open_socket_in();
127         if (fd == -1) {
128                 return NULL;
129         }
130
131         /* uggh, we have to broadcast to each interface in turn */
132         for (j=iface_count() - 1;
133              j >= 0;
134              j--) {
135                 const struct sockaddr_storage *bcast_ss = iface_n_bcast(j);
136                 if (!bcast_ss) {
137                         continue;
138                 }
139                 return_ss = name_query(fd,name,0x20,True,True,bcast_ss,count, &flags, NULL);
140                 if (return_ss) {
141                         break;
142                 }
143         }
144
145         close(fd);
146         return return_ss;
147 }
148
149 /* Get hostname from IP  */
150
151 void winbindd_wins_byip(struct winbindd_cli_state *state)
152 {
153         fstring response;
154         int i, count, maxlen, size;
155         struct node_status *status;
156
157         /* Ensure null termination */
158         state->request->data.winsreq[sizeof(state->request->data.winsreq)-1]='\0';
159
160         DEBUG(3, ("[%5lu]: wins_byip %s\n", (unsigned long)state->pid,
161                 state->request->data.winsreq));
162
163         *response = '\0';
164         maxlen = sizeof(response) - 1;
165
166         if ((status = lookup_byaddr_backend(
167                      state->mem_ctx, state->request->data.winsreq, &count))) {
168             size = strlen(state->request->data.winsreq);
169             if (size > maxlen) {
170                 TALLOC_FREE(status);
171                 request_error(state);
172                 return;
173             }
174             fstrcat(response,state->request->data.winsreq);
175             fstrcat(response,"\t");
176             for (i = 0; i < count; i++) {
177                 /* ignore group names */
178                 if (status[i].flags & 0x80) continue;
179                 if (status[i].type == 0x20) {
180                         size = sizeof(status[i].name) + strlen(response);
181                         if (size > maxlen) {
182                             TALLOC_FREE(status);
183                             request_error(state);
184                             return;
185                         }
186                         fstrcat(response, status[i].name);
187                         fstrcat(response, " ");
188                 }
189             }
190             /* make last character a newline */
191             response[strlen(response)-1] = '\n';
192             TALLOC_FREE(status);
193         }
194         fstrcpy(state->response->data.winsresp,response);
195         request_ok(state);
196 }
197
198 /* Get IP from hostname */
199
200 void winbindd_wins_byname(struct winbindd_cli_state *state)
201 {
202         struct sockaddr_storage *ip_list = NULL;
203         int i, count, maxlen, size;
204         fstring response;
205         char addr[INET6_ADDRSTRLEN];
206
207         /* Ensure null termination */
208         state->request->data.winsreq[sizeof(state->request->data.winsreq)-1]='\0';
209
210         DEBUG(3, ("[%5lu]: wins_byname %s\n", (unsigned long)state->pid,
211                 state->request->data.winsreq));
212
213         *response = '\0';
214         maxlen = sizeof(response) - 1;
215
216         if ((ip_list = lookup_byname_backend(state->request->data.winsreq,&count))){
217                 for (i = count; i ; i--) {
218                         print_sockaddr(addr, sizeof(addr), &ip_list[i-1]);
219                         size = strlen(addr);
220                         if (size > maxlen) {
221                                 SAFE_FREE(ip_list);
222                                 request_error(state);
223                                 return;
224                         }
225                         if (i != 0) {
226                                 /* Clear out the newline character */
227                                 /* But only if there is something in there,
228                                 otherwise we clobber something in the stack */
229                                 if (strlen(response)) {
230                                         response[strlen(response)-1] = ' ';
231                                 }
232                         }
233                         fstrcat(response,addr);
234                         fstrcat(response,"\t");
235                 }
236                 size = strlen(state->request->data.winsreq) + strlen(response);
237                 if (size > maxlen) {
238                     SAFE_FREE(ip_list);
239                     request_error(state);
240                     return;
241                 }
242                 fstrcat(response,state->request->data.winsreq);
243                 fstrcat(response,"\n");
244                 SAFE_FREE(ip_list);
245         } else {
246                 request_error(state);
247                 return;
248         }
249
250         fstrcpy(state->response->data.winsresp,response);
251
252         request_ok(state);
253 }