static bool test_connect_service(struct torture_context *tctx, struct libnet_context *ctx, const struct ndr_interface_table *iface, const char *binding_string, const char *hostname, const enum libnet_RpcConnect_level level, bool badcreds, NTSTATUS expected_status) { NTSTATUS status; struct libnet_RpcConnect connect_r; ZERO_STRUCT(connect_r); connect_r.level = level; connect_r.in.binding = binding_string; connect_r.in.name = hostname; connect_r.in.dcerpc_iface = iface; /* if bad credentials are needed, set baduser%badpassword instead of default commandline-passed credentials */ if (badcreds) { cli_credentials_set_username(ctx->cred, "baduser", CRED_SPECIFIED); cli_credentials_set_password(ctx->cred, "badpassword", CRED_SPECIFIED); } status = libnet_RpcConnect(ctx, ctx, &connect_r); if (!NT_STATUS_EQUAL(status, expected_status)) { torture_comment(tctx, "Connecting to rpc service %s on %s.\n\tFAILED. Expected: %s." "Received: %s\n", connect_r.in.dcerpc_iface->name, connect_r.in.binding, nt_errstr(expected_status), nt_errstr(status)); return false; } torture_comment(tctx, "PASSED. Expected: %s, received: %s\n", nt_errstr(expected_status), nt_errstr(status)); if (connect_r.level == LIBNET_RPC_CONNECT_DC_INFO && NT_STATUS_IS_OK(status)) { torture_comment(tctx, "Domain Controller Info:\n"); torture_comment(tctx, "\tDomain Name:\t %s\n", connect_r.out.domain_name); torture_comment(tctx, "\tDomain SID:\t %s\n", dom_sid_string(ctx, connect_r.out.domain_sid)); torture_comment(tctx, "\tRealm:\t\t %s\n", connect_r.out.realm); torture_comment(tctx, "\tGUID:\t\t %s\n", GUID_string(ctx, connect_r.out.guid)); } else if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "Error string: %s\n", connect_r.out.error_string); } return true; }
NTSTATUS libnet_AddShare(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_AddShare *r) { NTSTATUS status; struct libnet_RpcConnect c; struct srvsvc_NetShareAdd s; union srvsvc_NetShareInfo info; c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->in.server_name; c.in.dcerpc_iface = &ndr_table_srvsvc; status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to SRVSVC pipe of server %s " "failed: %s", r->in.server_name, nt_errstr(status)); return status; } info.info2 = &r->in.share; s.in.level = 2; s.in.info = &info; s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", r->in.server_name); status = dcerpc_srvsvc_NetShareAdd(c.out.dcerpc_pipe, mem_ctx, &s); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "srvsvc_NetShareAdd '%s' on server '%s' failed" ": %s", r->in.share.name, r->in.server_name, nt_errstr(status)); } else if (!W_ERROR_IS_OK(s.out.result)) { r->out.error_string = talloc_asprintf(mem_ctx, "srvsvc_NetShareAdd '%s' on server '%s' failed" ": %s", r->in.share.name, r->in.server_name, win_errstr(s.out.result)); status = werror_to_ntstatus(s.out.result); } talloc_free(c.out.dcerpc_pipe); return status; }
/* * do a domain join using DCERPC/SAMR calls * - connect to the LSA pipe, to try and find out information about the domain * - create a secondary connection to SAMR pipe * - do a samr_Connect to get a policy handle * - do a samr_LookupDomain to get the domain sid * - do a samr_OpenDomain to get a domain handle * - do a samr_CreateAccount to try and get a new account * * If that fails, do: * - do a samr_LookupNames to get the users rid * - do a samr_OpenUser to get a user handle * - potentially delete and recreate the user * - assert the account is of the right type with samrQueryUserInfo * * - call libnet_SetPassword_samr_handle to set the password, * and pass a samr_UserInfo21 struct to set full_name and the account flags * * - do some ADS specific things when we join as Domain Controller, * look at libnet_joinADSDomain() for the details */ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *r) { TALLOC_CTX *tmp_ctx; NTSTATUS status, cu_status; struct libnet_RpcConnect *connect_with_info; struct dcerpc_pipe *samr_pipe; struct samr_Connect sc; struct policy_handle p_handle; struct samr_OpenDomain od; struct policy_handle d_handle; struct samr_LookupNames ln; struct samr_Ids rids, types; struct samr_OpenUser ou; struct samr_CreateUser2 cu; struct policy_handle *u_handle = NULL; struct samr_QueryUserInfo qui; union samr_UserInfo *uinfo; struct samr_UserInfo21 u_info21; union libnet_SetPassword r2; struct samr_GetUserPwInfo pwp; struct samr_PwInfo info; struct lsa_String samr_account_name; uint32_t acct_flags, old_acct_flags; uint32_t rid, access_granted; int policy_min_pw_len = 0; struct dom_sid *account_sid = NULL; const char *password_str = NULL; r->out.error_string = NULL; r2.samr_handle.out.error_string = NULL; tmp_ctx = talloc_named(mem_ctx, 0, "libnet_Join temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } u_handle = talloc(tmp_ctx, struct policy_handle); if (!u_handle) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } connect_with_info = talloc_zero(tmp_ctx, struct libnet_RpcConnect); if (!connect_with_info) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* prepare connect to the SAMR pipe of PDC */ if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { connect_with_info->in.binding = NULL; connect_with_info->in.name = r->in.domain_name; } else { connect_with_info->in.binding = r->in.binding; connect_with_info->in.name = NULL; } /* This level makes a connection to the LSA pipe on the way, * to get some useful bits of information about the domain */ connect_with_info->level = LIBNET_RPC_CONNECT_DC_INFO; connect_with_info->in.dcerpc_iface = &ndr_table_samr; /* establish the SAMR connection */ status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info); if (!NT_STATUS_IS_OK(status)) { if (r->in.binding) { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of DC %s failed: %s", r->in.binding, connect_with_info->out.error_string); } else { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of PDC for %s failed: %s", r->in.domain_name, connect_with_info->out.error_string); } talloc_free(tmp_ctx); return status; } samr_pipe = connect_with_info->out.dcerpc_pipe; status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe, connect_with_info->out.dcerpc_pipe->binding, &ndr_table_samr, ctx->cred, ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "SAMR bind failed: %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* prepare samr_Connect */ ZERO_STRUCT(p_handle); sc.in.system_name = NULL; sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; sc.out.connect_handle = &p_handle; /* 2. do a samr_Connect to get a policy handle */ status = dcerpc_samr_Connect_r(samr_pipe->binding_handle, tmp_ctx, &sc); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sc.out.result)) { status = sc.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_Connect failed: %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* If this is a connection on ncacn_ip_tcp to Win2k3 SP1, we don't get back this useful info */ if (!connect_with_info->out.domain_name) { if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, r->in.domain_name); } else { /* Bugger, we just lost our way to automatically find the domain name */ connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lpcfg_workgroup(ctx->lp_ctx)); connect_with_info->out.realm = talloc_strdup(tmp_ctx, lpcfg_realm(ctx->lp_ctx)); } } /* Perhaps we didn't get a SID above, because we are against ncacn_ip_tcp */ if (!connect_with_info->out.domain_sid) { struct lsa_String name; struct samr_LookupDomain l; struct dom_sid2 *sid = NULL; name.string = connect_with_info->out.domain_name; l.in.connect_handle = &p_handle; l.in.domain_name = &name; l.out.sid = &sid; status = dcerpc_samr_LookupDomain_r(samr_pipe->binding_handle, tmp_ctx, &l); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(l.out.result)) { status = l.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "SAMR LookupDomain failed: %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } connect_with_info->out.domain_sid = *l.out.sid; } /* prepare samr_OpenDomain */ ZERO_STRUCT(d_handle); od.in.connect_handle = &p_handle; od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; od.in.sid = connect_with_info->out.domain_sid; od.out.domain_handle = &d_handle; /* do a samr_OpenDomain to get a domain handle */ status = dcerpc_samr_OpenDomain_r(samr_pipe->binding_handle, tmp_ctx, &od); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(od.out.result)) { status = od.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_OpenDomain for [%s] failed: %s", dom_sid_string(tmp_ctx, connect_with_info->out.domain_sid), nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* prepare samr_CreateUser2 */ ZERO_STRUCTP(u_handle); cu.in.domain_handle = &d_handle; cu.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; samr_account_name.string = r->in.account_name; cu.in.account_name = &samr_account_name; cu.in.acct_flags = r->in.acct_type; cu.out.user_handle = u_handle; cu.out.rid = &rid; cu.out.access_granted = &access_granted; /* do a samr_CreateUser2 to get an account handle, or an error */ cu_status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu); if (NT_STATUS_IS_OK(cu_status) && !NT_STATUS_IS_OK(cu.out.result)) { cu_status = cu.out.result; } status = cu_status; if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { /* prepare samr_LookupNames */ ln.in.domain_handle = &d_handle; ln.in.num_names = 1; ln.in.names = talloc_array(tmp_ctx, struct lsa_String, 1); ln.out.rids = &rids; ln.out.types = &types; if (!ln.in.names) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ln.in.names[0].string = r->in.account_name; /* 5. do a samr_LookupNames to get the users rid */ status = dcerpc_samr_LookupNames_r(samr_pipe->binding_handle, tmp_ctx, &ln); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ln.out.result)) { status = ln.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* check if we got one RID for the user */ if (ln.out.rids->count != 1) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] returns %d RIDs", r->in.account_name, ln.out.rids->count); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* prepare samr_OpenUser */ ZERO_STRUCTP(u_handle); ou.in.domain_handle = &d_handle; ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; ou.in.rid = ln.out.rids->ids[0]; rid = ou.in.rid; ou.out.user_handle = u_handle; /* 6. do a samr_OpenUser to get a user handle */ status = dcerpc_samr_OpenUser_r(samr_pipe->binding_handle, tmp_ctx, &ou); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ou.out.result)) { status = ou.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_OpenUser for [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } if (r->in.recreate_account) { struct samr_DeleteUser d; d.in.user_handle = u_handle; d.out.user_handle = u_handle; status = dcerpc_samr_DeleteUser_r(samr_pipe->binding_handle, mem_ctx, &d); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(d.out.result)) { status = d.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_DeleteUser (for recreate) of [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* We want to recreate, so delete and another samr_CreateUser2 */ /* &cu filled in above */ status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(cu.out.result)) { status = cu.out.result; } if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "samr_CreateUser2 (recreate) for [%s] failed: %s", r->in.account_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } } else if (!NT_STATUS_IS_OK(status)) {
NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamSync *r) { NTSTATUS nt_status, dbsync_nt_status; TALLOC_CTX *samsync_ctx, *loop_ctx, *delta_ctx; struct netlogon_creds_CredentialState *creds; struct netr_DatabaseSync dbsync; struct netr_Authenticator credential, return_authenticator; struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL; struct cli_credentials *machine_account; struct dcerpc_pipe *p; struct libnet_context *machine_net_ctx; struct libnet_RpcConnect *c; struct libnet_SamSync_state *state; const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; unsigned int i; samsync_ctx = talloc_named(mem_ctx, 0, "SamSync top context"); if (!r->in.machine_account) { machine_account = cli_credentials_init(samsync_ctx); if (!machine_account) { talloc_free(samsync_ctx); return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(machine_account, ctx->lp_ctx); nt_status = cli_credentials_set_machine_account(machine_account, ctx->lp_ctx); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?"); talloc_free(samsync_ctx); return nt_status; } } else { machine_account = r->in.machine_account; } /* We cannot do this unless we are a BDC. Check, before we get odd errors later */ if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) { r->out.error_string = talloc_asprintf(mem_ctx, "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC", cli_credentials_get_domain(machine_account), cli_credentials_get_secure_channel_type(machine_account)); talloc_free(samsync_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } c = talloc_zero(samsync_ctx, struct libnet_RpcConnect); if (!c) { r->out.error_string = NULL; talloc_free(samsync_ctx); return NT_STATUS_NO_MEMORY; } c->level = LIBNET_RPC_CONNECT_DC_INFO; if (r->in.binding_string) { c->in.binding = r->in.binding_string; c->in.name = NULL; } else { c->in.binding = NULL; c->in.name = cli_credentials_get_domain(machine_account); } /* prepare connect to the NETLOGON pipe of PDC */ c->in.dcerpc_iface = &ndr_table_netlogon; /* We must do this as the machine, not as any command-line * user. So we override the credentials in the * libnet_context */ machine_net_ctx = talloc(samsync_ctx, struct libnet_context); if (!machine_net_ctx) { r->out.error_string = NULL; talloc_free(samsync_ctx); return NT_STATUS_NO_MEMORY; } *machine_net_ctx = *ctx; machine_net_ctx->cred = machine_account; /* connect to the NETLOGON pipe of the PDC */ nt_status = libnet_RpcConnect(machine_net_ctx, samsync_ctx, c); if (!NT_STATUS_IS_OK(nt_status)) { if (r->in.binding_string) { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to NETLOGON pipe of DC %s failed: %s", r->in.binding_string, c->out.error_string); } else { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to NETLOGON pipe of DC for %s failed: %s", c->in.name, c->out.error_string); } talloc_free(samsync_ctx); return nt_status; } /* This makes a new pipe, on which we can do schannel. We * should do this in the RpcConnect code, but the abstaction * layers do not suit yet */ nt_status = dcerpc_secondary_connection(c->out.dcerpc_pipe, &p, c->out.dcerpc_pipe->binding); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_asprintf(mem_ctx, "Secondary connection to NETLOGON pipe of DC %s failed: %s", dcerpc_server_name(p), nt_errstr(nt_status)); talloc_free(samsync_ctx); return nt_status; } nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &ndr_table_netlogon, machine_account, ctx->lp_ctx, DCERPC_AUTH_LEVEL_PRIVACY); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_asprintf(mem_ctx, "SCHANNEL authentication to NETLOGON pipe of DC %s failed: %s", dcerpc_server_name(p), nt_errstr(nt_status)); talloc_free(samsync_ctx); return nt_status; } state = talloc(samsync_ctx, struct libnet_SamSync_state); if (!state) { r->out.error_string = NULL; talloc_free(samsync_ctx); return nt_status; } state->domain_name = c->out.domain_name; state->domain_sid = c->out.domain_sid; state->realm = c->out.realm; state->domain_guid = c->out.guid; state->machine_net_ctx = machine_net_ctx; state->netlogon_pipe = p; /* initialise the callback layer. It may wish to contact the * server with ldap, now we know the name */ if (r->in.init_fn) { char *error_string; nt_status = r->in.init_fn(samsync_ctx, r->in.fn_ctx, state, &error_string); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_steal(mem_ctx, error_string); talloc_free(samsync_ctx); return nt_status; } } /* get NETLOGON credentials */ nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer"); talloc_free(samsync_ctx); return nt_status; } /* Setup details for the synchronisation */ ZERO_STRUCT(return_authenticator); dbsync.in.logon_server = talloc_asprintf(samsync_ctx, "\\\\%s", dcerpc_server_name(p)); dbsync.in.computername = cli_credentials_get_workstation(machine_account); dbsync.in.preferredmaximumlength = (uint32_t)-1; dbsync.in.return_authenticator = &return_authenticator; dbsync.out.return_authenticator = &return_authenticator; dbsync.out.delta_enum_array = &delta_enum_array; for (i=0;i< ARRAY_SIZE(database_ids); i++) { uint32_t sync_context = 0; dbsync.in.database_id = database_ids[i]; dbsync.in.sync_context = &sync_context; dbsync.out.sync_context = &sync_context; do { uint32_t d; loop_ctx = talloc_named(samsync_ctx, 0, "DatabaseSync loop context"); netlogon_creds_client_authenticator(creds, &credential); dbsync.in.credential = &credential; dbsync_nt_status = dcerpc_netr_DatabaseSync_r(p->binding_handle, loop_ctx, &dbsync); if (NT_STATUS_IS_OK(dbsync_nt_status) && !NT_STATUS_IS_OK(dbsync.out.result)) { dbsync_nt_status = dbsync.out.result; } if (!NT_STATUS_IS_OK(dbsync_nt_status) && !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) { r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status)); talloc_free(samsync_ctx); return nt_status; } if (!netlogon_creds_client_check(creds, &dbsync.out.return_authenticator->cred)) { r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed"); talloc_free(samsync_ctx); return NT_STATUS_ACCESS_DENIED; } dbsync.in.sync_context = dbsync.out.sync_context; /* For every single remote 'delta' entry: */ for (d=0; d < delta_enum_array->num_deltas; d++) { char *error_string = NULL; delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context"); /* 'Fix' elements, by decrypting and * de-obfuscating the data */ nt_status = samsync_fix_delta(delta_ctx, creds, dbsync.in.database_id, &delta_enum_array->delta_enum[d]); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_steal(mem_ctx, error_string); talloc_free(samsync_ctx); return nt_status; } /* Now call the callback. This will * do something like print the data or * write to an ldb */ nt_status = r->in.delta_fn(delta_ctx, r->in.fn_ctx, dbsync.in.database_id, &delta_enum_array->delta_enum[d], &error_string); if (!NT_STATUS_IS_OK(nt_status)) { r->out.error_string = talloc_steal(mem_ctx, error_string); talloc_free(samsync_ctx); return nt_status; } talloc_free(delta_ctx); } talloc_free(loop_ctx); } while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)); if (!NT_STATUS_IS_OK(dbsync_nt_status)) { r->out.error_string = talloc_asprintf(mem_ctx, "libnet_SamSync_netlogon failed: unexpected inconsistancy. Should not get error %s here", nt_errstr(nt_status)); talloc_free(samsync_ctx); return dbsync_nt_status; } nt_status = NT_STATUS_OK; } talloc_free(samsync_ctx); return nt_status; }
/* * get the remote time of a server via srvsvc_NetRemoteTOD */ static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_RemoteTOD *r) { NTSTATUS status; struct libnet_RpcConnect c; struct srvsvc_NetRemoteTOD tod; struct srvsvc_NetRemoteTODInfo *info = NULL; struct tm tm; ZERO_STRUCT(c); /* prepare connect to the SRVSVC pipe of a timeserver */ c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->srvsvc.in.server_name; c.in.dcerpc_iface = &ndr_table_srvsvc; /* 1. connect to the SRVSVC pipe of a timeserver */ status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { r->srvsvc.out.error_string = talloc_asprintf(mem_ctx, "Connection to SRVSVC pipe of server '%s' failed: %s", r->srvsvc.in.server_name, nt_errstr(status)); return status; } /* prepare srvsvc_NetrRemoteTOD */ tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.name); tod.out.info = &info; /* 2. try srvsvc_NetRemoteTOD */ status = dcerpc_srvsvc_NetRemoteTOD(c.out.dcerpc_pipe, mem_ctx, &tod); if (!NT_STATUS_IS_OK(status)) { r->srvsvc.out.error_string = talloc_asprintf(mem_ctx, "srvsvc_NetrRemoteTOD on server '%s' failed: %s", r->srvsvc.in.server_name, nt_errstr(status)); goto disconnect; } /* check result of srvsvc_NetrRemoteTOD */ if (!W_ERROR_IS_OK(tod.out.result)) { r->srvsvc.out.error_string = talloc_asprintf(mem_ctx, "srvsvc_NetrRemoteTOD on server '%s' failed: %s", r->srvsvc.in.server_name, win_errstr(tod.out.result)); status = werror_to_ntstatus(tod.out.result); goto disconnect; } /* need to set the out parameters */ tm.tm_sec = (int)info->secs; tm.tm_min = (int)info->mins; tm.tm_hour = (int)info->hours; tm.tm_mday = (int)info->day; tm.tm_mon = (int)info->month -1; tm.tm_year = (int)info->year - 1900; tm.tm_wday = -1; tm.tm_yday = -1; tm.tm_isdst = -1; r->srvsvc.out.time = timegm(&tm); r->srvsvc.out.time_zone = info->timezone * 60; goto disconnect; disconnect: /* close connection */ talloc_free(c.out.dcerpc_pipe); return status; }
NTSTATUS libnet_ListShares(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_ListShares *r) { NTSTATUS status; struct libnet_RpcConnect c; struct srvsvc_NetShareEnumAll s; struct srvsvc_NetShareInfoCtr info_ctr; uint32_t resume_handle = 0; uint32_t totalentries = 0; struct srvsvc_NetShareCtr0 ctr0; struct srvsvc_NetShareCtr1 ctr1; struct srvsvc_NetShareCtr2 ctr2; struct srvsvc_NetShareCtr501 ctr501; struct srvsvc_NetShareCtr502 ctr502; c.level = LIBNET_RPC_CONNECT_SERVER; c.in.name = r->in.server_name; c.in.dcerpc_iface = &ndr_table_srvsvc; s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", c.in.name); status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "Connection to SRVSVC pipe of server %s " "failed: %s", r->in.server_name, nt_errstr(status)); return status; } info_ctr.level = r->in.level; switch (info_ctr.level) { case 0: info_ctr.ctr.ctr0 = &ctr0; ZERO_STRUCT(ctr0); break; case 1: info_ctr.ctr.ctr1 = &ctr1; ZERO_STRUCT(ctr1); break; case 2: info_ctr.ctr.ctr2 = &ctr2; ZERO_STRUCT(ctr2); break; case 501: info_ctr.ctr.ctr501 = &ctr501; ZERO_STRUCT(ctr501); break; case 502: info_ctr.ctr.ctr502 = &ctr502; ZERO_STRUCT(ctr502); break; default: r->out.error_string = talloc_asprintf(mem_ctx, "libnet_ListShares: Invalid info level requested: %d", info_ctr.level); return NT_STATUS_INVALID_PARAMETER; } s.in.max_buffer = ~0; s.in.resume_handle = &resume_handle; s.in.info_ctr = &info_ctr; s.out.info_ctr = &info_ctr; s.out.totalentries = &totalentries; status = dcerpc_srvsvc_NetShareEnumAll(c.out.dcerpc_pipe, mem_ctx, &s); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(mem_ctx, "srvsvc_NetShareEnumAll on server '%s' failed" ": %s", r->in.server_name, nt_errstr(status)); goto disconnect; } if (!W_ERROR_IS_OK(s.out.result) && !W_ERROR_EQUAL(s.out.result, WERR_MORE_DATA)) { r->out.error_string = talloc_asprintf(mem_ctx, "srvsvc_NetShareEnumAll on server '%s' failed: %s", r->in.server_name, win_errstr(s.out.result)); goto disconnect; } r->out.ctr = s.out.info_ctr->ctr; disconnect: talloc_free(c.out.dcerpc_pipe); return status; }
/* * set a password with DCERPC/SAMR calls * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) * is it correct to contact the the pdc of the domain of the user who's password should be set? * 2. do a samr_Connect to get a policy handle * 3. do a samr_LookupDomain to get the domain sid * 4. do a samr_OpenDomain to get a domain handle * 5. do a samr_LookupNames to get the users rid * 6. do a samr_OpenUser to get a user handle * 7 call libnet_SetPassword_samr_handle to set the password */ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r) { NTSTATUS status; struct libnet_RpcConnect c; struct samr_Connect sc; struct policy_handle p_handle; struct samr_LookupDomain ld; struct dom_sid2 *sid = NULL; struct lsa_String d_name; struct samr_OpenDomain od; struct policy_handle d_handle; struct samr_LookupNames ln; struct samr_Ids rids, types; struct samr_OpenUser ou; struct policy_handle u_handle; union libnet_SetPassword r2; ZERO_STRUCT(c); /* prepare connect to the SAMR pipe of users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; c.in.name = r->samr.in.domain_name; c.in.dcerpc_iface = &ndr_table_samr; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of PDC of domain '%s' failed: %s", r->samr.in.domain_name, nt_errstr(status)); return status; } /* prepare samr_Connect */ ZERO_STRUCT(p_handle); sc.in.system_name = NULL; sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; sc.out.connect_handle = &p_handle; /* 2. do a samr_Connect to get a policy handle */ status = dcerpc_samr_Connect(c.out.dcerpc_pipe, mem_ctx, &sc); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_Connect failed: %s", nt_errstr(status)); goto disconnect; } /* prepare samr_LookupDomain */ d_name.string = r->samr.in.domain_name; ld.in.connect_handle = &p_handle; ld.in.domain_name = &d_name; ld.out.sid = &sid; /* 3. do a samr_LookupDomain to get the domain sid */ status = dcerpc_samr_LookupDomain(c.out.dcerpc_pipe, mem_ctx, &ld); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_LookupDomain for [%s] failed: %s", r->samr.in.domain_name, nt_errstr(status)); goto disconnect; } /* prepare samr_OpenDomain */ ZERO_STRUCT(d_handle); od.in.connect_handle = &p_handle; od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; od.in.sid = *ld.out.sid; od.out.domain_handle = &d_handle; /* 4. do a samr_OpenDomain to get a domain handle */ status = dcerpc_samr_OpenDomain(c.out.dcerpc_pipe, mem_ctx, &od); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_OpenDomain for [%s] failed: %s", r->samr.in.domain_name, nt_errstr(status)); goto disconnect; } /* prepare samr_LookupNames */ ln.in.domain_handle = &d_handle; ln.in.num_names = 1; ln.in.names = talloc_array(mem_ctx, struct lsa_String, 1); ln.out.rids = &rids; ln.out.types = &types; if (!ln.in.names) { r->samr.out.error_string = "Out of Memory"; return NT_STATUS_NO_MEMORY; } ln.in.names[0].string = r->samr.in.account_name; /* 5. do a samr_LookupNames to get the users rid */ status = dcerpc_samr_LookupNames(c.out.dcerpc_pipe, mem_ctx, &ln); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] failed: %s", r->samr.in.account_name, nt_errstr(status)); goto disconnect; } /* check if we got one RID for the user */ if (ln.out.rids->count != 1) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] returns %d RIDs", r->samr.in.account_name, ln.out.rids->count); status = NT_STATUS_INVALID_PARAMETER; goto disconnect; } /* prepare samr_OpenUser */ ZERO_STRUCT(u_handle); ou.in.domain_handle = &d_handle; ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; ou.in.rid = ln.out.rids->ids[0]; ou.out.user_handle = &u_handle; /* 6. do a samr_OpenUser to get a user handle */ status = dcerpc_samr_OpenUser(c.out.dcerpc_pipe, mem_ctx, &ou); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_OpenUser for [%s] failed: %s", r->samr.in.account_name, nt_errstr(status)); goto disconnect; } r2.samr_handle.level = LIBNET_SET_PASSWORD_SAMR_HANDLE; r2.samr_handle.in.account_name = r->samr.in.account_name; r2.samr_handle.in.newpassword = r->samr.in.newpassword; r2.samr_handle.in.user_handle = &u_handle; r2.samr_handle.in.dcerpc_pipe = c.out.dcerpc_pipe; r2.samr_handle.in.info21 = NULL; status = libnet_SetPassword(ctx, mem_ctx, &r2); r->generic.out.error_string = r2.samr_handle.out.error_string; disconnect: /* close connection */ talloc_free(c.out.dcerpc_pipe); return status; }
/* * do a password change using DCERPC/SAMR calls * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) * 2. try samr_ChangePasswordUser3 * 3. try samr_ChangePasswordUser2 * 4. try samr_OemChangePasswordUser2 * (not yet: 5. try samr_ChangePasswordUser) */ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r) { NTSTATUS status; struct libnet_RpcConnect c; #if 0 struct policy_handle user_handle; struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6; struct samr_ChangePasswordUser pw; #endif struct samr_OemChangePasswordUser2 oe2; struct samr_ChangePasswordUser2 pw2; struct samr_ChangePasswordUser3 pw3; struct lsa_String server, account; struct lsa_AsciiString a_server, a_account; struct samr_CryptPassword nt_pass, lm_pass; struct samr_Password nt_verifier, lm_verifier; uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; struct samr_DomInfo1 *dominfo = NULL; struct userPwdChangeFailureInformation *reject = NULL; ZERO_STRUCT(c); /* prepare connect to the SAMR pipe of the users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; c.in.name = r->samr.in.domain_name; c.in.dcerpc_iface = &ndr_table_samr; c.in.dcerpc_flags = DCERPC_ANON_FALLBACK; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of PDC of domain '%s' failed: %s", r->samr.in.domain_name, nt_errstr(status)); return status; } /* prepare password change for account */ server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe)); account.string = r->samr.in.account_name; E_md4hash(r->samr.in.oldpassword, old_nt_hash); E_md4hash(r->samr.in.newpassword, new_nt_hash); E_deshash(r->samr.in.oldpassword, old_lm_hash); E_deshash(r->samr.in.newpassword, new_lm_hash); /* prepare samr_ChangePasswordUser3 */ encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(lm_pass.data, old_nt_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(nt_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); pw3.in.server = &server; pw3.in.account = &account; pw3.in.nt_password = &nt_pass; pw3.in.nt_verifier = &nt_verifier; pw3.in.lm_change = 1; pw3.in.lm_password = &lm_pass; pw3.in.lm_verifier = &lm_verifier; pw3.in.password3 = NULL; pw3.out.dominfo = &dominfo; pw3.out.reject = &reject; /* 2. try samr_ChangePasswordUser3 */ status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser3 failed: %s", nt_errstr(status)); r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser3 for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; } /* prepare samr_ChangePasswordUser2 */ encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE); arcfour_crypt(lm_pass.data, old_lm_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(nt_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); pw2.in.server = &server; pw2.in.account = &account; pw2.in.nt_password = &nt_pass; pw2.in.nt_verifier = &nt_verifier; pw2.in.lm_change = 1; pw2.in.lm_password = &lm_pass; pw2.in.lm_verifier = &lm_verifier; /* 3. try samr_ChangePasswordUser2 */ status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser2 for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; } /* prepare samr_OemChangePasswordUser2 */ a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe)); a_account.string = r->samr.in.account_name; encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII); arcfour_crypt(lm_pass.data, old_lm_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); oe2.in.server = &a_server; oe2.in.account = &a_account; oe2.in.password = &lm_pass; oe2.in.hash = &lm_verifier; /* 4. try samr_OemChangePasswordUser2 */ status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { if (!NT_STATUS_IS_OK(oe2.out.result)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; } #if 0 /* prepare samr_ChangePasswordUser */ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash); E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash); E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash); E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash); E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash); E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash); /* TODO: ask for a user_handle */ pw.in.handle = &user_handle; pw.in.lm_present = 1; pw.in.old_lm_crypted = &hash1; pw.in.new_lm_crypted = &hash2; pw.in.nt_present = 1; pw.in.old_nt_crypted = &hash3; pw.in.new_nt_crypted = &hash4; pw.in.cross1_present = 1; pw.in.nt_cross = &hash5; pw.in.cross2_present = 1; pw.in.lm_cross = &hash6; /* 5. try samr_ChangePasswordUser */ status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser failed: %s", nt_errstr(status)); goto disconnect; } /* check result of samr_ChangePasswordUser */ if (!NT_STATUS_IS_OK(pw.out.result)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(pw.out.result)); if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { status = pw.out.result; goto disconnect; } goto disconnect; } #endif disconnect: /* close connection */ talloc_free(c.out.dcerpc_pipe); return status; }