s4-smbtorture: fix test_DoPrintTest.
[tprouty/samba.git] / source4 / libcli / resolve / resolve.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    general name resolution interface
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Jelmer Vernooij 2007
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 "libcli/composite/composite.h"
25 #include "libcli/resolve/resolve.h"
26 #include "librpc/gen_ndr/ndr_nbt.h"
27 #include "system/network.h"
28 #include "lib/socket/socket.h"
29 #include "../lib/util/dlinklist.h"
30
31 struct resolve_state {
32         struct resolve_context *ctx;
33         struct resolve_method *method;
34         uint32_t flags;
35         uint16_t port;
36         struct nbt_name name;
37         struct composite_context *creq;
38         struct socket_address **addrs;
39         char **names;
40 };
41
42 static struct composite_context *setup_next_method(struct composite_context *c);
43
44
45 struct resolve_context {
46         struct resolve_method {
47                 resolve_name_send_fn send_fn;
48                 resolve_name_recv_fn recv_fn;
49                 void *privdata;
50                 struct resolve_method *prev, *next;
51         } *methods;
52 };
53
54 /**
55  * Initialize a resolve context
56  */
57 struct resolve_context *resolve_context_init(TALLOC_CTX *mem_ctx)
58 {
59         return talloc_zero(mem_ctx, struct resolve_context);
60 }
61
62 /**
63  * Add a resolve method
64  */
65 bool resolve_context_add_method(struct resolve_context *ctx, resolve_name_send_fn send_fn, 
66                                 resolve_name_recv_fn recv_fn, void *userdata)
67 {
68         struct resolve_method *method = talloc_zero(ctx, struct resolve_method);
69
70         if (method == NULL)
71                 return false;
72
73         method->send_fn = send_fn;
74         method->recv_fn = recv_fn;
75         method->privdata = userdata;
76         DLIST_ADD_END(ctx->methods, method, struct resolve_method *);
77         return true;
78 }
79
80 /**
81   handle completion of one name resolve method
82 */
83 static void resolve_handler(struct composite_context *creq)
84 {
85         struct composite_context *c = (struct composite_context *)creq->async.private_data;
86         struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state);
87         const struct resolve_method *method = state->method;
88
89         c->status = method->recv_fn(creq, state, &state->addrs, &state->names);
90         
91         if (!NT_STATUS_IS_OK(c->status)) {
92                 state->method = state->method->next;
93                 state->creq = setup_next_method(c);
94                 if (state->creq != NULL) {
95                         return;
96                 }
97         }
98
99         if (!NT_STATUS_IS_OK(c->status)) {
100                 c->state = COMPOSITE_STATE_ERROR;
101         } else {
102                 c->state = COMPOSITE_STATE_DONE;
103         }
104         if (c->async.fn) {
105                 c->async.fn(c);
106         }
107 }
108
109
110 static struct composite_context *setup_next_method(struct composite_context *c)
111 {
112         struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state);
113         struct composite_context *creq = NULL;
114
115         do {
116                 if (state->method) {
117                         creq = state->method->send_fn(c, c->event_ctx,
118                                                       state->method->privdata,
119                                                       state->flags,
120                                                       state->port,
121                                                       &state->name);
122                 }
123                 if (creq == NULL && state->method) state->method = state->method->next;
124
125         } while (!creq && state->method);
126
127         if (creq) {
128                 creq->async.fn = resolve_handler;
129                 creq->async.private_data = c;
130         }
131
132         return creq;
133 }
134
135 /*
136   general name resolution - async send
137  */
138 struct composite_context *resolve_name_all_send(struct resolve_context *ctx,
139                                                 uint32_t flags,
140                                                 uint16_t port,
141                                                 struct nbt_name *name,
142                                                 struct tevent_context *event_ctx)
143 {
144         struct composite_context *c;
145         struct resolve_state *state;
146
147         if (ctx == NULL || event_ctx == NULL) {
148                 return NULL;
149         }
150
151         c = composite_create(ctx, event_ctx);
152         if (c == NULL) return NULL;
153
154         if (composite_nomem(c->event_ctx, c)) return c;
155
156         state = talloc(c, struct resolve_state);
157         if (composite_nomem(state, c)) return c;
158         c->private_data = state;
159
160         state->flags = flags;
161         state->port = port;
162
163         c->status = nbt_name_dup(state, name, &state->name);
164         if (!composite_is_ok(c)) return c;
165         
166         state->ctx = talloc_reference(state, ctx);
167         if (composite_nomem(state->ctx, c)) return c;
168
169         if (is_ipaddress(state->name.name) || 
170             strcasecmp(state->name.name, "localhost") == 0) {
171                 struct in_addr ip = interpret_addr2(state->name.name);
172
173                 state->addrs = talloc_array(state, struct socket_address *, 2);
174                 if (composite_nomem(state->addrs, c)) return c;
175                 state->addrs[0] = socket_address_from_strings(state->addrs, "ipv4",
176                                                               inet_ntoa(ip), 0);
177                 if (composite_nomem(state->addrs[0], c)) return c;
178                 state->addrs[1] = NULL;
179                 state->names = talloc_array(state, char *, 2);
180                 if (composite_nomem(state->names, c)) return c;
181                 state->names[0] = talloc_strdup(state->names, state->name.name);
182                 if (composite_nomem(state->names[0], c)) return c;
183                 state->names[1] = NULL;
184                 composite_done(c);
185                 return c;
186         }
187
188         state->method = ctx->methods;
189         if (state->method == NULL) {
190                 composite_error(c, NT_STATUS_BAD_NETWORK_NAME);
191                 return c;
192         }
193         state->creq = setup_next_method(c);
194         if (composite_nomem(state->creq, c)) return c;
195         
196         return c;
197 }
198
199 /*
200   general name resolution method - recv side
201  */
202 NTSTATUS resolve_name_all_recv(struct composite_context *c,
203                                TALLOC_CTX *mem_ctx,
204                                struct socket_address ***addrs,
205                                char ***names)
206 {
207         NTSTATUS status;
208
209         status = composite_wait(c);
210
211         if (NT_STATUS_IS_OK(status)) {
212                 struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state);
213                 *addrs = talloc_steal(mem_ctx, state->addrs);
214                 if (names) {
215                         *names = talloc_steal(mem_ctx, state->names);
216                 }
217         }
218
219         talloc_free(c);
220         return status;
221 }
222
223 struct composite_context *resolve_name_send(struct resolve_context *ctx,
224                                             struct nbt_name *name,
225                                             struct tevent_context *event_ctx)
226 {
227         return resolve_name_all_send(ctx, 0, 0, name, event_ctx);
228 }
229
230 NTSTATUS resolve_name_recv(struct composite_context *c,
231                            TALLOC_CTX *mem_ctx,
232                            const char **reply_addr)
233 {
234         NTSTATUS status;
235         struct socket_address **addrs = NULL;
236
237         status = resolve_name_all_recv(c, mem_ctx, &addrs, NULL);
238
239         if (NT_STATUS_IS_OK(status)) {
240                 *reply_addr = talloc_steal(mem_ctx, addrs[0]->addr);
241                 talloc_free(addrs);
242         }
243
244         return status;
245 }
246
247 /*
248   general name resolution - sync call
249  */
250 NTSTATUS resolve_name(struct resolve_context *ctx,
251                           struct nbt_name *name,
252                           TALLOC_CTX *mem_ctx,
253                           const char **reply_addr,
254                           struct tevent_context *ev)
255 {
256         struct composite_context *c = resolve_name_send(ctx, name, ev);
257         return resolve_name_recv(c, mem_ctx, reply_addr);
258 }
259
260 /* Initialise a struct nbt_name with a NULL scope */
261
262 void make_nbt_name(struct nbt_name *nbt, const char *name, int type)
263 {
264         nbt->name = name;
265         nbt->scope = NULL;
266         nbt->type = type;
267 }
268
269 /* Initialise a struct nbt_name with a NBT_NAME_CLIENT (0x00) name */
270
271 void make_nbt_name_client(struct nbt_name *nbt, const char *name)
272 {
273         make_nbt_name(nbt, name, NBT_NAME_CLIENT);
274 }
275
276 /* Initialise a struct nbt_name with a NBT_NAME_SERVER (0x20) name */
277
278 void make_nbt_name_server(struct nbt_name *nbt, const char *name)
279 {
280         make_nbt_name(nbt, name, NBT_NAME_SERVER);
281 }
282
283