Hi!

This patch puts a RID allocator into the passdb backend. The outside interface
are two calls.

pdb_max_used_rid is for net rpc vampire to set the maximum RID that the PDC
gave us.

pdb_allocate_rid_for_gid allocates a new RID for the given unix group id. The
passdb backend must allocate RIDs for users itself. The group mapping code
should be able to get a new RID. The unix gid is handed to the pdb backend for
smbpasswd an unixsam to be able to use the algorithmic mapping.

The interface is definitely not the last word, as the group mapping might one
day be moved into the passdb backend.

One interesting part here might be the LDAP schema change which is to be
discussed.

The LDAP routines themselves quite reliably do an atomic set and increment. I
tested it with my laptop and 100 (really) concurrent pdbedit processes beating
the OpenLDAP 2.0.12. The random function in the sleep should probably done
differently. On my machine 100 concurrent processes can quite reliably get
their RID with a modulo of 200, 200 processes need more. But this is a bit
extreme load. At least I never got corruption.

The tdb backend could handle a load of 500 with no problem at all.

Volker

Index: examples/LDAP/samba.schema
===================================================================
RCS file: /data/cvs/samba/examples/LDAP/samba.schema,v
retrieving revision 1.8
diff -u -r1.8 samba.schema
--- examples/LDAP/samba.schema  19 Jul 2002 16:03:52 -0000      1.8
+++ examples/LDAP/samba.schema  17 Oct 2002 18:19:28 -0000
@@ -110,6 +110,11 @@
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
+attributetype ( 1.3.6.1.4.1.7165.2.1.19 NAME 'domainSID'
+       DESC 'Domain SID'
+       EQUALITY caseIgnoreIA5Match
+       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
 ##
 ## The smbPasswordEntry objectclass has been depreciated in favor of the
 ## sambaAccount objectclass
@@ -138,6 +143,11 @@
                logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $ 
                displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
                description $ userWorkstations $ primaryGroupID $ domain ))
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaDomainInfo' SUP top AUXILIARY
+       DESC 'Samba Domain Information'
+       MUST ( domain ) 
+       MAY  ( rid $ domainSID ))
 
 ##
 ## Used for Winbind experimentation
Index: source/include/passdb.h
===================================================================
RCS file: /data/cvs/samba/source/include/passdb.h,v
retrieving revision 1.20
diff -u -r1.20 passdb.h
--- source/include/passdb.h     12 Oct 2002 03:38:07 -0000      1.20
+++ source/include/passdb.h     17 Oct 2002 18:19:29 -0000
@@ -64,6 +64,10 @@
        NTSTATUS (*pdb_update_sam_account)(struct pdb_context *, SAM_ACCOUNT *sampass);
        
        NTSTATUS (*pdb_delete_sam_account)(struct pdb_context *, SAM_ACCOUNT 
*username);
+
+       NTSTATUS (*pdb_allocate_rid_for_gid)(struct pdb_context *, gid_t, uint32 *);
+
+       NTSTATUS (*pdb_max_used_rid)(struct pdb_context *, uint32);
        
        void (*free_fn)(struct pdb_context **);
        
@@ -95,6 +99,10 @@
        NTSTATUS (*update_sam_account)(struct pdb_methods *, SAM_ACCOUNT *sampass);
        
        NTSTATUS (*delete_sam_account)(struct pdb_methods *, SAM_ACCOUNT *username);
+
+       NTSTATUS (*allocate_rid_for_gid)(struct pdb_methods *, gid_t, uint32 *);
+
+       NTSTATUS (*max_used_rid)(struct pdb_methods *, uint32);
        
        void *private_data;  /* Private data of some kind */
        
Index: source/passdb/pdb_interface.c
===================================================================
RCS file: /data/cvs/samba/source/passdb/pdb_interface.c,v
retrieving revision 1.25
diff -u -r1.25 pdb_interface.c
--- source/passdb/pdb_interface.c       26 Sep 2002 09:50:52 -0000      1.25
+++ source/passdb/pdb_interface.c       17 Oct 2002 18:19:29 -0000
@@ -162,6 +162,34 @@
        return context->pdb_methods->add_sam_account(context->pdb_methods, sam_acct);
 }
 
+static NTSTATUS context_allocate_rid_for_gid(struct pdb_context *context, gid_t gid, 
+uint32 *rid)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+       if ((!context) || (!context->pdb_methods)) {
+               DEBUG(0, ("invalid pdb_context specified!\n"));
+               return ret;
+       }
+
+       return context->pdb_methods->allocate_rid_for_gid(context->pdb_methods, gid, 
+rid);
+}
+
+static NTSTATUS context_max_used_rid(struct pdb_context *context, uint32 rid)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+       if ((!context) || (!context->pdb_methods)) {
+               DEBUG(0, ("invalid pdb_context specified!\n"));
+               return ret;
+       }
+
+       /** @todo  This is where a 're-read on add' should be done */
+       /* We now add a new account to the first database listed. 
+        * Should we? */
+
+       return context->pdb_methods->max_used_rid(context->pdb_methods, rid);
+}
+
 static NTSTATUS context_update_sam_account(struct pdb_context *context, SAM_ACCOUNT 
*sam_acct)
 {
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
@@ -310,6 +338,8 @@
        (*context)->pdb_add_sam_account = context_add_sam_account;
        (*context)->pdb_update_sam_account = context_update_sam_account;
        (*context)->pdb_delete_sam_account = context_delete_sam_account;
+       (*context)->pdb_allocate_rid_for_gid = context_allocate_rid_for_gid;
+       (*context)->pdb_max_used_rid = context_max_used_rid;
 
        (*context)->free_fn = free_pdb_context;
 
@@ -455,6 +485,28 @@
        }
 
        return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, 
sam_acct));
+}
+
+BOOL pdb_allocate_rid_for_gid(gid_t gid, uint32 *rid)
+{
+       struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+       if (!pdb_context) {
+               return False;
+       }
+
+       return NT_STATUS_IS_OK(pdb_context->pdb_allocate_rid_for_gid(pdb_context, gid, 
+rid));
+}
+
+BOOL pdb_max_used_rid(uint32 rid)
+{
+       struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+       if (!pdb_context) {
+               return False;
+       }
+
+       return NT_STATUS_IS_OK(pdb_context->pdb_max_used_rid(pdb_context, rid));
 }
 
 BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct) 
Index: source/passdb/pdb_ldap.c
===================================================================
RCS file: /data/cvs/samba/source/passdb/pdb_ldap.c,v
retrieving revision 1.62
diff -u -r1.62 pdb_ldap.c
--- source/passdb/pdb_ldap.c    17 Oct 2002 07:08:43 -0000      1.62
+++ source/passdb/pdb_ldap.c    17 Oct 2002 18:19:30 -0000
@@ -1733,6 +1733,268 @@
        return NT_STATUS_OK;
 }
 
+/**********************************************************************
+Search for the domain info entry
+*********************************************************************/
+static int ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
+                                     LDAP * ldap_struct,
+                                     LDAPMessage ** result)
+{
+       pstring filter;
+       int scope = LDAP_SCOPE_SUBTREE;
+       int rc;
+       char *domain_info_attrs[] = {"domain", "rid", "domainSID", NULL };
+
+       slprintf(filter, sizeof(filter),
+                "(&(objectClass=sambaDomainInfo)(domain=%s))",
+                lp_workgroup());
+
+       DEBUG(2, ("Searching for:[%s]\n", filter));
+
+       rc = ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter,
+                          domain_info_attrs, 0, result);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
+               DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
+       }
+       
+       return rc;
+}
+
+/**********************************************************************
+Set the new highest RID
+*********************************************************************/
+static NTSTATUS ldapsam_max_used_rid(struct pdb_methods *my_methods, uint32 rid)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)my_methods->private_data;
+       int rc;
+       LDAP *ldap_struct = NULL;
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry  = NULL;
+       char *dn;
+       LDAPMod **mods = NULL;
+       pstring old_rid_string;
+       pstring new_rid_string;
+       uint32 new_rid;
+       int attempts = 0;
+       
+       if (!ldapsam_open_connection(ldap_state, &ldap_struct))
+               return ret;
+
+       if (!ldapsam_connect_system(ldap_state, ldap_struct)) {
+               ldap_unbind(ldap_struct);
+               return ret;
+       }
+
+       while (attempts < 10) {
+               char *ld_error;
+
+               if (ldapsam_search_domain_info(ldap_state, ldap_struct, &result)) {
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               if (ldap_count_entries(ldap_struct, result) < 1) {
+                       DEBUG(0, ("Got no domain info entries for domain %s\n",
+                                 lp_workgroup()));
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               entry = ldap_first_entry(ldap_struct, result);
+               if (!entry) {
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               if ((dn = ldap_get_dn(ldap_struct, entry)) == NULL) {
+                       DEBUG(0, ("Could not get domain info DN\n"));
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               if (!get_single_attribute(ldap_struct, result, "rid",
+                                         old_rid_string)) {
+                       /* TODO: Add new rid */
+                       ldap_memfree(dn);
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               /* This is the core of the whole routine. If we had
+                   scheme-style closures, there would be a *lot* less code
+                   duplication... */
+               new_rid = (uint32)atol(old_rid_string);
+               if (rid > new_rid) new_rid = rid;
+
+               slprintf(new_rid_string, sizeof(new_rid_string), "%d", new_rid);
+
+               /* Try to make the modification atomically by enforcing the
+                  old value in the delete mod. */
+               make_a_mod(&mods, LDAP_MOD_DELETE, "rid", old_rid_string);
+               make_a_mod(&mods, LDAP_MOD_ADD, "rid", new_rid_string);
+
+               if ((rc = ldap_modify_s(ldap_struct, dn, mods)) == LDAP_SUCCESS) {
+                       ldap_mods_free(mods, 1);
+                       ldap_memfree(dn);
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return NT_STATUS_OK;
+               }
+
+               ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+               DEBUG(2, ("Failed to modify rid: %s\n", ld_error));
+               SAFE_FREE(ld_error);
+
+               ldap_mods_free(mods, 1);
+               mods = NULL;
+
+               ldap_memfree(dn);
+               dn = NULL;
+
+               ldap_msgfree(result);
+               result = NULL;
+
+               attempts += 1;
+
+               {
+                       /* Sleep for a random timeout */
+                       unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
+                       sleeptime %= 100;
+                       msleep(sleeptime);
+               }
+       }
+
+       DEBUG(0, ("Failed to set new RID\n"));
+       ldap_unbind(ldap_struct);
+       return ret;
+}
+
+/**********************************************************************
+Allocate a new RID
+*********************************************************************/
+static NTSTATUS ldapsam_allocate_rid_for_gid(struct pdb_methods *my_methods,
+                                            gid_t gid, uint32 *rid)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)my_methods->private_data;
+       int rc;
+       LDAP *ldap_struct = NULL;
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry  = NULL;
+       char *dn;
+       LDAPMod **mods = NULL;
+       pstring old_rid_string;
+       pstring new_rid_string;
+       uint32 new_rid;
+       int attempts = 0;
+       
+       if (!ldapsam_open_connection(ldap_state, &ldap_struct))
+               return ret;
+
+       if (!ldapsam_connect_system(ldap_state, ldap_struct)) {
+               ldap_unbind(ldap_struct);
+               return ret;
+       }
+
+       while (attempts < 10) {
+               char *ld_error;
+
+               if (ldapsam_search_domain_info(ldap_state, ldap_struct, &result)) {
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               if (ldap_count_entries(ldap_struct, result) < 1) {
+                       DEBUG(0, ("Got no domain info entries for domain %s\n",
+                                 lp_workgroup()));
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               entry = ldap_first_entry(ldap_struct, result);
+               if (!entry) {
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               if ((dn = ldap_get_dn(ldap_struct, entry)) == NULL) {
+                       DEBUG(0, ("Could not get domain info DN\n"));
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               if (!get_single_attribute(ldap_struct, result, "rid",
+                                         old_rid_string)) {
+                       /* TODO: Add new rid */
+                       ldap_memfree(dn);
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return ret;
+               }
+
+               /* This is the core of the whole routine. If we had
+                   scheme-style closures, there would be a *lot* less code
+                   duplication... */
+               new_rid = (uint32)atol(old_rid_string) + 1;
+
+               slprintf(new_rid_string, sizeof(new_rid_string), "%d", new_rid);
+
+               /* Try to make the modification atomically by enforcing the
+                  old value in the delete mod. */
+               make_a_mod(&mods, LDAP_MOD_DELETE, "rid", old_rid_string);
+               make_a_mod(&mods, LDAP_MOD_ADD, "rid", new_rid_string);
+
+               if ((rc = ldap_modify_s(ldap_struct, dn, mods)) == LDAP_SUCCESS) {
+
+                       *rid = new_rid;
+
+                       ldap_mods_free(mods, 1);
+                       ldap_memfree(dn);
+                       ldap_msgfree(result);
+                       ldap_unbind(ldap_struct);
+                       return NT_STATUS_OK;
+               }
+
+               ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+               DEBUG(2, ("Failed to modify rid: %s\n", ld_error));
+               SAFE_FREE(ld_error);
+
+               ldap_mods_free(mods, 1);
+               mods = NULL;
+
+               ldap_memfree(dn);
+               dn = NULL;
+
+               ldap_msgfree(result);
+               result = NULL;
+
+               attempts += 1;
+
+               {
+                       /* Sleep for a random timeout */
+                       unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
+                       sleeptime %= 100;
+                       msleep(sleeptime);
+               }
+       }
+
+       DEBUG(0, ("Failed to allocate RID\n"));
+       ldap_unbind(ldap_struct);
+       return ret;
+}
+
 static void free_private_data(void **vp) 
 {
        struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
@@ -1772,6 +2034,8 @@
        (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
        (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
        (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
+       (*pdb_method)->allocate_rid_for_gid = ldapsam_allocate_rid_for_gid;
+       (*pdb_method)->max_used_rid = ldapsam_max_used_rid;
 
        /* TODO: Setup private data and free */
 
Index: source/passdb/pdb_smbpasswd.c
===================================================================
RCS file: /data/cvs/samba/source/passdb/pdb_smbpasswd.c,v
retrieving revision 1.57
diff -u -r1.57 pdb_smbpasswd.c
--- source/passdb/pdb_smbpasswd.c       12 Oct 2002 03:38:07 -0000      1.57
+++ source/passdb/pdb_smbpasswd.c       17 Oct 2002 18:19:30 -0000
@@ -1460,6 +1460,19 @@
        return NT_STATUS_OK;
 }
 
+static NTSTATUS smbpasswd_allocate_rid_for_gid(struct pdb_methods *my_methods,
+                                              gid_t gid, uint32 *rid)
+{
+       *rid = pdb_gid_to_group_rid(gid);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS smbpasswd_max_used_rid(struct pdb_methods *my_methods, uint32 rid)
+{
+       DEBUG(0, ("pdb_smbpasswd should not be used for full PDC.\n"));
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
 static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, 
SAM_ACCOUNT *sampass)
 {
        struct smbpasswd_privates *smbpasswd_state = (struct 
smbpasswd_privates*)my_methods->private_data;
@@ -1522,6 +1535,8 @@
        (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
        (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
        (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
+       (*pdb_method)->allocate_rid_for_gid = smbpasswd_allocate_rid_for_gid;
+       (*pdb_method)->max_used_rid = smbpasswd_max_used_rid;
 
        /* Setup private data and free function */
 
Index: source/passdb/pdb_tdb.c
===================================================================
RCS file: /data/cvs/samba/source/passdb/pdb_tdb.c,v
retrieving revision 1.71
diff -u -r1.71 pdb_tdb.c
--- source/passdb/pdb_tdb.c     12 Oct 2002 03:38:07 -0000      1.71
+++ source/passdb/pdb_tdb.c     17 Oct 2002 18:19:31 -0000
@@ -44,6 +44,7 @@
 #define TDB_FORMAT_STRING      "ddddddBBBBBBBBBBBBddBBwdwdBdd"
 #define USERPREFIX             "USER_"
 #define RIDPREFIX              "RID_"
+#define RIDCOUNTER              "RIDCOUNTER"
 
 struct tdbsam_privates {
        TDB_CONTEXT     *passwd_tdb;
@@ -896,6 +897,71 @@
                return NT_STATUS_UNSUCCESSFUL;
 }
 
+/***************************************************************************
+Set the new highest RID
+****************************************************************************/
+static NTSTATUS tdbsam_max_used_rid(struct pdb_methods *my_methods, uint32 rid)
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       struct tdbsam_privates *tdb_state =
+               (struct tdbsam_privates *)my_methods->private_data;
+       TDB_CONTEXT *pwd_tdb;
+       BOOL tdb_ret;
+
+       /* open the account TDB passwd*/
+       pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT,
+                              O_RDWR | O_CREAT, 0600);
+       if (!pwd_tdb)
+       {
+               DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n",
+                         tdb_state->tdbsam_location));
+               return nt_status;
+       }
+
+       tdb_ret = tdb_new_uint32_max(pwd_tdb, RIDCOUNTER, rid+1);
+       if (tdb_ret)
+               nt_status = NT_STATUS_OK;
+
+       tdb_close(pwd_tdb);
+       return nt_status;
+}
+
+/***************************************************************************
+Allocate a new RID
+****************************************************************************/
+static NTSTATUS tdbsam_allocate_rid_for_gid(struct pdb_methods *my_methods,
+                                           gid_t gid, uint32 *rid)
+{
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       struct tdbsam_privates *tdb_state =
+               (struct tdbsam_privates *)my_methods->private_data;
+       TDB_CONTEXT *pwd_tdb;
+       BOOL tdb_ret;
+
+       if (rid==NULL) {
+               DEBUG(0,("tdbsam_allocate_rid: rid is NULL\n"));
+               return nt_status;
+       }
+
+       /* open the account TDB passwd*/
+       pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT,
+                              O_RDWR | O_CREAT, 0600);
+       if (!pwd_tdb)
+       {
+               DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n",
+                         tdb_state->tdbsam_location));
+               return nt_status;
+       }
+
+       *rid = 1000; /* Initial value, one less than first used */
+       tdb_ret = tdb_change_uint32_atomic(pwd_tdb, RIDCOUNTER, rid, 1);
+       if (tdb_ret)
+               nt_status = NT_STATUS_OK;
+
+       tdb_close(pwd_tdb);
+       return nt_status;
+}
+
 static void free_private_data(void **vp) 
 {
        struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp;
@@ -933,6 +999,8 @@
        (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
        (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
        (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
+       (*pdb_method)->allocate_rid_for_gid = tdbsam_allocate_rid_for_gid;
+       (*pdb_method)->max_used_rid = tdbsam_max_used_rid;
 
        tdb_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct tdbsam_privates));
 
Index: source/passdb/pdb_unix.c
===================================================================
RCS file: /data/cvs/samba/source/passdb/pdb_unix.c,v
retrieving revision 1.8
diff -u -r1.8 pdb_unix.c
--- source/passdb/pdb_unix.c    26 Sep 2002 09:50:53 -0000      1.8
+++ source/passdb/pdb_unix.c    17 Oct 2002 18:19:31 -0000
@@ -96,6 +96,19 @@
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
+static NTSTATUS unixsam_allocate_rid_for_gid(struct pdb_methods *my_methods,
+                                            gid_t gid, uint32 *rid)
+{
+       *rid = pdb_gid_to_group_rid(gid);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS unixsam_max_used_rid(struct pdb_methods *my_methods, uint32 rid)
+{
+       DEBUG(1,("pdb_unix should not be used for full PDC.\n"));
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
 /***************************************************************************
   Updates a SAM_ACCOUNT
 
@@ -154,6 +167,8 @@
        (*pdb_method)->add_sam_account = unixsam_add_sam_account;
        (*pdb_method)->update_sam_account = unixsam_update_sam_account;
        (*pdb_method)->delete_sam_account = unixsam_delete_sam_account;
+       (*pdb_method)->allocate_rid_for_gid = unixsam_allocate_rid_for_gid;
+       (*pdb_method)->max_used_rid = unixsam_max_used_rid;
        
        /* There's not very much to initialise here */
        return NT_STATUS_OK;
Index: source/tdb/tdbutil.c
===================================================================
RCS file: /data/cvs/samba/source/tdb/tdbutil.c,v
retrieving revision 1.42
diff -u -r1.42 tdbutil.c
--- source/tdb/tdbutil.c        4 Oct 2002 22:53:30 -0000       1.42
+++ source/tdb/tdbutil.c        17 Oct 2002 18:19:31 -0000
@@ -343,6 +343,41 @@
        return ret;
 }
 
+/***************************************************************************
+ Set a tdb uint32 to a new maximum value.
+****************************************************************************/
+BOOL tdb_new_uint32_max(TDB_CONTEXT *my_tdb, char *keystr, uint32 new_max)
+{
+       uint32 stored;
+       BOOL ret = False;
+
+       if (tdb_lock_bystring(my_tdb, keystr, 10) == -1)
+               return False;
+
+       if (!tdb_fetch_uint32(my_tdb, keystr, &stored)) {
+               /* It failed */
+               if (tdb_error(my_tdb) != TDB_ERR_NOEXIST) { 
+                       /* and not becouse it didn't exist */
+                       goto err_out;
+               }
+               stored = new_max;
+       } else {
+               /* it worked, set the stored value to max(new_max, stored) */
+               if (new_max > stored)
+                       stored = new_max;
+       }
+
+       if (!tdb_store_uint32(my_tdb, keystr, stored))
+               goto err_out;
+
+       ret = True;
+
+  err_out:
+
+       tdb_unlock_bystring(my_tdb, keystr);
+       return ret;
+}
+
 /****************************************************************************
  Useful pair of routines for packing/unpacking data consisting of
  integers and strings.
Index: source/utils/pdbedit.c
===================================================================
RCS file: /data/cvs/samba/source/utils/pdbedit.c,v
retrieving revision 1.60
diff -u -r1.60 pdbedit.c
--- source/utils/pdbedit.c      12 Oct 2002 03:38:06 -0000      1.60
+++ source/utils/pdbedit.c      17 Oct 2002 18:19:32 -0000
@@ -43,7 +43,7 @@
 #define BIT_DELETE     0x00080000
 #define BIT_ACCPOLICY  0x00100000
 #define BIT_ACCPOLVAL  0x00200000
-#define BIT_RESERV_6   0x00400000
+#define BIT_ALLOCRID   0x00400000
 #define BIT_RESERV_7   0x00800000
 #define BIT_IMPORT     0x01000000
 #define BIT_EXPORT     0x02000000
@@ -436,6 +436,7 @@
        static BOOL add_user = False;
        static BOOL delete_user = False;
        static BOOL modify_user = False;
+       static BOOL allocate_rid = False;
        uint32  setparms, checkparms;
        int opt;
        static char *full_name = NULL;
@@ -468,6 +469,7 @@
                {"profile",     'p', POPT_ARG_STRING, &profile_path, 0, "set profile 
path", NULL},
                {"create",      'a', POPT_ARG_NONE, &add_user, 0, "create user", NULL},
                {"modify",      'r', POPT_ARG_NONE, &modify_user, 0, "modify user", 
NULL},
+               {"allocrid",    'R', POPT_ARG_NONE, &allocate_rid, 0, "allocate a 
+RID", NULL},
                {"machine",     'm', POPT_ARG_NONE, &machine, 0, "account is a machine 
account", NULL},
                {"delete",      'x', POPT_ARG_NONE, &delete_user, 0, "delete user", 
NULL},
                {"backend",     'b', POPT_ARG_STRING, &backend, 0, "use different 
passdb backend as default backend", NULL},
@@ -521,6 +523,7 @@
                        (user_name ? BIT_USER : 0) +
                        (list_users ? BIT_LIST : 0) +
                        (modify_user ? BIT_MODIFY : 0) +
+                        (allocate_rid ? BIT_ALLOCRID : 0) +
                        (add_user ? BIT_CREATE : 0) +
                        (delete_user ? BIT_DELETE : 0) +
                        (account_policy ? BIT_ACCPOLICY : 0) +
@@ -652,6 +655,13 @@
                                              logon_script,
                                              profile_path);
                }
+       }
+
+       if (checkparms & BIT_ALLOCRID) {
+               uint32 rid;
+               pdb_allocate_rid_for_gid(0, &rid);
+               printf("new rid: %d\n", rid);
+               return 0;
        }
 
        if (setparms >= 0x20) {

Attachment: msg04015/pgp00000.pgp
Description: PGP signature

Reply via email to