diff options
Diffstat (limited to 'source3/sam/gumm_tdb.c')
-rw-r--r-- | source3/sam/gumm_tdb.c | 891 |
1 files changed, 761 insertions, 130 deletions
diff --git a/source3/sam/gumm_tdb.c b/source3/sam/gumm_tdb.c index 52eaab9e17..53ea872a11 100644 --- a/source3/sam/gumm_tdb.c +++ b/source3/sam/gumm_tdb.c @@ -23,7 +23,6 @@ */ #include "includes.h" -#include "gums.h" #include "tdbsam2.h" #include "tdbsam2_parse_info.h" @@ -31,15 +30,25 @@ static int tdbgumm_debug_level = DBGC_ALL; #undef DBGC_CLASS #define DBGC_CLASS tdbgumm_debug_level -#define TDBSAM_VERSION "20021215" +#define TDBSAM_VERSION 20021215 #define TDB_FILE_NAME "tdbsam2.tdb" -#define DOMAINPREFIX "DOMAIN_" -#define OBJECTPREFIX "OBJECT_" +#define NAMEPREFIX "NAME_" #define SIDPREFIX "SID_" #define PRIVILEGEPREFIX "PRIV_" #define TDB_FORMAT_STRING "ddB" +#define TALLOC_CHECK(ptr, err, label) do { if ((ptr) == NULL) { DEBUG(0, ("%s: Out of memory!\n", __FUNCTION__)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0) +#define SET_OR_FAIL(func, label) do { if (NT_STATUS_IS_ERR(func)) { DEBUG(0, ("%s: Setting gums object data failed!\n", __FUNCTION__)); goto label; } } while(0) + +struct tdbsam2_enum_objs { + uint32 type; + fstring dom_sid; + TDB_CONTEXT *db; + TDB_DATA key; + struct tdbsam2_enum_objs *next; +}; + union tdbsam2_data { struct tdbsam2_domain_data *domain; struct tdbsam2_user_data *user; @@ -48,86 +57,363 @@ union tdbsam2_data { struct tdbsam2_object { uint32 type; + uint32 version; union tdbsam2_data data; }; static TDB_CONTEXT *tdbsam2_db; -#define TALLOC_CHECK(ptr, err, label) do { if ((ptr) == NULL) { DEBUG(0, ("%s: Out of memory!\n", __FUNCTION__)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0) -#define SET_OR_FAIL(func, label) do { if (NT_STATUS_IS_ERR(func)) { DEBUG(0, ("%s: Setting gums object data failed!\n", __FUNCTION__)); goto label; } } while(0) +struct tdbsam2_enum_objs **teo_handlers; + +static NTSTATUS init_tdbsam2_object_from_buffer(struct tdbsam2_object *object, TALLOC_CTX *mem_ctx, char *buffer, int size) +{ + + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + int iret; + char *obj_data; + int data_size = 0; + int len; + + len = tdb_unpack (buffer, size, TDB_FORMAT_STRING, + &(object->version), + &(object->type), + &data_size, &obj_data); + + if (len == -1) + goto done; + + /* version is checked inside this function so that backward compatibility code can be + called eventually. + this way we can easily handle database format upgrades */ + if (object->version != TDBSAM_VERSION) { + DEBUG(3,("init_tdbsam2_object_from_buffer: Error, db object has wrong tdbsam version!\n")); + goto done; + } + + /* be sure the string is terminated before trying to parse it */ + if (obj_data[data_size - 1] != '\0') + obj_data[data_size - 1] = '\0'; + + switch (object->type) { + case GUMS_OBJ_DOMAIN: + object->data.domain = (struct tdbsam2_domain_data *)talloc(mem_ctx, sizeof(struct tdbsam2_domain_data)); + TALLOC_CHECK(object->data.domain, ret, done); + memset(object->data.domain, 0, sizeof(struct tdbsam2_domain_data)); + + iret = gen_parse(mem_ctx, pinfo_tdbsam2_domain_data, (char *)(object->data.domain), obj_data); + break; + case GUMS_OBJ_GROUP: + case GUMS_OBJ_ALIAS: + object->data.group = (struct tdbsam2_group_data *)talloc(mem_ctx, sizeof(struct tdbsam2_group_data)); + TALLOC_CHECK(object->data.group, ret, done); + memset(object->data.group, 0, sizeof(struct tdbsam2_group_data)); + + iret = gen_parse(mem_ctx, pinfo_tdbsam2_group_data, (char *)(object->data.group), obj_data); + break; + case GUMS_OBJ_NORMAL_USER: + object->data.user = (struct tdbsam2_user_data *)talloc(mem_ctx, sizeof(struct tdbsam2_user_data)); + TALLOC_CHECK(object->data.user, ret, done); + memset(object->data.user, 0, sizeof(struct tdbsam2_user_data)); -static NTSTATUS init_tdbsam2_object_from_buffer(struct tdbsam2_object *object, TALLOC_CTX *mem_ctx, char *buffer, int size) { + iret = gen_parse(mem_ctx, pinfo_tdbsam2_user_data, (char *)(object->data.user), obj_data); + break; + default: + DEBUG(3,("init_tdbsam2_object_from_buffer: Error, wrong object type number!\n")); + goto done; + } + + if (iret != 0) { + DEBUG(0,("init_tdbsam2_object_from_buffer: Fatal Error! Unable to parse object!\n")); + DEBUG(0,("init_tdbsam2_object_from_buffer: DB Corrupted ?")); + goto done; + } + + ret = NT_STATUS_OK; +done: + SAFE_FREE(obj_data); + return ret; +} + +static NTSTATUS init_buffer_from_tdbsam2_object(char **buffer, size_t *len, TALLOC_CTX *mem_ctx, struct tdbsam2_object *object) +{ + + NTSTATUS ret; + char *buf1 = NULL; + size_t buflen; + + if (!buffer) + return NT_STATUS_INVALID_PARAMETER; + + switch (object->type) { + case GUMS_OBJ_DOMAIN: + buf1 = gen_dump(mem_ctx, pinfo_tdbsam2_domain_data, (char *)(object->data.domain), 0); + break; + case GUMS_OBJ_GROUP: + case GUMS_OBJ_ALIAS: + buf1 = gen_dump(mem_ctx, pinfo_tdbsam2_group_data, (char *)(object->data.group), 0); + break; + case GUMS_OBJ_NORMAL_USER: + buf1 = gen_dump(mem_ctx, pinfo_tdbsam2_user_data, (char *)(object->data.user), 0); + break; + default: + DEBUG(3,("init_buffer_from_tdbsam2_object: Error, wrong object type number!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + if (buf1 == NULL) { + DEBUG(0, ("init_buffer_from_tdbsam2_object: Fatal Error! Unable to dump object!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + buflen = tdb_pack(NULL, 0, TDB_FORMAT_STRING, + TDBSAM_VERSION, + object->type, + strlen(buf1) + 1, buf1); + + *buffer = talloc(mem_ctx, buflen); + TALLOC_CHECK(*buffer, ret, done); + + *len = tdb_pack(*buffer, buflen, TDB_FORMAT_STRING, + TDBSAM_VERSION, + object->type, + strlen(buf1) + 1, buf1); + + if (*len != buflen) { + DEBUG(0, ("init_tdb_data_from_tdbsam2_object: somthing odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n", + buflen, *len)); + *buffer = NULL; + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + ret = NT_STATUS_OK; +done: + return ret; +} + +static NTSTATUS opentdb(void) +{ + if (!tdbsam2_db) { + pstring tdbfile; + get_private_directory(tdbfile); + pstrcat(tdbfile, "/"); + pstrcat(tdbfile, TDB_FILE_NAME); + + tdbsam2_db = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600); + if (!tdbsam2_db) + { + DEBUG(0, ("opentdb: Unable to open database (%s)!\n", tdbfile)); + return NT_STATUS_UNSUCCESSFUL; + } + } return NT_STATUS_OK; } -static NTSTATUS tdbsam2_opentdb(void) { +static NTSTATUS get_object_by_sid(TALLOC_CTX *mem_ctx, struct tdbsam2_object *obj, const DOM_SID *sid) +{ + NTSTATUS ret; + TDB_DATA data, key; + fstring keystr; + + if (!obj || !mem_ctx || !sid) + return NT_STATUS_INVALID_PARAMETER; + + if (NT_STATUS_IS_ERR(ret = opentdb())) { + return ret; + } + + slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid)); + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + data = tdb_fetch(tdbsam2_db, key); + if (!data.dptr) { + DEBUG(5, ("get_object_by_sid: Error fetching database, domain entry not found!\n")); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); + DEBUGADD(5, (" Key: %s\n", keystr)); + return NT_STATUS_UNSUCCESSFUL; + } + + if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(obj, mem_ctx, data.dptr, data.dsize))) { + SAFE_FREE(data.dptr); + DEBUG(0, ("get_object_by_sid: Error fetching database, malformed entry!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + SAFE_FREE(data.dptr); return NT_STATUS_OK; + } -static NTSTATUS tdbsam2_get_object_by_name(struct tdbsam2_object *obj, TALLOC_CTX *mem_ctx, const char* name) { +static NTSTATUS get_object_by_name(TALLOC_CTX *mem_ctx, struct tdbsam2_object *obj, const char* name) +{ NTSTATUS ret; TDB_DATA data, key; fstring keystr; fstring objname; + DOM_SID sid; + char *obj_sidstr; + int obj_version, obj_type, obj_sidstr_len, len; if (!obj || !mem_ctx || !name) return NT_STATUS_INVALID_PARAMETER; - if (tdbsam2_db == NULL) { - if (NT_STATUS_IS_ERR(ret = tdbsam2_opentdb())) { - goto done; - } + if (NT_STATUS_IS_ERR(ret = opentdb())) { + return ret; } unix_strlower(name, -1, objname, sizeof(objname)); - slprintf(keystr, sizeof(keystr)-1, "%s%s", OBJECTPREFIX, objname); + slprintf(keystr, sizeof(keystr)-1, "%s%s", NAMEPREFIX, objname); key.dptr = keystr; key.dsize = strlen(keystr) + 1; data = tdb_fetch(tdbsam2_db, key); if (!data.dptr) { - DEBUG(5, ("get_domain_sid: Error fetching database, domain entry not found!\n")); + DEBUG(5, ("get_object_by_name: Error fetching database, domain entry not found!\n")); DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); DEBUGADD(5, (" Key: %s\n", keystr)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; + return NT_STATUS_UNSUCCESSFUL; } - if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(obj, mem_ctx, data.dptr, data.dsize))) { - SAFE_FREE(data.dptr); - DEBUG(0, ("get_domain_sid: Error fetching database, malformed entry!\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } + len = tdb_unpack(data.dptr, data.dsize, TDB_FORMAT_STRING, + &obj_version, + &obj_type, + &obj_sidstr_len, &obj_sidstr); + SAFE_FREE(data.dptr); - ret = NT_STATUS_OK; + if (len == -1 || obj_version != TDBSAM_VERSION || obj_sidstr_len <= 0) { + DEBUG(5, ("get_object_by_name: Error unpacking database object!\n")); + return NT_STATUS_UNSUCCESSFUL; + } -done: - return ret; + if (!string_to_sid(&sid, obj_sidstr)) { + DEBUG(5, ("get_object_by_name: Error invalid sid string found in database object!\n")); + SAFE_FREE(obj_sidstr); + return NT_STATUS_UNSUCCESSFUL; + } + SAFE_FREE(obj_sidstr); + + return get_object_by_sid(mem_ctx, obj, &sid); } - -static NTSTATUS tdbsam2_store(struct tdbsam2_object *object) { +static NTSTATUS store_object(TALLOC_CTX *mem_ctx, struct tdbsam2_object *object, BOOL new_obj) +{ NTSTATUS ret; + TDB_DATA data, key, key2; + fstring keystr; + fstring namestr; + int flag, r; + + if (NT_STATUS_IS_ERR(ret = opentdb())) { + return ret; + } + + if (new_obj) { + flag = TDB_INSERT; + } else { + flag = TDB_MODIFY; + } + + ret = init_buffer_from_tdbsam2_object(&(data.dptr), &(data.dsize), mem_ctx, object); + if (NT_STATUS_IS_ERR(ret)) + return ret; + + switch (object->type) { + case GUMS_OBJ_DOMAIN: + slprintf(keystr, sizeof(keystr) - 1, "%s%s", SIDPREFIX, sid_string_static(object->data.domain->dom_sid)); + slprintf(namestr, sizeof(namestr) - 1, "%s%s", NAMEPREFIX, object->data.domain->name); + break; + case GUMS_OBJ_GROUP: + case GUMS_OBJ_ALIAS: + slprintf(keystr, sizeof(keystr) - 1, "%s%s", SIDPREFIX, sid_string_static(object->data.group->group_sid)); + slprintf(namestr, sizeof(namestr) - 1, "%s%s", NAMEPREFIX, object->data.group->name); + break; + case GUMS_OBJ_NORMAL_USER: + slprintf(keystr, sizeof(keystr) - 1, "%s%s", SIDPREFIX, sid_string_static(object->data.user->user_sid)); + slprintf(namestr, sizeof(namestr) - 1, "%s%s", NAMEPREFIX, object->data.user->name); + break; + default: + return NT_STATUS_UNSUCCESSFUL; + } + + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + if ((r = tdb_store(tdbsam2_db, key, data, flag)) != TDB_SUCCESS) { + DEBUG(0, ("store_object: Unable to modify SAM!\n")); + DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam2_db))); + DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr)); + if (r == TDB_ERR_EXISTS) return NT_STATUS_UNSUCCESSFUL; + return NT_STATUS_INTERNAL_DB_ERROR; + } + + key2.dptr = namestr; + key2.dsize = strlen(namestr) + 1; + + if ((r = tdb_store(tdbsam2_db, key2, key, flag)) != TDB_SUCCESS) { + DEBUG(0, ("store_object: Unable to modify SAM!\n")); + DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam2_db))); + DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr)); + if (r == TDB_ERR_EXISTS) return NT_STATUS_UNSUCCESSFUL; + return NT_STATUS_INTERNAL_DB_ERROR; + } +/* TODO: update the general database counter */ +/* TODO: update this entry counter too */ return NT_STATUS_OK; } -static NTSTATUS tdbsam2_get_next_sid(TALLOC_CTX *mem_ctx, DOM_SID *sid) { - +static NTSTATUS get_next_sid(TALLOC_CTX *mem_ctx, DOM_SID **sid) +{ NTSTATUS ret; + struct tdbsam2_object obj; + DOM_SID *dom_sid = get_global_sam_sid(); + uint32 new_rid; + +/* TODO: LOCK DOMAIN OBJECT */ + ret = get_object_by_sid(mem_ctx, &obj, dom_sid); + if (NT_STATUS_IS_ERR(ret)) { + DEBUG(0, ("get_next_sid: unable to get root Domain object!\n")); + ret = NT_STATUS_INTERNAL_DB_ERROR; + goto error; + } + + new_rid = obj.data.domain->next_rid; + + /* Increment the RID Counter */ + obj.data.domain->next_rid++; + + /* Store back Domain object */ + ret = store_object(mem_ctx, &obj, False); + if (NT_STATUS_IS_ERR(ret)) { + DEBUG(0, ("get_next_sid: unable to update root Domain object!\n")); + ret = NT_STATUS_INTERNAL_DB_ERROR; + goto error; + } +/* TODO: UNLOCK DOMAIN OBJECT */ + + *sid = sid_dup_talloc(mem_ctx, dom_sid); + TALLOC_CHECK(*sid, ret, error); + + if (!sid_append_rid(*sid, new_rid)) { + DEBUG(0, ("get_next_sid: unable to build new SID !?!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto error; + } return NT_STATUS_OK; -} -static NTSTATUS tdbsam2_user_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_user_data *userdata, uint32 type) { +error: + return ret; +} +static NTSTATUS user_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_user_data *userdata) +{ NTSTATUS ret; if (!object || !userdata) { @@ -180,12 +466,12 @@ static NTSTATUS tdbsam2_user_data_to_gums_object(GUMS_OBJECT **object, struct td SET_OR_FAIL(gums_set_user_unknown_5(*object, userdata->unknown_5), error); SET_OR_FAIL(gums_set_user_unknown_6(*object, userdata->unknown_6), error); - SET_OR_FAIL(gums_set_user_logon_time(*object, userdata->logon_time), error); - SET_OR_FAIL(gums_set_user_logoff_time(*object, userdata->logoff_time), error); - SET_OR_FAIL(gums_set_user_kickoff_time(*object, userdata->kickoff_time), error); - SET_OR_FAIL(gums_set_user_pass_last_set_time(*object, userdata->pass_last_set_time), error); - SET_OR_FAIL(gums_set_user_pass_can_change_time(*object, userdata->pass_can_change_time), error); - SET_OR_FAIL(gums_set_user_pass_must_change_time(*object, userdata->pass_must_change_time), error); + SET_OR_FAIL(gums_set_user_logon_time(*object, *(userdata->logon_time)), error); + SET_OR_FAIL(gums_set_user_logoff_time(*object, *(userdata->logoff_time)), error); + SET_OR_FAIL(gums_set_user_kickoff_time(*object, *(userdata->kickoff_time)), error); + SET_OR_FAIL(gums_set_user_pass_last_set_time(*object, *(userdata->pass_last_set_time)), error); + SET_OR_FAIL(gums_set_user_pass_can_change_time(*object, *(userdata->pass_can_change_time)), error); + SET_OR_FAIL(gums_set_user_pass_must_change_time(*object, *(userdata->pass_must_change_time)), error); ret = NT_STATUS_OK; return ret; @@ -196,8 +482,8 @@ error: return ret; } -static NTSTATUS tdbsam2_group_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_group_data *groupdata, uint32 type) { - +static NTSTATUS group_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_group_data *groupdata) +{ NTSTATUS ret; if (!object || !groupdata) { @@ -226,11 +512,12 @@ error: return ret; } -static NTSTATUS tdbsam2_domain_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_domain_data *domdata, uint32 type) { +static NTSTATUS domain_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_domain_data *domdata) +{ NTSTATUS ret; - if (!object || !domdata) { + if (!object || !*object || !domdata) { DEBUG(0, ("tdbsam2_domain_data_to_gums_object: no NULL pointers are accepted here!\n")); return NT_STATUS_UNSUCCESSFUL; } @@ -253,7 +540,8 @@ error: return ret; } -static NTSTATUS tdbsam2_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_object *data) { +static NTSTATUS data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_object *data) +{ NTSTATUS ret; @@ -271,16 +559,16 @@ static NTSTATUS tdbsam2_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2 switch (data->type) { case GUMS_OBJ_DOMAIN: - ret = tdbsam2_domain_data_to_gums_object(object, data->data.domain, data->type); + ret = domain_data_to_gums_object(object, data->data.domain); break; case GUMS_OBJ_NORMAL_USER: - ret = tdbsam2_user_data_to_gums_object(object, data->data.user, data->type); + ret = user_data_to_gums_object(object, data->data.user); break; case GUMS_OBJ_GROUP: case GUMS_OBJ_ALIAS: - ret = tdbsam2_group_data_to_gums_object(object, data->data.group, data->type); + ret = group_data_to_gums_object(object, data->data.group); break; default: @@ -292,83 +580,118 @@ done: } +/* GUMM object functions */ +static NTSTATUS tdbsam2_get_domain_sid(DOM_SID *sid, const char* name) +{ + NTSTATUS ret; + struct tdbsam2_object obj; + TALLOC_CTX *mem_ctx; + fstring domname; -/* GUMM object functions */ + if (!sid || !name) + return NT_STATUS_INVALID_PARAMETER; -static NTSTATUS get_domain_sid(DOM_SID *sid, const char* name) { + mem_ctx = talloc_init("tdbsam2_get_domain_sid"); + if (!mem_ctx) { + DEBUG(0, ("tdbsam2_new_object: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + if (NT_STATUS_IS_ERR(ret = opentdb())) { + goto done; + } + + unix_strlower(name, -1, domname, sizeof(domname)); + + ret = get_object_by_name(mem_ctx, &obj, domname); + + if (NT_STATUS_IS_ERR(ret)) { + DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n")); + goto done; + } + + if (obj.type != GUMS_OBJ_DOMAIN) { + DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + sid_copy(sid, obj.data.domain->dom_sid); + + ret = NT_STATUS_OK; + +done: + talloc_destroy(mem_ctx); + return ret; +} + +static NTSTATUS tdbsam2_set_domain_sid (const DOM_SID *sid, const char *name) +{ NTSTATUS ret; struct tdbsam2_object obj; TALLOC_CTX *mem_ctx; - TDB_DATA data, key; - fstring keystr; fstring domname; if (!sid || !name) return NT_STATUS_INVALID_PARAMETER; - mem_ctx = talloc_init("get_domain_sid"); + mem_ctx = talloc_init("tdbsam2_set_domain_sid"); if (!mem_ctx) { DEBUG(0, ("tdbsam2_new_object: Out of memory!\n")); return NT_STATUS_NO_MEMORY; } if (tdbsam2_db == NULL) { - if (NT_STATUS_IS_ERR(ret = tdbsam2_opentdb())) { + if (NT_STATUS_IS_ERR(ret = opentdb())) { goto done; } } unix_strlower(name, -1, domname, sizeof(domname)); - slprintf(keystr, sizeof(keystr)-1, "%s%s", DOMAINPREFIX, domname); - key.dptr = keystr; - key.dsize = strlen(keystr) + 1; +/* TODO: we need to lock this entry until updated! */ - data = tdb_fetch(tdbsam2_db, key); - if (!data.dptr) { - DEBUG(5, ("get_domain_sid: Error fetching database, domain entry not found!\n")); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); - DEBUGADD(5, (" Key: %s\n", keystr)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } + ret = get_object_by_name(mem_ctx, &obj, domname); - if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(&obj, mem_ctx, data.dptr, data.dsize))) { - SAFE_FREE(data.dptr); - DEBUG(0, ("get_domain_sid: Error fetching database, malformed entry!\n")); - ret = NT_STATUS_UNSUCCESSFUL; + if (NT_STATUS_IS_ERR(ret)) { + DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n")); goto done; } - SAFE_FREE(data.dptr); if (obj.type != GUMS_OBJ_DOMAIN) { - DEBUG(5, ("get_domain_sid: Requested object is not a domain!\n")); + DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n")); ret = NT_STATUS_UNSUCCESSFUL; goto done; } - sid_copy(sid, obj.data.domain->dom_sid); + sid_copy(obj.data.domain->dom_sid, sid); - ret = NT_STATUS_OK; + ret = store_object(mem_ctx, &obj, False); done: +/* TODO: unlock here */ if (mem_ctx) talloc_destroy(mem_ctx); return ret; } - NTSTATUS (*set_domain_sid) (const DOM_SID *sid, const char *name); - +/* TODO */ NTSTATUS (*get_sequence_number) (void); -static NTSTATUS tdbsam2_new_object(DOM_SID **sid, const char *name, const int obj_type) { +extern DOM_SID global_sid_NULL; + +static NTSTATUS tdbsam2_new_object(DOM_SID *sid, const char *name, const int obj_type) +{ NTSTATUS ret; struct tdbsam2_object obj; TALLOC_CTX *mem_ctx; + NTTIME zero_time = {0,0}; + const char *defpw = "NOPASSWORDXXXXXX"; + uint8 defhours[21] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}; if (!sid || !name) { DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n")); @@ -381,19 +704,51 @@ static NTSTATUS tdbsam2_new_object(DOM_SID **sid, const char *name, const int ob return NT_STATUS_NO_MEMORY; } + obj.type = obj_type; + obj.version = TDBSAM_VERSION; + switch (obj_type) { case GUMS_OBJ_NORMAL_USER: obj.data.user = (struct tdbsam2_user_data *)talloc_zero(mem_ctx, sizeof(struct tdbsam2_user_data)); TALLOC_CHECK(obj.data.user, ret, done); - /*obj.data.user->sec_desc*/ - - tdbsam2_get_next_sid(mem_ctx, obj.data.user->user_sid); + get_next_sid(mem_ctx, &(obj.data.user->user_sid)); TALLOC_CHECK(obj.data.user->user_sid, ret, done); + sid_copy(sid, obj.data.user->user_sid); obj.data.user->name = talloc_strdup(mem_ctx, name); TALLOC_CHECK(obj.data.user, ret, done); + obj.data.user->xcounter = 1; + /*obj.data.user->sec_desc*/ + obj.data.user->description = ""; + obj.data.user->group_sid = &global_sid_NULL; + obj.data.user->logon_time = &zero_time; + obj.data.user->logoff_time = &zero_time; + obj.data.user->kickoff_time = &zero_time; + obj.data.user->pass_last_set_time = &zero_time; + obj.data.user->pass_can_change_time = &zero_time; + obj.data.user->pass_must_change_time = &zero_time; + + obj.data.user->full_name = ""; + obj.data.user->home_dir = ""; + obj.data.user->dir_drive = ""; + obj.data.user->logon_script = ""; + obj.data.user->profile_path = ""; + obj.data.user->workstations = ""; + obj.data.user->unknown_str = ""; + obj.data.user->munged_dial = ""; + + obj.data.user->lm_pw_ptr = defpw; + obj.data.user->nt_pw_ptr = defpw; + + obj.data.user->logon_divs = 168; + obj.data.user->hours_len = 21; + obj.data.user->hours = &defhours; + + obj.data.user->unknown_3 = 0x00ffffff; + obj.data.user->unknown_5 = 0x00020000; + obj.data.user->unknown_6 = 0x000004ec; break; case GUMS_OBJ_GROUP: @@ -401,133 +756,373 @@ static NTSTATUS tdbsam2_new_object(DOM_SID **sid, const char *name, const int ob obj.data.group = (struct tdbsam2_group_data *)talloc_zero(mem_ctx, sizeof(struct tdbsam2_group_data)); TALLOC_CHECK(obj.data.group, ret, done); - /*obj.data.user->sec_desc*/ - - tdbsam2_get_next_sid(mem_ctx, obj.data.group->group_sid); + get_next_sid(mem_ctx, &(obj.data.group->group_sid)); TALLOC_CHECK(obj.data.group->group_sid, ret, done); + sid_copy(sid, obj.data.group->group_sid); obj.data.group->name = talloc_strdup(mem_ctx, name); TALLOC_CHECK(obj.data.group, ret, done); + obj.data.group->xcounter = 1; + /*obj.data.group->sec_desc*/ + obj.data.group->description = ""; + break; case GUMS_OBJ_DOMAIN: - /* TODO: SHOULD WE ALLOW TO CREATE NEW DOMAINS ? */ + + /* FIXME: should we check against global_sam_sid to make it impossible + to store more than one domain ? */ + + obj.data.domain = (struct tdbsam2_domain_data *)talloc_zero(mem_ctx, sizeof(struct tdbsam2_domain_data)); + TALLOC_CHECK(obj.data.domain, ret, done); + + obj.data.domain->dom_sid = sid_dup_talloc(mem_ctx, get_global_sam_sid()); + TALLOC_CHECK(obj.data.domain->dom_sid, ret, done); + sid_copy(sid, obj.data.domain->dom_sid); + + obj.data.domain->name = talloc_strdup(mem_ctx, name); + TALLOC_CHECK(obj.data.domain, ret, done); + + obj.data.domain->xcounter = 1; + /*obj.data.domain->sec_desc*/ + obj.data.domain->next_rid = 0x3e9; + obj.data.domain->description = ""; + + ret = NT_STATUS_OK; + break; default: ret = NT_STATUS_UNSUCCESSFUL; goto done; } - ret = tdbsam2_store(&obj); + ret = store_object(mem_ctx, &obj, True); done: talloc_destroy(mem_ctx); return ret; } -static NTSTATUS tdbsam2_delete_object(const DOM_SID *sid) { - +static NTSTATUS tdbsam2_delete_object(const DOM_SID *sid) +{ NTSTATUS ret; struct tdbsam2_object obj; TALLOC_CTX *mem_ctx; TDB_DATA data, key; fstring keystr; - fstring sidstr; - char *obj_name = NULL; - int obj_type, obj_version, len; if (!sid) { - DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n")); + DEBUG(0, ("tdbsam2_delete_object: no NULL pointers are accepted here!\n")); return NT_STATUS_INVALID_PARAMETER; } mem_ctx = talloc_init("tdbsam2_delete_object"); if (!mem_ctx) { - DEBUG(0, ("tdbsam2_new_object: Out of memory!\n")); + DEBUG(0, ("tdbsam2_delete_object: Out of memory!\n")); return NT_STATUS_NO_MEMORY; } if (tdbsam2_db == NULL) { - if (NT_STATUS_IS_ERR(ret = tdbsam2_opentdb())) { + if (NT_STATUS_IS_ERR(ret = opentdb())) { goto done; } } - sid_to_string(sidstr, sid); - - slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sidstr); + slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid)); key.dptr = keystr; key.dsize = strlen(keystr) + 1; data = tdb_fetch(tdbsam2_db, key); if (!data.dptr) { - DEBUG(5, ("get_domain_sid: Error fetching database, SID entry not found!\n")); + DEBUG(5, ("tdbsam2_delete_object: Error fetching database, SID entry not found!\n")); DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); DEBUGADD(5, (" Key: %s\n", keystr)); ret = NT_STATUS_UNSUCCESSFUL; goto done; } - len = tdb_unpack(data.dptr, data.dsize, TDB_FORMAT_STRING, - &obj_version, - &obj_type, - &obj_name); + if (tdb_delete(tdbsam2_db, key) != TDB_SUCCESS) { + DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n")); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); + DEBUGADD(5, (" Key: %s\n", keystr)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } - if (len == -1) { + if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(&obj, mem_ctx, data.dptr, data.dsize))) { + SAFE_FREE(data.dptr); + DEBUG(0, ("tdbsam2_delete_object: Error fetching database, malformed entry!\n")); ret = NT_STATUS_UNSUCCESSFUL; goto done; } + switch (obj.type) { + case GUMS_OBJ_DOMAIN: + /* TODO: SHOULD WE ALLOW TO DELETE DOMAINS ? */ + slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, obj.data.domain->name); + break; + case GUMS_OBJ_GROUP: + case GUMS_OBJ_ALIAS: + slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, obj.data.group->name); + break; + case GUMS_OBJ_NORMAL_USER: + slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, obj.data.user->name); + break; + default: + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + if (tdb_delete(tdbsam2_db, key) != TDB_SUCCESS) { - DEBUG(5, ("tdbsam2_object_delete: Error deleting object!\n")); + DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n")); DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); DEBUGADD(5, (" Key: %s\n", keystr)); ret = NT_STATUS_UNSUCCESSFUL; goto done; - } + } - switch (obj_type) { - case GUMS_OBJ_NORMAL_USER: - case GUMS_OBJ_GROUP: - case GUMS_OBJ_ALIAS: - - slprintf(keystr, sizeof(keystr)-1, "%s%s", OBJECTPREFIX, obj_name); - key.dptr = keystr; - key.dsize = strlen(keystr) + 1; - - if (tdb_delete(tdbsam2_db, key) != TDB_SUCCESS) { - DEBUG(5, ("tdbsam2_object_delete: Error deleting object!\n")); - DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db))); - DEBUGADD(5, (" Key: %s\n", keystr)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; +/* TODO: update the general database counter */ + +done: + SAFE_FREE(data.dptr); + talloc_destroy(mem_ctx); + return ret; +} + +static NTSTATUS tdbsam2_get_object_from_sid(GUMS_OBJECT **object, const DOM_SID *sid, const int obj_type) +{ + NTSTATUS ret; + struct tdbsam2_object obj; + TALLOC_CTX *mem_ctx; + + if (!object || !sid) { + DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + mem_ctx = talloc_init("tdbsam2_get_object_from_sid"); + if (!mem_ctx) { + DEBUG(0, ("tdbsam2_get_object_from_sid: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + ret = get_object_by_sid(mem_ctx, &obj, sid); + if (NT_STATUS_IS_ERR(ret) || (obj_type && obj.type != obj_type)) { + DEBUG(0, ("tdbsam2_get_object_from_sid: error fetching object or wrong object type!\n")); + goto done; + } + + ret = data_to_gums_object(object, &obj); + if (NT_STATUS_IS_ERR(ret)) { + DEBUG(0, ("tdbsam2_get_object_from_sid: error setting object data!\n")); + goto done; + } + +done: + talloc_destroy(mem_ctx); + return ret; +} + +static NTSTATUS tdbsam2_get_object_from_name(GUMS_OBJECT **object, const char *name, const int obj_type) +{ + NTSTATUS ret; + struct tdbsam2_object obj; + TALLOC_CTX *mem_ctx; + + if (!object || !name) { + DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + mem_ctx = talloc_init("tdbsam2_get_object_from_sid"); + if (!mem_ctx) { + DEBUG(0, ("tdbsam2_get_object_from_sid: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + ret = get_object_by_name(mem_ctx, &obj, name); + if (NT_STATUS_IS_ERR(ret) || (obj_type && obj.type != obj_type)) { + DEBUG(0, ("tdbsam2_get_object_from_sid: error fetching object or wrong object type!\n")); + goto done; + } + + ret = data_to_gums_object(object, &obj); + if (NT_STATUS_IS_ERR(ret)) { + DEBUG(0, ("tdbsam2_get_object_from_sid: error setting object data!\n")); + goto done; + } + +done: + talloc_destroy(mem_ctx); + return ret; +} + + /* This function is used to get the list of all objects changed since base_time, it is + used to support PDC<->BDC synchronization */ + NTSTATUS (*get_updated_objects) (GUMS_OBJECT **objects, const NTTIME base_time); + +static NTSTATUS tdbsam2_enumerate_objects_start(void *handle, const DOM_SID *sid, const int obj_type) +{ + struct tdbsam2_enum_objs *teo, *t; + pstring tdbfile; + + teo = (struct tdbsam2_enum_objs *)calloc(1, sizeof(struct tdbsam2_enum_objs)); + if (!teo) { + DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + teo->type = obj_type; + if (sid) { + sid_to_string(teo->dom_sid, sid); + } + + get_private_directory(tdbfile); + pstrcat(tdbfile, "/"); + pstrcat(tdbfile, TDB_FILE_NAME); + + teo->db = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDONLY, 0600); + if (!teo->db) + { + DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", tdbfile)); + SAFE_FREE(teo); + return NT_STATUS_UNSUCCESSFUL; + } + + if (!teo_handlers) { + *teo_handlers = teo; + } else { + t = *teo_handlers; + while (t->next) { + t = t->next; + } + t->next = teo; + } + + handle = teo; + + teo->key = tdb_firstkey(teo->db); + + return NT_STATUS_OK; +} + +static NTSTATUS tdbsam2_enumerate_objects_get_next(GUMS_OBJECT **object, void *handle) +{ + NTSTATUS ret; + TALLOC_CTX *mem_ctx; + TDB_DATA data; + struct tdbsam2_enum_objs *teo; + struct tdbsam2_object obj; + const char *prefix = SIDPREFIX; + const int preflen = strlen(prefix); + + if (!object || !handle) { + DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + teo = (struct tdbsam2_enum_objs *)handle; + + mem_ctx = talloc_init("tdbsam2_enumerate_objects_get_next"); + if (!mem_ctx) { + DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + while ((teo->key.dsize != 0)) { + int len, version, type, size; + char *ptr; + + if (strncmp(teo->key.dptr, prefix, preflen)) { + teo->key = tdb_nextkey(teo->db, teo->key); + continue; + } + + if (teo->dom_sid) { + if (strncmp(&(teo->key.dptr[preflen]), teo->dom_sid, strlen(teo->dom_sid))) { + teo->key = tdb_nextkey(teo->db, teo->key); + continue; } - break; + } - case GUMS_OBJ_DOMAIN: - /* TODO: SHOULD WE ALLOW TO DELETE DOMAINS ? */ + data = tdb_fetch(teo->db, teo->key); + if (!data.dptr) { + DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error fetching database, SID entry not found!\n")); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(teo->db))); + DEBUGADD(5, (" Key: %s\n", teo->key.dptr)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } - default: + len = tdb_unpack (data.dptr, data.dsize, TDB_FORMAT_STRING, + &version, + &type, + &size, &ptr); + + if (len == -1) { + DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n")); ret = NT_STATUS_UNSUCCESSFUL; goto done; + } + SAFE_FREE(ptr); + + if (teo->type && type != teo->type) { + SAFE_FREE(data.dptr); + data.dsize = 0; + teo->key = tdb_nextkey(teo->db, teo->key); + continue; + } + + break; } + if (data.dsize != 0) { + if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(&obj, mem_ctx, data.dptr, data.dsize))) { + SAFE_FREE(data.dptr); + DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Error fetching database, malformed entry!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + SAFE_FREE(data.dptr); + } + + ret = data_to_gums_object(object, &obj); + done: - SAFE_FREE(obj_name); talloc_destroy(mem_ctx); return ret; } - NTSTATUS (*get_object_from_sid) (GUMS_OBJECT **object, const DOM_SID *sid, const int obj_type); - NTSTATUS (*get_sid_from_name) (GUMS_OBJECT **object, const char *name); - /* This function is used to get the list of all objects changed since b_time, it is - used to support PDC<->BDC synchronization */ - NTSTATUS (*get_updated_objects) (GUMS_OBJECT **objects, const NTTIME base_time); +static NTSTATUS tdbsam2_enumerate_objects_stop(void *handle) +{ + struct tdbsam2_enum_objs *teo, *t, *p; + + teo = (struct tdbsam2_enum_objs *)handle; + + if (*teo_handlers == teo) { + *teo_handlers = teo->next; + } else { + t = *teo_handlers; + while (t != teo) { + p = t; + t = t->next; + if (t == NULL) { + DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + } + p = t->next; + } + + tdb_close(teo->db); + SAFE_FREE(teo); - NTSTATUS (*enumerate_objects_start) (void *handle, const DOM_SID *sid, const int obj_type); - NTSTATUS (*enumerate_objects_get_next) (GUMS_OBJECT **object, void *handle); - NTSTATUS (*enumerate_objects_stop) (void *handle); + return NT_STATUS_OK; +} /* This function MUST be used ONLY by PDC<->BDC replication code or recovery tools. Never use this function to update an object in the database, use set_object_values() */ @@ -556,7 +1151,43 @@ done: NTSTATUS (*set_privilege) (GUMS_PRIVILEGE *priv); -int gumm_init(GUMS_FUNCTIONS **storage) { +int gumm_init(GUMS_FUNCTIONS **storage) +{ + tdbsam2_db = NULL; + teo_handlers = 0; return 0; } + +#if 0 +int main(int argc, char *argv[]) +{ + NTSTATUS ret; + DOM_SID dsid; + + if (argc < 2) { + printf ("not enough arguments!\n"); + exit(0); + } + + if (!lp_load(dyn_CONFIGFILE,True,False,False)) { + fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); + exit(1); + } + + ret = tdbsam2_new_object(&dsid, "_domain_", GUMS_OBJ_DOMAIN); + if (NT_STATUS_IS_OK(ret)) { + printf ("_domain_ created, sid=%s\n", sid_string_static(&dsid)); + } else { + printf ("_domain_ creation error n. 0x%08x\n", ret.v); + } + ret = tdbsam2_new_object(&dsid, argv[1], GUMS_OBJ_NORMAL_USER); + if (NT_STATUS_IS_OK(ret)) { + printf ("%s user created, sid=%s\n", argv[1], sid_string_static(&dsid)); + } else { + printf ("%s user creation error n. 0x%08x\n", argv[1], ret.v); + } + + exit(0); +} +#endif |