Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/libcli/resolve/resolve.c
Line
Count
Source
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
#include "lib/tsocket/tsocket.h"
31
#include "lib/util/util_net.h"
32
33
#undef strcasecmp
34
35
struct resolve_state {
36
  struct resolve_context *ctx;
37
  struct resolve_method *method;
38
  uint32_t flags;
39
  uint16_t port;
40
  struct nbt_name name;
41
  struct composite_context *creq;
42
  struct socket_address **addrs;
43
  char **names;
44
};
45
46
static struct composite_context *setup_next_method(struct composite_context *c);
47
48
49
struct resolve_context {
50
  struct resolve_method {
51
    resolve_name_send_fn send_fn;
52
    resolve_name_recv_fn recv_fn;
53
    void *privdata;
54
    struct resolve_method *prev, *next;
55
  } *methods;
56
};
57
58
/**
59
 * Initialize a resolve context
60
 */
61
struct resolve_context *resolve_context_init(TALLOC_CTX *mem_ctx)
62
0
{
63
0
  return talloc_zero(mem_ctx, struct resolve_context);
64
0
}
65
66
/**
67
 * Add a resolve method
68
 */
69
bool resolve_context_add_method(struct resolve_context *ctx, resolve_name_send_fn send_fn, 
70
        resolve_name_recv_fn recv_fn, void *userdata)
71
0
{
72
0
  struct resolve_method *method = talloc_zero(ctx, struct resolve_method);
73
74
0
  if (method == NULL)
75
0
    return false;
76
77
0
  method->send_fn = send_fn;
78
0
  method->recv_fn = recv_fn;
79
0
  method->privdata = userdata;
80
0
  DLIST_ADD_END(ctx->methods, method);
81
0
  return true;
82
0
}
83
84
/**
85
  handle completion of one name resolve method
86
*/
87
static void resolve_handler(struct composite_context *creq)
88
0
{
89
0
  struct composite_context *c = (struct composite_context *)creq->async.private_data;
90
0
  struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state);
91
0
  const struct resolve_method *method = state->method;
92
93
0
  c->status = method->recv_fn(creq, state, &state->addrs, &state->names);
94
  
95
0
  if (!NT_STATUS_IS_OK(c->status)) {
96
0
    state->method = state->method->next;
97
0
    state->creq = setup_next_method(c);
98
0
    if (state->creq != NULL) {
99
0
      return;
100
0
    }
101
0
  }
102
103
0
  if (!NT_STATUS_IS_OK(c->status)) {
104
0
    c->state = COMPOSITE_STATE_ERROR;
105
0
  } else {
106
0
    c->state = COMPOSITE_STATE_DONE;
107
0
  }
108
0
  if (c->async.fn) {
109
0
    c->async.fn(c);
110
0
  }
111
0
}
112
113
114
static struct composite_context *setup_next_method(struct composite_context *c)
115
0
{
116
0
  struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state);
117
0
  struct composite_context *creq = NULL;
118
119
0
  do {
120
0
    if (state->method) {
121
0
      creq = state->method->send_fn(c, c->event_ctx,
122
0
                  state->method->privdata,
123
0
                  state->flags,
124
0
                  state->port,
125
0
                  &state->name);
126
0
    }
127
0
    if (creq == NULL && state->method) state->method = state->method->next;
128
129
0
  } while (!creq && state->method);
130
131
0
  if (creq) {
132
0
    creq->async.fn = resolve_handler;
133
0
    creq->async.private_data = c;
134
0
  }
135
136
0
  return creq;
137
0
}
138
139
/*
140
  general name resolution - async send
141
 */
142
struct composite_context *resolve_name_all_send(struct resolve_context *ctx,
143
            TALLOC_CTX *mem_ctx,
144
            uint32_t flags, /* RESOLVE_NAME_FLAG_* */
145
            uint16_t port,
146
            struct nbt_name *name,
147
            struct tevent_context *event_ctx)
148
0
{
149
0
  struct composite_context *c;
150
0
  struct resolve_state *state;
151
152
0
  if (event_ctx == NULL) {
153
0
    return NULL;
154
0
  }
155
156
0
  c = composite_create(mem_ctx, event_ctx);
157
0
  if (c == NULL) return NULL;
158
159
0
  if (composite_nomem(c->event_ctx, c)) return c;
160
161
0
  state = talloc(c, struct resolve_state);
162
0
  if (composite_nomem(state, c)) return c;
163
0
  c->private_data = state;
164
165
0
  state->flags = flags;
166
0
  state->port = port;
167
168
0
  c->status = nbt_name_dup(state, name, &state->name);
169
0
  if (!composite_is_ok(c)) return c;
170
  
171
0
  state->ctx = talloc_reference(state, ctx);
172
0
  if (composite_nomem(state->ctx, c)) return c;
173
174
0
  if (is_ipaddress(state->name.name) || 
175
0
      strcasecmp(state->name.name, "localhost") == 0) {
176
0
    state->addrs = talloc_array(state, struct socket_address *, 2);
177
0
    if (composite_nomem(state->addrs, c)) return c;
178
0
    state->addrs[0] = socket_address_from_strings(state->addrs, "ip",
179
0
                    state->name.name, 0);
180
0
    if (composite_nomem(state->addrs[0], c)) return c;
181
0
    state->addrs[1] = NULL;
182
0
    state->names = talloc_array(state, char *, 2);
183
0
    if (composite_nomem(state->names, c)) return c;
184
0
    state->names[0] = talloc_strdup(state->names, state->name.name);
185
0
    if (composite_nomem(state->names[0], c)) return c;
186
0
    state->names[1] = NULL;
187
0
    composite_done(c);
188
0
    return c;
189
0
  }
190
191
0
  state->method = ctx->methods;
192
0
  if (state->method == NULL) {
193
0
    composite_error(c, NT_STATUS_BAD_NETWORK_NAME);
194
0
    return c;
195
0
  }
196
0
  state->creq = setup_next_method(c);
197
0
  if (composite_nomem(state->creq, c)) return c;
198
  
199
0
  return c;
200
0
}
201
202
/*
203
  general name resolution method - recv side
204
 */
205
NTSTATUS resolve_name_all_recv(struct composite_context *c,
206
             TALLOC_CTX *mem_ctx,
207
             struct socket_address ***addrs,
208
             char ***names)
209
0
{
210
0
  NTSTATUS status;
211
212
0
  status = composite_wait(c);
213
214
0
  if (NT_STATUS_IS_OK(status)) {
215
0
    struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state);
216
0
    *addrs = talloc_steal(mem_ctx, state->addrs);
217
0
    if (names) {
218
0
      *names = talloc_steal(mem_ctx, state->names);
219
0
    }
220
0
  }
221
222
0
  talloc_free(c);
223
0
  return status;
224
0
}
225
226
struct composite_context *resolve_name_ex_send(struct resolve_context *ctx,
227
                 TALLOC_CTX *mem_ctx,
228
                 uint32_t flags, /* RESOLVE_NAME_FLAG_* */
229
                 uint16_t port,
230
                 struct nbt_name *name,
231
                 struct tevent_context *event_ctx)
232
0
{
233
0
  return resolve_name_all_send(ctx, mem_ctx, flags, port, name, event_ctx);
234
0
}
235
236
struct composite_context *resolve_name_send(struct resolve_context *ctx,
237
              TALLOC_CTX *mem_ctx,
238
              struct nbt_name *name,
239
              struct tevent_context *event_ctx)
240
0
{
241
0
  return resolve_name_ex_send(ctx, mem_ctx, 0, 0, name, event_ctx);
242
0
}
243
244
NTSTATUS resolve_name_recv(struct composite_context *c,
245
         TALLOC_CTX *mem_ctx,
246
         const char **reply_addr)
247
0
{
248
0
  NTSTATUS status;
249
0
  struct socket_address **addrs = NULL;
250
251
0
  status = resolve_name_all_recv(c, mem_ctx, &addrs, NULL);
252
253
0
  if (NT_STATUS_IS_OK(status)) {
254
0
    struct tsocket_address *t_addr = socket_address_to_tsocket_address(addrs, addrs[0]);
255
0
    if (!t_addr) {
256
0
      return NT_STATUS_NO_MEMORY;
257
0
    }
258
259
0
    *reply_addr = tsocket_address_inet_addr_string(t_addr, mem_ctx);
260
0
    talloc_free(addrs);
261
0
    if (!*reply_addr) {
262
0
      return NT_STATUS_NO_MEMORY;
263
0
    }
264
0
  }
265
266
0
  return status;
267
0
}
268
269
/*
270
  receive multiple responses from resolve_name_send()
271
 */
272
NTSTATUS resolve_name_multiple_recv(struct composite_context *c,
273
            TALLOC_CTX *mem_ctx,
274
            const char ***reply_addrs)
275
0
{
276
0
  NTSTATUS status;
277
0
  struct socket_address **addrs = NULL;
278
0
  int i;
279
280
0
  status = resolve_name_all_recv(c, mem_ctx, &addrs, NULL);
281
0
  NT_STATUS_NOT_OK_RETURN(status);
282
283
  /* count the addresses */
284
0
  for (i=0; addrs[i]; i++) ;
285
286
0
  *reply_addrs = talloc_array(mem_ctx, const char *, i+1);
287
0
  NT_STATUS_HAVE_NO_MEMORY(*reply_addrs);
288
289
0
  for (i=0; addrs[i]; i++) {
290
0
    struct tsocket_address *t_addr = socket_address_to_tsocket_address(addrs, addrs[i]);
291
0
    NT_STATUS_HAVE_NO_MEMORY(t_addr);
292
293
0
    (*reply_addrs)[i] = tsocket_address_inet_addr_string(t_addr, *reply_addrs);
294
0
    NT_STATUS_HAVE_NO_MEMORY((*reply_addrs)[i]);
295
0
  }
296
0
  (*reply_addrs)[i] = NULL;
297
298
0
  talloc_free(addrs);
299
300
0
  return status;
301
0
}
302
303
/*
304
  general name resolution - sync call
305
 */
306
NTSTATUS resolve_name_ex(struct resolve_context *ctx,
307
       uint32_t flags, /* RESOLVE_NAME_FLAG_* */
308
       uint16_t port,
309
       struct nbt_name *name,
310
       TALLOC_CTX *mem_ctx,
311
       const char **reply_addr,
312
       struct tevent_context *ev)
313
0
{
314
0
  struct composite_context *c = resolve_name_ex_send(ctx, mem_ctx, flags, port, name, ev);
315
0
  return resolve_name_recv(c, mem_ctx, reply_addr);
316
0
}
317
318
319
/* Initialise a struct nbt_name with a NULL scope */
320
321
void make_nbt_name(struct nbt_name *nbt, const char *name, int type)
322
0
{
323
0
  nbt->name = name;
324
0
  nbt->scope = NULL;
325
0
  nbt->type = type;
326
0
}
327
328
/* Initialise a struct nbt_name with a NBT_NAME_CLIENT (0x00) name */
329
330
void make_nbt_name_client(struct nbt_name *nbt, const char *name)
331
0
{
332
0
  make_nbt_name(nbt, name, NBT_NAME_CLIENT);
333
0
}
334
335
/* Initialise a struct nbt_name with a NBT_NAME_SERVER (0x20) name */
336
337
void make_nbt_name_server(struct nbt_name *nbt, const char *name)
338
0
{
339
0
  make_nbt_name(nbt, name, NBT_NAME_SERVER);
340
0
}
341
342