From eebc94d84af736bb1fdd8e0c511237b0da978e7a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 1 Mar 2004 16:10:28 +0000 Subject: Ok here it is my latest work on privileges This patch add privilege support for samba Currently it is implemented only for tdbsam backend but estending it to other sam backends is straightforward. I must make a big thank to JFM for his teachings on the matter and the functions at the base of this work. At thye moment only samr_create_user honours SeAddUsersPrivilege and SeMachineAccountPrivilege to permit any user to add machines and/or users to the server. The command "net priv" has been provided to manipulate the privileges database. There are still many things to do (like support in "net rpc vampire") but the working core is here. Feel free to comment/extend on this work. Of course I will deny that any bug may affect this code :-) Simo. This patch adds also my patch about add share command enhancements. (This used to be commit 7a78c3605e203bd8e0d7ae244605f076a5d0b0bc) --- source3/passdb/pdb_interface.c | 157 ++++++++++++++++++ source3/passdb/pdb_tdb.c | 353 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 510 insertions(+) (limited to 'source3/passdb') diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index 2005885c45..180db58c2d 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -587,6 +587,86 @@ static NTSTATUS context_delete_trust_passwd(struct pdb_context *context, return trust->methods->delete_trust_passwd(trust->methods, trust); } +static NTSTATUS context_add_sid_to_privilege(struct pdb_context *context, const char *priv_name, const DOM_SID *sid) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + + struct pdb_methods *curmethods; + if ((!context)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return ret; + } + curmethods = context->pdb_methods; + while (curmethods){ + if (NT_STATUS_IS_OK(ret = curmethods->add_sid_to_privilege(curmethods, priv_name, sid))) { + return ret; + } + curmethods = curmethods->next; + } + + return ret; +} + +static NTSTATUS context_remove_sid_from_privilege(struct pdb_context *context, const char *priv_name, const DOM_SID *sid) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + + struct pdb_methods *curmethods; + if ((!context)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return ret; + } + curmethods = context->pdb_methods; + while (curmethods){ + if (NT_STATUS_IS_OK(ret = curmethods->remove_sid_from_privilege(curmethods, priv_name, sid))) { + return ret; + } + curmethods = curmethods->next; + } + + return ret; +} + +static NTSTATUS context_get_privilege_set(struct pdb_context *context, NT_USER_TOKEN *token, PRIVILEGE_SET *privset) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + + struct pdb_methods *curmethods; + if ((!context)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return ret; + } + curmethods = context->pdb_methods; + while (curmethods){ + if (NT_STATUS_IS_OK(ret = curmethods->get_privilege_set(curmethods, token, privset))) { + return ret; + } + curmethods = curmethods->next; + } + + return ret; +} + +static NTSTATUS context_get_privilege_entry(struct pdb_context *context, const char *privname, char **sid_list) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + + struct pdb_methods *curmethods; + if ((!context)) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return ret; + } + curmethods = context->pdb_methods; + while (curmethods){ + if (NT_STATUS_IS_OK(ret = curmethods->get_privilege_entry(curmethods, privname, sid_list))) { + return ret; + } + curmethods = curmethods->next; + } + + return ret; +} + /****************************************************************** Free and cleanup a pdb context, any associated data and anything that the attached modules might have associated. @@ -711,6 +791,10 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*context)->pdb_add_trust_passwd = context_add_trust_passwd; (*context)->pdb_update_trust_passwd = context_update_trust_passwd; (*context)->pdb_delete_trust_passwd = context_delete_trust_passwd; + (*context)->pdb_add_sid_to_privilege = context_add_sid_to_privilege; + (*context)->pdb_remove_sid_from_privilege = context_remove_sid_from_privilege; + (*context)->pdb_get_privilege_set = context_get_privilege_set; + (*context)->pdb_get_privilege_entry = context_get_privilege_entry; (*context)->free_fn = free_pdb_context; @@ -1072,6 +1156,54 @@ BOOL pdb_enum_alias_memberships(const DOM_SID *sid, aliases, num)); } +BOOL pdb_add_sid_to_privilege(char *priv_name, DOM_SID *sid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_add_sid_to_privilege(pdb_context, priv_name, sid)); +} + +BOOL pdb_remove_sid_from_privilege(char *priv_name, DOM_SID *sid) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_remove_sid_from_privilege(pdb_context, priv_name, sid)); +} + +BOOL pdb_get_privilege_set(NT_USER_TOKEN *token, PRIVILEGE_SET *privset) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_get_privilege_set(pdb_context, token, privset)); +} + +BOOL pdb_get_privilege_entry(const char *privname, char **sid_list) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return False; + } + + return NT_STATUS_IS_OK(pdb_context-> + pdb_get_privilege_entry(pdb_context, privname, sid_list)); +} + /*************************************************************** Initialize the static context (at smbd startup etc). @@ -1155,6 +1287,26 @@ static NTSTATUS pdb_default_delete_trust_passwd(struct pdb_methods *methods, con return NT_STATUS_NOT_IMPLEMENTED; } +static NTSTATUS pdb_default_add_sid_to_privilege(struct pdb_methods *methods, const char *priv_name, const DOM_SID *sid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_default_remove_sid_from_privilege(struct pdb_methods *methods, const char *priv_name, const DOM_SID *sid) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_default_get_privilege_set(struct pdb_methods *methods, NT_USER_TOKEN *token, PRIVILEGE_SET *privset) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS pdb_default_get_privilege_entry(struct pdb_methods *methods, const char *privname, char **sid_list) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) { @@ -1193,5 +1345,10 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) (*methods)->update_trust_passwd = pdb_default_update_trust_passwd; (*methods)->delete_trust_passwd = pdb_default_delete_trust_passwd; + (*methods)->add_sid_to_privilege = pdb_default_add_sid_to_privilege; + (*methods)->remove_sid_from_privilege = pdb_default_remove_sid_from_privilege; + (*methods)->get_privilege_set = pdb_default_get_privilege_set; + (*methods)->get_privilege_entry = pdb_default_get_privilege_entry; + return NT_STATUS_OK; } diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index f54463e158..39de791b07 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -42,6 +42,7 @@ static int tdbsam_debug_level = DBGC_ALL; #define PASSDB_FILE_NAME "passdb.tdb" #define USERPREFIX "USER_" #define RIDPREFIX "RID_" +#define PRIVPREFIX "PRIV_" #define tdbsamver_t int32 struct tdbsam_privates { @@ -895,6 +896,354 @@ static NTSTATUS tdbsam_delete_trust_passwd(struct pdb_methods *methods, const SA } +/*************************************************************************** + Add sid to privilege +****************************************************************************/ + +static NTSTATUS tdbsam_add_sid_to_privilege(struct pdb_methods *my_methods, const char *priv_name, const DOM_SID *sid) +{ + struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; + TDB_CONTEXT *pwd_tdb = NULL; + TDB_DATA key, data; + fstring keystr; + fstring name; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + fstring sid_str; + char *sid_list = NULL, *s = NULL; + size_t str_size; + int flag; + + /* invalidate the existing TDB iterator if it is open */ + + if (tdb_state->passwd_tdb) { + tdb_close(tdb_state->passwd_tdb); + tdb_state->passwd_tdb = NULL; + } + + /* open the account TDB passwd*/ + + pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); + + if (!pwd_tdb) { + DEBUG(0, ("tdb_add_sid_to_privilege: Unable to open TDB passwd (%s)!\n", + tdb_state->tdbsam_location)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* setup the PRIV index key */ + fstrcpy(name, priv_name); + strlower_m(name); + + slprintf(keystr, sizeof(keystr)-1, "%s%s", PRIVPREFIX, name); + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + /* check if the privilege already exist in the database */ + + /* get the record */ + data = tdb_fetch (pwd_tdb, key); + + if (data.dptr) { + /* check the list is not empty */ + if (*(data.dptr)) { + sid_list = strdup(data.dptr); + if (!sid_list) { + DEBUG(0, ("tdbsam_add_sid_to_privilege: Out of Memory!\n")); + goto done; + } + } + SAFE_FREE(data.dptr); + + flag = TDB_MODIFY; + } else { + /* if privilege does not exist create one */ + flag = TDB_INSERT; + } + + /* add the given sid */ + sid_to_string(sid_str, sid); + + if (sid_list) { + str_size = strlen(sid_list) + strlen(sid_str) + 2; + s = realloc(sid_list, str_size); + if (!s) { + DEBUG(0, ("tdbsam_add_sid_to_privilege: Out of Memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + sid_list = s; + s = &sid_list[strlen(sid_list)]; + snprintf(s, strlen(sid_str) + 2, ",%s", sid_str); + + } else { + sid_list = strdup(sid_str); + if (!sid_list) { + DEBUG(0, ("tdbsam_add_sid_to_privilege: Out of Memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + } + + /* copy the PRIVILEGE struct into a BYTE buffer for storage */ + data.dsize = strlen(sid_list) + 1; + data.dptr = sid_list; + + /* add the account */ + if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) { + DEBUG(0, ("Unable to modify passwd TDB!")); + DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb))); + DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr)); + goto done; + } + + ret = NT_STATUS_OK; + +done: + /* cleanup */ + tdb_close (pwd_tdb); + SAFE_FREE(sid_list); + + return (ret); +} + +/*************************************************************************** + Reomve sid to privilege +****************************************************************************/ + +static NTSTATUS tdbsam_remove_sid_from_privilege(struct pdb_methods *my_methods, const char *priv_name, const DOM_SID *sid) +{ + struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; + TDB_CONTEXT *pwd_tdb = NULL; + TDB_DATA key, data; + fstring keystr; + fstring name; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + fstring sid_str; + char *sid_list = NULL, *s = NULL; + + /* invalidate the existing TDB iterator if it is open */ + + if (tdb_state->passwd_tdb) { + tdb_close(tdb_state->passwd_tdb); + tdb_state->passwd_tdb = NULL; + } + + /* open the account TDB passwd*/ + + pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); + + if (!pwd_tdb) { + DEBUG(0, ("tdbsam_remove_sid_from_privilege: Unable to open TDB passwd (%s)!\n", + tdb_state->tdbsam_location)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* setup the PRIV index key */ + fstrcpy(name, priv_name); + strlower_m(name); + + slprintf(keystr, sizeof(keystr)-1, "%s%s", PRIVPREFIX, name); + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + /* check if the privilege already exist in the database */ + + /* get the record */ + data = tdb_fetch (pwd_tdb, key); + + /* if privilege does not exist, just leave */ + if (!data.dptr) { + ret = NT_STATUS_OK; + goto done; + } + + if (data.dptr) { + sid_list = strdup(data.dptr); + if (!sid_list) { + DEBUG(0, ("tdbsam_remove_sid_from_privilege: Out of Memory!\n")); + goto done; + } + SAFE_FREE(data.dptr); + } + + /* remove the given sid */ + sid_to_string(sid_str, sid); + + s = strstr(sid_list, sid_str); + if (s) { + char *p; + p = strstr(s, ","); + if (p) { + size_t l = strlen(sid_list) + 1 - (s - sid_list); + memmove(s, ++p, l); + } else { + if (s != sid_list) + s--; + *s = '\0'; + } + } else { + /* sid not found */ + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + /* copy the PRIVILEGE struct into a BYTE buffer for storage */ + data.dsize = strlen(sid_list) + 1; + data.dptr = sid_list; + + /* add the account */ + if (tdb_store(pwd_tdb, key, data, TDB_MODIFY) != TDB_SUCCESS) { + DEBUG(0, ("Unable to modify passwd TDB!")); + DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb))); + DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr)); + goto done; + } + + ret = NT_STATUS_OK; + +done: + /* cleanup */ + tdb_close (pwd_tdb); + SAFE_FREE(sid_list); + + return (ret); +} + +/*************************************************************************** + get the privilege list for the given token +****************************************************************************/ + +struct priv_traverse { + char **sid_list; + PRIVILEGE_SET *privset; +}; + +static int tdbsam_traverse_privilege(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state) +{ + struct priv_traverse *pt = (struct priv_traverse *)state; + int prefixlen = strlen(PRIVPREFIX); + + if (strncmp(key.dptr, PRIVPREFIX, prefixlen) == 0) { + + /* add to privilege_set if any of the sid in the token + * is contained in the privilege */ + int i; + + for(i=0; pt->sid_list[i] != NULL; i++) { + char *c, *s; + int len; + + s = data.dptr; + while (c = strchr(s, ',')) { + len = MAX((c - s), strlen(pt->sid_list[i])); + if (strncmp(s, pt->sid_list[i], len) == 0) { + DEBUG(10, ("sid [%s] found in users sid list\n", pt->sid_list[i])); + DEBUG(10, ("adding privilege [%s] to the users privilege list\n", &(key.dptr[prefixlen]))); + add_privilege_by_name(pt->privset, &(key.dptr[prefixlen])); + return 0; + } + s = c + 1; + } + len = MAX(strlen(s), strlen(pt->sid_list[i])); + if (strncmp(s, pt->sid_list[i], len) == 0) { + DEBUG(10, ("sid [%s] found in users sid list\n", pt->sid_list[i])); + DEBUG(10, ("adding privilege [%s] to the users privilege list\n", &(key.dptr[prefixlen]))); + add_privilege_by_name(pt->privset, &(key.dptr[prefixlen])); + return 0; + } + } + } + + return 0; +} + +static NTSTATUS tdbsam_get_privilege_set(struct pdb_methods *my_methods, NT_USER_TOKEN *token, PRIVILEGE_SET *privset) +{ + struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + TDB_CONTEXT *pwd_tdb = NULL; + struct priv_traverse pt; + fstring sid_str; + char **sid_list; + int i; + + if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY ))) + return NT_STATUS_UNSUCCESSFUL; + + sid_list = (char **)malloc(sizeof(char *) * (token->num_sids + 1)); + for (i = 0; i < token->num_sids; i++) { + sid_to_string(sid_str, &token->user_sids[i]); + sid_list[i] = strdup(sid_str); + if ( ! sid_list[i]) { + ret = NT_STATUS_NO_MEMORY; + goto done; + } + } + sid_list[i] = NULL; + + pt.sid_list = sid_list; + pt.privset = privset; + tdb_traverse(pwd_tdb, tdbsam_traverse_privilege, &pt); + + ret = NT_STATUS_OK; + +done: + i = 0; + while (sid_list[i]) { + free(sid_list[i]); + i++; + } + free(sid_list); + + tdb_close(pwd_tdb); + + return ret; +} + +static NTSTATUS tdbsam_get_privilege_entry(struct pdb_methods *my_methods, const char *privname, char **sid_list) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + TDB_CONTEXT *pwd_tdb = NULL; + TDB_DATA key, data; + fstring name; + fstring keystr; + + struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; + + if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) + return ret; + + /* setup the PRIV index key */ + fstrcpy(name, privname); + strlower_m(name); + + slprintf(keystr, sizeof(keystr)-1, "%s%s", PRIVPREFIX, name); + key.dptr = keystr; + key.dsize = strlen(keystr) + 1; + + data = tdb_fetch(pwd_tdb, key); + if (!data.dptr) + goto done; + + *sid_list = strdup(data.dptr); + SAFE_FREE(data.dptr); + + if (!*sid_list) + goto done; + + ret = NT_STATUS_OK; +done: + tdb_close(pwd_tdb); + return ret; +} + + + + + + + static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) { NTSTATUS nt_status; @@ -919,6 +1268,10 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth (*pdb_method)->add_trust_passwd = tdbsam_add_trust_passwd; (*pdb_method)->update_trust_passwd = tdbsam_update_trust_passwd; (*pdb_method)->delete_trust_passwd = tdbsam_delete_trust_passwd; + (*pdb_method)->add_sid_to_privilege = tdbsam_add_sid_to_privilege; + (*pdb_method)->remove_sid_from_privilege = tdbsam_remove_sid_from_privilege; + (*pdb_method)->get_privilege_set = tdbsam_get_privilege_set; + (*pdb_method)->get_privilege_entry = tdbsam_get_privilege_entry; tdb_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct tdbsam_privates)); -- cgit