1/* 2 Unix SMB/CIFS mplementation. 3 4 test CLDAP operations 5 6 Copyright (C) Andrew Tridgell 2005 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 23#include "includes.h" 24#include "libcli/cldap/cldap.h" 25#include "libcli/ldap/ldap.h" 26#include "librpc/gen_ndr/ndr_nbt.h" 27#include "librpc/gen_ndr/netlogon.h" 28#include "torture/torture.h" 29#include "lib/ldb/include/ldb.h" 30#include "param/param.h" 31#include "../lib/tsocket/tsocket.h" 32 33#define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status") 34 35#define CHECK_VAL(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value"); 36 37#define CHECK_STRING(v, correct) torture_assert_str_equal(tctx, v, correct, "incorrect value"); 38/* 39 test netlogon operations 40*/ 41static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest) 42{ 43 struct cldap_socket *cldap; 44 NTSTATUS status; 45 struct cldap_netlogon search, empty_search; 46 struct netlogon_samlogon_response n1; 47 struct GUID guid; 48 int i; 49 struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx); 50 struct tsocket_address *dest_addr; 51 int ret; 52 53 ret = tsocket_address_inet_from_strings(tctx, "ip", 54 dest, 55 lp_cldap_port(tctx->lp_ctx), 56 &dest_addr); 57 CHECK_VAL(ret, 0); 58 59 status = cldap_socket_init(tctx, NULL, NULL, dest_addr, &cldap); 60 CHECK_STATUS(status, NT_STATUS_OK); 61 62 ZERO_STRUCT(search); 63 search.in.dest_address = NULL; 64 search.in.dest_port = 0; 65 search.in.acct_control = -1; 66 search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 67 search.in.map_response = true; 68 69 empty_search = search; 70 71 printf("Trying without any attributes\n"); 72 search = empty_search; 73 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 74 CHECK_STATUS(status, NT_STATUS_OK); 75 76 n1 = search.out.netlogon; 77 78 search.in.user = "Administrator"; 79 search.in.realm = n1.data.nt5_ex.dns_domain; 80 search.in.host = "__cldap_torture__"; 81 82 printf("Scanning for netlogon levels\n"); 83 for (i=0;i<256;i++) { 84 search.in.version = i; 85 printf("Trying netlogon level %d\n", i); 86 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 87 CHECK_STATUS(status, NT_STATUS_OK); 88 } 89 90 printf("Scanning for netlogon level bits\n"); 91 for (i=0;i<31;i++) { 92 search.in.version = (1<<i); 93 printf("Trying netlogon level 0x%x\n", i); 94 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 95 CHECK_STATUS(status, NT_STATUS_OK); 96 } 97 98 search.in.version = NETLOGON_NT_VERSION_5|NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_IP; 99 100 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 101 CHECK_STATUS(status, NT_STATUS_OK); 102 103 printf("Trying with User=NULL\n"); 104 105 search.in.user = NULL; 106 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 107 CHECK_STATUS(status, NT_STATUS_OK); 108 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 109 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 110 111 printf("Trying with User=Administrator\n"); 112 113 search.in.user = "Administrator"; 114 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 115 CHECK_STATUS(status, NT_STATUS_OK); 116 117 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); 118 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); 119 120 search.in.version = NETLOGON_NT_VERSION_5; 121 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 122 CHECK_STATUS(status, NT_STATUS_OK); 123 124 printf("Trying with User=NULL\n"); 125 126 search.in.user = NULL; 127 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 128 CHECK_STATUS(status, NT_STATUS_OK); 129 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 130 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE); 131 132 printf("Trying with User=Administrator\n"); 133 134 search.in.user = "Administrator"; 135 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 136 CHECK_STATUS(status, NT_STATUS_OK); 137 138 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); 139 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN); 140 141 search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 142 143 printf("Trying with a GUID\n"); 144 search.in.realm = NULL; 145 search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid); 146 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 147 CHECK_STATUS(status, NT_STATUS_OK); 148 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); 149 CHECK_STRING(GUID_string(tctx, &search.out.netlogon.data.nt5_ex.domain_uuid), search.in.domain_guid); 150 151 printf("Trying with a incorrect GUID\n"); 152 guid = GUID_random(); 153 search.in.user = NULL; 154 search.in.domain_guid = GUID_string(tctx, &guid); 155 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 156 CHECK_STATUS(status, NT_STATUS_NOT_FOUND); 157 158 printf("Trying with a AAC\n"); 159 search.in.acct_control = ACB_WSTRUST|ACB_SVRTRUST; 160 search.in.realm = n1.data.nt5_ex.dns_domain; 161 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 162 CHECK_STATUS(status, NT_STATUS_OK); 163 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 164 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 165 166 printf("Trying with a zero AAC\n"); 167 search.in.acct_control = 0x0; 168 search.in.realm = n1.data.nt5_ex.dns_domain; 169 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 170 CHECK_STATUS(status, NT_STATUS_OK); 171 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 172 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 173 174 printf("Trying with a zero AAC and user=Administrator\n"); 175 search.in.acct_control = 0x0; 176 search.in.user = "Administrator"; 177 search.in.realm = n1.data.nt5_ex.dns_domain; 178 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 179 CHECK_STATUS(status, NT_STATUS_OK); 180 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); 181 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "Administrator"); 182 183 printf("Trying with a bad AAC\n"); 184 search.in.user = NULL; 185 search.in.acct_control = 0xFF00FF00; 186 search.in.realm = n1.data.nt5_ex.dns_domain; 187 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 188 CHECK_STATUS(status, NT_STATUS_OK); 189 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 190 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 191 192 printf("Trying with a user only\n"); 193 search = empty_search; 194 search.in.user = "Administrator"; 195 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 196 CHECK_STATUS(status, NT_STATUS_OK); 197 CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); 198 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); 199 200 printf("Trying with just a bad username\n"); 201 search.in.user = "___no_such_user___"; 202 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 203 CHECK_STATUS(status, NT_STATUS_OK); 204 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); 205 CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); 206 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); 207 208 printf("Trying with just a bad domain\n"); 209 search = empty_search; 210 search.in.realm = "___no_such_domain___"; 211 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 212 CHECK_STATUS(status, NT_STATUS_NOT_FOUND); 213 214 printf("Trying with a incorrect domain and correct guid\n"); 215 search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid); 216 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 217 CHECK_STATUS(status, NT_STATUS_OK); 218 CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); 219 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 220 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 221 222 printf("Trying with a incorrect domain and incorrect guid\n"); 223 search.in.domain_guid = GUID_string(tctx, &guid); 224 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 225 CHECK_STATUS(status, NT_STATUS_NOT_FOUND); 226 CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); 227 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 228 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 229 230 printf("Trying with a incorrect GUID and correct domain\n"); 231 search.in.domain_guid = GUID_string(tctx, &guid); 232 search.in.realm = n1.data.nt5_ex.dns_domain; 233 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 234 CHECK_STATUS(status, NT_STATUS_OK); 235 CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); 236 CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); 237 CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); 238 239 return true; 240} 241 242/* 243 test cldap netlogon server type flags 244*/ 245static bool test_cldap_netlogon_flags(struct torture_context *tctx, 246 const char *dest) 247{ 248 struct cldap_socket *cldap; 249 NTSTATUS status; 250 struct cldap_netlogon search; 251 struct netlogon_samlogon_response n1; 252 uint32_t server_type; 253 struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx); 254 255 /* cldap_socket_init should now know about the dest. address */ 256 status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap); 257 CHECK_STATUS(status, NT_STATUS_OK); 258 259 printf("Printing out netlogon server type flags: %s\n", dest); 260 261 ZERO_STRUCT(search); 262 search.in.dest_address = dest; 263 search.in.dest_port = lp_cldap_port(tctx->lp_ctx); 264 search.in.acct_control = -1; 265 search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 266 search.in.map_response = true; 267 268 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 269 CHECK_STATUS(status, NT_STATUS_OK); 270 271 n1 = search.out.netlogon; 272 if (n1.ntver == NETLOGON_NT_VERSION_5) 273 server_type = n1.data.nt5.server_type; 274 else if (n1.ntver == NETLOGON_NT_VERSION_5EX) 275 server_type = n1.data.nt5_ex.server_type; 276 277 printf("The word is: %i\n", server_type); 278 if (server_type & NBT_SERVER_PDC) 279 printf("NBT_SERVER_PDC "); 280 if (server_type & NBT_SERVER_GC) 281 printf("NBT_SERVER_GC "); 282 if (server_type & NBT_SERVER_LDAP) 283 printf("NBT_SERVER_LDAP "); 284 if (server_type & NBT_SERVER_DS) 285 printf("NBT_SERVER_DS "); 286 if (server_type & NBT_SERVER_KDC) 287 printf("NBT_SERVER_KDC "); 288 if (server_type & NBT_SERVER_TIMESERV) 289 printf("NBT_SERVER_TIMESERV "); 290 if (server_type & NBT_SERVER_CLOSEST) 291 printf("NBT_SERVER_CLOSEST "); 292 if (server_type & NBT_SERVER_WRITABLE) 293 printf("NBT_SERVER_WRITABLE "); 294 if (server_type & NBT_SERVER_GOOD_TIMESERV) 295 printf("NBT_SERVER_GOOD_TIMESERV "); 296 if (server_type & NBT_SERVER_NDNC) 297 printf("NBT_SERVER_NDNC "); 298 if (server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) 299 printf("NBT_SERVER_SELECT_SECRET_DOMAIN_6"); 300 if (server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) 301 printf("NBT_SERVER_FULL_SECRET_DOMAIN_6"); 302 if (server_type & DS_DNS_CONTROLLER) 303 printf("DS_DNS_CONTROLLER "); 304 if (server_type & DS_DNS_DOMAIN) 305 printf("DS_DNS_DOMAIN "); 306 if (server_type & DS_DNS_FOREST) 307 printf("DS_DNS_FOREST "); 308 309 printf("\n"); 310 311 return true; 312} 313 314/* 315 convert a ldap result message to a ldb message. This allows us to 316 use the convenient ldif dump routines in ldb to print out cldap 317 search results 318*/ 319static struct ldb_message *ldap_msg_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldap_SearchResEntry *res) 320{ 321 struct ldb_message *msg; 322 323 msg = ldb_msg_new(mem_ctx); 324 msg->dn = ldb_dn_new(msg, ldb, res->dn); 325 msg->num_elements = res->num_attributes; 326 msg->elements = talloc_steal(msg, res->attributes); 327 return msg; 328} 329 330/* 331 dump a set of cldap results 332*/ 333static void cldap_dump_results(struct cldap_search *search) 334{ 335 struct ldb_ldif ldif; 336 struct ldb_context *ldb; 337 338 if (!search || !(search->out.response)) { 339 return; 340 } 341 342 /* we need a ldb context to use ldb_ldif_write_file() */ 343 ldb = ldb_init(NULL, NULL); 344 345 ZERO_STRUCT(ldif); 346 ldif.msg = ldap_msg_to_ldb(ldb, ldb, search->out.response); 347 348 ldb_ldif_write_file(ldb, stdout, &ldif); 349 350 talloc_free(ldb); 351} 352 353 354/* 355 test cldap netlogon server type flag "NBT_SERVER_DS_DNS_FOREST" 356*/ 357static bool test_cldap_netlogon_flag_ds_dns_forest(struct torture_context *tctx, 358 const char *dest) 359{ 360 struct cldap_socket *cldap; 361 NTSTATUS status; 362 struct cldap_netlogon search; 363 uint32_t server_type; 364 struct netlogon_samlogon_response n1; 365 struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx); 366 bool result = true; 367 368 /* cldap_socket_init should now know about the dest. address */ 369 status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap); 370 CHECK_STATUS(status, NT_STATUS_OK); 371 372 printf("Testing netlogon server type flag NBT_SERVER_DS_DNS_FOREST: "); 373 374 ZERO_STRUCT(search); 375 search.in.dest_address = dest; 376 search.in.dest_port = lp_cldap_port(tctx->lp_ctx); 377 search.in.acct_control = -1; 378 search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 379 search.in.map_response = true; 380 381 status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); 382 CHECK_STATUS(status, NT_STATUS_OK); 383 384 n1 = search.out.netlogon; 385 if (n1.ntver == NETLOGON_NT_VERSION_5) 386 server_type = n1.data.nt5.server_type; 387 else if (n1.ntver == NETLOGON_NT_VERSION_5EX) 388 server_type = n1.data.nt5_ex.server_type; 389 390 if (server_type & DS_DNS_FOREST) { 391 struct cldap_search search2; 392 const char *attrs[] = { "defaultNamingContext", "rootDomainNamingContext", 393 NULL }; 394 struct ldb_context *ldb; 395 struct ldb_message *msg; 396 397 /* Trying to fetch the attributes "defaultNamingContext" and 398 "rootDomainNamingContext" */ 399 ZERO_STRUCT(search2); 400 search2.in.dest_address = dest; 401 search2.in.dest_port = lp_cldap_port(tctx->lp_ctx); 402 search2.in.timeout = 10; 403 search2.in.retries = 3; 404 search2.in.filter = "(objectclass=*)"; 405 search2.in.attributes = attrs; 406 407 status = cldap_search(cldap, tctx, &search2); 408 CHECK_STATUS(status, NT_STATUS_OK); 409 410 ldb = ldb_init(NULL, NULL); 411 412 msg = ldap_msg_to_ldb(ldb, ldb, search2.out.response); 413 414 /* Try to compare the two attributes */ 415 if (ldb_msg_element_compare(ldb_msg_find_element(msg, attrs[0]), 416 ldb_msg_find_element(msg, attrs[1]))) 417 result = false; 418 419 talloc_free(ldb); 420 } 421 422 if (result) 423 printf("passed\n"); 424 else 425 printf("failed\n"); 426 427 return result; 428} 429 430/* 431 test generic cldap operations 432*/ 433static bool test_cldap_generic(struct torture_context *tctx, const char *dest) 434{ 435 struct cldap_socket *cldap; 436 NTSTATUS status; 437 struct cldap_search search; 438 const char *attrs1[] = { "currentTime", "highestCommittedUSN", NULL }; 439 const char *attrs2[] = { "currentTime", "highestCommittedUSN", "netlogon", NULL }; 440 const char *attrs3[] = { "netlogon", NULL }; 441 442 /* cldap_socket_init should now know about the dest. address */ 443 status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap); 444 CHECK_STATUS(status, NT_STATUS_OK); 445 446 ZERO_STRUCT(search); 447 search.in.dest_address = dest; 448 search.in.dest_port = lp_cldap_port(tctx->lp_ctx); 449 search.in.timeout = 10; 450 search.in.retries = 3; 451 452 status = cldap_search(cldap, tctx, &search); 453 CHECK_STATUS(status, NT_STATUS_OK); 454 455 printf("fetching whole rootDSE\n"); 456 search.in.filter = "(objectclass=*)"; 457 search.in.attributes = NULL; 458 459 status = cldap_search(cldap, tctx, &search); 460 CHECK_STATUS(status, NT_STATUS_OK); 461 462 if (DEBUGLVL(3)) cldap_dump_results(&search); 463 464 printf("fetching currentTime and USN\n"); 465 search.in.filter = "(objectclass=*)"; 466 search.in.attributes = attrs1; 467 468 status = cldap_search(cldap, tctx, &search); 469 CHECK_STATUS(status, NT_STATUS_OK); 470 471 if (DEBUGLVL(3)) cldap_dump_results(&search); 472 473 printf("Testing currentTime, USN and netlogon\n"); 474 search.in.filter = "(objectclass=*)"; 475 search.in.attributes = attrs2; 476 477 status = cldap_search(cldap, tctx, &search); 478 CHECK_STATUS(status, NT_STATUS_OK); 479 480 if (DEBUGLVL(3)) cldap_dump_results(&search); 481 482 printf("Testing objectClass=* and netlogon\n"); 483 search.in.filter = "(objectclass2=*)"; 484 search.in.attributes = attrs3; 485 486 status = cldap_search(cldap, tctx, &search); 487 CHECK_STATUS(status, NT_STATUS_OK); 488 489 if (DEBUGLVL(3)) cldap_dump_results(&search); 490 491 printf("Testing a false expression\n"); 492 search.in.filter = "(&(objectclass=*)(highestCommittedUSN=2))"; 493 search.in.attributes = attrs1; 494 495 status = cldap_search(cldap, tctx, &search); 496 CHECK_STATUS(status, NT_STATUS_OK); 497 498 if (DEBUGLVL(3)) cldap_dump_results(&search); 499 500 return true; 501} 502 503bool torture_cldap(struct torture_context *torture) 504{ 505 bool ret = true; 506 const char *host = torture_setting_string(torture, "host", NULL); 507 508 ret &= test_cldap_netlogon(torture, host); 509 ret &= test_cldap_netlogon_flags(torture, host); 510 ret &= test_cldap_netlogon_flag_ds_dns_forest(torture, host); 511 ret &= test_cldap_generic(torture, host); 512 513 return ret; 514} 515 516