This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[kai/samba.git] / source3 / nsswitch / 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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "winbindd.h"
25
26 /* Use our own create socket code so we don't recurse.... */
27
28 static int wins_lookup_open_socket_in(void)
29 {
30         struct sockaddr_in sock;
31         int val=1;
32         int res;
33
34         memset((char *)&sock,'\0',sizeof(sock));
35
36 #ifdef HAVE_SOCK_SIN_LEN
37         sock.sin_len = sizeof(sock);
38 #endif
39         sock.sin_port = 0;
40         sock.sin_family = AF_INET;
41         sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
42         res = socket(AF_INET, SOCK_DGRAM, 0);
43         if (res == -1)
44                 return -1;
45
46         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
47 #ifdef SO_REUSEPORT
48         setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
49 #endif /* SO_REUSEPORT */
50
51         /* now we've got a socket - we need to bind it */
52
53         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
54                 close(res);
55                 return(-1);
56         }
57
58         set_socket_options(res,"SO_BROADCAST");
59
60         return res;
61 }
62
63
64 static struct node_status *lookup_byaddr_backend(char *addr, int *count)
65 {
66         int fd;
67         struct in_addr  ip;
68         struct nmb_name nname;
69         struct node_status *status;
70
71         fd = wins_lookup_open_socket_in();
72         if (fd == -1)
73                 return NULL;
74
75         make_nmb_name(&nname, "*", 0);
76         ip = *interpret_addr2(addr);
77         status = node_status_query(fd,&nname,ip, count);
78
79         close(fd);
80         return status;
81 }
82
83 static struct in_addr *lookup_byname_backend(const char *name, int *count)
84 {
85         int fd;
86         struct in_addr *ret = NULL;
87         struct in_addr  p;
88         int j;
89
90         *count = 0;
91
92         fd = wins_lookup_open_socket_in();
93         if (fd == -1)
94                 return NULL;
95
96         p = wins_srv_ip();
97         if( !is_zero_ip(p) ) {
98                 ret = name_query(fd,name,0x20,False,True, p, count);
99                 goto out;
100         }
101
102         if (lp_wins_support()) {
103                 /* we are our own WINS server */
104                 ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count);
105                 goto out;
106         }
107
108         /* uggh, we have to broadcast to each interface in turn */
109         for (j=iface_count() - 1;
110              j >= 0;
111              j--) {
112                 struct in_addr *bcast = iface_n_bcast(j);
113                 ret = name_query(fd,name,0x20,True,True,*bcast,count);
114                 if (ret) break;
115         }
116
117  out:
118
119         close(fd);
120         return ret;
121 }
122
123 /* Get hostname from IP  */
124
125 enum winbindd_result winbindd_wins_byip(struct winbindd_cli_state *state)
126 {
127         fstring response;
128         int i, count, maxlen, size;
129         struct node_status *status;
130
131         DEBUG(3, ("[%5d]: wins_byip %s\n", state->pid,
132                 state->request.data.winsreq));
133
134         *response = '\0';
135         maxlen = sizeof(response) - 1;
136
137         if ((status = lookup_byaddr_backend(state->request.data.winsreq, &count))){
138             size = strlen(state->request.data.winsreq);
139             if (size > maxlen) {
140                 SAFE_FREE(status);
141                 return WINBINDD_ERROR;
142             }
143             safe_strcat(response,state->request.data.winsreq,maxlen);
144             safe_strcat(response,"\t",maxlen);
145             for (i = 0; i < count; i++) {
146                 /* ignore group names */
147                 if (status[i].flags & 0x80) continue;
148                 if (status[i].type == 0x20) {
149                         size = sizeof(status[i].name) + strlen(response);
150                         if (size > maxlen) {
151                             SAFE_FREE(status);
152                             return WINBINDD_ERROR;
153                         }
154                         safe_strcat(response, status[i].name, maxlen);
155                         safe_strcat(response, " ", maxlen);
156                 }
157             }
158             /* make last character a newline */
159             response[strlen(response)-1] = '\n';
160             SAFE_FREE(status);
161         }
162         fstrcpy(state->response.data.winsresp,response);
163         return WINBINDD_OK;
164 }
165
166 /* Get IP from hostname */
167
168 enum winbindd_result winbindd_wins_byname(struct winbindd_cli_state *state)
169 {
170         struct in_addr *ip_list;
171         int i, count, maxlen, size;
172         fstring response;
173         char * addr;
174
175         DEBUG(3, ("[%5d]: wins_byname %s\n", state->pid,
176                 state->request.data.winsreq));
177
178         *response = '\0';
179         maxlen = sizeof(response) - 1;
180
181         if ((ip_list = lookup_byname_backend(state->request.data.winsreq,&count))){
182                 for (i = count; i ; i--) {
183                     addr = inet_ntoa(ip_list[i-1]);
184                     size = strlen(addr);
185                     if (size > maxlen) {
186                         SAFE_FREE(ip_list);
187                         return WINBINDD_ERROR;
188                     }
189                     if (i != 0) {
190                         /* Clear out the newline character */
191                         response[strlen(response)-1] = ' '; 
192                     }
193                     safe_strcat(response,addr,maxlen);
194                     safe_strcat(response,"\t",maxlen);
195                 }
196                 size = strlen(state->request.data.winsreq) + strlen(response);
197                 if (size > maxlen) {
198                     SAFE_FREE(ip_list);
199                     return WINBINDD_ERROR;
200                 }   
201                 safe_strcat(response,state->request.data.winsreq,maxlen);
202                 safe_strcat(response,"\n",maxlen);
203                 SAFE_FREE(ip_list);
204         } else
205                 return WINBINDD_ERROR;
206
207         fstrcpy(state->response.data.winsresp,response);
208
209         return WINBINDD_OK;
210 }