1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

r8752: With all the infrustructure done, details like a SamSync migration

into LDB are actually quite easy.

This brings us the users, and sets basic domain information.

You are expected to have provisioned with the settings for the target
domain, and have joined the domain as a BDC.  Then simply 'net
samsync'.

Now we just need to flesh out the delta types.

Andrew Bartlett
This commit is contained in:
Andrew Bartlett 2005-07-25 06:33:51 +00:00 committed by Gerald (Jerry) Carter
parent d974bf3589
commit 1e0f7792bb
6 changed files with 467 additions and 0 deletions

View File

@ -180,6 +180,7 @@ struct libnet_DelShare;
struct libnet_Lookup;
struct libnet_SamDump;
struct libnet_SamSync;
struct libnet_samsync_ldb;
struct net_functable;
struct net_context;

View File

@ -10,6 +10,7 @@ ADD_OBJ_FILES = \
libnet/libnet_join.o \
libnet/libnet_vampire.o \
libnet/libnet_samdump.o \
libnet/libnet_samsync_ldb.o \
libnet/libnet_user.o \
libnet/libnet_share.o \
libnet/libnet_lookup.o \

View File

@ -0,0 +1,414 @@
/*
Unix SMB/CIFS implementation.
Extract the user/system database from a remote SamSync server
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
Copyright (C) Andrew Tridgell 2004
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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.
*/
#include "includes.h"
#include "libnet/libnet.h"
#include "librpc/gen_ndr/ndr_netlogon.h"
#include "librpc/gen_ndr/ndr_samr.h"
#include "dlinklist.h"
#include "lib/ldb/include/ldb.h"
struct samsync_ldb_secret {
struct samsync_ldb_secret *prev, *next;
DATA_BLOB secret;
char *name;
NTTIME mtime;
};
struct samsync_ldb_trusted_domain {
struct samsync_ldb_trusted_domain *prev, *next;
struct dom_sid *sid;
char *name;
};
struct samsync_ldb_state {
struct dom_sid *dom_sid[3];
struct ldb_context *sam_ldb;
char *base_dn[3];
struct samsync_ldb_secret *secrets;
struct samsync_ldb_trusted_domain *trusted_domains;
};
static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
struct samsync_ldb_state *state,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta)
{
struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
const char *domain_name = domain->domain_name.string;
struct ldb_message *msg;
int ret;
if (database == SAM_DATABASE_DOMAIN) {
const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
struct ldb_message **msgs_domain;
int ret_domain;
ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
"(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
domain_name);
if (ret_domain == -1) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
if (ret_domain != 1) {
return NT_STATUS_NO_SUCH_DOMAIN;
}
state->base_dn[database]
= talloc_steal(state, samdb_result_string(msgs_domain[0],
"nCName", NULL));
state->dom_sid[database]
= talloc_steal(state,
samdb_search_dom_sid(state->sam_ldb, state,
state->base_dn[database], "objectSid",
"dn=%s", state->base_dn[database]));
} else if (database == SAM_DATABASE_BUILTIN) {
/* work out the builtin_dn - useful for so many calls its worth
fetching here */
state->base_dn[database]
= talloc_steal(state,
samdb_search_string(state->sam_ldb, mem_ctx, NULL,
"dn", "objectClass=builtinDomain"));
state->dom_sid[database]
= dom_sid_parse_talloc(state, SID_BUILTIN);
} else {
/* PRIVs DB */
return NT_STATUS_INVALID_PARAMETER;
}
msg = ldb_msg_new(mem_ctx);
if (msg == NULL) {
return NT_STATUS_NO_MEMORY;
}
msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
if (!msg->dn) {
return NT_STATUS_NO_MEMORY;
}
samdb_msg_add_string(state->sam_ldb, mem_ctx,
msg, "oEMInformation", domain->comment.string);
samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
msg, "forceLogff", domain->force_logoff_time);
samdb_msg_add_uint(state->sam_ldb, mem_ctx,
msg, "minPwdLen", domain->min_password_length);
samdb_msg_add_int64(state->sam_ldb, mem_ctx,
msg, "maxPwdAge", domain->max_password_age);
samdb_msg_add_int64(state->sam_ldb, mem_ctx,
msg, "minPwdAge", domain->min_password_age);
samdb_msg_add_uint(state->sam_ldb, mem_ctx,
msg, "pwdHistoryLength", domain->password_history_length);
samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
msg, "modifiedCountAtLastProm",
domain->sequence_num);
samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
msg, "creationTime", domain->domain_create_time);
/* TODO: Account lockout, password properties */
ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
if (ret) {
return NT_STATUS_INTERNAL_ERROR;
}
return NT_STATUS_OK;
}
static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
struct samsync_ldb_state *state,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta)
{
uint32_t rid = delta->delta_id_union.rid;
struct netr_DELTA_USER *user = delta->delta_union.user;
const char *container, *obj_class;
char *cn_name;
int cn_name_len;
struct ldb_message *msg;
struct ldb_message **msgs;
int ret;
uint32_t acb;
BOOL add = False;
const char *attrs[] = { NULL };
msg = ldb_msg_new(mem_ctx);
if (msg == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* search for the user, by rid */
ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
"(&(objectClass=user)(objectSid=%s))",
ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
if (ret == -1) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
} else if (ret == 0) {
add = True;
} else if (ret > 1) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
} else {
msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
}
cn_name = talloc_strdup(mem_ctx, user->account_name.string);
NT_STATUS_HAVE_NO_MEMORY(cn_name);
cn_name_len = strlen(cn_name);
#define ADD_OR_DEL(type, attrib, field) do {\
if (user->field) { \
samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
attrib, user->field); \
} else if (!add) { \
samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
attrib); \
} \
} while (0);
ADD_OR_DEL(string, "samAccountName", account_name.string);
ADD_OR_DEL(string, "displayName", full_name.string);
if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
"objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
return NT_STATUS_NO_MEMORY;
}
ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
ADD_OR_DEL(string, "homeDirectory", home_directory.string);
ADD_OR_DEL(string, "homeDrive", home_drive.string);
ADD_OR_DEL(string, "scriptPath", logon_script.string);
ADD_OR_DEL(string, "description", description.string);
ADD_OR_DEL(string, "userWorkstations", workstations.string);
ADD_OR_DEL(uint64, "lastLogon", last_logon);
ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
/* TODO: Logon hours */
ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
ADD_OR_DEL(uint, "logonCount", logon_count);
ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
"userAccountConrol", user->acct_flags) != 0) {
return NT_STATUS_NO_MEMORY;
}
/* Passwords */
samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
"unicodePwd");
if (user->lm_password_present) {
samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
"lmPwdHash", &user->lmpassword);
} else {
samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
"lmPwdHash");
}
if (user->nt_password_present) {
samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
"ntPwdHash", &user->ntpassword);
} else {
samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
"ntPwdHash");
}
ADD_OR_DEL(string, "comment", comment.string);
ADD_OR_DEL(string, "userParameters", parameters.string);
ADD_OR_DEL(uint, "countryCode", country_code);
ADD_OR_DEL(uint, "codePage", code_page);
ADD_OR_DEL(string, "profilePath", profile_path.string);
acb = user->acct_flags;
if (acb & (ACB_WSTRUST)) {
cn_name[cn_name_len - 1] = '\0';
container = "Computers";
obj_class = "computer";
} else if (acb & ACB_SVRTRUST) {
if (cn_name[cn_name_len - 1] != '$') {
return NT_STATUS_FOOBAR;
}
cn_name[cn_name_len - 1] = '\0';
container = "Domain Controllers";
obj_class = "computer";
} else {
container = "Users";
obj_class = "user";
}
if (add) {
samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
"objectClass", obj_class);
msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
cn_name, container, state->base_dn[database]);
if (!msg->dn) {
return NT_STATUS_NO_MEMORY;
}
ret = samdb_add(state->sam_ldb, mem_ctx, msg);
if (ret != 0) {
DEBUG(0,("Failed to create user record %s\n", msg->dn));
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
} else {
ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
if (ret != 0) {
DEBUG(0,("Failed to modify user record %s\n", msg->dn));
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
}
return NT_STATUS_OK;
}
static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
struct samsync_ldb_state *state,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta)
{
uint32_t rid = delta->delta_id_union.rid;
struct netr_DELTA_GROUP *group = delta->delta_union.group;
const char *groupname = group->group_name.string;
return NT_STATUS_OK;
}
static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
void *private,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
NTSTATUS nt_status = NT_STATUS_OK;
struct samsync_ldb_state *state = private;
*error_string = NULL;
switch (delta->delta_type) {
case NETR_DELTA_DOMAIN:
{
nt_status = samsync_ldb_handle_domain(mem_ctx,
state,
creds,
database,
delta);
break;
}
case NETR_DELTA_USER:
{
nt_status = samsync_ldb_handle_user(mem_ctx,
state,
creds,
database,
delta);
break;
}
case NETR_DELTA_GROUP:
{
nt_status = samsync_ldb_handle_group(mem_ctx,
state,
creds,
database,
delta);
break;
}
default:
/* Can't dump them all right now */
break;
}
return nt_status;
}
static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
{
NTSTATUS nt_status;
struct libnet_SamSync r2;
struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
if (!state) {
return NT_STATUS_NO_MEMORY;
}
state->secrets = NULL;
state->trusted_domains = NULL;
state->sam_ldb = samdb_connect(state);
r2.error_string = NULL;
r2.delta_fn = libnet_samsync_ldb_fn;
r2.fn_ctx = state;
r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
r->error_string = r2.error_string;
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(state);
return nt_status;
}
talloc_free(state);
return nt_status;
}
static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
{
NTSTATUS nt_status;
struct libnet_samsync_ldb r2;
r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
r2.error_string = NULL;
nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
r->error_string = r2.error_string;
return nt_status;
}
NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
{
switch (r->level) {
case LIBNET_SAMSYNC_LDB_GENERIC:
return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
case LIBNET_SAMSYNC_LDB_NETLOGON:
return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
}
return NT_STATUS_INVALID_LEVEL;
}

View File

@ -43,3 +43,13 @@ struct libnet_SamDump {
char *error_string;
};
enum libnet_samsync_ldb_level {
LIBNET_SAMSYNC_LDB_GENERIC,
LIBNET_SAMSYNC_LDB_NETLOGON,
};
struct libnet_samsync_ldb {
enum libnet_samsync_ldb_level level;
char *error_string;
};

View File

@ -106,6 +106,7 @@ static const struct net_functable net_functable[] = {
{"time", "get remote server's time\n", net_time, net_time_usage},
{"join", "join a domain\n", net_join, net_join_usage},
{"samdump", "dump the sam of a domain\n", net_samdump, net_samdump_usage},
{"samsync", "syncrosnise into the local ldb the sam of a domain\n", net_samsync_ldb, net_samsync_ldb_usage},
{"user", "manage user accounts\n", net_user, net_user_usage},
{NULL, NULL, NULL, NULL}
};

View File

@ -64,3 +64,43 @@ int net_samdump_help(struct net_context *ctx, int argc, const char **argv)
d_printf("Dumps the sam of the domain we are joined to.\n");
return 0;
}
int net_samsync_ldb(struct net_context *ctx, int argc, const char **argv)
{
NTSTATUS status;
struct libnet_context *libnetctx;
struct libnet_samsync_ldb r;
libnetctx = libnet_context_init(NULL);
if (!libnetctx) {
return -1;
}
libnetctx->cred = ctx->credentials;
r.level = LIBNET_SAMSYNC_LDB_GENERIC;
r.error_string = NULL;
status = libnet_samsync_ldb(libnetctx, ctx->mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("libnet_samsync_ldb returned %s: %s\n",
nt_errstr(status),
r.error_string));
return -1;
}
talloc_free(libnetctx);
return 0;
}
int net_samsync_ldb_usage(struct net_context *ctx, int argc, const char **argv)
{
d_printf("net samsync_ldb\n");
return 0;
}
int net_samsync_ldb_help(struct net_context *ctx, int argc, const char **argv)
{
d_printf("Syncrosnise into the local ldb the SAM of a domain.\n");
return 0;
}