avoid races in getting high watermark
authorSimo Sorce <idra@samba.org>
Wed, 11 Jun 2003 18:14:34 +0000 (18:14 +0000)
committerSimo Sorce <idra@samba.org>
Wed, 11 Jun 2003 18:14:34 +0000 (18:14 +0000)
(This used to be commit df0df941d84386a7de5c97149c6c06d01a8720d0)

source3/sam/idmap_tdb.c

index 278269e8198e90ad50657329f02e3ed1444cba6b..209f9066e04563682b96951bee1f7b03f4fb3eb2 100644 (file)
@@ -48,6 +48,7 @@ static struct idmap_state {
 /* Allocate either a user or group id from the pool */
 static NTSTATUS db_allocate_id(unid_t *id, int id_type)
 {
+       BOOL ret;
        int hwm;
 
        if (!id) return NT_STATUS_INVALID_PARAMETER;
@@ -59,30 +60,55 @@ static NTSTATUS db_allocate_id(unid_t *id, int id_type)
                                return NT_STATUS_INTERNAL_DB_ERROR;
                        }
 
+                       /* check it is in the range */
                        if (hwm > idmap_state.uid_high) {
                                DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %u)\n", idmap_state.uid_high));
                                return NT_STATUS_UNSUCCESSFUL;
                        }
 
-                       (*id).uid = hwm++;
+                       /* fetch a new id and increment it */
+                       ret = tdb_change_uint32_atomic(idmap_tdb, HWM_USER, &hwm, 1);
+                       if (!ret) {
+                               DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
+                               return NT_STATUS_UNSUCCESSFUL;
+                       }
+
+                       /* recheck it is in the range */
+                       if (hwm > idmap_state.uid_high) {
+                               DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %u)\n", idmap_state.uid_high));
+                               return NT_STATUS_UNSUCCESSFUL;
+                       }
+                       
+                       (*id).uid = hwm;
 
-                       /* Store new high water mark */
-                       tdb_store_int32(idmap_tdb, HWM_USER, hwm);
                        break;
                case ID_GROUPID:
                        if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
                                return NT_STATUS_INTERNAL_DB_ERROR;
                        }
 
+                       /* check it is in the range */
                        if (hwm > idmap_state.gid_high) {
                                DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %u)\n", idmap_state.gid_high));
                                return NT_STATUS_UNSUCCESSFUL;
                        }
 
-                       (*id).gid = hwm++;
+                       /* fetch a new id and increment it */
+                       ret = tdb_change_uint32_atomic(idmap_tdb, HWM_USER, &hwm, 1);
+
+                       if (!ret) {
+                               DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
+                               return NT_STATUS_UNSUCCESSFUL;
+                       }
+
+                       /* recheck it is in the range */
+                       if (hwm > idmap_state.uid_high) {
+                               DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %u)\n", idmap_state.uid_high));
+                               return NT_STATUS_UNSUCCESSFUL;
+                       }
+                       
+                       (*id).gid = hwm;
                        
-                       /* Store new high water mark */
-                       tdb_store_int32(idmap_tdb, HWM_GROUP, hwm);
                        break;
                default:
                        return NT_STATUS_INVALID_PARAMETER;