c568a3439ec4f63086c6c765285ff3dfbb8684d5
[kai/samba.git] / source3 / nsswitch / winbindd_wins.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4
5    Winbind daemon - WINS related functions
6
7    Copyright (C) Andrew Tridgell 1999
8    Copyright (C) Herb Lewis 2002
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "winbindd.h"
26
27 /* Use our own create socket code so we don't recurse.... */
28
29 static int wins_lookup_open_socket_in(void)
30 {
31         struct sockaddr_in sock;
32         int val=1;
33         int res;
34
35         memset((char *)&sock,'\0',sizeof(sock));
36
37 #ifdef HAVE_SOCK_SIN_LEN
38         sock.sin_len = sizeof(sock);
39 #endif
40         sock.sin_port = 0;
41         sock.sin_family = AF_INET;
42         sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
43         res = socket(AF_INET, SOCK_DGRAM, 0);
44         if (res == -1)
45                 return -1;
46
47         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
48 #ifdef SO_REUSEPORT
49         setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
50 #endif /* SO_REUSEPORT */
51
52         /* now we've got a socket - we need to bind it */
53
54         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
55                 close(res);
56                 return(-1);
57         }
58
59         set_socket_options(res,"SO_BROADCAST");
60
61         return res;
62 }
63
64
65 static struct node_status *lookup_byaddr_backend(char *addr, int *count)
66 {
67         int fd;
68         struct in_addr  ip;
69         struct nmb_name nname;
70         struct node_status *status;
71
72         fd = wins_lookup_open_socket_in();
73         if (fd == -1)
74                 return NULL;
75
76         make_nmb_name(&nname, "*", 0);
77         ip = *interpret_addr2(addr);
78         status = node_status_query(fd,&nname,ip, count);
79
80         close(fd);
81         return status;
82 }
83
84 static struct in_addr *lookup_byname_backend(const char *name, int *count)
85 {
86         int fd;
87         struct in_addr *ret = NULL;
88         struct in_addr  p;
89         int j;
90
91         *count = 0;
92
93         fd = wins_lookup_open_socket_in();
94         if (fd == -1)
95                 return NULL;
96
97         p = wins_srv_ip();
98         if( !zero_ip(p) ) {
99                 ret = name_query(fd,name,0x20,False,True, p, count);
100                 goto out;
101         }
102
103         if (lp_wins_support()) {
104                 /* we are our own WINS server */
105                 ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count);
106                 goto out;
107         }
108
109         /* uggh, we have to broadcast to each interface in turn */
110         for (j=iface_count() - 1;
111              j >= 0;
112              j--) {
113                 struct in_addr *bcast = iface_n_bcast(j);
114                 ret = name_query(fd,name,0x20,True,True,*bcast,count);
115                 if (ret) break;
116         }
117
118  out:
119
120         close(fd);
121         return ret;
122 }
123
124 /* Get hostname from IP  */
125
126 enum winbindd_result winbindd_wins_byip(struct winbindd_cli_state *state)
127 {
128         char response[1024];
129         int i, count, len, size;
130         struct node_status *status;
131
132         DEBUG(3, ("[%5d]: wins_byip %s\n", state->pid,
133                 state->request.data.name));
134
135         *response = '\0';
136         len = sizeof(response) - 2;
137
138         if ((status = lookup_byaddr_backend(state->request.data.name, &count))){
139             size = strlen(state->request.data.name) + 1;
140             if (size > len) {
141                 SAFE_FREE(status);
142                 return WINBINDD_ERROR;
143             }
144             len -= size;
145             safe_strcat(response,state->request.data.name,size);
146             safe_strcat(response,"\t",1);
147             for (i = 0; i < count; i++) {
148                 /* ignore group names */
149                 if (status[i].flags & 0x80) continue;
150                 if (status[i].type == 0x20) {
151                         size = sizeof(status[i].name) + 1;
152                         if (size > len) {
153                             SAFE_FREE(status);
154                             return WINBINDD_ERROR;
155                         }
156                         len -= size;
157                         safe_strcat(response, status[i].name, size);
158                         safe_strcat(response, " ", 1);
159                 }
160             }
161             response[strlen(response)-1] = '\n';
162             SAFE_FREE(status);
163         }
164         fstrcpy(state->response.data.name.name,response);
165         return WINBINDD_OK;
166 }
167
168 /* Get IP from hostname */
169
170 enum winbindd_result winbindd_wins_byname(struct winbindd_cli_state *state)
171 {
172         struct in_addr *ip_list;
173         int i, count, len, size;
174         char response[1024];
175         char * addr;
176
177         DEBUG(3, ("[%5d]: wins_byname %s\n", state->pid,
178                 state->request.data.name));
179
180         *response = '\0';
181         len = sizeof(response) - 2;
182
183         if ((ip_list = lookup_byname_backend(state->request.data.name,&count))){
184                 for (i = count; i ; i--) {
185                     addr = inet_ntoa(ip_list[i-1]);
186                     size = strlen(addr) + 1;
187                     if (size > len) {
188                         SAFE_FREE(ip_list);
189                         return WINBINDD_ERROR;
190                     }
191                     len -= size;
192                     if (i != 0)
193                         response[strlen(response)-1] = ' ';
194                     safe_strcat(response,addr,size);
195                     safe_strcat(response,"\t",1);
196                 }
197                 size = strlen(state->request.data.name) + 1;
198                 if (size > len) {
199                     SAFE_FREE(ip_list);
200                     return WINBINDD_ERROR;
201                 }   
202                 safe_strcat(response,state->request.data.name,size);
203                 safe_strcat(response,"\n",1);
204                 SAFE_FREE(ip_list);
205         } else
206                 return WINBINDD_ERROR;
207
208         fstrcpy(state->response.data.name.name,response);
209
210         return WINBINDD_OK;
211 }