Merge commit 'release-4-0-0alpha15' into master4-tmp
[ira/wip.git] / source3 / winbindd / winbindd_wins_byname.c
1 /*
2    Unix SMB/CIFS implementation.
3    async implementation of WINBINDD_WINS_BYNAME
4    Copyright (C) Volker Lendecke 2011
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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "librpc/gen_ndr/ndr_wbint_c.h"
23 #include "libsmb/nmblib.h"
24 #include "lib/util/string_wrappers.h"
25
26 struct winbindd_wins_byname_state {
27         struct tevent_context *ev;
28         struct winbindd_request *request;
29         struct sockaddr_storage *addrs;
30         int num_addrs;
31 };
32
33 static void winbindd_wins_byname_wins_done(struct tevent_req *subreq);
34 static void winbindd_wins_byname_bcast_done(struct tevent_req *subreq);
35
36 struct tevent_req *winbindd_wins_byname_send(TALLOC_CTX *mem_ctx,
37                                              struct tevent_context *ev,
38                                              struct winbindd_cli_state *cli,
39                                              struct winbindd_request *request)
40 {
41         struct tevent_req *req, *subreq;
42         struct winbindd_wins_byname_state *state;
43
44         req = tevent_req_create(mem_ctx, &state,
45                                 struct winbindd_wins_byname_state);
46         if (req == NULL) {
47                 return NULL;
48         }
49         state->ev = ev;
50         state->request = request;
51
52         /* Ensure null termination */
53         request->data.winsreq[sizeof(request->data.winsreq)-1]='\0';
54
55         DEBUG(3, ("[%5lu]: wins_byname %s\n", (unsigned long)cli->pid,
56                   request->data.winsreq));
57
58         subreq = resolve_wins_send(state, ev, state->request->data.winsreq,
59                                    0x20);
60         if (tevent_req_nomem(subreq, req)) {
61                 return tevent_req_post(req, ev);
62         }
63         tevent_req_set_callback(subreq, winbindd_wins_byname_wins_done, req);
64         return req;
65 }
66
67 static void winbindd_wins_byname_wins_done(struct tevent_req *subreq)
68 {
69         struct tevent_req *req = tevent_req_callback_data(
70                 subreq, struct tevent_req);
71         struct winbindd_wins_byname_state *state = tevent_req_data(
72                 req, struct winbindd_wins_byname_state);
73         NTSTATUS status;
74
75         status = resolve_wins_recv(subreq, talloc_tos(), &state->addrs,
76                                    &state->num_addrs, NULL);
77         TALLOC_FREE(subreq);
78         if (NT_STATUS_IS_OK(status)) {
79                 tevent_req_done(req);
80                 return;
81         }
82         subreq = name_resolve_bcast_send(state, state->ev,
83                                          state->request->data.winsreq, 0x20);
84         if (tevent_req_nomem(subreq, req)) {
85                 return;
86         }
87         tevent_req_set_callback(subreq, winbindd_wins_byname_bcast_done, req);
88 }
89
90 static void winbindd_wins_byname_bcast_done(struct tevent_req *subreq)
91 {
92         struct tevent_req *req = tevent_req_callback_data(
93                 subreq, struct tevent_req);
94         struct winbindd_wins_byname_state *state = tevent_req_data(
95                 req, struct winbindd_wins_byname_state);
96         NTSTATUS status;
97
98         status = name_resolve_bcast_recv(subreq, talloc_tos(), &state->addrs,
99                                          &state->num_addrs);
100         TALLOC_FREE(subreq);
101         if (tevent_req_nterror(req, status)) {
102                 return;
103         }
104         tevent_req_done(req);
105 }
106
107 NTSTATUS winbindd_wins_byname_recv(struct tevent_req *req,
108                                    struct winbindd_response *presp)
109 {
110         struct winbindd_wins_byname_state *state = tevent_req_data(
111                 req, struct winbindd_wins_byname_state);
112         char *response;
113         NTSTATUS status;
114         int i;
115
116         if (tevent_req_is_nterror(req, &status)) {
117                 return status;
118         }
119
120         response = talloc_strdup(talloc_tos(), "");
121         if (response == NULL) {
122                 return NT_STATUS_NO_MEMORY;
123         }
124
125         for (i=0; i<state->num_addrs; i++) {
126                 char addr[INET6_ADDRSTRLEN];
127                 print_sockaddr(addr, sizeof(addr), &state->addrs[i]);
128
129                 response = talloc_asprintf_append_buffer(
130                         response, "%s\t", addr);
131                 if (response == NULL) {
132                         return NT_STATUS_NO_MEMORY;
133                 }
134         }
135
136         response = talloc_asprintf_append_buffer(
137                 response, "%s\n", state->request->data.winsreq);
138         if (response == NULL) {
139                 return NT_STATUS_NO_MEMORY;
140         }
141
142         if (talloc_get_size(response) > sizeof(presp->data.winsresp)) {
143                 TALLOC_FREE(response);
144                 return NT_STATUS_MARSHALL_OVERFLOW;
145         }
146         fstrcpy(presp->data.winsresp, response);
147         TALLOC_FREE(response);
148         return NT_STATUS_OK;
149 }