From faf30e69ae0a54a770ef230c0ebae802c0a86be4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 12 Feb 2003 09:14:35 +0000 Subject: initial server side privileges implementation, using a tdb. This needs to be hooked into pdb, and we need some access control on changing privileges. That's next (This used to be commit f4f1f84a6bf1d356ccc83f0ecb135bef4a39619e) --- source3/Makefile.in | 2 +- source3/passdb/privileges.c | 341 ++++++++++++++++++++++++++++++++++++++++ source3/rpc_client/cli_lsarpc.c | 2 +- source3/rpc_server/srv_lsa_nt.c | 37 ++++- 4 files changed, 375 insertions(+), 7 deletions(-) create mode 100644 source3/passdb/privileges.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 76c3d73b7c..bec4a24fa3 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -278,7 +278,7 @@ PASSDB_OBJ = $(PASSDB_GET_SET_OBJ) passdb/passdb.o passdb/pdb_interface.o \ passdb/machine_sid.o passdb/pdb_smbpasswd.o \ passdb/pdb_tdb.o passdb/pdb_ldap.o \ passdb/pdb_unix.o passdb/util_sam_sid.o \ - passdb/pdb_compat.o passdb/pdb_nisplus.o + passdb/pdb_compat.o passdb/pdb_nisplus.o passdb/privileges.o XML_OBJ = modules/xml.o MYSQL_OBJ = modules/mysql.o diff --git a/source3/passdb/privileges.c b/source3/passdb/privileges.c new file mode 100644 index 0000000000..688053674b --- /dev/null +++ b/source3/passdb/privileges.c @@ -0,0 +1,341 @@ +/* + * Unix SMB/CIFS implementation. + * + * default privileges backend for passdb + * + * Copyright (C) Andrew Tridgell 2003 + * + * 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" + +/* + this is a local implementation of a privileges backend, with + privileges stored in a tdb. Most passdb implementations will + probably use this backend, although some (such as pdb_ldap) will + store the privileges in another manner. + + The basic principle is that the backend should store a list of SIDs + associated with each right, where a right is a string name such as + 'SeTakeOwnershipPrivilege'. The SIDs can be of any type, and do not + need to belong to the local domain. + + The way this is used is that certain places in the code which + require access control will ask the privileges backend 'does this + user have the following privilege'. The 'user' will be a NT_TOKEN, + which is essentially just a list of SIDs. If any of those SIDs are + listed in the list of SIDs for that privilege then the answer will + be 'yes'. That will usually mean that the user gets unconditional + access to that functionality, regradless of any ACLs. In this way + privileges act in a similar fashion to unix setuid bits. +*/ + +/* + The terms 'right' and 'privilege' are used interchangably in this + file. This follows MSDN convention where the LSA calls are calls on + 'rights', which really means privileges. My apologies for the + confusion. +*/ + + +/* 15 seconds seems like an ample time for timeouts on the privileges db */ +#define LOCK_TIMEOUT 15 + + +/* the tdb handle for the privileges database */ +static TDB_CONTEXT *tdb; + + +/* initialise the privilege database */ +BOOL privilege_init(void) +{ + tdb = tdb_open_log(lock_path("privilege.tdb"), 0, TDB_DEFAULT, + O_RDWR|O_CREAT, 0600); + if (!tdb) { + DEBUG(0,("Failed to open privilege database\n")); + return False; + } + + return True; +} + +/* + lock the record for a particular privilege (write lock) +*/ +static NTSTATUS privilege_lock_right(const char *right) +{ + if (tdb_lock_bystring(tdb, right, LOCK_TIMEOUT) != 0) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} + +/* + unlock the record for a particular privilege (write lock) +*/ +static void privilege_unlock_right(const char *right) +{ + tdb_unlock_bystring(tdb, right); +} + + +/* + return a list of SIDs that have a particular right +*/ +NTSTATUS privilege_enum_account_with_right(const char *right, + uint32 *count, + DOM_SID **sids) +{ + TDB_DATA data; + char *p; + int i; + + if (!tdb) { + return NT_STATUS_INTERNAL_ERROR; + } + + data = tdb_fetch_by_string(tdb, right); + if (!data.dptr) { + *count = 0; + *sids = NULL; + return NT_STATUS_OK; + } + + /* count them */ + for (i=0, p=data.dptr; p 1) { + memmove(¤t_sids[i], ¤t_sids[i+1], + sizeof(current_sids[0]) * ((current_count-i)-1)); + } + current_count--; + status = privilege_set_accounts_with_right(right, + current_count, + current_sids); + free(current_sids); + privilege_unlock_right(right); + return status; + } + } + + /* removing a right that you don't have is not an error */ + + safe_free(current_sids); + privilege_unlock_right(right); + return NT_STATUS_OK; +} + + +/* + an internal function for checking if a SID has a right +*/ +static BOOL privilege_sid_has_right(DOM_SID *sid, const char *right) +{ + NTSTATUS status; + uint32 count; + DOM_SID *sids; + int i; + + status = privilege_enum_account_with_right(right, &count, &sids); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + for (i=0;istatus = NT_STATUS_OK; @@ -1277,8 +1278,15 @@ NTSTATUS _lsa_enum_acct_rights(pipes_struct *p, LSA_Q_ENUM_ACCT_RIGHTS *q_u, LSA if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; + r_u->status = privilege_enum_account_rights(&q_u->sid.sid, &num_rights, &rights); + init_r_enum_acct_rights(r_u, num_rights, rights); + for (i=0;istatus; } @@ -1304,10 +1312,12 @@ NTSTATUS _lsa_enum_acct_with_right(pipes_struct *p, DEBUG(5,("lsa_enum_acct_with_right on right %s\n", right)); - /* no backend db yet .... */ + r_u->status = privilege_enum_account_with_right(right, &count, &sids); init_r_enum_acct_with_right(r_u, count, sids); + safe_free(sids); + return r_u->status; } @@ -1325,8 +1335,6 @@ NTSTATUS _lsa_add_acct_rights(pipes_struct *p, LSA_Q_ADD_ACCT_RIGHTS *q_u, LSA_R if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - /* no backend yet - just print them */ - DEBUG(5,("_lsa_add_acct_rights to %s (%d rights)\n", sid_string_static(&q_u->sid.sid), q_u->rights.count)); @@ -1334,6 +1342,17 @@ NTSTATUS _lsa_add_acct_rights(pipes_struct *p, LSA_Q_ADD_ACCT_RIGHTS *q_u, LSA_R DEBUG(5,("\t%s\n", unistr2_static(&q_u->rights.strings[i].string))); } + + for (i=0;irights.count;i++) { + r_u->status = privilege_add_account_right(unistr2_static(&q_u->rights.strings[i].string), + &q_u->sid.sid); + if (!NT_STATUS_IS_OK(r_u->status)) { + DEBUG(2,("Failed to add right '%s'\n", + unistr2_static(&q_u->rights.strings[i].string))); + break; + } + } + init_r_add_acct_rights(r_u); return r_u->status; @@ -1355,8 +1374,6 @@ NTSTATUS _lsa_remove_acct_rights(pipes_struct *p, LSA_Q_REMOVE_ACCT_RIGHTS *q_u, return NT_STATUS_INVALID_HANDLE; - /* no backend yet - just print them */ - DEBUG(5,("_lsa_remove_acct_rights from %s all=%d (%d rights)\n", sid_string_static(&q_u->sid.sid), q_u->removeall, @@ -1366,6 +1383,16 @@ NTSTATUS _lsa_remove_acct_rights(pipes_struct *p, LSA_Q_REMOVE_ACCT_RIGHTS *q_u, DEBUG(5,("\t%s\n", unistr2_static(&q_u->rights.strings[i].string))); } + for (i=0;irights.count;i++) { + r_u->status = privilege_remove_account_right(unistr2_static(&q_u->rights.strings[i].string), + &q_u->sid.sid); + if (!NT_STATUS_IS_OK(r_u->status)) { + DEBUG(2,("Failed to remove right '%s'\n", + unistr2_static(&q_u->rights.strings[i].string))); + break; + } + } + init_r_remove_acct_rights(r_u); return r_u->status; -- cgit