1/* 2 Unix SMB/CIFS implementation. 3 Test suite for libnet calls. 4 5 Copyright (C) Rafal Szczesniak 2005 6 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. 11 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. 16 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/>. 19*/ 20 21#include "includes.h" 22#include "torture/rpc/rpc.h" 23#include "torture/libnet/usertest.h" 24#include "libnet/libnet.h" 25#include "librpc/gen_ndr/ndr_samr_c.h" 26#include "param/param.h" 27 28#include "torture/libnet/utils.h" 29 30 31static bool test_useradd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 32 struct policy_handle *domain_handle, 33 const char *name) 34{ 35 NTSTATUS status; 36 bool ret = true; 37 struct libnet_rpc_useradd user; 38 39 user.in.domain_handle = *domain_handle; 40 user.in.username = name; 41 42 printf("Testing libnet_rpc_useradd\n"); 43 44 status = libnet_rpc_useradd(p, mem_ctx, &user); 45 if (!NT_STATUS_IS_OK(status)) { 46 printf("Failed to call libnet_rpc_useradd - %s\n", nt_errstr(status)); 47 return false; 48 } 49 50 return ret; 51} 52 53 54static bool test_useradd_async(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 55 struct policy_handle *handle, const char* username) 56{ 57 NTSTATUS status; 58 struct composite_context *c; 59 struct libnet_rpc_useradd user; 60 61 user.in.domain_handle = *handle; 62 user.in.username = username; 63 64 printf("Testing async libnet_rpc_useradd\n"); 65 66 c = libnet_rpc_useradd_send(p, &user, msg_handler); 67 if (!c) { 68 printf("Failed to call async libnet_rpc_useradd\n"); 69 return false; 70 } 71 72 status = libnet_rpc_useradd_recv(c, mem_ctx, &user); 73 if (!NT_STATUS_IS_OK(status)) { 74 printf("Calling async libnet_rpc_useradd failed - %s\n", nt_errstr(status)); 75 return false; 76 } 77 78 return true; 79 80} 81 82static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p, 83 TALLOC_CTX *mem_ctx, 84 struct policy_handle *handle, int num_changes, 85 struct libnet_rpc_usermod *mod, char **username) 86{ 87 const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" }; 88 const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" }; 89 const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" }; 90 const char *homedir, *homedrive, *logonscript; 91 const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED), 92 (ACB_NORMAL | ACB_PWNOEXP), 93 (ACB_NORMAL | ACB_PW_EXPIRED) }; 94 95 NTSTATUS status; 96 struct timeval now; 97 enum test_fields testfld; 98 int i; 99 100 ZERO_STRUCT(*mod); 101 srandom((unsigned)time(NULL)); 102 103 mod->in.username = talloc_strdup(mem_ctx, *username); 104 mod->in.domain_handle = *handle; 105 106 torture_comment(tctx, "modifying user (%d simultaneous change(s))\n", 107 num_changes); 108 109 torture_comment(tctx, "fields to change: ["); 110 111 for (i = 0; i < num_changes && i < FIELDS_NUM - 1; i++) { 112 const char *fldname; 113 114 testfld = (random() % (FIELDS_NUM - 1)) + 1; 115 116 gettimeofday(&now, NULL); 117 118 switch (testfld) { 119 case account_name: 120 continue_if_field_set(mod->in.change.account_name); 121 mod->in.change.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME, 122 (int)(random() % 100)); 123 mod->in.change.fields |= USERMOD_FIELD_ACCOUNT_NAME; 124 fldname = "account_name"; 125 *username = talloc_strdup(mem_ctx, mod->in.change.account_name); 126 break; 127 128 case full_name: 129 continue_if_field_set(mod->in.change.full_name); 130 mod->in.change.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME, 131 (int)random(), (int)random()); 132 mod->in.change.fields |= USERMOD_FIELD_FULL_NAME; 133 fldname = "full_name"; 134 break; 135 136 case description: 137 continue_if_field_set(mod->in.change.description); 138 mod->in.change.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION, 139 random()); 140 mod->in.change.fields |= USERMOD_FIELD_DESCRIPTION; 141 fldname = "description"; 142 break; 143 144 case home_directory: 145 continue_if_field_set(mod->in.change.home_directory); 146 homedir = home_dirs[random() % (sizeof(home_dirs)/sizeof(char*))]; 147 mod->in.change.home_directory = talloc_strdup(mem_ctx, homedir); 148 mod->in.change.fields |= USERMOD_FIELD_HOME_DIRECTORY; 149 fldname = "home_directory"; 150 break; 151 152 case home_drive: 153 continue_if_field_set(mod->in.change.home_drive); 154 homedrive = home_drives[random() % (sizeof(home_drives)/sizeof(char*))]; 155 mod->in.change.home_drive = talloc_strdup(mem_ctx, homedrive); 156 mod->in.change.fields |= USERMOD_FIELD_HOME_DRIVE; 157 fldname = "home_drive"; 158 break; 159 160 case comment: 161 continue_if_field_set(mod->in.change.comment); 162 mod->in.change.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT, 163 random(), random()); 164 mod->in.change.fields |= USERMOD_FIELD_COMMENT; 165 fldname = "comment"; 166 break; 167 168 case logon_script: 169 continue_if_field_set(mod->in.change.logon_script); 170 logonscript = logon_scripts[random() % (sizeof(logon_scripts)/sizeof(char*))]; 171 mod->in.change.logon_script = talloc_strdup(mem_ctx, logonscript); 172 mod->in.change.fields |= USERMOD_FIELD_LOGON_SCRIPT; 173 fldname = "logon_script"; 174 break; 175 176 case profile_path: 177 continue_if_field_set(mod->in.change.profile_path); 178 mod->in.change.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH, 179 (long int)random(), (unsigned int)random()); 180 mod->in.change.fields |= USERMOD_FIELD_PROFILE_PATH; 181 fldname = "profile_path"; 182 break; 183 184 case acct_expiry: 185 continue_if_field_set(mod->in.change.acct_expiry); 186 now = timeval_add(&now, (random() % (31*24*60*60)), 0); 187 mod->in.change.acct_expiry = (struct timeval *)talloc_memdup(mem_ctx, &now, sizeof(now)); 188 mod->in.change.fields |= USERMOD_FIELD_ACCT_EXPIRY; 189 fldname = "acct_expiry"; 190 break; 191 192 case acct_flags: 193 continue_if_field_set(mod->in.change.acct_flags); 194 mod->in.change.acct_flags = flags[random() % ARRAY_SIZE(flags)]; 195 mod->in.change.fields |= USERMOD_FIELD_ACCT_FLAGS; 196 fldname = "acct_flags"; 197 break; 198 199 default: 200 fldname = talloc_asprintf(mem_ctx, "unknown_field (%d)", testfld); 201 break; 202 } 203 204 torture_comment(tctx, ((i < num_changes - 1) ? "%s," : "%s"), fldname); 205 } 206 torture_comment(tctx, "]\n"); 207 208 status = libnet_rpc_usermod(p, mem_ctx, mod); 209 torture_assert_ntstatus_ok(tctx, status, "Failed to call sync libnet_rpc_usermod"); 210 211 return true; 212} 213 214 215static bool test_userdel(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 216 struct policy_handle *handle, const char *username) 217{ 218 NTSTATUS status; 219 struct libnet_rpc_userdel user; 220 221 user.in.domain_handle = *handle; 222 user.in.username = username; 223 224 status = libnet_rpc_userdel(p, mem_ctx, &user); 225 if (!NT_STATUS_IS_OK(status)) { 226 printf("Failed to call sync libnet_rpc_userdel - %s\n", nt_errstr(status)); 227 return false; 228 } 229 230 return true; 231} 232 233 234#define CMP_LSA_STRING_FLD(fld, flags) \ 235 if ((mod->in.change.fields & flags) && \ 236 !strequal(i->fld.string, mod->in.change.fld)) { \ 237 printf("'%s' field does not match\n", #fld); \ 238 printf("received: '%s'\n", i->fld.string); \ 239 printf("expected: '%s'\n", mod->in.change.fld); \ 240 return false; \ 241 } 242 243 244#define CMP_TIME_FLD(fld, flags) \ 245 if (mod->in.change.fields & flags) { \ 246 nttime_to_timeval(&t, i->fld); \ 247 if (timeval_compare(&t, mod->in.change.fld)) { \ 248 printf("'%s' field does not match\n", #fld); \ 249 printf("received: '%s (+%ld us)'\n", \ 250 timestring(mem_ctx, t.tv_sec), t.tv_usec); \ 251 printf("expected: '%s (+%ld us)'\n", \ 252 timestring(mem_ctx, mod->in.change.fld->tv_sec), \ 253 mod->in.change.fld->tv_usec); \ 254 return false; \ 255 } \ 256 } 257 258#define CMP_NUM_FLD(fld, flags) \ 259 if ((mod->in.change.fields & flags) && \ 260 (i->fld != mod->in.change.fld)) { \ 261 printf("'%s' field does not match\n", #fld); \ 262 printf("received: '%04x'\n", i->fld); \ 263 printf("expected: '%04x'\n", mod->in.change.fld); \ 264 return false; \ 265 } 266 267 268static bool test_compare(struct torture_context *tctx, 269 struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 270 struct policy_handle *handle, struct libnet_rpc_usermod *mod, 271 const char *username) 272{ 273 NTSTATUS status; 274 struct libnet_rpc_userinfo info; 275 struct samr_UserInfo21 *i; 276 struct timeval t; 277 278 ZERO_STRUCT(info); 279 280 info.in.username = username; 281 info.in.domain_handle = *handle; 282 info.in.level = 21; /* the most rich infolevel available */ 283 284 status = libnet_rpc_userinfo(p, mem_ctx, &info); 285 torture_assert_ntstatus_ok(tctx, status, "Failed to call sync libnet_rpc_userinfo"); 286 287 i = &info.out.info.info21; 288 289 CMP_LSA_STRING_FLD(account_name, USERMOD_FIELD_ACCOUNT_NAME); 290 CMP_LSA_STRING_FLD(full_name, USERMOD_FIELD_FULL_NAME); 291 CMP_LSA_STRING_FLD(description, USERMOD_FIELD_DESCRIPTION); 292 CMP_LSA_STRING_FLD(comment, USERMOD_FIELD_COMMENT); 293 CMP_LSA_STRING_FLD(logon_script, USERMOD_FIELD_LOGON_SCRIPT); 294 CMP_LSA_STRING_FLD(profile_path, USERMOD_FIELD_PROFILE_PATH); 295 CMP_LSA_STRING_FLD(home_directory, USERMOD_FIELD_HOME_DIRECTORY); 296 CMP_LSA_STRING_FLD(home_drive, USERMOD_FIELD_HOME_DRIVE); 297 CMP_TIME_FLD(acct_expiry, USERMOD_FIELD_ACCT_EXPIRY); 298 CMP_NUM_FLD(acct_flags, USERMOD_FIELD_ACCT_FLAGS) 299 300 return true; 301} 302 303 304bool torture_useradd(struct torture_context *torture) 305{ 306 NTSTATUS status; 307 struct dcerpc_pipe *p; 308 struct policy_handle h; 309 struct lsa_String domain_name; 310 struct dom_sid2 sid; 311 const char *name = TEST_USERNAME; 312 TALLOC_CTX *mem_ctx; 313 bool ret = true; 314 315 mem_ctx = talloc_init("test_useradd"); 316 317 status = torture_rpc_connection(torture, 318 &p, 319 &ndr_table_samr); 320 321 torture_assert_ntstatus_ok(torture, status, "RPC connect failed"); 322 323 domain_name.string = lp_workgroup(torture->lp_ctx); 324 if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) { 325 ret = false; 326 goto done; 327 } 328 329 if (!test_useradd(p, mem_ctx, &h, name)) { 330 ret = false; 331 goto done; 332 } 333 334 if (!test_user_cleanup(torture, p, mem_ctx, &h, name)) { 335 ret = false; 336 goto done; 337 } 338 339 if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) { 340 ret = false; 341 goto done; 342 } 343 344 if (!test_useradd_async(p, mem_ctx, &h, name)) { 345 ret = false; 346 goto done; 347 } 348 349 if (!test_user_cleanup(torture, p, mem_ctx, &h, name)) { 350 ret = false; 351 goto done; 352 } 353 354done: 355 talloc_free(mem_ctx); 356 return ret; 357} 358 359 360bool torture_userdel(struct torture_context *torture) 361{ 362 NTSTATUS status; 363 struct dcerpc_pipe *p; 364 struct policy_handle h; 365 struct lsa_String domain_name; 366 struct dom_sid2 sid; 367 uint32_t rid; 368 const char *name = TEST_USERNAME; 369 TALLOC_CTX *mem_ctx; 370 bool ret = true; 371 372 mem_ctx = talloc_init("test_userdel"); 373 374 status = torture_rpc_connection(torture, 375 &p, 376 &ndr_table_samr); 377 378 if (!NT_STATUS_IS_OK(status)) { 379 return false; 380 } 381 382 domain_name.string = lp_workgroup(torture->lp_ctx); 383 if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) { 384 ret = false; 385 goto done; 386 } 387 388 if (!test_user_create(torture, p, mem_ctx, &h, name, &rid)) { 389 ret = false; 390 goto done; 391 } 392 393 if (!test_userdel(p, mem_ctx, &h, name)) { 394 ret = false; 395 goto done; 396 } 397 398done: 399 talloc_free(mem_ctx); 400 return ret; 401} 402 403 404bool torture_usermod(struct torture_context *torture) 405{ 406 NTSTATUS status; 407 struct dcerpc_pipe *p; 408 struct policy_handle h; 409 struct lsa_String domain_name; 410 struct dom_sid2 sid; 411 uint32_t rid; 412 int i; 413 char *name; 414 TALLOC_CTX *mem_ctx; 415 bool ret = true; 416 417 mem_ctx = talloc_init("test_userdel"); 418 419 status = torture_rpc_connection(torture, 420 &p, 421 &ndr_table_samr); 422 423 torture_assert_ntstatus_ok(torture, status, "RPC connect"); 424 425 domain_name.string = lp_workgroup(torture->lp_ctx); 426 name = talloc_strdup(mem_ctx, TEST_USERNAME); 427 428 if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) { 429 ret = false; 430 goto done; 431 } 432 433 if (!test_user_create(torture, p, mem_ctx, &h, name, &rid)) { 434 ret = false; 435 goto done; 436 } 437 438 for (i = 1; i < FIELDS_NUM; i++) { 439 struct libnet_rpc_usermod m; 440 441 if (!test_usermod(torture, p, mem_ctx, &h, i, &m, &name)) { 442 ret = false; 443 goto cleanup; 444 } 445 446 if (!test_compare(torture, p, mem_ctx, &h, &m, name)) { 447 ret = false; 448 goto cleanup; 449 } 450 } 451 452cleanup: 453 if (!test_user_cleanup(torture, p, mem_ctx, &h, name)) { 454 ret = false; 455 goto done; 456 } 457 458done: 459 talloc_free(mem_ctx); 460 return ret; 461} 462