CVE-2020-25719 kdc: Avoid races and multiple DB lookups in s4u2self check
[Samba.git] / source3 / utils / nmblookup.c
bloba78967fdb886bd40315fcf6e6d1f748199fed73d
1 /*
2 Unix SMB/CIFS implementation.
3 NBT client - used to lookup netbios names
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "lib/cmdline/cmdline.h"
24 #include "libsmb/nmblib.h"
25 #include "libsmb/namequery.h"
26 #include "lib/util/string_wrappers.h"
28 static bool give_flags = false;
29 static bool use_bcast = true;
30 static bool got_bcast = false;
31 static struct sockaddr_storage bcast_addr;
32 static bool recursion_desired = false;
33 static bool translate_addresses = false;
34 static int ServerFD= -1;
35 static bool RootPort = false;
36 static bool find_status = false;
38 /****************************************************************************
39 Open the socket communication.
40 **************************************************************************/
42 static bool open_sockets(void)
44 struct sockaddr_storage ss;
45 const char *sock_addr = lp_nbt_client_socket_address();
47 if (!interpret_string_addr(&ss, sock_addr,
48 AI_NUMERICHOST|AI_PASSIVE)) {
49 DEBUG(0,("open_sockets: unable to get socket address "
50 "from string %s", sock_addr));
51 return false;
53 ServerFD = open_socket_in(
54 SOCK_DGRAM, &ss, (RootPort ? 137 : 0), true);
55 if (ServerFD < 0) {
56 if (RootPort) {
57 DBG_ERR("open_socket_in failed: %s\n",
58 strerror(-ServerFD));
59 } else {
60 DBG_NOTICE("open_socket_in failed: %s\n",
61 strerror(-ServerFD));
63 return false;
66 set_socket_options( ServerFD, "SO_BROADCAST" );
68 DEBUG(3, ("Socket opened.\n"));
69 return true;
72 /****************************************************************************
73 turn a node status flags field into a string
74 ****************************************************************************/
75 static char *node_status_flags(unsigned char flags)
77 static fstring ret;
78 fstrcpy(ret,"");
80 fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " ");
81 if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
82 if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
83 if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
84 if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
85 if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
86 if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
87 if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
88 if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
90 return ret;
93 /****************************************************************************
94 Turn the NMB Query flags into a string.
95 ****************************************************************************/
97 static char *query_flags(int flags)
99 static fstring ret1;
100 fstrcpy(ret1, "");
102 if (flags & NM_FLAGS_RS) fstrcat(ret1, "Response ");
103 if (flags & NM_FLAGS_AA) fstrcat(ret1, "Authoritative ");
104 if (flags & NM_FLAGS_TC) fstrcat(ret1, "Truncated ");
105 if (flags & NM_FLAGS_RD) fstrcat(ret1, "Recursion_Desired ");
106 if (flags & NM_FLAGS_RA) fstrcat(ret1, "Recursion_Available ");
107 if (flags & NM_FLAGS_B) fstrcat(ret1, "Broadcast ");
109 return ret1;
112 /****************************************************************************
113 Do a node status query.
114 ****************************************************************************/
116 static bool do_node_status(const char *name,
117 int type,
118 struct sockaddr_storage *pss)
120 struct nmb_name nname;
121 size_t count = 0;
122 size_t i, j;
123 struct node_status *addrs;
124 struct node_status_extra extra;
125 fstring cleanname;
126 char addr[INET6_ADDRSTRLEN];
127 NTSTATUS status;
129 print_sockaddr(addr, sizeof(addr), pss);
130 d_printf("Looking up status of %s\n",addr);
131 make_nmb_name(&nname, name, type);
132 status = node_status_query(talloc_tos(), &nname, pss,
133 &addrs, &count, &extra);
134 if (NT_STATUS_IS_OK(status)) {
135 for (i=0;i<count;i++) {
136 pull_ascii_fstring(cleanname, addrs[i].name);
137 for (j=0;cleanname[j];j++) {
138 if (!isprint((int)cleanname[j])) {
139 cleanname[j] = '.';
142 d_printf("\t%-15s <%02x> - %s\n",
143 cleanname,addrs[i].type,
144 node_status_flags(addrs[i].flags));
146 d_printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
147 extra.mac_addr[0], extra.mac_addr[1],
148 extra.mac_addr[2], extra.mac_addr[3],
149 extra.mac_addr[4], extra.mac_addr[5]);
150 d_printf("\n");
151 TALLOC_FREE(addrs);
152 return true;
153 } else {
154 d_printf("No reply from %s\n\n",addr);
155 return false;
160 /****************************************************************************
161 Send out one query.
162 ****************************************************************************/
164 static bool query_one(const char *lookup, unsigned int lookup_type)
166 size_t j, count = 0;
167 uint8_t flags;
168 struct sockaddr_storage *ip_list=NULL;
169 NTSTATUS status = NT_STATUS_NOT_FOUND;
171 if (got_bcast) {
172 char addr[INET6_ADDRSTRLEN];
173 print_sockaddr(addr, sizeof(addr), &bcast_addr);
174 d_printf("querying %s on %s\n", lookup, addr);
175 status = name_query(lookup,lookup_type,use_bcast,
176 use_bcast?true:recursion_desired,
177 &bcast_addr, talloc_tos(),
178 &ip_list, &count, &flags);
179 } else {
180 status = name_resolve_bcast(talloc_tos(),
181 lookup,
182 lookup_type,
183 &ip_list,
184 &count);
187 if (!NT_STATUS_IS_OK(status)) {
188 return false;
191 if (give_flags) {
192 d_printf("Flags: %s\n", query_flags(flags));
195 for (j=0;j<count;j++) {
196 char addr[INET6_ADDRSTRLEN];
197 if (translate_addresses) {
198 char h_name[MAX_DNS_NAME_LENGTH];
199 h_name[0] = '\0';
200 if (sys_getnameinfo((const struct sockaddr *)&ip_list[j],
201 sizeof(struct sockaddr_storage),
202 h_name, sizeof(h_name),
203 NULL, 0,
204 NI_NAMEREQD)) {
205 continue;
207 d_printf("%s, ", h_name);
209 print_sockaddr(addr, sizeof(addr), &ip_list[j]);
210 d_printf("%s %s<%02x>\n", addr,lookup, lookup_type);
211 /* We can only do find_status if the ip address returned
212 was valid - ie. name_query returned true.
214 if (find_status) {
215 if (!do_node_status(lookup, lookup_type, &ip_list[j])) {
216 status = NT_STATUS_UNSUCCESSFUL;
221 TALLOC_FREE(ip_list);
223 return NT_STATUS_IS_OK(status);
227 /****************************************************************************
228 main program
229 ****************************************************************************/
230 enum nmblookup_cmdline_options {
231 CMDLINE_RECURSIVE = 1,
234 int main(int argc, const char *argv[])
236 int opt;
237 unsigned int lookup_type = 0x0;
238 fstring lookup;
239 static bool find_master=False;
240 static bool lookup_by_ip = False;
241 poptContext pc = NULL;
242 TALLOC_CTX *frame = talloc_stackframe();
243 int rc = 0;
244 bool ok;
246 struct poptOption long_options[] = {
247 POPT_AUTOHELP
249 .longName = "broadcast",
250 .shortName = 'B',
251 .argInfo = POPT_ARG_STRING,
252 .arg = NULL,
253 .val = 'B',
254 .descrip = "Specify address to use for broadcasts",
255 .argDescrip = "BROADCAST-ADDRESS",
258 .longName = "flags",
259 .shortName = 'f',
260 .argInfo = POPT_ARG_NONE,
261 .arg = NULL,
262 .val = 'f',
263 .descrip = "List the NMB flags returned",
266 .longName = "unicast",
267 .shortName = 'U',
268 .argInfo = POPT_ARG_STRING,
269 .arg = NULL,
270 .val = 'U',
271 .descrip = "Specify address to use for unicast",
274 .longName = "master-browser",
275 .shortName = 'M',
276 .argInfo = POPT_ARG_NONE,
277 .arg = NULL,
278 .val = 'M',
279 .descrip = "Search for a master browser",
282 .longName = "recursion",
283 .shortName = 0,
284 .argInfo = POPT_ARG_NONE,
285 .arg = NULL,
286 .val = CMDLINE_RECURSIVE,
287 .descrip = "Set recursion desired in package",
290 .longName = "status",
291 .shortName = 'S',
292 .argInfo = POPT_ARG_NONE,
293 .arg = NULL,
294 .val = 'S',
295 .descrip = "Lookup node status as well",
298 .longName = "translate",
299 .shortName = 'T',
300 .argInfo = POPT_ARG_NONE,
301 .arg = NULL,
302 .val = 'T',
303 .descrip = "Translate IP addresses into names",
306 .longName = "root-port",
307 .shortName = 'r',
308 .argInfo = POPT_ARG_NONE,
309 .arg = NULL,
310 .val = 'r',
311 .descrip = "Use root port 137 (Win95 only replies to this)",
314 .longName = "lookup-by-ip",
315 .shortName = 'A',
316 .argInfo = POPT_ARG_NONE,
317 .arg = NULL,
318 .val = 'A',
319 .descrip = "Do a node status on <name> as an IP Address",
321 POPT_COMMON_SAMBA
322 POPT_COMMON_CONNECTION
323 POPT_COMMON_VERSION
324 POPT_TABLEEND
327 *lookup = 0;
329 smb_init_locale();
331 ok = samba_cmdline_init(frame,
332 SAMBA_CMDLINE_CONFIG_CLIENT,
333 false /* require_smbconf */);
334 if (!ok) {
335 DBG_ERR("Failed to init cmdline parser!\n");
336 TALLOC_FREE(frame);
337 exit(1);
340 pc = samba_popt_get_context(getprogname(),
341 argc,
342 argv,
343 long_options,
344 POPT_CONTEXT_KEEP_FIRST);
345 if (pc == NULL) {
346 DBG_ERR("Failed to setup popt context!\n");
347 TALLOC_FREE(frame);
348 exit(1);
351 poptSetOtherOptionHelp(pc, "<NODE> ...");
353 while ((opt = poptGetNextOpt(pc)) != -1) {
354 switch (opt) {
355 case 'f':
356 give_flags = true;
357 break;
358 case 'M':
359 find_master = true;
360 break;
361 case CMDLINE_RECURSIVE:
362 recursion_desired = true;
363 break;
364 case 'S':
365 find_status = true;
366 break;
367 case 'r':
368 RootPort = true;
369 break;
370 case 'A':
371 lookup_by_ip = true;
372 break;
373 case 'B':
374 if (interpret_string_addr(&bcast_addr,
375 poptGetOptArg(pc),
376 NI_NUMERICHOST)) {
377 got_bcast = True;
378 use_bcast = True;
380 break;
381 case 'U':
382 if (interpret_string_addr(&bcast_addr,
383 poptGetOptArg(pc),
384 0)) {
385 got_bcast = True;
386 use_bcast = False;
388 break;
389 case 'T':
390 translate_addresses = !translate_addresses;
391 break;
392 case POPT_ERROR_BADOPT:
393 fprintf(stderr, "\nInvalid option %s: %s\n\n",
394 poptBadOption(pc, 0), poptStrerror(opt));
395 poptPrintUsage(pc, stderr, 0);
396 exit(1);
400 poptGetArg(pc); /* Remove argv[0] */
402 if(!poptPeekArg(pc)) {
403 poptPrintUsage(pc, stderr, 0);
404 rc = 1;
405 goto out;
408 if (!open_sockets()) {
409 rc = 1;
410 goto out;
413 while(poptPeekArg(pc)) {
414 char *p;
415 struct in_addr ip;
416 size_t nbt_len;
418 fstrcpy(lookup,poptGetArg(pc));
420 if(lookup_by_ip) {
421 struct sockaddr_storage ss;
422 ip = interpret_addr2(lookup);
423 in_addr_to_sockaddr_storage(&ss, ip);
424 fstrcpy(lookup,"*");
425 if (!do_node_status(lookup, lookup_type, &ss)) {
426 rc = 1;
428 continue;
431 if (find_master) {
432 if (*lookup == '-') {
433 fstrcpy(lookup,"\01\02__MSBROWSE__\02");
434 lookup_type = 1;
435 } else {
436 lookup_type = 0x1d;
440 p = strchr_m(lookup,'#');
441 if (p) {
442 *p = '\0';
443 sscanf(++p,"%x",&lookup_type);
446 nbt_len = strlen(lookup);
447 if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
448 d_printf("The specified netbios name [%s] is too long!\n",
449 lookup);
450 continue;
454 if (!query_one(lookup, lookup_type)) {
455 rc = 1;
456 d_printf( "name_query failed to find name %s", lookup );
457 if( 0 != lookup_type ) {
458 d_printf( "#%02x", lookup_type );
460 d_printf( "\n" );
464 out:
465 poptFreeContext(pc);
466 TALLOC_FREE(frame);
467 return rc;