s3: Fix paranoia check in sam_rids_to_names
[samba.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 static struct node_status *lookup_byaddr_backend(TALLOC_CTX *mem_ctx,
30                                                  const char *addr, int *count)
31 {
32         struct sockaddr_storage ss;
33         struct nmb_name nname;
34         struct node_status *result;
35         NTSTATUS status;
36
37         make_nmb_name(&nname, "*", 0);
38         if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) {
39                 return NULL;
40         }
41         status = node_status_query(mem_ctx, &nname, &ss,
42                                    &result, count, NULL);
43         if (!NT_STATUS_IS_OK(status)) {
44                 return NULL;
45         }
46         return result;
47 }
48
49 static struct sockaddr_storage *lookup_byname_backend(TALLOC_CTX *mem_ctx,
50                                                       const char *name,
51                                                       int *count)
52 {
53         struct ip_service *ret = NULL;
54         struct sockaddr_storage *return_ss = NULL;
55         int j, i;
56         NTSTATUS status;
57
58         *count = 0;
59
60         /* always try with wins first */
61         if (NT_STATUS_IS_OK(resolve_wins(name,0x20,&ret,count))) {
62                 if ( *count == 0 )
63                         return NULL;
64                 return_ss = TALLOC_ARRAY(mem_ctx, struct sockaddr_storage,
65                                          *count);
66                 if (return_ss == NULL ) {
67                         free( ret );
68                         return NULL;
69                 }
70
71                 /* copy the IP addresses */
72                 for ( i=0; i<(*count); i++ )
73                         return_ss[i] = ret[i].ss;
74
75                 free( ret );
76                 return return_ss;
77         }
78
79         /* uggh, we have to broadcast to each interface in turn */
80         for (j=iface_count() - 1;
81              j >= 0;
82              j--) {
83                 const struct sockaddr_storage *bcast_ss = iface_n_bcast(j);
84                 if (!bcast_ss) {
85                         continue;
86                 }
87                 status = name_query(name, 0x20, True, True,bcast_ss,
88                                     mem_ctx, &return_ss, count, NULL);
89                 if (NT_STATUS_IS_OK(status)) {
90                         break;
91                 }
92         }
93
94         return return_ss;
95 }
96
97 /* Get hostname from IP  */
98
99 void winbindd_wins_byip(struct winbindd_cli_state *state)
100 {
101         fstring response;
102         int i, count, maxlen, size;
103         struct node_status *status;
104
105         /* Ensure null termination */
106         state->request->data.winsreq[sizeof(state->request->data.winsreq)-1]='\0';
107
108         DEBUG(3, ("[%5lu]: wins_byip %s\n", (unsigned long)state->pid,
109                 state->request->data.winsreq));
110
111         *response = '\0';
112         maxlen = sizeof(response) - 1;
113
114         if ((status = lookup_byaddr_backend(
115                      state->mem_ctx, state->request->data.winsreq, &count))) {
116             size = strlen(state->request->data.winsreq);
117             if (size > maxlen) {
118                 TALLOC_FREE(status);
119                 request_error(state);
120                 return;
121             }
122             fstrcat(response,state->request->data.winsreq);
123             fstrcat(response,"\t");
124             for (i = 0; i < count; i++) {
125                 /* ignore group names */
126                 if (status[i].flags & 0x80) continue;
127                 if (status[i].type == 0x20) {
128                         size = sizeof(status[i].name) + strlen(response);
129                         if (size > maxlen) {
130                             TALLOC_FREE(status);
131                             request_error(state);
132                             return;
133                         }
134                         fstrcat(response, status[i].name);
135                         fstrcat(response, " ");
136                 }
137             }
138             /* make last character a newline */
139             response[strlen(response)-1] = '\n';
140             TALLOC_FREE(status);
141         }
142         fstrcpy(state->response->data.winsresp,response);
143         request_ok(state);
144 }
145
146 /* Get IP from hostname */
147
148 void winbindd_wins_byname(struct winbindd_cli_state *state)
149 {
150         struct sockaddr_storage *ip_list = NULL;
151         int i, count, maxlen, size;
152         fstring response;
153         char addr[INET6_ADDRSTRLEN];
154
155         /* Ensure null termination */
156         state->request->data.winsreq[sizeof(state->request->data.winsreq)-1]='\0';
157
158         DEBUG(3, ("[%5lu]: wins_byname %s\n", (unsigned long)state->pid,
159                 state->request->data.winsreq));
160
161         *response = '\0';
162         maxlen = sizeof(response) - 1;
163
164         ip_list = lookup_byname_backend(
165                 state->mem_ctx, state->request->data.winsreq, &count);
166         if (ip_list != NULL){
167                 for (i = count; i ; i--) {
168                         print_sockaddr(addr, sizeof(addr), &ip_list[i-1]);
169                         size = strlen(addr);
170                         if (size > maxlen) {
171                                 TALLOC_FREE(ip_list);
172                                 request_error(state);
173                                 return;
174                         }
175                         if (i != 0) {
176                                 /* Clear out the newline character */
177                                 /* But only if there is something in there,
178                                 otherwise we clobber something in the stack */
179                                 if (strlen(response)) {
180                                         response[strlen(response)-1] = ' ';
181                                 }
182                         }
183                         fstrcat(response,addr);
184                         fstrcat(response,"\t");
185                 }
186                 size = strlen(state->request->data.winsreq) + strlen(response);
187                 if (size > maxlen) {
188                     TALLOC_FREE(ip_list);
189                     request_error(state);
190                     return;
191                 }
192                 fstrcat(response,state->request->data.winsreq);
193                 fstrcat(response,"\n");
194                 TALLOC_FREE(ip_list);
195         } else {
196                 request_error(state);
197                 return;
198         }
199
200         fstrcpy(state->response->data.winsresp,response);
201
202         request_ok(state);
203 }