This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "libnet/libnet.h"
+#include "libcli/auth/libcli_auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/schannel_proto.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "param/param.h"
/**
*/
static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
struct creds_CredentialState *creds,
+ bool rid_crypt,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
const char *username = user->account_name.string;
NTSTATUS nt_status;
- if (user->lm_password_present) {
- sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
- user->lmpassword = lm_hash;
- }
-
- if (user->nt_password_present) {
- sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
- user->ntpassword = nt_hash;
+ if (rid_crypt) {
+ if (user->lm_password_present) {
+ sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
+ user->lmpassword = lm_hash;
+ }
+
+ if (user->nt_password_present) {
+ sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
+ user->ntpassword = nt_hash;
+ }
}
if (user->user_private_info.SensitiveData) {
nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
if (NT_STATUS_IS_OK(nt_status)) {
if (keys.keys.keys2.lmpassword.length == 16) {
- sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
- user->lmpassword = lm_hash;
- user->lm_password_present = True;
+ if (rid_crypt) {
+ sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
+ user->lmpassword = lm_hash;
+ } else {
+ user->lmpassword = keys.keys.keys2.lmpassword.pwd;
+ }
+ user->lm_password_present = true;
}
if (keys.keys.keys2.ntpassword.length == 16) {
- sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
- user->ntpassword = nt_hash;
- user->nt_password_present = True;
+ if (rid_crypt) {
+ sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
+ user->ntpassword = nt_hash;
+ } else {
+ user->ntpassword = keys.keys.keys2.ntpassword.pwd;
+ }
+ user->nt_password_present = true;
}
+ /* TODO: rid decrypt history fields */
} else {
- *error_string = talloc_asprintf(mem_ctx, "Failed to parse Sensitive Data for %s:\n", username);
+ *error_string = talloc_asprintf(mem_ctx, "Failed to parse Sensitive Data for %s:", username);
dump_data(10, data.data, data.length);
return nt_status;
}
static NTSTATUS fix_delta(TALLOC_CTX *mem_ctx,
struct creds_CredentialState *creds,
+ bool rid_crypt,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
nt_status = fix_user(mem_ctx,
creds,
+ rid_crypt,
database,
delta,
error_string);
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};
int i;
talloc_free(samsync_ctx);
return NT_STATUS_NO_MEMORY;
}
- cli_credentials_set_conf(machine_account);
+ cli_credentials_set_conf(machine_account, global_loadparm);
nt_status = cli_credentials_set_machine_account(machine_account);
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?");
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_NO_MEMORY;
}
+ c->level = LIBNET_RPC_CONNECT_DC_INFO;
if (r->in.binding_string) {
- c->level = LIBNET_RPC_CONNECT_BINDING;
c->in.binding = r->in.binding_string;
+ c->in.name = NULL;
} else {
- /* prepare connect to the NETLOGON pipe of PDC */
- c->level = LIBNET_RPC_CONNECT_PDC;
+ c->in.binding = NULL;
c->in.name = cli_credentials_get_domain(machine_account);
}
- c->in.dcerpc_iface = &dcerpc_table_netlogon;
+
+ /* 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
machine_net_ctx->cred = machine_account;
/* connect to the NETLOGON pipe of the PDC */
- nt_status = libnet_RpcConnect(machine_net_ctx, c, c);
+ nt_status = libnet_RpcConnect(machine_net_ctx, samsync_ctx, c);
if (!NT_STATUS_IS_OK(nt_status)) {
- r->out.error_string = talloc_asprintf(mem_ctx,
- "Connection to NETLOGON pipe of DC failed: %s",
- c->out.error_string);
+ 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;
}
return nt_status;
}
- nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &dcerpc_table_netlogon,
+ nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &ndr_table_netlogon,
machine_account, DCERPC_AUTH_LEVEL_PRIVACY);
if (!NT_STATUS_IS_OK(nt_status)) {
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 credentails */
nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds);
return nt_status;
}
- /* Setup details for the syncronisation */
+ /* Setup details for the synchronisation */
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_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
!NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
- r->out.error_string = talloc_asprintf(samsync_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
+ r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
talloc_free(samsync_ctx);
return nt_status;
}
if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
- r->out.error_string = talloc_strdup(samsync_ctx, "Credential chaining failed");
+ r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed");
talloc_free(samsync_ctx);
return NT_STATUS_ACCESS_DENIED;
}
char *error_string = NULL;
delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
/* 'Fix' elements, by decrypting and
- * de-obfustiating the data */
+ * de-obfuscating the data */
nt_status = fix_delta(delta_ctx,
creds,
+ r->in.rid_crypt,
dbsync.in.database_id,
&dbsync.out.delta_enum_array->delta_enum[d],
&error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
- r->out.error_string = talloc_steal(samsync_ctx, error_string);
+ r->out.error_string = talloc_steal(mem_ctx, error_string);
talloc_free(samsync_ctx);
return nt_status;
}
* write to an ldb */
nt_status = r->in.delta_fn(delta_ctx,
r->in.fn_ctx,
- creds,
dbsync.in.database_id,
&dbsync.out.delta_enum_array->delta_enum[d],
&error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
- r->out.error_string = talloc_steal(samsync_ctx, error_string);
+ r->out.error_string = talloc_steal(mem_ctx, error_string);
talloc_free(samsync_ctx);
return nt_status;
}
}
talloc_free(loop_ctx);
} while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
- nt_status = dbsync_nt_status;
+
+ 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;