diff options
author | Gerald Carter <jerry@samba.org> | 2005-01-13 18:20:37 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:53:51 -0500 |
commit | d94d87472ca2f3875caa146424caa178ce20274f (patch) | |
tree | a4c6f78f7b22c649b7d9405aa27f64daf749c1fb | |
parent | 94b88f8f26342b6ca4afecec459235c523355f6c (diff) | |
download | samba-d94d87472ca2f3875caa146424caa178ce20274f.tar.gz samba-d94d87472ca2f3875caa146424caa178ce20274f.tar.bz2 samba-d94d87472ca2f3875caa146424caa178ce20274f.zip |
r4724: Add support for Windows privileges in Samba 3.0
(based on Simo's code in trunk). Rewritten with the
following changes:
* privilege set is based on a 32-bit mask instead of strings
(plans are to extend this to a 64 or 128-bit mask before
the next 3.0.11preX release).
* Remove the privilege code from the passdb API
(replication to come later)
* Only support the minimum amount of privileges that make
sense.
* Rewrite the domain join checks to use the SeMachineAccountPrivilege
instead of the 'is a member of "Domain Admins"?' check that started
all this.
Still todo:
* Utilize the SePrintOperatorPrivilege in addition to the 'printer admin'
parameter
* Utilize the SeAddUserPrivilege for adding users and groups
* Fix some of the hard coded _lsa_*() calls
* Start work on enough of SAM replication to get privileges from one
Samba DC to another.
* Come up with some management tool for manipultaing privileges
instead of user manager since it is buggy when run on a 2k client
(haven't tried xp). Works ok on NT4.
(This used to be commit 77c10ff9aa6414a31eece6dfec00793f190a9d6c)
-rw-r--r-- | source3/Makefile.in | 6 | ||||
-rw-r--r-- | source3/auth/auth_util.c | 54 | ||||
-rw-r--r-- | source3/groupdb/mapping.c | 13 | ||||
-rw-r--r-- | source3/include/includes.h | 2 | ||||
-rw-r--r-- | source3/include/privileges.h | 74 | ||||
-rw-r--r-- | source3/include/rpc_lsa.h | 20 | ||||
-rw-r--r-- | source3/include/smb.h | 6 | ||||
-rw-r--r-- | source3/lib/account_pol.c | 34 | ||||
-rw-r--r-- | source3/lib/privileges.c | 647 | ||||
-rw-r--r-- | source3/lib/util_sid.c | 64 | ||||
-rw-r--r-- | source3/passdb/pdb_tdb.c | 15 | ||||
-rw-r--r-- | source3/passdb/privileges.c | 341 | ||||
-rw-r--r-- | source3/passdb/util_sam_sid.c | 24 | ||||
-rw-r--r-- | source3/rpc_client/cli_lsarpc.c | 6 | ||||
-rw-r--r-- | source3/rpc_parse/parse_lsa.c | 81 | ||||
-rw-r--r-- | source3/rpc_server/srv_lsa.c | 32 | ||||
-rw-r--r-- | source3/rpc_server/srv_lsa_nt.c | 299 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 44 |
18 files changed, 937 insertions, 825 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 79579b21c1..aeb6c456d2 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -310,7 +310,7 @@ PASSDB_GET_SET_OBJ = passdb/pdb_get_set.o PASSDB_OBJ = $(PASSDB_GET_SET_OBJ) passdb/passdb.o passdb/pdb_interface.o \ passdb/util_sam_sid.o passdb/pdb_compat.o \ - passdb/privileges.o passdb/lookup_sid.o \ + passdb/lookup_sid.o \ passdb/login_cache.o @PDB_STATIC@ passdb/pdb_sql.o \ lib/system_smbd.o @@ -460,7 +460,7 @@ TESTPARM_OBJ = utils/testparm.o \ $(SECRETS_OBJ) $(LIBSAMBA_OBJ) TESTPRNS_OBJ = utils/testprns.o $(PARAM_OBJ) $(PRINTING_OBJ) $(UBIQX_OBJ) \ - $(LIB_NONSMBD_OBJ) + $(LIB_NONSMBD_OBJ) libsmb/nterr.o SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSCHANGE_OBJ) $(PARAM_OBJ) $(SECRETS_OBJ) \ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ)\ @@ -592,7 +592,7 @@ SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \ $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_GET_SET_OBJ) \ $(LIBMSRPC_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ) -TALLOCTORT_OBJ = lib/talloctort.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(UBIQX_OBJ) +TALLOCTORT_OBJ = lib/talloctort.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(UBIQX_OBJ) libsmb/nterr.o RPCTORTURE_OBJ = torture/rpctorture.o \ rpcclient/display.o \ diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 98ecd00d1c..e4793c3df3 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -493,6 +493,11 @@ void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token) for (i = 0; i < token->num_sids; i++) DEBUGADDC(dbg_class, dbg_lev, ("SID[%3lu]: %s\n", (unsigned long)i, sid_to_string(sid_str, &token->user_sids[i]))); + + DEBUGADDC(dbg_class, dbg_lev, ("Privileges: [%d]\n", token->privileges.count)); + for ( i=0; i<token->privileges.count; i++ ) { + DEBUGADDC(dbg_class, dbg_lev, ("\t%s\n", luid_to_privilege_name(&token->privileges.set[i].luid) )); + } } /**************************************************************************** @@ -583,6 +588,13 @@ static NTSTATUS create_nt_user_token(const DOM_SID *user_sid, const DOM_SID *gro ptoken->num_sids--; } } + + /* add privileges assigned to this user */ + + privilege_set_init( &ptoken->privileges ); + + get_privileges_for_sids( &ptoken->privileges, ptoken->user_sids, ptoken->num_sids ); + debug_nt_user_token(DBGC_AUTH, 10, ptoken); @@ -1410,12 +1422,15 @@ BOOL make_auth_methods(struct auth_context *auth_context, auth_methods **auth_me void delete_nt_token(NT_USER_TOKEN **pptoken) { - if (*pptoken) { - NT_USER_TOKEN *ptoken = *pptoken; - SAFE_FREE( ptoken->user_sids ); - ZERO_STRUCTP(ptoken); - } - SAFE_FREE(*pptoken); + if (*pptoken) { + NT_USER_TOKEN *ptoken = *pptoken; + + SAFE_FREE( ptoken->user_sids ); + privilege_set_free( &ptoken->privileges ); + + ZERO_STRUCTP(ptoken); + } + SAFE_FREE(*pptoken); } /**************************************************************************** @@ -1429,17 +1444,26 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) if (!ptoken) return NULL; - if ((token = SMB_MALLOC_P(NT_USER_TOKEN)) == NULL) - return NULL; - - ZERO_STRUCTP(token); + if ((token = SMB_MALLOC_P(NT_USER_TOKEN)) == NULL) + return NULL; - if ((token->user_sids = (DOM_SID *)memdup( ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids )) == NULL) { - SAFE_FREE(token); - return NULL; - } + ZERO_STRUCTP(token); + + token->user_sids = (DOM_SID *)memdup( ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids ); + + if ( !token ) { + SAFE_FREE(token); + return NULL; + } - token->num_sids = ptoken->num_sids; + token->num_sids = ptoken->num_sids; + + /* copy the privileges; don't consider failure to be critical here */ + + privilege_set_init( &token->privileges); + if ( !dup_privilege_set( &token->privileges, &ptoken->privileges ) ) { + DEBUG(0,("dup_nt_token: Failure to copy PRIVILEGE_SET!. Continuing with 0 privileges assigned.\n")); + } return token; } diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c index 7095997dc8..e574a7cf20 100644 --- a/source3/groupdb/mapping.c +++ b/source3/groupdb/mapping.c @@ -2,7 +2,7 @@ * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-2000, - * Copyright (C) Jean François Micouleau 1998-2001. + * Copyright (C) Jean François Micouleau 1998-2001. * * 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 @@ -35,17 +35,6 @@ static TDB_CONTEXT *tdb; /* used for driver files */ */ #define MEMBEROF_PREFIX "MEMBEROF/" -PRIVS privs[] = { - {SE_PRIV_NONE, "no_privs", "No privilege" }, /* this one MUST be first */ - {SE_PRIV_ADD_MACHINES, "SeMachineAccountPrivilege", "Add workstations to the domain" }, - {SE_PRIV_SEC_PRIV, "SeSecurityPrivilege", "Manage the audit logs" }, - {SE_PRIV_TAKE_OWNER, "SeTakeOwnershipPrivilege", "Take ownership of file" }, - {SE_PRIV_ADD_USERS, "SaAddUsers", "Add users to the domain - Samba" }, - {SE_PRIV_PRINT_OPERATOR, "SaPrintOp", "Add or remove printers - Samba" }, - {SE_PRIV_ALL, "SaAllPrivs", "all privileges" } -}; - - /**************************************************************************** dump the mapping group mapping to a text file ****************************************************************************/ diff --git a/source3/include/includes.h b/source3/include/includes.h index 66ff4fa9f0..45c7133f1e 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -814,6 +814,8 @@ extern int errno; #include "version.h" +#include "privileges.h" + #include "smb.h" #include "nameserv.h" diff --git a/source3/include/privileges.h b/source3/include/privileges.h index b7e1b44c2a..cdf62b7f85 100644 --- a/source3/include/privileges.h +++ b/source3/include/privileges.h @@ -4,6 +4,8 @@ Copyright (C) Andrew Tridgell 1992-1997 Copyright (C) Luke Kenneth Casson Leighton 1996-1997 Copyright (C) Paul Ashton 1997 + Copyright (C) Simo Sorce 2003 + Copyright (C) Gerald (Jerry) Carter 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 @@ -23,22 +25,73 @@ #ifndef PRIVILEGES_H #define PRIVILEGES_H -#define PRIV_ALL_INDEX 5 +/* common privilege defines */ -#define SE_PRIV_NONE 0x0000 -#define SE_PRIV_ADD_MACHINES 0x0006 -#define SE_PRIV_SEC_PRIV 0x0008 -#define SE_PRIV_TAKE_OWNER 0x0009 -#define SE_PRIV_ADD_USERS 0xff01 -#define SE_PRIV_PRINT_OPERATOR 0xff03 -#define SE_PRIV_ALL 0xffff +#define SE_END 0x00000000 +#define SE_NONE 0x00000000 +#define SE_ALL_PRIVS 0xFFFFFFFF + +/* + * We will use our own set of privileges since it makes no sense + * to implement all of the Windows set when only a portion will + * be used. + */ + +#define SE_NETWORK_LOGON 0x00000001 +#define SE_INTERACTIVE_LOGON 0x00000002 +#define SE_BATCH_LOGON 0x00000004 +#define SE_SERVICE_LOGON 0x00000008 +#define SE_MACHINE_ACCOUNT 0x00000010 +#define SE_PRINT_OPERATOR 0x00000020 +#define SE_ADD_USERS 0x00000040 + +#if 0 /* not needed currently */ + +#define SE_ASSIGN_PRIMARY_TOKEN +#define SE_CREATE_TOKEN +#define SE_LOCK_MEMORY +#define SE_INCREASE_QUOTA +#define SE_UNSOLICITED_INPUT +#define SE_TCB +#define SE_SECURITY +#define SE_TAKE_OWNERSHIP +#define SE_LOAD_DRIVER +#define SE_SYSTEM_PROFILE +#define SE_SYSTEM_TIME +#define SE_PROF_SINGLE_PROCESS +#define SE_INC_BASE_PRIORITY +#define SE_CREATE_PAGEFILE +#define SE_CREATE_PERMANENT +#define SE_BACKUP +#define SE_RESTORE +#define SE_SHUTDOWN +#define SE_DEBUG +#define SE_AUDIT +#define SE_SYSTEM_ENVIRONMENT +#define SE_CHANGE_NOTIFY +#define SE_REMOTE_SHUTDOWN +#define SE_UNDOCK +#define SE_SYNC_AGENT +#define SE_ENABLE_DELEGATION + +#endif /* not needed currently */ + +/* + * These are used in Lsa replies (srv_lsa_nt.c) + */ #define PR_NONE 0x0000 #define PR_LOG_ON_LOCALLY 0x0001 #define PR_ACCESS_FROM_NETWORK 0x0002 #define PR_LOG_ON_BATCH_JOB 0x0004 #define PR_LOG_ON_SERVICE 0x0010 + +#ifndef _BOOL +typedef int BOOL; +#define _BOOL /* So we don't typedef BOOL again in vfs.h */ +#endif + typedef struct LUID { uint32 low; @@ -49,7 +102,7 @@ typedef struct LUID_ATTR { LUID luid; uint32 attr; -} LUID_ATTR ; +} LUID_ATTR; typedef struct privilege_set { @@ -62,9 +115,8 @@ typedef struct privilege_set typedef struct _PRIVS { uint32 se_priv; - const char *priv; + const char *name; const char *description; } PRIVS; - #endif /* PRIVILEGES_H */ diff --git a/source3/include/rpc_lsa.h b/source3/include/rpc_lsa.h index 43ffa37d59..a2bc72d2b2 100644 --- a/source3/include/rpc_lsa.h +++ b/source3/include/rpc_lsa.h @@ -635,6 +635,20 @@ typedef struct lsa_r_unk_get_connuser } LSA_R_UNK_GET_CONNUSER; +typedef struct lsa_q_createaccount +{ + POLICY_HND pol; /* policy handle */ + DOM_SID2 sid; + uint32 access; /* access */ +} LSA_Q_CREATEACCOUNT; + +typedef struct lsa_r_createaccount +{ + POLICY_HND pol; /* policy handle */ + NTSTATUS status; +} LSA_R_CREATEACCOUNT; + + typedef struct lsa_q_openaccount { POLICY_HND pol; /* policy handle */ @@ -657,7 +671,7 @@ typedef struct lsa_r_enumprivsaccount { uint32 ptr; uint32 count; - PRIVILEGE_SET *set; + PRIVILEGE_SET set; NTSTATUS status; } LSA_R_ENUMPRIVSACCOUNT; @@ -703,7 +717,7 @@ typedef struct lsa_q_addprivs { POLICY_HND pol; /* policy handle */ uint32 count; - PRIVILEGE_SET *set; + PRIVILEGE_SET set; } LSA_Q_ADDPRIVS; typedef struct lsa_r_addprivs @@ -718,7 +732,7 @@ typedef struct lsa_q_removeprivs uint32 allrights; uint32 ptr; uint32 count; - PRIVILEGE_SET *set; + PRIVILEGE_SET set; } LSA_Q_REMOVEPRIVS; typedef struct lsa_r_removeprivs diff --git a/source3/include/smb.h b/source3/include/smb.h index d15f630507..1cf5aac0c5 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -281,6 +281,11 @@ typedef struct sid_info } DOM_SID; +typedef struct sid_list { + uint32 count; + DOM_SID *list; +} SID_LIST; + /* * The complete list of SIDS belonging to this user. * Created when a vuid is registered. @@ -297,6 +302,7 @@ typedef struct sid_info typedef struct _nt_user_token { size_t num_sids; DOM_SID *user_sids; + PRIVILEGE_SET privileges; } NT_USER_TOKEN; /*** query a local group, get a list of these: shows who is in that group ***/ diff --git a/source3/lib/account_pol.c b/source3/lib/account_pol.c index c62396c22d..72d6e77ddd 100644 --- a/source3/lib/account_pol.c +++ b/source3/lib/account_pol.c @@ -20,10 +20,18 @@ */ #include "includes.h" -static TDB_CONTEXT *tdb; /* used for driver files */ +static TDB_CONTEXT *tdb; #define DATABASE_VERSION 2 +extern DOM_SID global_sid_World; +extern DOM_SID global_sid_Builtin_Administrators; +extern DOM_SID global_sid_Builtin_Account_Operators; +extern DOM_SID global_sid_Builtin_Server_Operators; +extern DOM_SID global_sid_Builtin_Print_Operators; +extern DOM_SID global_sid_Builtin_Backup_Operators; + + /**************************************************************************** Set default for a field if it is empty ****************************************************************************/ @@ -91,6 +99,15 @@ BOOL init_account_policy(void) } tdb_unlock_bystring(tdb, vstring); + /* These exist by default on NT4 in [HKLM\SECURITY\Policy\Accounts] */ + + privilege_create_account( &global_sid_World ); + privilege_create_account( &global_sid_Builtin_Administrators ); + privilege_create_account( &global_sid_Builtin_Account_Operators ); + privilege_create_account( &global_sid_Builtin_Server_Operators ); + privilege_create_account( &global_sid_Builtin_Print_Operators ); + privilege_create_account( &global_sid_Builtin_Backup_Operators ); + return True; } @@ -218,3 +235,18 @@ BOOL account_policy_set(int field, uint32 value) return True; } + +/**************************************************************************** +****************************************************************************/ + +TDB_CONTEXT *get_account_pol_tdb( void ) +{ + + if ( !tdb ) { + if ( !init_account_policy() ) + return NULL; + } + + return tdb; +} + diff --git a/source3/lib/privileges.c b/source3/lib/privileges.c index 2b8d7613c1..eabb652c3e 100644 --- a/source3/lib/privileges.c +++ b/source3/lib/privileges.c @@ -3,6 +3,7 @@ Privileges handling functions Copyright (C) Jean François Micouleau 1998-2001 Copyright (C) Simo Sorce 2002-2003 + Copyright (C) Gerald (Jerry) Carter 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 @@ -19,138 +20,152 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include "includes.h" -/* defines */ +#define PRIVPREFIX "PRIV_" -#define ALLOC_CHECK(ptr, err, label, str) do { if ((ptr) == NULL) { DEBUG(0, ("%s: out of memory!\n", str)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0) -#define NTSTATUS_CHECK(err, label, str1, str2) do { if (!NT_STATUS_IS_OK(err)) { DEBUG(0, ("%s: %s failed!\n", str1, str2)); } } while(0) - -/**************************************************************************** - Check if a user is a mapped group. - - This function will check if the group SID is mapped onto a - system managed gid or onto a winbind manged sid. - In the first case it will be threated like a mapped group - and the backend should take the member list with a getgrgid - and ignore any user that have been possibly set into the group - object. - - In the second case, the group is a fully SAM managed group - served back to the system through winbind. In this case the - members of a Local group are "unrolled" to cope with the fact - that unix cannot contain groups inside groups. - The backend MUST never call any getgr* / getpw* function or - loops with winbind may happen. - ****************************************************************************/ - -#if 0 -NTSTATUS is_mapped_group(BOOL *mapped, const DOM_SID *sid) -{ - NTSTATUS result; - gid_t id; - - /* look if mapping exist, do not make idmap alloc an uid if SID is not found */ - result = idmap_get_gid_from_sid(&id, sid, False); - if (NT_STATUS_IS_OK(result)) { - *mapped = gid_is_in_winbind_range(id); - } else { - *mapped = False; - } +#define ALLOC_CHECK(ptr, err, label, str) do { if ((ptr) == NULL) \ + { DEBUG(0, ("%s: out of memory!\n", str)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0) + +PRIVS privs[] = { + {SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from the network"}, + {SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally"}, + {SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job"}, + {SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service"}, + + {SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain"}, + {SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Printer Admin"}, + {SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain"}, + + {SE_END, "", ""} +}; + - return result; -} +#if 0 /* not needed currently */ +PRIVS privs[] = { + {SE_ASSIGN_PRIMARY_TOKEN, "SeAssignPrimaryTokenPrivilege", "Assign Primary Token"}, + {SE_CREATE_TOKEN, "SeCreateTokenPrivilege", "Create Token"}, + {SE_LOCK_MEMORY, "SeLockMemoryPrivilege", "Lock Memory"}, + {SE_INCREASE_QUOTA, "SeIncreaseQuotaPrivilege", "Increase Quota"}, + {SE_UNSOLICITED_INPUT, "SeUnsolicitedInputPrivilege", "Unsolicited Input"}, + {SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Can add Machine Accounts to the Domain"}, + {SE_TCB, "SeTcbPrivilege", "Act as part of the operating system"}, + {SE_SECURITY, "SeSecurityPrivilege", "Security Privilege"}, + {SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take Ownership Privilege"}, + {SE_LOAD_DRIVER, "SeLocalDriverPrivilege", "Local Driver Privilege"}, + {SE_SYSTEM_PROFILE, "SeSystemProfilePrivilege", "System Profile Privilege"}, + {SE_SYSTEM_TIME, "SeSystemtimePrivilege", "System Time"}, + {SE_PROF_SINGLE_PROCESS, "SeProfileSingleProcessPrivilege", "Profile Single Process Privilege"}, + {SE_INC_BASE_PRIORITY, "SeIncreaseBasePriorityPrivilege", "Increase Base Priority Privilege"}, + {SE_CREATE_PAGEFILE, "SeCreatePagefilePrivilege", "Create Pagefile Privilege"}, + {SE_CREATE_PERMANENT, "SeCreatePermanentPrivilege", "Create Permanent"}, + {SE_BACKUP, "SeBackupPrivilege", "Backup Privilege"}, + {SE_RESTORE, "SeRestorePrivilege", "Restore Privilege"}, + {SE_SHUTDOWN, "SeShutdownPrivilege", "Shutdown Privilege"}, + {SE_DEBUG, "SeDebugPrivilege", "Debug Privilege"}, + {SE_AUDIT, "SeAuditPrivilege", "Audit"}, + {SE_SYSTEM_ENVIRONMENT, "SeSystemEnvironmentPrivilege", "System Environment Privilege"}, + {SE_CHANGE_NOTIFY, "SeChangeNotifyPrivilege", "Change Notify"}, + {SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Remote Shutdown Privilege"}, + {SE_UNDOCK, "SeUndockPrivilege", "Undock"}, + {SE_SYNC_AGENT, "SeSynchronizationAgentPrivilege", "Synchronization Agent"}, + {SE_ENABLE_DELEGATION, "SeEnableDelegationPrivilege", "Enable Delegation"}, + {SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Printer Operator"}, + {SE_ADD_USERS, "SeAddUsersPrivilege", "Add Users"}, + {SE_ALL_PRIVS, "SeAllPrivileges", "All Privileges"} + {SE_END, "", ""} +}; #endif -/**************************************************************************** - duplicate alloc luid_attr - ****************************************************************************/ -NTSTATUS dupalloc_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la) -{ - NTSTATUS ret; +typedef struct priv_sid_list { + uint32 se_priv; + SID_LIST sids; +} PRIV_SID_LIST; - /* don't crash if the source pointer is NULL (since we don't - do priviledges now anyways) */ +/*************************************************************************** + Retrieve the privilege mask (set) for a given SID +****************************************************************************/ - if ( !old_la ) - return NT_STATUS_OK; +static uint32 get_privileges( const DOM_SID *sid ) +{ + TDB_CONTEXT *tdb = get_account_pol_tdb(); + fstring keystr; + uint32 priv_mask; + + if ( !tdb ) + return 0; - *new_la = TALLOC_P(mem_ctx, LUID_ATTR); - ALLOC_CHECK(new_la, ret, done, "dupalloc_luid_attr"); + fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) ); - (*new_la)->luid.high = old_la->luid.high; - (*new_la)->luid.low = old_la->luid.low; - (*new_la)->attr = old_la->attr; + if ( !tdb_fetch_uint32( tdb, keystr, &priv_mask ) ) { + DEBUG(3,("get_privileges: No privileges assigned to SID [%s]\n", + sid_string_static(sid))); + return 0; + } - ret = NT_STATUS_OK; - -done: - return ret; + return priv_mask; } -/**************************************************************************** - initialise a privilege list - ****************************************************************************/ -NTSTATUS init_privilege(PRIVILEGE_SET **priv_set) -{ - NTSTATUS ret; - TALLOC_CTX *mem_ctx = talloc_init("privilege set"); - ALLOC_CHECK(mem_ctx, ret, done, "init_privilege"); - - *priv_set = TALLOC_ZERO_P(mem_ctx, PRIVILEGE_SET); - ALLOC_CHECK(*priv_set, ret, done, "init_privilege"); +/*************************************************************************** + Store the privilege mask (set) for a given SID +****************************************************************************/ - (*priv_set)->mem_ctx = mem_ctx; +static BOOL set_privileges( const DOM_SID *sid, uint32 mask ) +{ + TDB_CONTEXT *tdb = get_account_pol_tdb(); + fstring keystr; + + if ( !tdb ) + return False; - ret = NT_STATUS_OK; + fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) ); -done: - return ret; + return tdb_store_uint32( tdb, keystr, mask ); } -NTSTATUS init_priv_with_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET **priv_set) +/**************************************************************************** + check if the privilege is in the privilege list +****************************************************************************/ + +static BOOL check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set) { - NTSTATUS ret; + int i; - *priv_set = TALLOC_ZERO_P(mem_ctx, PRIVILEGE_SET); - ALLOC_CHECK(*priv_set, ret, done, "init_privilege"); + if ( !priv_set ) + return False; - (*priv_set)->mem_ctx = mem_ctx; - (*priv_set)->ext_ctx = True; + for ( i = 0; i < priv_set->count; i++ ) { + LUID_ATTR *cur_set; - ret = NT_STATUS_OK; + cur_set = &priv_set->set[i]; -done: - return ret; -} + /* check only the low and high part. Checking the attr + field has no meaning */ -void reset_privilege(PRIVILEGE_SET *priv_set) -{ - priv_set->count = 0; - priv_set->control = 0; - priv_set->set = NULL; -} + if ( (cur_set->luid.low == set.luid.low) + && (cur_set->luid.high == set.luid.high) ) + { + return True; + } + } -void destroy_privilege(PRIVILEGE_SET **priv_set) -{ - reset_privilege(*priv_set); - if (!((*priv_set)->ext_ctx)) - /* mem_ctx is local, destroy it */ - talloc_destroy((*priv_set)->mem_ctx); - *priv_set = NULL; + return False; } /**************************************************************************** add a privilege to a privilege array ****************************************************************************/ -NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set) + +static NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set) { NTSTATUS ret; LUID_ATTR *new_set; /* check if the privilege is not already in the list */ - if (NT_STATUS_IS_OK(check_priv_in_privilege(priv_set, set))) - return NT_STATUS_UNSUCCESSFUL; + + if ( check_priv_in_privilege(priv_set, set) ) + return NT_STATUS_OK; /* we can allocate memory to add the new privilege */ @@ -170,132 +185,222 @@ done: return ret; } -/**************************************************************************** - add all the privileges to a privilege array - ****************************************************************************/ -NTSTATUS add_all_privilege(PRIVILEGE_SET *priv_set) +/********************************************************************* + Generate the LUID_ATTR structure based on a bitmask +*********************************************************************/ + +static LUID_ATTR get_privilege_luid( uint32 mask ) { - NTSTATUS result = NT_STATUS_OK; - LUID_ATTR set; + LUID_ATTR priv_luid; + + priv_luid.attr = 0; + priv_luid.luid.high = 0; + priv_luid.luid.low = mask; + + return priv_luid; +} - set.attr = 0; - set.luid.high = 0; +/********************************************************************* + Convert a privilege mask to an LUID_ATTR[] and add the privileges to + the PRIVILEGE_SET +*********************************************************************/ - /* TODO: set a proper list of privileges */ - set.luid.low = SE_PRIV_ADD_USERS; - result = add_privilege(priv_set, set); - NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege"); +static void add_privilege_set( PRIVILEGE_SET *privset, uint32 mask ) +{ + LUID_ATTR luid; + int i; + + for (i=0; privs[i].se_priv != SE_END; i++) { - set.luid.low = SE_PRIV_ADD_MACHINES; - result = add_privilege(priv_set, set); - NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege"); + /* skip if the privilege is not part of the mask */ - set.luid.low = SE_PRIV_PRINT_OPERATOR; - result = add_privilege(priv_set, set); - NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege"); + if ( !(mask & privs[i].se_priv) ) + continue; - return result; + /* remove the bit from the mask */ + + mask &= ~privs[i].se_priv; + + luid = get_privilege_luid( privs[i].se_priv ); + + add_privilege( privset, luid ); + } + + /* log an error if we have anything left at this point */ + if ( mask ) + DEBUG(0,("add_privilege_set: leftover bits! [0x%x]\n", mask )); } -/**************************************************************************** - check if the privilege list is empty - ****************************************************************************/ -NTSTATUS check_empty_privilege(PRIVILEGE_SET *priv_set) +/********************************************************************* + get a list of all privleges for all sids the in list +*********************************************************************/ + +void get_privileges_for_sids(PRIVILEGE_SET *privset, DOM_SID *slist, int scount) { - if (!priv_set) - return NT_STATUS_INVALID_PARAMETER; + uint32 priv_mask; + int i; + + for ( i=0; i<scount; i++ ) { + priv_mask = get_privileges( &slist[i] ); - if (priv_set->count == 0) - return NT_STATUS_OK; + /* don't add unless we actually have a privilege assigned */ - return NT_STATUS_UNSUCCESSFUL; + if ( priv_mask == 0 ) + continue; + + DEBUG(5,("get_privileges_for_sids: sid = %s, privilege mask = 0x%x\n", + sid_string_static(&slist[i]), priv_mask)); + + add_privilege_set( privset, priv_mask ); + } } -/**************************************************************************** - check if the privilege is in the privilege list - ****************************************************************************/ -NTSTATUS check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set) + +/********************************************************************* + travseral functions for privilege_enumerate_accounts +*********************************************************************/ + +static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state) { - int i; + PRIV_SID_LIST *priv = state; + int prefixlen = strlen(PRIVPREFIX); + DOM_SID sid; + fstring sid_string; - if (!priv_set) - return NT_STATUS_INVALID_PARAMETER; + /* check we have a PRIV_+SID entry */ - /* if the list is empty, obviously we can't have it */ - if (NT_STATUS_IS_OK(check_empty_privilege(priv_set))) - return NT_STATUS_UNSUCCESSFUL; + if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0) + return 0; + + /* check to see if we are looking for a particular privilege */ - for (i = 0; i < priv_set->count; i++) { - LUID_ATTR *cur_set; + if ( priv->se_priv != SE_NONE ) { + uint32 mask = SVAL(data.dptr, 0); + + /* if the SID does not have the specified privilege + then just return */ + + if ( !(mask & priv->se_priv) ) + return 0; + } + + fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] ); - cur_set = &priv_set->set[i]; - /* check only the low and high part. Checking the attr field has no meaning */ - if ( (cur_set->luid.low == set.luid.low) && - (cur_set->luid.high == set.luid.high) ) { - return NT_STATUS_OK; - } + if ( !string_to_sid(&sid, sid_string) ) { + DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n", + sid_string)); + return 0; } - return NT_STATUS_UNSUCCESSFUL; + add_sid_to_array( &sid, &priv->sids.list, &priv->sids.count ); + + return 0; } -/**************************************************************************** - remove a privilege from a privilege array - ****************************************************************************/ -NTSTATUS remove_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set) +/********************************************************************* + Retreive list of privileged SIDs (for _lsa_enumerate_accounts() +*********************************************************************/ + +NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids) { - NTSTATUS ret; - LUID_ATTR *new_set; - LUID_ATTR *old_set; - int i,j; + TDB_CONTEXT *tdb = get_account_pol_tdb(); + PRIV_SID_LIST priv; + + ZERO_STRUCT(priv); + priv.se_priv = SE_NONE; - if (!priv_set) - return NT_STATUS_INVALID_PARAMETER; + tdb_traverse( tdb, priv_traverse_fn, &priv); - /* check if the privilege is in the list */ - if (!NT_STATUS_IS_OK(check_priv_in_privilege(priv_set, set))) - return NT_STATUS_UNSUCCESSFUL; + /* give the memory away; caller will free */ + + *sids = priv.sids.list; + *num_sids = priv.sids.count; - /* special case if it's the only privilege in the list */ - if (priv_set->count == 1) { - reset_privilege(priv_set); - return NT_STATUS_OK; - } + return NT_STATUS_OK; +} + +/*************************************************************************** + Retrieve the SIDs assigned to a given privilege +****************************************************************************/ - /* - * the privilege is there, create a new list, - * and copy the other privileges - */ +NTSTATUS priv_get_sids(const char *privname, DOM_SID **sids, int *num_sids) +{ + TDB_CONTEXT *tdb = get_account_pol_tdb(); + PRIV_SID_LIST priv; + + ZERO_STRUCT(priv); + priv.se_priv = + - old_set = priv_set->set; + tdb_traverse( tdb, priv_traverse_fn, &priv); - new_set = TALLOC_ARRAY(priv_set->mem_ctx, LUID_ATTR, priv_set->count - 1); - ALLOC_CHECK(new_set, ret, done, "remove_privilege"); + /* give the memory away; caller will free */ + + *sids = priv.sids.list; + *num_sids = priv.sids.count; - for (i=0, j=0; i < priv_set->count; i++) { - if ( (old_set[i].luid.low == set.luid.low) && - (old_set[i].luid.high == set.luid.high) ) { - continue; - } - - new_set[j].luid.low = old_set[i].luid.low; - new_set[j].luid.high = old_set[i].luid.high; - new_set[j].attr = old_set[i].attr; + return NT_STATUS_OK; +} - j++; - } +/*************************************************************************** + Add privilege to sid +****************************************************************************/ + +BOOL grant_privilege(const DOM_SID *sid, uint32 priv_mask) +{ + uint32 old_mask, new_mask; - if (j != priv_set->count - 1) { - DEBUG(0,("remove_privilege: mismatch ! difference is not -1\n")); - DEBUGADD(0,("old count:%d, new count:%d\n", priv_set->count, j)); - return NT_STATUS_INTERNAL_ERROR; - } - - /* ok everything is fine */ + old_mask = get_privileges( sid ); - priv_set->count--; - priv_set->set = new_set; + new_mask = old_mask | priv_mask; + + DEBUG(10,("grant_privilege: %s, orig priv set = 0x%x, new privilege set = 0x%x\n", + sid_string_static(sid), old_mask, new_mask )); + return set_privileges( sid, new_mask ); +} + +/*************************************************************************** + Remove privilege from sid +****************************************************************************/ + +BOOL revoke_privilege(const DOM_SID *sid, uint32 priv_mask) +{ + uint32 old_mask, new_mask; + + old_mask = get_privileges( sid ); + + new_mask = old_mask & ~priv_mask; + + DEBUG(10,("revoke_privilege: %s, orig priv set = 0x%x, new priv set = 0x%x\n", + sid_string_static(sid), old_mask, new_mask )); + + return set_privileges( sid, new_mask ); +} + +/*************************************************************************** + Retrieve the SIDs assigned to a given privilege +****************************************************************************/ + +NTSTATUS privilege_create_account(const DOM_SID *sid ) +{ + return ( grant_privilege( sid, SE_NONE ) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL); +} + +/**************************************************************************** + initialise a privilege list and set the talloc context + ****************************************************************************/ +NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set) +{ + NTSTATUS ret; + + ZERO_STRUCTP( priv_set ); + + TALLOC_CTX *mem_ctx = talloc_init("privilege set"); + ALLOC_CHECK(mem_ctx, ret, done, "init_privilege"); + + priv_set->mem_ctx = mem_ctx; + ret = NT_STATUS_OK; done: @@ -303,48 +408,154 @@ done: } /**************************************************************************** - duplicates a privilege array - the new privilege set must be passed inited - (use init_privilege or init_priv_with_ctx) + initialise a privilege list and with someone else's talloc context +****************************************************************************/ + +NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set) +{ + ZERO_STRUCTP( priv_set ); + + priv_set->mem_ctx = mem_ctx; + priv_set->ext_ctx = True; + + return NT_STATUS_OK; +} + +/**************************************************************************** + Free all memory used by a PRIVILEGE_SET +****************************************************************************/ + +void privilege_set_free(PRIVILEGE_SET *priv_set) +{ + if ( !priv_set ) + return; + + if ( !( priv_set->ext_ctx ) ) + talloc_destroy( priv_set->mem_ctx ); + + ZERO_STRUCTP( priv_set ); +} + +/**************************************************************************** + duplicate alloc luid_attr ****************************************************************************/ -NTSTATUS dup_priv_set(PRIVILEGE_SET *new_priv_set, PRIVILEGE_SET *priv_set) + +NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count) { NTSTATUS ret; - LUID_ATTR *new_set; - LUID_ATTR *old_set; int i; - if (!new_priv_set || !priv_set) - return NT_STATUS_INVALID_PARAMETER; + /* don't crash if the source pointer is NULL (since we don't + do priviledges now anyways) */ - /* special case if there are no privileges in the list */ - if (priv_set->count == 0) { + if ( !old_la ) return NT_STATUS_OK; - } - - /* - * create a new list, - * and copy the other privileges - */ - old_set = priv_set->set; - - new_set = TALLOC_ARRAY(new_priv_set->mem_ctx, LUID_ATTR, priv_set->count - 1); - ALLOC_CHECK(new_set, ret, done, "dup_priv_set"); + *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count); + ALLOC_CHECK(new_la, ret, done, "dupalloc_luid_attr"); - for (i=0; i < priv_set->count; i++) { - - new_set[i].luid.low = old_set[i].luid.low; - new_set[i].luid.high = old_set[i].luid.high; - new_set[i].attr = old_set[i].attr; + for (i=0; i<count; i++) { + (*new_la)[i].luid.high = old_la[i].luid.high; + (*new_la)[i].luid.low = old_la[i].luid.low; + (*new_la)[i].attr = old_la[i].attr; } - - new_priv_set->count = priv_set->count; - new_priv_set->control = priv_set->control; - new_priv_set->set = new_set; ret = NT_STATUS_OK; done: return ret; } + +/**************************************************************************** + Performa deep copy of a PRIVILEGE_SET structure. Assumes an initialized + destination structure. +*****************************************************************************/ + +BOOL dup_privilege_set( PRIVILEGE_SET *dest, PRIVILEGE_SET *src ) +{ + NTSTATUS result; + + if ( !dest || !src ) + return False; + + result = dup_luid_attr( dest->mem_ctx, &dest->set, src->set, src->count ); + if ( !NT_STATUS_IS_OK(result) ) { + DEBUG(0,("dup_privilege_set: Failed to dup LUID_ATTR array [%s]\n", + nt_errstr(result) )); + return False; + } + + dest->control = src->control; + dest->count = src->count; + + return True; +} + +/**************************************************************************** + Does the user have the specified privilege ? We only deal with one privilege + at a time here. +*****************************************************************************/ + +BOOL user_has_privilege(NT_USER_TOKEN *token, uint32 privilege) +{ + return check_priv_in_privilege( &token->privileges, get_privilege_luid(privilege) ); +} + +/**************************************************************************** + Convert a LUID to a named string +****************************************************************************/ + +char* luid_to_privilege_name(const LUID *set) +{ + static fstring name; + int i = 0; + + if (set->high != 0) + return NULL; + + for ( i=0; privs[i].se_priv!=SE_END; i++ ) { + if (set->low == privs[i].se_priv) { + fstrcpy(name, privs[i].name); + return name; + } + } + + return NULL; +} + +/**************************************************************************** + Convert an LUID to a 32-bit mask +****************************************************************************/ + +uint32 luid_to_privilege_mask(const LUID *set) +{ + int i = 0; + + if (set->high != 0) + return SE_END; + + for ( i=0; privs[i].se_priv != SE_END; i++ ) { + if (set->low == privs[i].se_priv) + return privs[i].se_priv; + } + + return SE_END; +} + +/******************************************************************* + return the number of elements in the privlege array +*******************************************************************/ + +int count_all_privileges( void ) +{ + static int count; + + if ( count ) + return count; + + /* loop over the array and count it */ + for ( count=0; privs[count].se_priv != SE_END; count++ ) ; + + return count; +} + diff --git a/source3/lib/util_sid.c b/source3/lib/util_sid.c index 197157a2f7..0ba774e184 100644 --- a/source3/lib/util_sid.c +++ b/source3/lib/util_sid.c @@ -647,3 +647,67 @@ DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, const DOM_SID *src) return dst; } + +/******************************************************************** + Add SID to an array SIDs +********************************************************************/ + +void add_sid_to_array(const DOM_SID *sid, DOM_SID **sids, int *num) +{ + *sids = SMB_REALLOC_ARRAY(*sids, DOM_SID, (*num)+1); + + if (*sids == NULL) + return; + + sid_copy(&((*sids)[*num]), sid); + *num += 1; + + return; +} + + +/******************************************************************** + Add SID to an array SIDs ensuring that it is not already there +********************************************************************/ + +void add_sid_to_array_unique(const DOM_SID *sid, DOM_SID **sids, int *num_sids) +{ + int i; + + for (i=0; i<(*num_sids); i++) { + if (sid_compare(sid, &(*sids)[i]) == 0) + return; + } + + add_sid_to_array(sid, sids, num_sids); +} + +/******************************************************************** + Remove SID from an array +********************************************************************/ + +void del_sid_from_array(const DOM_SID *sid, DOM_SID **sids, int *num) +{ + DOM_SID *sid_list = *sids; + int i; + + for ( i=0; i<*num; i++ ) { + + /* if we find the SID, then decrement the count + and break out of the loop */ + + if ( sid_equal(sid, &sid_list[i]) ) { + *num -= 1; + break; + } + } + + /* This loop will copy the remainder of the array + if i < num of sids ni the array */ + + for ( ; i<*num; i++ ) + sid_copy( &sid_list[i], &sid_list[i+1] ); + + return; +} + diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index c792d229b9..53baaf580d 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -2,7 +2,7 @@ * Unix SMB/CIFS implementation. * SMB parameters and setup * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Simo Sorce 2000-2002 + * Copyright (C) Simo Sorce 2000-2003 * Copyright (C) Gerald Carter 2000 * Copyright (C) Jeremy Allison 2001 * Copyright (C) Andrew Bartlett 2002 @@ -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 { @@ -704,6 +705,18 @@ static void free_private_data(void **vp) } + + +/** + * Init tdbsam backend + * + * @param pdb_context initialised passdb context + * @param pdb_method backend methods structure to be filled with function pointers + * @param location the backend tdb file location + * + * @return nt_status code + **/ + static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) { NTSTATUS nt_status; diff --git a/source3/passdb/privileges.c b/source3/passdb/privileges.c deleted file mode 100644 index 69fc75a618..0000000000 --- a/source3/passdb/privileges.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * 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_bystring(tdb, right); - if (!data.dptr) { - *count = 0; - *sids = NULL; - return NT_STATUS_OK; - } - - /* count them */ - for (i=0, p=data.dptr; p<data.dptr+data.dsize; i++) { - p += strlen(p) + 1; - } - *count = i; - - /* allocate and parse */ - *sids = SMB_MALLOC_ARRAY(DOM_SID, *count); - if (! *sids) { - return NT_STATUS_NO_MEMORY; - } - for (i=0, p=data.dptr; p<data.dptr+data.dsize; i++) { - if (!string_to_sid(&(*sids)[i], p)) { - free(data.dptr); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - p += strlen(p) + 1; - } - - free(data.dptr); - - return NT_STATUS_OK; -} - -/* - set what accounts have a given right - this is an internal interface -*/ -static NTSTATUS privilege_set_accounts_with_right(const char *right, - uint32 count, - DOM_SID *sids) -{ - TDB_DATA data; - char *p; - int i; - - if (!tdb) { - return NT_STATUS_INTERNAL_ERROR; - } - - /* allocate the maximum size that we might use */ - data.dptr = SMB_MALLOC(count * ((MAXSUBAUTHS*11) + 30)); - if (!data.dptr) { - return NT_STATUS_NO_MEMORY; - } - - p = data.dptr; - - for (i=0;i<count;i++) { - sid_to_string(p, &sids[i]); - p += strlen(p) + 1; - } - - data.dsize = PTR_DIFF(p, data.dptr); - - if (tdb_store_bystring(tdb, right, data, TDB_REPLACE) != 0) { - free(data.dptr); - return NT_STATUS_INTERNAL_ERROR; - } - - free(data.dptr); - return NT_STATUS_OK; -} - - -/* - add a SID to the list of SIDs for a right -*/ -NTSTATUS privilege_add_account_right(const char *right, - DOM_SID *sid) -{ - NTSTATUS status; - DOM_SID *current_sids; - uint32 current_count; - int i; - - status = privilege_lock_right(right); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = privilege_enum_account_with_right(right, ¤t_count, ¤t_sids); - if (!NT_STATUS_IS_OK(status)) { - privilege_unlock_right(right); - return status; - } - - /* maybe that SID is already listed? this is not an error */ - for (i=0;i<current_count;i++) { - if (sid_equal(¤t_sids[i], sid)) { - privilege_unlock_right(right); - free(current_sids); - return NT_STATUS_OK; - } - } - - /* add it in */ - current_sids = SMB_REALLOC_ARRAY(current_sids, DOM_SID, current_count+1); - if (!current_sids) { - privilege_unlock_right(right); - return NT_STATUS_NO_MEMORY; - } - - sid_copy(¤t_sids[current_count], sid); - current_count++; - - status = privilege_set_accounts_with_right(right, current_count, current_sids); - - free(current_sids); - privilege_unlock_right(right); - - return status; -} - - -/* - remove a SID from the list of SIDs for a right -*/ -NTSTATUS privilege_remove_account_right(const char *right, - DOM_SID *sid) -{ - NTSTATUS status; - DOM_SID *current_sids; - uint32 current_count; - int i; - - status = privilege_lock_right(right); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = privilege_enum_account_with_right(right, ¤t_count, ¤t_sids); - if (!NT_STATUS_IS_OK(status)) { - privilege_unlock_right(right); - return status; - } - - for (i=0;i<current_count;i++) { - if (sid_equal(¤t_sids[i], sid)) { - /* found it - so remove it */ - if (current_count-i > 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;i<count;i++) { - if (sid_equal(sid, &sids[i])) { - free(sids); - return True; - } - } - - safe_free(sids); - return False; -} - -/* - list the rights for an account. This involves traversing the database -*/ -NTSTATUS privilege_enum_account_rights(DOM_SID *sid, - uint32 *count, - char ***rights) -{ - TDB_DATA key, nextkey; - char *right; - - if (!tdb) { - return NT_STATUS_INTERNAL_ERROR; - } - - *rights = NULL; - *count = 0; - - for (key = tdb_firstkey(tdb); key.dptr; key = nextkey) { - nextkey = tdb_nextkey(tdb, key); - - right = key.dptr; - - if (privilege_sid_has_right(sid, right)) { - (*rights) = SMB_REALLOC_ARRAY(*rights,char *, (*count)+1); - if (! *rights) { - safe_free(nextkey.dptr); - free(key.dptr); - return NT_STATUS_NO_MEMORY; - } - - (*rights)[*count] = SMB_STRDUP(right); - (*count)++; - } - - free(key.dptr); - } - - return NT_STATUS_OK; -} diff --git a/source3/passdb/util_sam_sid.c b/source3/passdb/util_sam_sid.c index c93c3400bd..1fddfc7925 100644 --- a/source3/passdb/util_sam_sid.c +++ b/source3/passdb/util_sam_sid.c @@ -315,28 +315,4 @@ BOOL map_name_to_wellknown_sid(DOM_SID *sid, enum SID_NAME_USE *use, const char return False; } -void add_sid_to_array(const DOM_SID *sid, DOM_SID **sids, int *num) -{ - *sids = SMB_REALLOC_ARRAY(*sids, DOM_SID, (*num)+1); - - if (*sids == NULL) - return; - - sid_copy(&((*sids)[*num]), sid); - *num += 1; - - return; -} - -void add_sid_to_array_unique(const DOM_SID *sid, DOM_SID **sids, int *num_sids) -{ - int i; - - for (i=0; i<(*num_sids); i++) { - if (sid_compare(sid, &(*sids)[i]) == 0) - return; - } - - add_sid_to_array(sid, sids, num_sids); -} diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index edff25da7d..b08fa169ef 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -1037,9 +1037,9 @@ NTSTATUS cli_lsa_enum_privsaccount(struct cli_state *cli, TALLOC_CTX *mem_ctx, } for (i=0; i<r.count; i++) { - (*set)[i].luid.low = r.set->set[i].luid.low; - (*set)[i].luid.high = r.set->set[i].luid.high; - (*set)[i].attr = r.set->set[i].attr; + (*set)[i].luid.low = r.set.set[i].luid.low; + (*set)[i].luid.high = r.set.set[i].luid.high; + (*set)[i].attr = r.set.set[i].attr; } *count=r.count; diff --git a/source3/rpc_parse/parse_lsa.c b/source3/rpc_parse/parse_lsa.c index e2cb94c8fe..20ccc39ce0 100644 --- a/source3/rpc_parse/parse_lsa.c +++ b/source3/rpc_parse/parse_lsa.c @@ -1650,6 +1650,61 @@ BOOL lsa_io_r_unk_get_connuser(const char *desc, LSA_R_UNK_GET_CONNUSER *r_c, pr return True; } +void init_lsa_q_create_account(LSA_Q_CREATEACCOUNT *trn, POLICY_HND *hnd, DOM_SID *sid, uint32 desired_access) +{ + memcpy(&trn->pol, hnd, sizeof(trn->pol)); + + init_dom_sid2(&trn->sid, sid); + trn->access = desired_access; +} + + +/******************************************************************* + Reads or writes an LSA_Q_CREATEACCOUNT structure. +********************************************************************/ + +BOOL lsa_io_q_create_account(const char *desc, LSA_Q_CREATEACCOUNT *r_c, prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "lsa_io_q_create_account"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth)) + return False; + + if(!smb_io_dom_sid2("sid", &r_c->sid, ps, depth)) /* domain SID */ + return False; + + if(!prs_uint32("access", ps, depth, &r_c->access)) + return False; + + return True; +} + +/******************************************************************* + Reads or writes an LSA_R_CREATEACCOUNT structure. +********************************************************************/ + +BOOL lsa_io_r_create_account(const char *desc, LSA_R_CREATEACCOUNT *r_c, prs_struct *ps, int depth) +{ + prs_debug(ps, depth, desc, "lsa_io_r_open_account"); + depth++; + + if(!prs_align(ps)) + return False; + + if(!smb_io_pol_hnd("pol", &r_c->pol, ps, depth)) + return False; + + if(!prs_ntstatus("status", ps, depth, &r_c->status)) + return False; + + return True; +} + + void init_lsa_q_open_account(LSA_Q_OPENACCOUNT *trn, POLICY_HND *hnd, DOM_SID *sid, uint32 desired_access) { memcpy(&trn->pol, hnd, sizeof(trn->pol)); @@ -1804,13 +1859,15 @@ NTSTATUS init_lsa_r_enum_privsaccount(TALLOC_CTX *mem_ctx, LSA_R_ENUMPRIVSACCOUN r_u->ptr = 1; r_u->count = count; - if (!NT_STATUS_IS_OK(ret = init_priv_with_ctx(mem_ctx, &(r_u->set)))) + if ( !NT_STATUS_IS_OK(ret = privilege_set_init_by_ctx(mem_ctx, &(r_u->set))) ) return ret; - if (!NT_STATUS_IS_OK(ret = dupalloc_luid_attr(r_u->set->mem_ctx, &(r_u->set->set), set))) + r_u->set.count = count; + + if (!NT_STATUS_IS_OK(ret = dup_luid_attr(r_u->set.mem_ctx, &(r_u->set.set), set, count))) return ret; - DEBUG(10,("init_lsa_r_enum_privsaccount: %d %d privileges\n", r_u->count, r_u->set->count)); + DEBUG(10,("init_lsa_r_enum_privsaccount: %d privileges\n", r_u->count)); return ret; } @@ -1837,15 +1894,15 @@ BOOL lsa_io_r_enum_privsaccount(const char *desc, LSA_R_ENUMPRIVSACCOUNT *r_c, p /* malloc memory if unmarshalling here */ if (UNMARSHALLING(ps) && r_c->count != 0) { - if (!NT_STATUS_IS_OK(init_priv_with_ctx(ps->mem_ctx, &(r_c->set)))) + if (!NT_STATUS_IS_OK(privilege_set_init_by_ctx(ps->mem_ctx, &(r_c->set)))) return False; - if (!(r_c->set->set = PRS_ALLOC_MEM(ps,LUID_ATTR,r_c->count))) + if (!(r_c->set.set = PRS_ALLOC_MEM(ps,LUID_ATTR,r_c->count))) return False; } - if(!lsa_io_privilege_set(desc, r_c->set, ps, depth)) + if(!lsa_io_privilege_set(desc, &r_c->set, ps, depth)) return False; } @@ -2007,14 +2064,14 @@ BOOL lsa_io_q_addprivs(const char *desc, LSA_Q_ADDPRIVS *r_c, prs_struct *ps, in return False; if (UNMARSHALLING(ps) && r_c->count!=0) { - if (!NT_STATUS_IS_OK(init_priv_with_ctx(ps->mem_ctx, &(r_c->set)))) + if (!NT_STATUS_IS_OK(privilege_set_init_by_ctx(ps->mem_ctx, &(r_c->set)))) return False; - if (!(r_c->set->set = PRS_ALLOC_MEM(ps, LUID_ATTR, r_c->count))) + if (!(r_c->set.set = PRS_ALLOC_MEM(ps, LUID_ATTR, r_c->count))) return False; } - if(!lsa_io_privilege_set(desc, r_c->set, ps, depth)) + if(!lsa_io_privilege_set(desc, &r_c->set, ps, depth)) return False; return True; @@ -2069,14 +2126,14 @@ BOOL lsa_io_q_removeprivs(const char *desc, LSA_Q_REMOVEPRIVS *r_c, prs_struct * return False; if (UNMARSHALLING(ps) && r_c->count!=0) { - if (!NT_STATUS_IS_OK(init_priv_with_ctx(ps->mem_ctx, &(r_c->set)))) + if (!NT_STATUS_IS_OK(privilege_set_init_by_ctx(ps->mem_ctx, &(r_c->set)))) return False; - if (!(r_c->set->set = PRS_ALLOC_MEM(ps, LUID_ATTR, r_c->count))) + if (!(r_c->set.set = PRS_ALLOC_MEM(ps, LUID_ATTR, r_c->count))) return False; } - if(!lsa_io_privilege_set(desc, r_c->set, ps, depth)) + if(!lsa_io_privilege_set(desc, &r_c->set, ps, depth)) return False; } diff --git a/source3/rpc_server/srv_lsa.c b/source3/rpc_server/srv_lsa.c index 5d6c1551c9..63e74ec891 100644 --- a/source3/rpc_server/srv_lsa.c +++ b/source3/rpc_server/srv_lsa.c @@ -393,6 +393,37 @@ static BOOL api_lsa_unk_get_connuser(pipes_struct *p) } /*************************************************************************** + api_lsa_create_user + ***************************************************************************/ + +static BOOL api_lsa_create_account(pipes_struct *p) +{ + LSA_Q_CREATEACCOUNT q_u; + LSA_R_CREATEACCOUNT r_u; + + prs_struct *data = &p->in_data.data; + prs_struct *rdata = &p->out_data.rdata; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if(!lsa_io_q_create_account("", &q_u, data, 0)) { + DEBUG(0,("api_lsa_create_account: failed to unmarshall LSA_Q_CREATEACCOUNT.\n")); + return False; + } + + r_u.status = _lsa_create_account(p, &q_u, &r_u); + + /* store the response in the SMB stream */ + if(!lsa_io_r_create_account("", &r_u, rdata, 0)) { + DEBUG(0,("api_lsa_create_account: Failed to marshall LSA_R_CREATEACCOUNT.\n")); + return False; + } + + return True; +} + +/*************************************************************************** api_lsa_open_user ***************************************************************************/ @@ -659,6 +690,7 @@ static struct api_struct api_lsa_cmds[] = { "LSA_PRIV_GET_DISPNAME",LSA_PRIV_GET_DISPNAME,api_lsa_priv_get_dispname}, { "LSA_ENUM_ACCOUNTS" , LSA_ENUM_ACCOUNTS , api_lsa_enum_accounts }, { "LSA_UNK_GET_CONNUSER", LSA_UNK_GET_CONNUSER, api_lsa_unk_get_connuser }, + { "LSA_CREATEACCOUNT" , LSA_CREATEACCOUNT , api_lsa_create_account }, { "LSA_OPENACCOUNT" , LSA_OPENACCOUNT , api_lsa_open_account }, { "LSA_ENUMPRIVSACCOUNT", LSA_ENUMPRIVSACCOUNT, api_lsa_enum_privsaccount}, { "LSA_GETSYSTEMACCOUNT", LSA_GETSYSTEMACCOUNT, api_lsa_getsystemaccount }, diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index fcd574971f..89633935a2 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -1,4 +1,4 @@ -/* +/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-1997, @@ -7,6 +7,7 @@ * Copyright (C) Jeremy Allison 2001, * Copyright (C) Rafal Szczesniak 2002, * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002, + * Copyright (C) Simo Sorce 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 @@ -411,9 +412,12 @@ NTSTATUS _lsa_open_policy2(pipes_struct *p, LSA_Q_OPEN_POL2 *q_u, LSA_R_OPEN_POL DEBUG(4,("ACCESS should be DENIED (granted: %#010x; required: %#010x)\n", acc_granted, des_access)); DEBUGADD(4,("but overwritten by euid == 0\n")); - acc_granted = des_access; } + /* This is needed for lsa_open_account and rpcclient .... :-) */ + + if (geteuid() == 0) + acc_granted = POLICY_ALL_ACCESS; /* associate the domain SID with the (unique) handle. */ if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) @@ -758,49 +762,51 @@ NTSTATUS _lsa_enum_privs(pipes_struct *p, LSA_Q_ENUM_PRIVS *q_u, LSA_R_ENUM_PRIV { struct lsa_info *handle; uint32 i; + uint32 enum_context = q_u->enum_context; + int num_privs = count_all_privileges(); + LSA_PRIV_ENTRY *entries = NULL; - uint32 enum_context=q_u->enum_context; - LSA_PRIV_ENTRY *entry; - LSA_PRIV_ENTRY *entries=NULL; + /* remember that the enum_context starts at 0 and not 1 */ - if (enum_context >= PRIV_ALL_INDEX) + if ( enum_context >= num_privs ) return NT_STATUS_NO_MORE_ENTRIES; - - entries = TALLOC_ZERO_ARRAY(p->mem_ctx, LSA_PRIV_ENTRY, PRIV_ALL_INDEX); - if (entries==NULL) + + DEBUG(10,("_lsa_enum_privs: enum_context:%d total entries:%d\n", + enum_context, num_privs)); + + if ( !(entries = TALLOC_ZERO_ARRAY(p->mem_ctx, LSA_PRIV_ENTRY, num_privs + 1))) return NT_STATUS_NO_MEMORY; if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) return NT_STATUS_INVALID_HANDLE; - /* check if the user have enough rights */ + /* check if the user have enough rights + I don't know if it's the right one. not documented. */ - /* - * I don't know if it's the right one. not documented. - */ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION)) return NT_STATUS_ACCESS_DENIED; - entry = entries; - - DEBUG(10,("_lsa_enum_privs: enum_context:%d total entries:%d\n", enum_context, PRIV_ALL_INDEX)); - - for (i = 0; i < PRIV_ALL_INDEX; i++, entry++) { - if( i<enum_context) { - init_unistr2(&entry->name, NULL, UNI_FLAGS_NONE); - init_uni_hdr(&entry->hdr_name, &entry->name); - entry->luid_low = 0; - entry->luid_high = 0; + if ( !(entries = TALLOC_ZERO_ARRAY(p->mem_ctx, LSA_PRIV_ENTRY, num_privs )) ) + return NT_STATUS_NO_MEMORY; + + + for (i = 0; i < num_privs; i++) { + if( i < enum_context) { + init_unistr2(&entries[i].name, NULL, UNI_FLAGS_NONE); + init_uni_hdr(&entries[i].hdr_name, &entries[i].name); + entries[i].luid_low = 0; + entries[i].luid_high = 0; } else { - init_unistr2(&entry->name, privs[i+1].priv, UNI_FLAGS_NONE); - init_uni_hdr(&entry->hdr_name, &entry->name); - entry->luid_low = privs[i+1].se_priv; - entry->luid_high = 0; + init_unistr2(&entries[i].name, privs[i].name, UNI_FLAGS_NONE); + init_uni_hdr(&entries[i].hdr_name, &entries[i].name); + entries[i].luid_low = privs[i].se_priv; + entries[i].luid_high = 0; } } - enum_context = PRIV_ALL_INDEX; - init_lsa_r_enum_privs(r_u, enum_context, PRIV_ALL_INDEX, entries); + enum_context = num_privs; + + init_lsa_r_enum_privs(r_u, enum_context, num_privs, entries); return NT_STATUS_OK; } @@ -813,7 +819,7 @@ NTSTATUS _lsa_priv_get_dispname(pipes_struct *p, LSA_Q_PRIV_GET_DISPNAME *q_u, L { struct lsa_info *handle; fstring name_asc; - int i=1; + int i = 0; if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) return NT_STATUS_INVALID_HANDLE; @@ -828,22 +834,22 @@ NTSTATUS _lsa_priv_get_dispname(pipes_struct *p, LSA_Q_PRIV_GET_DISPNAME *q_u, L unistr2_to_ascii(name_asc, &q_u->name, sizeof(name_asc)); - DEBUG(10,("_lsa_priv_get_dispname: %s", name_asc)); + DEBUG(10,("_lsa_priv_get_dispname: %s\n", name_asc)); - while (privs[i].se_priv!=SE_PRIV_ALL && strcmp(name_asc, privs[i].priv)) + while (privs[i].se_priv != SE_END && !strequal(name_asc, privs[i].name)) i++; - if (privs[i].se_priv!=SE_PRIV_ALL) { + if (privs[i].se_priv != SE_END) { DEBUG(10,(": %s\n", privs[i].description)); init_unistr2(&r_u->desc, privs[i].description, UNI_FLAGS_NONE); init_uni_hdr(&r_u->hdr_desc, &r_u->desc); - r_u->ptr_info=0xdeadbeef; - r_u->lang_id=q_u->lang_id; + r_u->ptr_info = 0xdeadbeef; + r_u->lang_id = q_u->lang_id; return NT_STATUS_OK; } else { DEBUG(10,("_lsa_priv_get_dispname: doesn't exist\n")); - r_u->ptr_info=0; + r_u->ptr_info = 0; return NT_STATUS_NO_SUCH_PRIVILEGE; } } @@ -855,32 +861,26 @@ _lsa_enum_accounts. NTSTATUS _lsa_enum_accounts(pipes_struct *p, LSA_Q_ENUM_ACCOUNTS *q_u, LSA_R_ENUM_ACCOUNTS *r_u) { struct lsa_info *handle; - GROUP_MAP *map=NULL; - int num_entries=0; + DOM_SID *sid_list; + int i, j, num_entries; LSA_SID_ENUM *sids=&r_u->sids; - int i=0,j=0; - BOOL ret; + NTSTATUS ret; if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) return NT_STATUS_INVALID_HANDLE; - /* check if the user have enough rights */ - - /* - * I don't know if it's the right one. not documented. - */ if (!(handle->access & POLICY_VIEW_LOCAL_INFORMATION)) return NT_STATUS_ACCESS_DENIED; - /* get the list of mapped groups (domain, local, builtin) */ - become_root(); - ret = pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, ENUM_ONLY_MAPPED); - unbecome_root(); - if( !ret ) { - DEBUG(3,("_lsa_enum_accounts: enumeration of groups failed!\n")); - return NT_STATUS_OK; + sid_list = NULL; + num_entries = 0; + + /* The only way we can currently find out all the SIDs that have been + privileged is to scan all privileges */ + + if (!NT_STATUS_IS_OK(ret = privilege_enumerate_accounts(&sid_list, &num_entries))) { + return ret; } - if (q_u->enum_context >= num_entries) return NT_STATUS_NO_MORE_ENTRIES; @@ -889,19 +889,18 @@ NTSTATUS _lsa_enum_accounts(pipes_struct *p, LSA_Q_ENUM_ACCOUNTS *q_u, LSA_R_ENU sids->sid = TALLOC_ZERO_ARRAY(p->mem_ctx, DOM_SID2, num_entries-q_u->enum_context); if (sids->ptr_sid==NULL || sids->sid==NULL) { - SAFE_FREE(map); + SAFE_FREE(sid_list); return NT_STATUS_NO_MEMORY; } - for (i=q_u->enum_context, j=0; i<num_entries; i++) { - init_dom_sid2( &(*sids).sid[j], &map[i].sid); - (*sids).ptr_sid[j]=1; - j++; + for (i = q_u->enum_context, j = 0; i < num_entries; i++, j++) { + init_dom_sid2(&(*sids).sid[j], &sid_list[i]); + (*sids).ptr_sid[j] = 1; } - SAFE_FREE(map); + SAFE_FREE(sid_list); - init_lsa_r_enum_accounts(r_u, j); + init_lsa_r_enum_accounts(r_u, num_entries); return NT_STATUS_OK; } @@ -934,15 +933,51 @@ NTSTATUS _lsa_unk_get_connuser(pipes_struct *p, LSA_Q_UNK_GET_CONNUSER *q_u, LSA } /*************************************************************************** - + Lsa Create Account ***************************************************************************/ -NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENACCOUNT *r_u) +NTSTATUS _lsa_create_account(pipes_struct *p, LSA_Q_CREATEACCOUNT *q_u, LSA_R_CREATEACCOUNT *r_u) { struct lsa_info *handle; struct lsa_info *info; - r_u->status = NT_STATUS_OK; + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) + return NT_STATUS_INVALID_HANDLE; + + /* check if the user have enough rights */ + + /* + * I don't know if it's the right one. not documented. + * but guessed with rpcclient. + */ + if (!(handle->access & POLICY_GET_PRIVATE_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + /* associate the user/group SID with the (unique) handle. */ + if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) + return NT_STATUS_NO_MEMORY; + + ZERO_STRUCTP(info); + info->sid = q_u->sid.sid; + info->access = q_u->access; + + /* get a (unique) handle. open a policy on it. */ + if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + + return privilege_create_account( &info->sid ); +} + + +/*************************************************************************** + Lsa Open Account + ***************************************************************************/ + +NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENACCOUNT *r_u) +{ + struct lsa_info *handle; + struct lsa_info *info; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&handle)) @@ -957,6 +992,11 @@ NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENAC if (!(handle->access & POLICY_GET_PRIVATE_INFORMATION)) return NT_STATUS_ACCESS_DENIED; + /* TODO: Fis the parsing routine before reenabling this check! */ + #if 0 + if (!lookup_sid(&handle->sid, dom_name, name, &type)) + return NT_STATUS_ACCESS_DENIED; + #endif /* associate the user/group SID with the (unique) handle. */ if ((info = SMB_MALLOC_P(struct lsa_info)) == NULL) return NT_STATUS_NO_MEMORY; @@ -969,7 +1009,7 @@ NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENAC if (!create_policy_hnd(p, &r_u->pol, free_lsa_info, (void *)info)) return NT_STATUS_OBJECT_NAME_NOT_FOUND; - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -979,44 +1019,24 @@ NTSTATUS _lsa_open_account(pipes_struct *p, LSA_Q_OPENACCOUNT *q_u, LSA_R_OPENAC NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, prs_struct *ps, LSA_Q_ENUMPRIVSACCOUNT *q_u, LSA_R_ENUMPRIVSACCOUNT *r_u) { struct lsa_info *info=NULL; - GROUP_MAP map; - LUID_ATTR *set=NULL; - - r_u->status = NT_STATUS_OK; + PRIVILEGE_SET priv; /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid)) - return NT_STATUS_NO_SUCH_GROUP; + privilege_set_init( &priv ); -#if 0 /* privileges currently not implemented! */ - DEBUG(10,("_lsa_enum_privsaccount: %d privileges\n", map.priv_set->count)); - if (map.priv_set->count!=0) { - - set=(LUID_ATTR *)talloc(map.priv_set->mem_ctx, map.priv_set.count*sizeof(LUID_ATTR)); - if (set == NULL) { - destroy_privilege(&map.priv_set); - return NT_STATUS_NO_MEMORY; - } + get_privileges_for_sids( &priv, &info->sid, 1 ); - for (i = 0; i < map.priv_set.count; i++) { - set[i].luid.low = map.priv_set->set[i].luid.low; - set[i].luid.high = map.priv_set->set[i].luid.high; - set[i].attr = map.priv_set->set[i].attr; - DEBUG(10,("_lsa_enum_privsaccount: priv %d: %d:%d:%d\n", i, - set[i].luid.high, set[i].luid.low, set[i].attr)); - } - } + DEBUG(10,("_lsa_enum_privsaccount: %s has %d privileges\n", + sid_string_static(&info->sid), priv.count)); - init_lsa_r_enum_privsaccount(ps->mem_ctx, r_u, set, map.priv_set->count, 0); - destroy_privilege(&map.priv_set); -#endif + init_lsa_r_enum_privsaccount(ps->mem_ctx, r_u, priv.set, priv.count, 0); - init_lsa_r_enum_privsaccount(ps->mem_ctx, r_u, set, 0, 0); + privilege_set_free( &priv ); - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -1026,15 +1046,16 @@ NTSTATUS _lsa_enum_privsaccount(pipes_struct *p, prs_struct *ps, LSA_Q_ENUMPRIVS NTSTATUS _lsa_getsystemaccount(pipes_struct *p, LSA_Q_GETSYSTEMACCOUNT *q_u, LSA_R_GETSYSTEMACCOUNT *r_u) { struct lsa_info *info=NULL; - GROUP_MAP map; - r_u->status = NT_STATUS_OK; + fstring name, dom_name; + enum SID_NAME_USE type; /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid)) - return NT_STATUS_NO_SUCH_GROUP; + if (!lookup_sid(&info->sid, dom_name, name, &type)) + return NT_STATUS_ACCESS_DENIED; /* 0x01 -> Log on locally @@ -1047,7 +1068,7 @@ NTSTATUS _lsa_getsystemaccount(pipes_struct *p, LSA_Q_GETSYSTEMACCOUNT *q_u, LSA r_u->access = PR_LOG_ON_LOCALLY | PR_ACCESS_FROM_NETWORK; - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -1079,44 +1100,31 @@ NTSTATUS _lsa_setsystemaccount(pipes_struct *p, LSA_Q_SETSYSTEMACCOUNT *q_u, LSA NTSTATUS _lsa_addprivs(pipes_struct *p, LSA_Q_ADDPRIVS *q_u, LSA_R_ADDPRIVS *r_u) { -#if 0 struct lsa_info *info = NULL; - GROUP_MAP map; int i = 0; - LUID_ATTR *luid_attr = NULL; + uint32 mask; PRIVILEGE_SET *set = NULL; -#endif - - r_u->status = NT_STATUS_OK; -#if 0 /* privileges are not implemented */ /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid)) - return NT_STATUS_NO_SUCH_GROUP; - set = &q_u->set; for (i = 0; i < set->count; i++) { - luid_attr = &set->set[i]; - - /* check if the privilege is already there */ - if (check_priv_in_privilege(map.priv_set, *luid_attr)){ - destroy_privilege(&map.priv_set); + + mask = luid_to_privilege_mask( &(set->set[i].luid) ); + + if ( mask != SE_END ) { + if ( !grant_privilege( &info->sid, mask ) ) { + DEBUG(3,("_lsa_addprivs: grant_privilege( %s, 0x%x) failed!\n", + sid_string_static(&info->sid), mask )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } } - - add_privilege(map.priv_set, *luid_attr); } - if(!pdb_update_group_mapping_entry(&map)) - return NT_STATUS_NO_SUCH_GROUP; - - destroy_privilege(&map.priv_set); - -#endif - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** @@ -1125,57 +1133,30 @@ NTSTATUS _lsa_addprivs(pipes_struct *p, LSA_Q_ADDPRIVS *q_u, LSA_R_ADDPRIVS *r_u NTSTATUS _lsa_removeprivs(pipes_struct *p, LSA_Q_REMOVEPRIVS *q_u, LSA_R_REMOVEPRIVS *r_u) { -#if 0 struct lsa_info *info = NULL; - GROUP_MAP map; - int i=0; - LUID_ATTR *luid_attr = NULL; + int i = 0; + uint32 mask; PRIVILEGE_SET *set = NULL; -#endif - - r_u->status = NT_STATUS_OK; -#if 0 /* privileges are not implemented */ /* find the connection policy handle. */ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info)) return NT_STATUS_INVALID_HANDLE; - if (!pdb_getgrsid(&map, info->sid)) - return NT_STATUS_NO_SUCH_GROUP; - - if (q_u->allrights != 0) { - /* log it and return, until I see one myself don't do anything */ - DEBUG(5,("_lsa_removeprivs: trying to remove all privileges ?\n")); - return NT_STATUS_OK; - } - - if (q_u->ptr == 0) { - /* log it and return, until I see one myself don't do anything */ - DEBUG(5,("_lsa_removeprivs: no privileges to remove ?\n")); - return NT_STATUS_OK; - } - set = &q_u->set; for (i = 0; i < set->count; i++) { - luid_attr = &set->set[i]; - - /* if we don't have the privilege, we're trying to remove, give up */ - /* what else can we do ??? JFM. */ - if (!check_priv_in_privilege(map.priv_set, *luid_attr)){ - destroy_privilege(&map.priv_set); - return NT_STATUS_NO_SUCH_PRIVILEGE; + mask = luid_to_privilege_mask( &(set->set[i].luid) ); + + if ( mask != SE_END ) { + if ( !revoke_privilege( &info->sid, mask ) ) { + DEBUG(3,("_lsa_removeprivs: revoke_privilege( %s, 0x%x) failed!\n", + sid_string_static(&info->sid), mask )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } } - - remove_privilege(map.priv_set, *luid_attr); } - if(!pdb_update_group_mapping_entry(&map)) - return NT_STATUS_NO_SUCH_GROUP; - - destroy_privilege(&map.priv_set); -#endif - return r_u->status; + return NT_STATUS_OK; } /*************************************************************************** diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index da1c386fd2..271553f4b2 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -2215,7 +2215,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA uint32 new_rid = 0; /* check this, when giving away 'add computer to domain' privs */ uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS; - BOOL is_domain_admin = False; + BOOL can_add_machines = False; /* Get the domain SID stored in the domain policy */ if (!get_lsa_policy_samr_sid(p, &dom_pol, &sid, &acc_granted)) @@ -2242,10 +2242,10 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA /* check to see if we are a domain admin */ - is_domain_admin = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ); + can_add_machines = user_has_privilege( p->pipe_user.nt_user_token, SE_MACHINE_ACCOUNT ); DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n", - p->pipe_user_name, is_domain_admin ? "" : " not")); + p->pipe_user_name, can_add_machines ? "" : " not")); pdb_init_sam(&sam_pass); @@ -2280,9 +2280,9 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA pw = Get_Pwnam(account); - /* ================ BEGIN DOMAIN ADMIN BLOCK ================ */ + /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ - if ( is_domain_admin ) + if ( can_add_machines ) become_root(); if ( !pw ) { @@ -2317,7 +2317,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA /* implicit call to getpwnam() next. we have a valid SID coming out of this call */ if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account, new_rid)) ) { - if ( is_domain_admin ) + if ( can_add_machines ) unbecome_root(); return nt_status; } @@ -2326,10 +2326,10 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA ret = pdb_add_sam_account(sam_pass); - if ( is_domain_admin ) + if ( can_add_machines ) unbecome_root(); - /* ================ END DOMAIN ADMIN BLOCK ================ */ + /* ================ END SeMachineAccountPrivilege BLOCK ================ */ if ( !ret ) { pdb_free_sam(&sam_pass); @@ -3033,7 +3033,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE SAM_USERINFO_CTR *ctr = q_u->ctr; uint32 acc_granted; uint32 acc_required; - BOOL is_domain_admin; + BOOL can_add_machines; DEBUG(5, ("_samr_set_userinfo: %d\n", __LINE__)); @@ -3067,14 +3067,14 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE /* check to see if we are a domain admin */ - is_domain_admin = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ); + can_add_machines = user_has_privilege( p->pipe_user.nt_user_token, SE_MACHINE_ACCOUNT ); DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n", - p->pipe_user_name, is_domain_admin ? "" : " not")); + p->pipe_user_name, can_add_machines ? "" : " not")); - /* ================ BEGIN DOMAIN ADMIN BLOCK ================ */ + /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ - if ( is_domain_admin ) + if ( can_add_machines ) become_root(); /* ok! user info levels (lots: see MSDEV help), off we go... */ @@ -3138,10 +3138,10 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE } - if ( is_domain_admin ) + if ( can_add_machines ) unbecome_root(); - /* ================ END DOMAIN ADMIN BLOCK ================ */ + /* ================ END SeMachineAccountPrivilege BLOCK ================ */ return r_u->status; } @@ -3158,7 +3158,7 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ uint16 switch_value = q_u->switch_value; uint32 acc_granted; uint32 acc_required; - BOOL is_domain_admin; + BOOL can_add_machines; DEBUG(5, ("samr_reply_set_userinfo2: %d\n", __LINE__)); @@ -3184,14 +3184,14 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ /* check to see if we are a domain admin */ - is_domain_admin = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS ); + can_add_machines = user_has_privilege( p->pipe_user.nt_user_token, SE_MACHINE_ACCOUNT ); DEBUG(5, ("_samr_create_user: %s is%s a member of the Domain Admins group\n", - p->pipe_user_name, is_domain_admin ? "" : " not")); + p->pipe_user_name, can_add_machines ? "" : " not")); - /* ================ BEGIN DOMAIN ADMIN BLOCK ================ */ + /* ================ BEGIN SeMachineAccountPrivilege BLOCK ================ */ - if ( is_domain_admin ) + if ( can_add_machines ) become_root(); /* ok! user info levels (lots: see MSDEV help), off we go... */ @@ -3218,10 +3218,10 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ r_u->status = NT_STATUS_INVALID_INFO_CLASS; } - if ( is_domain_admin ) + if ( can_add_machines ) unbecome_root(); - /* ================ END DOMAIN ADMIN BLOCK ================ */ + /* ================ END SeMachineAccountPrivilege BLOCK ================ */ return r_u->status; } |