1 /*
2  * Samba Unix/Linux SMB client library
3  * Distributed SMB/CIFS Server Management Utility
4  * Nltest netlogon testing tool
5  *
6  * Copyright (C) Guenther Deschner 2009
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <sys/types.h>
23 #include <inttypes.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <netapi.h>
29 
30 #include "common.h"
31 
32 enum {
33 	OPT_SERVER = 1,
34 	OPT_DBFLAG,
35 	OPT_SC_QUERY,
36 	OPT_SC_RESET,
37 	OPT_SC_VERIFY,
38 	OPT_SC_CHANGE_PWD,
39 	OPT_DSGETDC,
40 	OPT_PDC,
41 	OPT_DS,
42 	OPT_DSP,
43 	OPT_GC,
44 	OPT_KDC,
45 	OPT_TIMESERV,
46 	OPT_GTIMESERV,
47 	OPT_WS,
48 	OPT_NETBIOS,
49 	OPT_DNS,
50 	OPT_IP,
51 	OPT_FORCE,
52 	OPT_WRITABLE,
53 	OPT_AVOIDSELF,
54 	OPT_LDAPONLY,
55 	OPT_BACKG,
56 	OPT_DS_6,
57 	OPT_TRY_NEXT_CLOSEST_SITE,
58 	OPT_SITE,
59 	OPT_ACCOUNT,
60 	OPT_RET_DNS,
61 	OPT_RET_NETBIOS,
62 	OPT_DSREGDNS
63 };
64 
65 /****************************************************************
66 ****************************************************************/
67 
print_netlogon_info_result(uint32_t level,uint8_t * buffer)68 static void print_netlogon_info_result(uint32_t level,
69 				       uint8_t *buffer)
70 {
71 	struct NETLOGON_INFO_1 *i1 = NULL;
72 	struct NETLOGON_INFO_2 *i2 = NULL;
73 	struct NETLOGON_INFO_3 *i3 = NULL;
74 	struct NETLOGON_INFO_4 *i4 = NULL;
75 
76 	if (!buffer) {
77 		return;
78 	}
79 
80 	switch (level) {
81 	case 1:
82 		i1 = (struct NETLOGON_INFO_1 *)buffer;
83 
84 		printf("Flags: %x\n", i1->netlog1_flags);
85 		printf("Connection Status Status = %d 0x%x %s\n",
86 			i1->netlog1_pdc_connection_status,
87 			i1->netlog1_pdc_connection_status,
88 			libnetapi_errstr(i1->netlog1_pdc_connection_status));
89 
90 		break;
91 	case 2:
92 		i2 = (struct NETLOGON_INFO_2 *)buffer;
93 
94 		printf("Flags: %x\n", i2->netlog2_flags);
95 		printf("Trusted DC Name %s\n", i2->netlog2_trusted_dc_name);
96 		printf("Trusted DC Connection Status Status = %d 0x%x %s\n",
97 			i2->netlog2_tc_connection_status,
98 			i2->netlog2_tc_connection_status,
99 			libnetapi_errstr(i2->netlog2_tc_connection_status));
100 		printf("Trust Verification Status Status = %d 0x%x %s\n",
101 			i2->netlog2_pdc_connection_status,
102 			i2->netlog2_pdc_connection_status,
103 			libnetapi_errstr(i2->netlog2_pdc_connection_status));
104 
105 		break;
106 	case 3:
107 		i3 = (struct NETLOGON_INFO_3 *)buffer;
108 
109 		printf("Flags: %x\n", i3->netlog1_flags);
110 		printf("Logon Attempts: %d\n", i3->netlog3_logon_attempts);
111 
112 		break;
113 	case 4:
114 		i4 = (struct NETLOGON_INFO_4 *)buffer;
115 
116 		printf("Trusted DC Name %s\n", i4->netlog4_trusted_dc_name);
117 		printf("Trusted Domain Name %s\n", i4->netlog4_trusted_domain_name);
118 
119 		break;
120 	default:
121 		break;
122 	}
123 }
124 
125 /****************************************************************
126 ****************************************************************/
127 
print_dc_info_flags(uint32_t flags)128 static void print_dc_info_flags(uint32_t flags)
129 {
130 	if (flags & DS_PDC_FLAG)
131 		printf("PDC ");
132 	if (flags & DS_GC_FLAG)
133 		printf("GC ");
134 	if (flags & DS_DS_FLAG)
135 		printf("DS ");
136 	if (flags & DS_LDAP_FLAG)
137 		printf("LDAP ");
138 	if (flags & DS_KDC_FLAG)
139 		printf("KDC ");
140 	if (flags & DS_TIMESERV_FLAG)
141 		printf("TIMESERV ");
142 	if (flags & DS_GOOD_TIMESERV_FLAG)
143 		printf("GTIMESERV ");
144 	if (flags & DS_WRITABLE_FLAG)
145 		printf("WRITABLE ");
146 	if (flags & DS_DNS_FOREST_FLAG)
147 		printf("DNS_FOREST ");
148 	if (flags & DS_CLOSEST_FLAG)
149 		printf("CLOSE_SITE ");
150 	if (flags & DS_FULL_SECRET_DOMAIN_6_FLAG)
151 		printf("FULL_SECRET ");
152 	if (flags & DS_WS_FLAG)
153 		printf("WS ");
154 	if (flags & DS_DS_8_FLAG)
155 		printf("DS_8 ");
156 	printf("\n");
157 }
158 
159 /****************************************************************
160 ****************************************************************/
161 
print_dc_info(struct DOMAIN_CONTROLLER_INFO * dc_info)162 static void print_dc_info(struct DOMAIN_CONTROLLER_INFO *dc_info)
163 {
164 	if (dc_info->flags) {
165 		printf("           DC: %s\n", dc_info->domain_controller_name);
166 		printf("      Address: %s\n", dc_info->domain_controller_address);
167 /*		printf("     Dom Guid: %s\n", X(domain_guid)); */
168 		printf("     Dom Name: %s\n", dc_info->domain_name);
169 		printf("  Forest Name: %s\n", dc_info->dns_forest_name);
170 		printf(" Dc Site Name: %s\n", dc_info->dc_site_name);
171 		printf("Our Site Name: %s\n", dc_info->client_site_name);
172 		printf("        Flags: ");
173 		print_dc_info_flags(dc_info->flags);
174 	} else {
175 		printf("           DC: %s\n", dc_info->domain_controller_name);
176 		printf("      Address: %s\n", dc_info->domain_controller_address);
177 		printf("     Dom Name: %s\n", dc_info->domain_name);
178 	}
179 }
180 
181 /****************************************************************
182 ****************************************************************/
183 
main(int argc,const char ** argv)184 int main(int argc, const char **argv)
185 {
186 	int opt;
187 	NET_API_STATUS status;
188 	struct libnetapi_ctx *ctx = NULL;
189 	char *opt_server = NULL;
190 	char *opt_domain = NULL;
191 	int opt_dbflag = 0;
192 	int opt_pdc = 0;
193 	int opt_ds = 0;
194 	int opt_dsp = 0;
195 	int opt_gc = 0;
196 	int opt_kdc = 0;
197 	int opt_timeserv = 0;
198 	int opt_gtimeserv = 0;
199 	int opt_ws = 0;
200 	int opt_netbios = 0;
201 	int opt_dns = 0;
202 	int opt_ip = 0;
203 	int opt_force = 0;
204 	int opt_writable = 0;
205 	int opt_avoidself = 0;
206 	int opt_ldaponly = 0;
207 	int opt_backg = 0;
208 	int opt_ds_6 = 0;
209 	int opt_try_next_closest_site = 0;
210 	char *opt_site = NULL;
211 	char *opt_account = NULL;
212 	int opt_ret_dns = 0;
213 	int opt_ret_netbios = 0;
214 	int opt_dsregdns = 0;
215 	uint32_t query_level = 0;
216 	uint8_t *buffer = NULL;
217 	uint32_t flags = 0;
218 	struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
219 
220 	poptContext pc;
221 	struct poptOption long_options[] = {
222 		POPT_AUTOHELP
223 		{
224 			.longName   = "server",
225 			.shortName  = 0,
226 			.argInfo    = POPT_ARG_STRING,
227 			.arg        = &opt_server,
228 			.val        = OPT_SERVER,
229 			.descrip    = "Servername",
230 			.argDescrip = "SERVER",
231 		},
232 		{
233 			.longName   = "dbflag",
234 			.shortName  = 0,
235 			.argInfo    = POPT_ARG_INT,
236 			.arg        = &opt_dbflag,
237 			.val        = OPT_DBFLAG,
238 			.descrip    = "New Debug Flag",
239 			.argDescrip = "HEXFLAGS",
240 		},
241 		{
242 			.longName   = "sc_query",
243 			.shortName  = 0,
244 			.argInfo    = POPT_ARG_STRING,
245 			.arg        = &opt_domain,
246 			.val        = OPT_SC_QUERY,
247 			.descrip    = "Query secure channel for domain on server",
248 			.argDescrip = "DOMAIN",
249 		},
250 		{
251 			.longName   = "sc_reset",
252 			.shortName  = 0,
253 			.argInfo    = POPT_ARG_STRING,
254 			.arg        = &opt_domain,
255 			.val        = OPT_SC_RESET,
256 			.descrip    = "Reset secure channel for domain on server to dcname",
257 			.argDescrip = "DOMAIN",
258 		},
259 		{
260 			.longName   = "sc_verify",
261 			.shortName  = 0,
262 			.argInfo    = POPT_ARG_STRING,
263 			.arg        = &opt_domain,
264 			.val        = OPT_SC_VERIFY,
265 			.descrip    = "Verify secure channel for domain on server",
266 			.argDescrip = "DOMAIN",
267 		},
268 		{
269 			.longName   = "sc_change_pwd",
270 			.shortName  = 0,
271 			.argInfo    = POPT_ARG_STRING,
272 			.arg        = &opt_domain,
273 			.val        = OPT_SC_CHANGE_PWD,
274 			.descrip    = "Change a secure channel password for domain on server",
275 			.argDescrip = "DOMAIN",
276 		},
277 		{
278 			.longName   = "dsgetdc",
279 			.shortName  = 0,
280 			.argInfo    = POPT_ARG_STRING,
281 			.arg        = &opt_domain,
282 			.val        = OPT_DSGETDC,
283 			.descrip    = "Call DsGetDcName",
284 			.argDescrip = "DOMAIN",
285 		},
286 		{
287 			.longName   = "pdc",
288 			.shortName  = 0,
289 			.argInfo    = POPT_ARG_NONE,
290 			.arg        = &opt_pdc,
291 			.val        = OPT_PDC,
292 			.descrip    = NULL,
293 		},
294 		{
295 			.longName   = "ds",
296 			.shortName  = 0,
297 			.argInfo    = POPT_ARG_NONE,
298 			.arg        = &opt_ds,
299 			.val        = OPT_DS,
300 			.descrip    = NULL,
301 		},
302 		{
303 			.longName   = "dsp",
304 			.shortName  = 0,
305 			.argInfo    = POPT_ARG_NONE,
306 			.arg        = &opt_dsp,
307 			.val        = OPT_DSP,
308 			.descrip    = NULL,
309 		},
310 		{
311 			.longName   = "gc",
312 			.shortName  = 0,
313 			.argInfo    = POPT_ARG_NONE,
314 			.arg        = &opt_gc,
315 			.val        = OPT_GC,
316 			.descrip    = NULL,
317 		},
318 		{
319 			.longName   = "kdc",
320 			.shortName  = 0,
321 			.argInfo    = POPT_ARG_NONE,
322 			.arg        = &opt_kdc,
323 			.val        = OPT_KDC,
324 			.descrip    = NULL,
325 		},
326 		{
327 			.longName   = "timeserv",
328 			.shortName  = 0,
329 			.argInfo    = POPT_ARG_NONE,
330 			.arg        = &opt_timeserv,
331 			.val        = OPT_TIMESERV,
332 			.descrip    = NULL,
333 		},
334 		{
335 			.longName   = "gtimeserv",
336 			.shortName  = 0,
337 			.argInfo    = POPT_ARG_NONE,
338 			.arg        = &opt_gtimeserv,
339 			.val        = OPT_GTIMESERV,
340 			.descrip    = NULL,
341 		},
342 		{
343 			.longName   = "ws",
344 			.shortName  = 0,
345 			.argInfo    = POPT_ARG_NONE,
346 			.arg        = &opt_ws,
347 			.val        = OPT_WS,
348 			.descrip    = NULL,
349 		},
350 		{
351 			.longName   = "netbios",
352 			.shortName  = 0,
353 			.argInfo    = POPT_ARG_NONE,
354 			.arg        = &opt_netbios,
355 			.val        = OPT_NETBIOS,
356 			.descrip    = NULL,
357 		},
358 		{
359 			.longName   = "dns",
360 			.shortName  = 0,
361 			.argInfo    = POPT_ARG_NONE,
362 			.arg        = &opt_dns,
363 			.val        = OPT_DNS,
364 			.descrip    = NULL,
365 		},
366 		{
367 			.longName   = "ip",
368 			.shortName  = 0,
369 			.argInfo    = POPT_ARG_NONE,
370 			.arg        = &opt_ip,
371 			.val        = OPT_IP,
372 			.descrip    = NULL,
373 		},
374 		{
375 			.longName   = "force",
376 			.shortName  = 0,
377 			.argInfo    = POPT_ARG_NONE,
378 			.arg        = &opt_force,
379 			.val        = OPT_FORCE,
380 			.descrip    = NULL,
381 		},
382 		{
383 			.longName   = "writable",
384 			.shortName  = 0,
385 			.argInfo    = POPT_ARG_NONE,
386 			.arg        = &opt_writable,
387 			.val        = OPT_WRITABLE,
388 			.descrip    = NULL,
389 		},
390 		{
391 			.longName   = "avoidself",
392 			.shortName  = 0,
393 			.argInfo    = POPT_ARG_NONE,
394 			.arg        = &opt_avoidself,
395 			.val        = OPT_AVOIDSELF,
396 			.descrip    = NULL,
397 		},
398 		{
399 			.longName   = "ldaponly",
400 			.shortName  = 0,
401 			.argInfo    = POPT_ARG_NONE,
402 			.arg        = &opt_ldaponly,
403 			.val        = OPT_LDAPONLY,
404 			.descrip    = NULL,
405 		},
406 		{
407 			.longName   = "backg",
408 			.shortName  = 0,
409 			.argInfo    = POPT_ARG_NONE,
410 			.arg        = &opt_backg,
411 			.val        = OPT_BACKG,
412 			.descrip    = NULL,
413 		},
414 		{
415 			.longName   = "ds_6",
416 			.shortName  = 0,
417 			.argInfo    = POPT_ARG_NONE,
418 			.arg        = &opt_ds_6,
419 			.val        = OPT_DS_6,
420 			.descrip    = NULL,
421 		},
422 		{
423 			.longName   = "try_next_closest_site",
424 			.shortName  = 0,
425 			.argInfo    = POPT_ARG_NONE,
426 			.arg        = &opt_try_next_closest_site,
427 			.val        = OPT_TRY_NEXT_CLOSEST_SITE,
428 			.descrip    = NULL,
429 		},
430 		{
431 			.longName   = "site",
432 			.shortName  = 0,
433 			.argInfo    = POPT_ARG_STRING,
434 			.arg        = &opt_site,
435 			.val        = OPT_SITE,
436 			.descrip    = "SITE",
437 		},
438 		{
439 			.longName   = "account",
440 			.shortName  = 0,
441 			.argInfo    = POPT_ARG_STRING,
442 			.arg        = &opt_account,
443 			.val        = OPT_ACCOUNT,
444 			.descrip    = "ACCOUNT",
445 		},
446 		{
447 			.longName   = "ret_dns",
448 			.shortName  = 0,
449 			.argInfo    = POPT_ARG_NONE,
450 			.arg        = &opt_ret_dns,
451 			.val        = OPT_RET_DNS,
452 			.descrip    = NULL,
453 		},
454 		{
455 			.longName   = "ret_netbios",
456 			.shortName  = 0,
457 			.argInfo    = POPT_ARG_NONE,
458 			.arg        = &opt_ret_netbios,
459 			.val        = OPT_RET_NETBIOS,
460 			.descrip    = NULL,
461 		},
462 		{
463 			.longName   = "dsregdns",
464 			.shortName  = 0,
465 			.argInfo    = POPT_ARG_NONE,
466 			.arg        = &opt_dsregdns,
467 			.val        = OPT_DSREGDNS,
468 			.descrip    = "Force registration of all DC-specific DNS records",
469 		},
470 		POPT_COMMON_LIBNETAPI_EXAMPLES
471 		POPT_TABLEEND
472 	};
473 
474 	status = libnetapi_init(&ctx);
475 	if (status != 0) {
476 		return status;
477 	}
478 
479 	pc = poptGetContext("nltest", argc, argv, long_options, 0);
480 
481 	poptSetOtherOptionHelp(pc, "<options>");
482 	while((opt = poptGetNextOpt(pc)) != -1) {
483 	}
484 
485 	if (argc == 1) {
486 		poptPrintHelp(pc, stderr, 0);
487 		goto done;
488 	}
489 
490 	poptResetContext(pc);
491 
492 	while ((opt = poptGetNextOpt(pc)) != -1) {
493 		switch (opt) {
494 
495 		case OPT_SERVER:
496 
497 			if ((opt_server[0] == '/' && opt_server[1] == '/') ||
498 			    (opt_server[0] == '\\' && opt_server[1] ==  '\\')) {
499 				opt_server += 2;
500 			}
501 
502 			break;
503 
504 		case OPT_DBFLAG:
505 			query_level = 1;
506 			status = I_NetLogonControl2(opt_server,
507 						    NETLOGON_CONTROL_SET_DBFLAG,
508 						    query_level,
509 						    (uint8_t *)&opt_dbflag,
510 						    &buffer);
511 			if (status != 0) {
512 				fprintf(stderr, "I_NetlogonControl failed: Status = %d 0x%x %s\n",
513 					status, status,
514 					libnetapi_get_error_string(ctx, status));
515 				goto done;
516 			}
517 
518 			print_netlogon_info_result(query_level, buffer);
519 
520 			break;
521 		case OPT_SC_QUERY:
522 			query_level = 2;
523 			status = I_NetLogonControl2(opt_server,
524 						    NETLOGON_CONTROL_TC_QUERY,
525 						    query_level,
526 						    (uint8_t *)opt_domain,
527 						    &buffer);
528 			if (status != 0) {
529 				fprintf(stderr, "I_NetlogonControl failed: Status = %d 0x%x %s\n",
530 					status, status,
531 					libnetapi_get_error_string(ctx, status));
532 				goto done;
533 			}
534 
535 			print_netlogon_info_result(query_level, buffer);
536 
537 			break;
538 		case OPT_SC_VERIFY:
539 			query_level = 2;
540 			status = I_NetLogonControl2(opt_server,
541 						    NETLOGON_CONTROL_TC_VERIFY,
542 						    query_level,
543 						    (uint8_t *)opt_domain,
544 						    &buffer);
545 			if (status != 0) {
546 				fprintf(stderr, "I_NetlogonControl failed: Status = %d 0x%x %s\n",
547 					status, status,
548 					libnetapi_get_error_string(ctx, status));
549 				goto done;
550 			}
551 
552 			print_netlogon_info_result(query_level, buffer);
553 
554 			break;
555 		case OPT_SC_RESET:
556 			query_level = 2;
557 			status = I_NetLogonControl2(opt_server,
558 						    NETLOGON_CONTROL_REDISCOVER,
559 						    query_level,
560 						    (uint8_t *)opt_domain,
561 						    &buffer);
562 			if (status != 0) {
563 				fprintf(stderr, "I_NetlogonControl failed: Status = %d 0x%x %s\n",
564 					status, status,
565 					libnetapi_get_error_string(ctx, status));
566 				goto done;
567 			}
568 
569 			print_netlogon_info_result(query_level, buffer);
570 
571 			break;
572 		case OPT_SC_CHANGE_PWD:
573 			query_level = 1;
574 			status = I_NetLogonControl2(opt_server,
575 						    NETLOGON_CONTROL_CHANGE_PASSWORD,
576 						    query_level,
577 						    (uint8_t *)opt_domain,
578 						    &buffer);
579 			if (status != 0) {
580 				fprintf(stderr, "I_NetlogonControl failed: Status = %d 0x%x %s\n",
581 					status, status,
582 					libnetapi_get_error_string(ctx, status));
583 				goto done;
584 			}
585 
586 			print_netlogon_info_result(query_level, buffer);
587 
588 			break;
589 		case OPT_DSREGDNS:
590 			query_level = 1;
591 			status = I_NetLogonControl2(opt_server,
592 						    NETLOGON_CONTROL_FORCE_DNS_REG,
593 						    query_level,
594 						    NULL,
595 						    &buffer);
596 			if (status != 0) {
597 				fprintf(stderr, "I_NetlogonControl failed: Status = %d 0x%x %s\n",
598 					status, status,
599 					libnetapi_get_error_string(ctx, status));
600 				goto done;
601 			}
602 
603 			print_netlogon_info_result(query_level, buffer);
604 
605 			break;
606 		case OPT_DSGETDC:
607 			if (opt_pdc)
608 				flags |= DS_PDC_REQUIRED;
609 			if (opt_ds)
610 				flags |= DS_DIRECTORY_SERVICE_REQUIRED;
611 			if (opt_dsp)
612 				flags |= DS_DIRECTORY_SERVICE_PREFERRED;
613 			if (opt_kdc)
614 				flags |= DS_KDC_REQUIRED;
615 			if (opt_timeserv)
616 				flags |= DS_TIMESERV_REQUIRED;
617 			if (opt_gtimeserv)
618 				flags |= DS_GOOD_TIMESERV_PREFERRED;
619 			if (opt_ws)
620 				flags |= DS_WEB_SERVICE_REQUIRED;
621 			if (opt_netbios)
622 				flags |= DS_IS_FLAT_NAME;
623 			if (opt_dns)
624 				flags |= DS_IS_DNS_NAME;
625 			if (opt_ip)
626 				flags |= DS_IP_REQUIRED;
627 			if (opt_force)
628 				flags |= DS_FORCE_REDISCOVERY;
629 			if (opt_writable)
630 				flags |= DS_WRITABLE_REQUIRED;
631 			if (opt_avoidself)
632 				flags |= DS_AVOID_SELF;
633 			if (opt_ldaponly)
634 				flags |= DS_ONLY_LDAP_NEEDED;
635 			if (opt_backg)
636 				flags |= DS_BACKGROUND_ONLY;
637 			if (opt_ds_6)
638 				flags |= DS_DIRECTORY_SERVICE_6_REQUIRED;
639 			if (opt_try_next_closest_site)
640 				flags |= DS_TRY_NEXTCLOSEST_SITE;
641 			if (opt_ret_dns)
642 				flags |= DS_RETURN_DNS_NAME;
643 			if (opt_ret_netbios)
644 				flags |= DS_RETURN_FLAT_NAME;
645 
646 			status = DsGetDcName(opt_server,
647 					     opt_domain,
648 					     NULL, /* domain_guid */
649 					     opt_site,
650 					     flags,
651 					     &dc_info);
652 			if (status != 0) {
653 				fprintf(stderr, "DsGetDcName failed: Status = %d 0x%x %s\n",
654 					status, status,
655 					libnetapi_get_error_string(ctx, status));
656 				goto done;
657 			}
658 
659 			print_dc_info(dc_info);
660 
661 			break;
662 		default:
663 			continue;
664 		}
665 	}
666 
667 	printf("The command completed successfully\n");
668 	status = 0;
669 
670  done:
671 
672 	printf("\n");
673 	libnetapi_free(ctx);
674 	poptFreeContext(pc);
675 
676 	return status;
677 }
678