r4724: Add support for Windows privileges in Samba 3.0
authorGerald Carter <jerry@samba.org>
Thu, 13 Jan 2005 18:20:37 +0000 (18:20 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:53:51 +0000 (10:53 -0500)
(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)

18 files changed:
source3/Makefile.in
source3/auth/auth_util.c
source3/groupdb/mapping.c
source3/include/includes.h
source3/include/privileges.h
source3/include/rpc_lsa.h
source3/include/smb.h
source3/lib/account_pol.c
source3/lib/privileges.c
source3/lib/util_sid.c
source3/passdb/pdb_tdb.c
source3/passdb/privileges.c [deleted file]
source3/passdb/util_sam_sid.c
source3/rpc_client/cli_lsarpc.c
source3/rpc_parse/parse_lsa.c
source3/rpc_server/srv_lsa.c
source3/rpc_server/srv_lsa_nt.c
source3/rpc_server/srv_samr_nt.c

index 79579b21c12d8fc3db5624de36e668864f4b4ee6..aeb6c456d20dce5465c9a94e0e79122cbc0cd3cd 100644 (file)
@@ -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 \
index 98ecd00d1c50e164bdac68c3c5db4d81890751ce..e4793c3df39745dbbbe444a94632ea827df26591 100644 (file)
@@ -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;
 }
index 7095997dc8d4aeae40596be55fc655df4f2a788c..e574a7cf204a74cb65f02ab1b31d05c8d2af6dba 100644 (file)
@@ -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
 ****************************************************************************/
index 66ff4fa9f02e2dd9e024525252e6fdf62158b76e..45c7133f1ea676ac63afa27e2635e41420115851 100644 (file)
@@ -814,6 +814,8 @@ extern int errno;
 
 #include "version.h"
 
+#include "privileges.h"
+
 #include "smb.h"
 
 #include "nameserv.h"
index b7e1b44c2aff91c2debfc11159808344da288fa0..cdf62b7f858db718e4dd7a288685505675e3153e 100644 (file)
@@ -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
 #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 */
index 43ffa37d59729f1a18fc7c183d9393f22f227b97..a2bc72d2b2e16fe0da5ea352bd26ac174a75eca5 100644 (file)
@@ -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
index d15f63050747baaf35e99727a87322805a800293..1cf5aac0c507906a3ad5ce5c98f0ba9cd976d5ec 100644 (file)
@@ -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 ***/
index c62396c22d59756968f3fd68df1774417195420f..72d6e77ddda8fd5b2b681ec06f25490a742f5fe5 100644 (file)
  */
 
 #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;
+}
+
index 2b8d7613c188ba2879a9cc5a05b4ddea2c7c7bbd..eabb652c3eb37eacec553a6d2ccedc72f574775d 100644 (file)
@@ -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
    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;
+}
+
index 197157a2f72356dec98befa84b48e14ba87e6adf..0ba774e184dc38a5f73b2bf2b89e949b1fcc512d 100644 (file)
@@ -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;
+}
+
index c792d229b9af49ed45a8605b7c7b90fb39b86e41..53baaf580de541e07dbe912cb19852335929fbfc 100644 (file)
@@ -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 (file)
index 69fc75a..0000000
+++ /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, &current_count, &current_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(&current_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(&current_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, &current_count, &current_sids);
-       if (!NT_STATUS_IS_OK(status)) {
-               privilege_unlock_right(right);
-               return status;
-       }       
-
-       for (i=0;i<current_count;i++) {
-               if (sid_equal(&current_sids[i], sid)) {
-                       /* found it - so remove it */
-                       if (current_count-i > 1) {
-                               memmove(&current_sids[i], &current_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;
-}
index c93c3400bd00e45e4f4b46ffa07a6c5c1f69ea59..1fddfc7925534dcd754dc73ed246cb9839bd5ca8 100644 (file)
@@ -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);
-}
index edff25da7d8b594dceecd13957e8546ee3fe570c..b08fa169efc1c2a0bcbfa12a3d666c800b21af46 100644 (file)
@@ -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;
index e2cb94c8fe95d200a4c0fd6d03769df0a0b26026..20ccc39ce0737d361bd07715c105de6fea34210c 100644 (file)
@@ -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;
        }
 
index 5d6c1551c91b8d5ce685d0384bff9954742eb86d..63e74ec89110544119655b68f4965334095d36f2 100644 (file)
@@ -392,6 +392,37 @@ static BOOL api_lsa_unk_get_connuser(pipes_struct *p)
        return True;
 }
 
+/***************************************************************************
+ 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 },
index fcd574971f75c22fc42398fdb4bf223e8231a03a..89633935a2796d676f4673bb993bb70677827a4c 100644 (file)
@@ -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;
 }
 
 /***************************************************************************
index da1c386fd22f2049d8d68fb6eb7b217bc4a99ac7..271553f4b2ef2fa2b89ced5f62de7c35397ff309 100644 (file)
@@ -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;
 }