Replace sid_string_static by sid_string_dbg in DEBUGs
[amitay/samba.git] / source3 / lib / privileges.c
index 1ed583382de1565f816732c31dbe49c5861a5db1..3e2c756849c085e3b292f1a09a7224abfa655967 100644 (file)
@@ -1,12 +1,14 @@
 /*
    Unix SMB/CIFS implementation.
    Privileges handling functions
-   Copyright (C) Jean François Micouleau       1998-2001
+   Copyright (C) Jean François Micouleau      1998-2001
    Copyright (C) Simo Sorce                    2002-2003
+   Copyright (C) Gerald (Jerry) Carter          2005
+   Copyright (C) Michael Adam                  2007
    
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #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)
+typedef struct {
+       size_t count;
+       DOM_SID *list;
+} SID_LIST;
+
+typedef struct {
+       TALLOC_CTX *mem_ctx;
+       SE_PRIV privilege;
+       SID_LIST sids;
+} PRIV_SID_LIST;
 
-/****************************************************************************
- 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)
+static bool get_privileges( const DOM_SID *sid, SE_PRIV *mask )
 {
-       NTSTATUS result;
-       gid_t id;
+       TDB_CONTEXT *tdb = get_account_pol_tdb();
+       fstring keystr;
+       TDB_DATA data;
 
-       /* 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;
+       /* Fail if the admin has not enable privileges */
+       
+       if ( !lp_enable_privileges() ) {
+               return False;
        }
+       
+       if ( !tdb )
+               return False;
+
+       /* PRIV_<SID> (NULL terminated) as the key */
+       
+       fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
 
-       return result;
+       data = tdb_fetch_bystring( tdb, keystr );
+       
+       if ( !data.dptr ) {
+               DEBUG(3, ("get_privileges: No privileges assigned to SID "
+                         "[%s]\n", sid_string_dbg(sid)));
+               return False;
+       }
+       
+       SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) );
+       
+       se_priv_copy( mask, (SE_PRIV*)data.dptr );
+       SAFE_FREE(data.dptr);
+
+       return True;
 }
-#endif
 
-/****************************************************************************
- duplicate alloc luid_attr
- ****************************************************************************/
-NTSTATUS dupalloc_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la)
+/***************************************************************************
+ Store the privilege mask (set) for a given SID
+****************************************************************************/
+
+static bool set_privileges( const DOM_SID *sid, SE_PRIV *mask )
 {
-       NTSTATUS ret;
+       TDB_CONTEXT *tdb = get_account_pol_tdb();
+       fstring keystr;
+       TDB_DATA data;
+       
+       if ( !lp_enable_privileges() )
+               return False;
+
+       if ( !tdb )
+               return False;
 
-       *new_la = (LUID_ATTR *)talloc(mem_ctx, sizeof(LUID_ATTR));
-       ALLOC_CHECK(new_la, ret, done, "dupalloc_luid_attr");
+       if ( !sid || (sid->num_auths == 0) ) {
+               DEBUG(0,("set_privileges: Refusing to store empty SID!\n"));
+               return False;
+       }
 
-       (*new_la)->luid.high = old_la->luid.high;
-       (*new_la)->luid.low = old_la->luid.low;
-       (*new_la)->attr = old_la->attr;
+       /* PRIV_<SID> (NULL terminated) as the key */
+       
+       fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
        
-       ret = NT_STATUS_OK;
+       /* no packing.  static size structure, just write it out */
+       
+       data.dptr  = (uint8 *)mask;
+       data.dsize = sizeof(SE_PRIV);
 
-done:
-       return ret;
+       return ( tdb_store_bystring(tdb, keystr, data, TDB_REPLACE) != -1 );
 }
 
-/****************************************************************************
- initialise a privilege list
- ****************************************************************************/
-NTSTATUS init_privilege(PRIVILEGE_SET **priv_set)
+/*********************************************************************
+ get a list of all privileges for all sids in the list
+*********************************************************************/
+
+bool get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount)
 {
-       NTSTATUS ret;
-       TALLOC_CTX *mem_ctx = talloc_init("privilege set");
-       ALLOC_CHECK(mem_ctx, ret, done, "init_privilege");
+       SE_PRIV mask;
+       int i;
+       bool found = False;
 
-       *priv_set = talloc_zero(mem_ctx, sizeof(PRIVILEGE_SET));
-       ALLOC_CHECK(*priv_set, ret, done, "init_privilege");
+       se_priv_copy( privileges, &se_priv_none );
+       
+       for ( i=0; i<scount; i++ ) {
+               /* don't add unless we actually have a privilege assigned */
 
-       (*priv_set)->mem_ctx = mem_ctx;
+               if ( !get_privileges( &slist[i], &mask ) )
+                       continue;
 
-       ret = NT_STATUS_OK;
+               DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege "
+                        "set:\n", sid_string_dbg(&slist[i])));
+               dump_se_priv( DBGC_ALL, 5, &mask );
+                       
+               se_priv_add( privileges, &mask );
+               found = True;
+       }
 
-done:
-       return ret;
+       return found;
 }
 
-NTSTATUS init_priv_with_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET **priv_set)
+
+/*********************************************************************
+ travseral functions for privilege_enumerate_accounts
+*********************************************************************/
+
+static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
 {
-       NTSTATUS ret;
+       PRIV_SID_LIST *priv = (PRIV_SID_LIST *)state;
+       int  prefixlen = strlen(PRIVPREFIX);
+       DOM_SID sid;
+       fstring sid_string;
+       
+       /* easy check first */
+       
+       if ( data.dsize != sizeof(SE_PRIV) )
+               return 0;
 
-       *priv_set = talloc_zero(mem_ctx, sizeof(PRIVILEGE_SET));
-       ALLOC_CHECK(*priv_set, ret, done, "init_privilege");
+       /* check we have a PRIV_+SID entry */
 
-       (*priv_set)->mem_ctx = mem_ctx;
-       (*priv_set)->ext_ctx = True;
+       if ( strncmp((const char *)key.dptr, PRIVPREFIX, prefixlen) != 0)
+               return 0;
+               
+       /* check to see if we are looking for a particular privilege */
+
+       if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
+               SE_PRIV mask;
+               
+               se_priv_copy( &mask, (SE_PRIV*)data.dptr );
+               
+               /* if the SID does not have the specified privilege 
+                  then just return */
+                  
+               if ( !is_privilege_assigned( &mask, &priv->privilege) )
+                       return 0;
+       }
+               
+       fstrcpy( sid_string, (const char *)&key.dptr[strlen(PRIVPREFIX)] );
 
-       ret = NT_STATUS_OK;
+       /* this is a last ditch safety check to preventing returning
+          and invalid SID (i've somehow run into this on development branches) */
 
-done:
-       return ret;
-}
+       if ( strcmp( "S-0-0", sid_string ) == 0 )
+               return 0;
 
-void reset_privilege(PRIVILEGE_SET *priv_set)
-{
-       priv_set->count = 0;
-       priv_set->control = 0;
-       priv_set->set = NULL;
+       if ( !string_to_sid(&sid, sid_string) ) {
+               DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
+                       sid_string));
+               return 0;
+       }
+
+       if (!add_sid_to_array( priv->mem_ctx, &sid, &priv->sids.list,
+                              &priv->sids.count )) {
+               return 0;
+       }
+       
+       return 0;
 }
 
-void destroy_privilege(PRIVILEGE_SET **priv_set)
+/*********************************************************************
+ Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
+*********************************************************************/
+
+NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
 {
-       reset_privilege(*priv_set);
-       if (!((*priv_set)->ext_ctx))
-               /* mem_ctx is local, destroy it */
-               talloc_destroy((*priv_set)->mem_ctx);
-       *priv_set = NULL;
+       TDB_CONTEXT *tdb = get_account_pol_tdb();
+       PRIV_SID_LIST priv;
+       
+       if (!tdb) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       ZERO_STRUCT(priv);
+
+       se_priv_copy( &priv.privilege, &se_priv_none );
+
+       tdb_traverse( tdb, priv_traverse_fn, &priv);
+
+       /* give the memory away; caller will free */
+       
+       *sids      = priv.sids.list;
+       *num_sids  = priv.sids.count;
+
+       return NT_STATUS_OK;
 }
 
-/****************************************************************************
- add a privilege to a privilege array
- ****************************************************************************/
-NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+/*********************************************************************
+ Retrieve list of SIDs granted a particular privilege
+*********************************************************************/
+
+NTSTATUS privilege_enum_sids(const SE_PRIV *mask, TALLOC_CTX *mem_ctx,
+                            DOM_SID **sids, int *num_sids)
 {
-       NTSTATUS ret;
-       LUID_ATTR *new_set;
+       TDB_CONTEXT *tdb = get_account_pol_tdb();
+       PRIV_SID_LIST priv;
 
-       /* 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 (!tdb) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
 
-       /* we can allocate memory to add the new privilege */
+       ZERO_STRUCT(priv);
 
-       new_set = (LUID_ATTR *)talloc_realloc(priv_set->mem_ctx, priv_set->set, (priv_set->count + 1) * (sizeof(LUID_ATTR)));
-       ALLOC_CHECK(new_set, ret, done, "add_privilege");
+       se_priv_copy(&priv.privilege, mask);
+       priv.mem_ctx = mem_ctx;
 
-       new_set[priv_set->count].luid.high = set.luid.high;
-       new_set[priv_set->count].luid.low = set.luid.low;
-       new_set[priv_set->count].attr = set.attr;
+       tdb_traverse( tdb, priv_traverse_fn, &priv);
 
-       priv_set->count++;
-       priv_set->set = new_set;
+       /* give the memory away; caller will free */
 
-       ret = NT_STATUS_OK;
+       *sids      = priv.sids.list;
+       *num_sids  = priv.sids.count;
 
-done:
-       return ret;
+       return NT_STATUS_OK;
 }
 
-/****************************************************************************
- add all the privileges to a privilege array
- ****************************************************************************/
-NTSTATUS add_all_privilege(PRIVILEGE_SET *priv_set)
+/***************************************************************************
+ Add privilege to sid
+****************************************************************************/
+
+bool grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
 {
-       NTSTATUS result = NT_STATUS_OK;
-       LUID_ATTR set;
+       SE_PRIV old_mask, new_mask;
+       
+       ZERO_STRUCT( old_mask );
+       ZERO_STRUCT( new_mask );
+
+       if ( get_privileges( sid, &old_mask ) )
+               se_priv_copy( &new_mask, &old_mask );
+       else
+               se_priv_copy( &new_mask, &se_priv_none );
 
-       set.attr = 0;
-       set.luid.high = 0;
+       se_priv_add( &new_mask, priv_mask );
+
+       DEBUG(10,("grant_privilege: %s\n", sid_string_dbg(sid)));
+       
+       DEBUGADD( 10, ("original privilege mask:\n"));
+       dump_se_priv( DBGC_ALL, 10, &old_mask );
+       
+       DEBUGADD( 10, ("new privilege mask:\n"));
+       dump_se_priv( DBGC_ALL, 10, &new_mask );
+       
+       return set_privileges( sid, &new_mask );
+}
 
-       /* 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");
+/*********************************************************************
+ Add a privilege based on its name
+*********************************************************************/
 
-       set.luid.low = SE_PRIV_ADD_MACHINES;
-       result = add_privilege(priv_set, set);
-       NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege");
+bool grant_privilege_by_name(DOM_SID *sid, const char *name)
+{
+       SE_PRIV mask;
 
-       set.luid.low = SE_PRIV_PRINT_OPERATOR;
-       result = add_privilege(priv_set, set);
-       NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege");
+       if (! se_priv_from_name(name, &mask)) {
+               DEBUG(3, ("grant_privilege_by_name: "
+                         "No Such Privilege Found (%s)\n", name));
+               return False;
+       }
 
-       return result;
+       return grant_privilege( sid, &mask );
 }
 
-/****************************************************************************
- check if the privilege list is empty
- ****************************************************************************/
-NTSTATUS check_empty_privilege(PRIVILEGE_SET *priv_set)
+/***************************************************************************
+ Remove privilege from sid
+****************************************************************************/
+
+bool revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
 {
-       if (!priv_set)
-               return NT_STATUS_INVALID_PARAMETER;
+       SE_PRIV mask;
+       
+       /* if the user has no privileges, then we can't revoke any */
+       
+       if ( !get_privileges( sid, &mask ) )
+               return True;
+       
+       DEBUG(10,("revoke_privilege: %s\n", sid_string_dbg(sid)));
+       
+       DEBUGADD( 10, ("original privilege mask:\n"));
+       dump_se_priv( DBGC_ALL, 10, &mask );
 
-       if (priv_set->count == 0)
-               return NT_STATUS_OK;
+       se_priv_remove( &mask, priv_mask );
+       
+       DEBUGADD( 10, ("new privilege mask:\n"));
+       dump_se_priv( DBGC_ALL, 10, &mask );
+       
+       return set_privileges( sid, &mask );
+}
+
+/*********************************************************************
+ Revoke all privileges
+*********************************************************************/
 
-       return NT_STATUS_UNSUCCESSFUL;
+bool revoke_all_privileges( DOM_SID *sid )
+{
+       return revoke_privilege( sid, &se_priv_all );
 }
 
-/****************************************************************************
- check if the privilege is in the privilege list
- ****************************************************************************/
-NTSTATUS check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+/*********************************************************************
+ Add a privilege based on its name
+*********************************************************************/
+
+bool revoke_privilege_by_name(DOM_SID *sid, const char *name)
 {
-       int i;
+       SE_PRIV mask;
 
-       if (!priv_set)
-               return NT_STATUS_INVALID_PARAMETER;
+       if (! se_priv_from_name(name, &mask)) {
+               DEBUG(3, ("revoke_privilege_by_name: "
+                         "No Such Privilege Found (%s)\n", name));
+               return False;
+       }
 
-       /* 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;
+       return revoke_privilege(sid, &mask);
 
-       for (i = 0; i < priv_set->count; i++) {
-               LUID_ATTR *cur_set;
+}
 
-               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;
-               }
-       }
+/***************************************************************************
+ Retrieve the SIDs assigned to a given privilege
+****************************************************************************/
 
-       return NT_STATUS_UNSUCCESSFUL;
+NTSTATUS privilege_create_account(const DOM_SID *sid )
+{
+       return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
 }
 
 /****************************************************************************
- remove a privilege from a privilege array
+ initialise a privilege list and set the talloc context 
  ****************************************************************************/
-NTSTATUS remove_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
+NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
 {
-       NTSTATUS ret;
-       LUID_ATTR *new_set;
-       LUID_ATTR *old_set;
-       int i,j;
+       TALLOC_CTX *mem_ctx;
+       
+       ZERO_STRUCTP( priv_set );
 
-       if (!priv_set)
-               return NT_STATUS_INVALID_PARAMETER;
+       mem_ctx = talloc_init("privilege set");
+       if ( !mem_ctx ) {
+               DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       /* check if the privilege is in the list */
-       if (!NT_STATUS_IS_OK(check_priv_in_privilege(priv_set, set)))
-               return NT_STATUS_UNSUCCESSFUL;
+       priv_set->mem_ctx = mem_ctx;
 
-       /* 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;
+}
 
-       /* 
-        * the privilege is there, create a new list,
-        * and copy the other privileges
-        */
+/****************************************************************************
+  initialise a privilege list and with someone else's talloc context 
+****************************************************************************/
 
-       old_set = priv_set->set;
+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;
 
-       new_set = (LUID_ATTR *)talloc(priv_set->mem_ctx, (priv_set->count - 1) * (sizeof(LUID_ATTR)));
-       ALLOC_CHECK(new_set, ret, done, "remove_privilege");
+       return NT_STATUS_OK;
+}
 
-       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;
+/****************************************************************************
+ Free all memory used by a PRIVILEGE_SET
+****************************************************************************/
 
-               j++;
-       }
-       
-       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 */
-       
-       priv_set->count--;
-       priv_set->set = new_set;
-       
-       ret = NT_STATUS_OK;
+void privilege_set_free(PRIVILEGE_SET *priv_set)
+{
+       if ( !priv_set )
+               return;
+
+       if ( !( priv_set->ext_ctx ) )
+               talloc_destroy( priv_set->mem_ctx );
 
-done:
-       return ret;
+       ZERO_STRUCTP( priv_set );
 }
 
 /****************************************************************************
- duplicates a privilege array
- the new privilege set must be passed inited
- (use init_privilege or init_priv_with_ctx)
+ 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;
-
-       /* special case if there are no privileges in the list */
-       if (priv_set->count == 0) {
+       if ( !old_la )
                return NT_STATUS_OK;
+
+       if (count) {
+               *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
+               if ( !*new_la ) {
+                       DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count));
+                       return NT_STATUS_NO_MEMORY;
+               }
+       } else {
+               *new_la = NULL;
        }
 
-       /* 
-        * create a new list,
-        * and copy the other privileges
-        */
+       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;
+       }
+       
+       return NT_STATUS_OK;
+}
+
+/*******************************************************************
+*******************************************************************/
 
-       old_set = priv_set->set;
+bool is_privileged_sid( const DOM_SID *sid )
+{
+       SE_PRIV mask;
+       
+       return get_privileges( sid, &mask );
+}
 
-       new_set = (LUID_ATTR *)talloc(new_priv_set->mem_ctx, (priv_set->count - 1) * (sizeof(LUID_ATTR)));
-       ALLOC_CHECK(new_set, ret, done, "dup_priv_set");
+/*******************************************************************
+*******************************************************************/
 
-       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;
+bool grant_all_privileges( const DOM_SID *sid )
+{
+       SE_PRIV mask;
+
+       if (!se_priv_put_all_privileges(&mask)) {
+               return False;
        }
-                       
-       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;
+       return grant_privilege( sid, &mask );
 }