r23468: Open registry.tdb with sequence number.
[sfrench/samba-autobuild/.git] / source / registry / reg_db.c
index 2afecffec7592867f8afd0bf67d0cd50a06b32e1..555ae6adda325b10de103a46d128ae8e1d91cc90 100644 (file)
@@ -29,6 +29,9 @@ static TDB_CONTEXT *tdb_reg;
 static int tdb_refcount;
 
 #define VALUE_PREFIX   "SAMBA_REGVAL"
+#define SECDESC_PREFIX  "SAMBA_SECDESC"
+
+#define REG_TDB_FLAGS TDB_SEQNUM
 
 /* List the deepest path into the registry.  All part components will be created.*/
 
@@ -46,6 +49,7 @@ static const char *builtin_registry_paths[] = {
        KEY_PRINTING,
        KEY_SHARES,
        KEY_EVENTLOG,
+       KEY_SMBCONF,
        "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
        "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009",
        "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors",
@@ -96,6 +100,20 @@ static BOOL init_registry_data( void )
        int i;
        const char *p, *p2;
        UNISTR2 data;
+
+       /*
+        * There are potentially quite a few store operations which are all
+        * indiviually wrapped in tdb transactions. Wrapping them in a single
+        * transaction gives just a single transaction_commit() to actually do
+        * its fsync()s. See tdb/common/transaction.c for info about nested
+        * transaction behaviour.
+        */
+
+       if ( tdb_transaction_start( tdb_reg ) == -1 ) {
+               DEBUG(0, ("init_registry_data: tdb_transaction_start "
+                         "failed\n"));
+               return False;
+       }
        
        /* loop over all of the predefined paths and add each component */
        
@@ -135,14 +153,14 @@ static BOOL init_registry_data( void )
                        
                        if ( !(subkeys = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
                                DEBUG(0,("talloc() failure!\n"));
-                               return False;
+                               goto fail;
                        }
 
                        regdb_fetch_keys( base, subkeys );
                        if ( *subkeyname ) 
                                regsubkey_ctr_addkey( subkeys, subkeyname );
                        if ( !regdb_store_keys( base, subkeys ))
-                               return False;
+                               goto fail;
                        
                        TALLOC_FREE( subkeys );
                }
@@ -153,7 +171,7 @@ static BOOL init_registry_data( void )
        for ( i=0; builtin_registry_values[i].path != NULL; i++ ) {
                if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
                        DEBUG(0,("talloc() failure!\n"));
-                       return False;
+                       goto fail;
                }
 
                regdb_fetch_values( builtin_registry_values[i].path, values );
@@ -190,7 +208,22 @@ static BOOL init_registry_data( void )
                TALLOC_FREE( values );
        }
        
+       if (tdb_transaction_commit( tdb_reg ) == -1) {
+               DEBUG(0, ("init_registry_data: Could not commit "
+                         "transaction\n"));
+               return False;
+       }
+
        return True;
+
+ fail:
+
+       if (tdb_transaction_cancel( tdb_reg ) == -1) {
+               smb_panic("init_registry_data: tdb_transaction_cancel "
+                         "failed\n");
+       }
+
+       return False;
 }
 
 /***********************************************************************
@@ -205,9 +238,9 @@ BOOL regdb_init( void )
        if ( tdb_reg )
                return True;
 
-       if ( !(tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600)) )
+       if ( !(tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR, 0600)) )
        {
-               tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+               tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600);
                if ( !tdb_reg ) {
                        DEBUG(0,("regdb_init: Failed to open registry %s (%s)\n",
                                lock_path("registry.tdb"), strerror(errno) ));
@@ -252,7 +285,7 @@ WERROR regdb_open( void )
        
        become_root();
 
-       tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
+       tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR, 0600);
        if ( !tdb_reg ) {
                result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
                DEBUG(0,("regdb_open: Failed to open %s! (%s)\n", 
@@ -289,6 +322,16 @@ int regdb_close( void )
        return ret;
 }
 
+/***********************************************************************
+ return the tdb sequence number of the registry tdb.
+ this is an indicator for the content of the registry
+ having changed. it will change upon regdb_init, too, though.
+ ***********************************************************************/
+int regdb_get_seqnum(void)
+{
+       return tdb_get_seqnum(tdb_reg);
+}
+
 /***********************************************************************
  Add subkey strings to the registry tdb under a defined key
  fmt is the same format as tdb_pack except this function only supports
@@ -297,8 +340,8 @@ int regdb_close( void )
  
 static BOOL regdb_store_keys_internal( const char *key, REGSUBKEY_CTR *ctr )
 {
-       TDB_DATA kbuf, dbuf;
-       char *buffer;
+       TDB_DATA dbuf;
+       uint8 *buffer;
        int i = 0;
        uint32 len, buflen;
        BOOL ret = True;
@@ -313,7 +356,7 @@ static BOOL regdb_store_keys_internal( const char *key, REGSUBKEY_CTR *ctr )
 
        /* allocate some initial memory */
                
-       if (!(buffer = (char *)SMB_MALLOC(sizeof(pstring)))) {
+       if (!(buffer = (uint8 *)SMB_MALLOC(sizeof(pstring)))) {
                return False;
        }
        buflen = sizeof(pstring);
@@ -329,7 +372,7 @@ static BOOL regdb_store_keys_internal( const char *key, REGSUBKEY_CTR *ctr )
                len += tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
                if ( len > buflen ) {
                        /* allocate some extra space */
-                       if ((buffer = (char *)SMB_REALLOC( buffer, len*2 )) == NULL) {
+                       if ((buffer = (uint8 *)SMB_REALLOC( buffer, len*2 )) == NULL) {
                                DEBUG(0,("regdb_store_keys: Failed to realloc memory of size [%d]\n", len*2));
                                ret = False;
                                goto done;
@@ -342,11 +385,9 @@ static BOOL regdb_store_keys_internal( const char *key, REGSUBKEY_CTR *ctr )
        
        /* finally write out the data */
        
-       kbuf.dptr = keyname;
-       kbuf.dsize = strlen(keyname)+1;
        dbuf.dptr = buffer;
        dbuf.dsize = len;
-       if ( tdb_store( tdb_reg, kbuf, dbuf, TDB_REPLACE ) == -1) {
+       if ( tdb_store_bystring( tdb_reg, keyname, dbuf, TDB_REPLACE ) == -1) {
                ret = False;
                goto done;
        }
@@ -441,7 +482,7 @@ BOOL regdb_store_keys( const char *key, REGSUBKEY_CTR *ctr )
                        /* create a record with 0 subkeys */
                        if ( !regdb_store_keys_internal( path, subkeys ) ) {
                                DEBUG(0,("regdb_store_keys: Failed to store "
-                                        "new record for key [%s}\n", path ));
+                                        "new record for key [%s]\n", path ));
                                goto fail;
                        }
                }
@@ -478,7 +519,7 @@ int regdb_fetch_keys( const char* key, REGSUBKEY_CTR *ctr )
        pstring path;
        uint32 num_items;
        TDB_DATA dbuf;
-       char *buf;
+       uint8 *buf;
        uint32 buflen, len;
        int i;
        fstring subkeyname;
@@ -519,7 +560,7 @@ int regdb_fetch_keys( const char* key, REGSUBKEY_CTR *ctr )
  Unpack a list of registry values frem the TDB
  ***************************************************************************/
  
-static int regdb_unpack_values(REGVAL_CTR *values, char *buf, int buflen)
+static int regdb_unpack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
 {
        int             len = 0;
        uint32          type;
@@ -564,7 +605,7 @@ static int regdb_unpack_values(REGVAL_CTR *values, char *buf, int buflen)
  Pack all values in all printer keys
  ***************************************************************************/
  
-static int regdb_pack_values(REGVAL_CTR *values, char *buf, int buflen)
+static int regdb_pack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
 {
        int             len = 0;
        int             i;
@@ -644,7 +685,7 @@ BOOL regdb_store_values( const char *key, REGVAL_CTR *values )
                return False;
        }
        
-       data.dptr = SMB_MALLOC_ARRAY( char, len );
+       data.dptr = SMB_MALLOC_ARRAY( uint8, len );
        data.dsize = len;
        
        len = regdb_pack_values( values, data.dptr, data.dsize );
@@ -661,6 +702,88 @@ BOOL regdb_store_values( const char *key, REGVAL_CTR *values )
        return ret != -1 ;
 }
 
+void normalize_dbkey(char *key)
+{
+       size_t len = strlen(key);
+       string_sub(key, "\\", "/", len+1);
+       strupper_m(key);
+}
+
+static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
+                               struct security_descriptor **psecdesc)
+{
+       char *tdbkey;
+       TDB_DATA data;
+       NTSTATUS status;
+
+       DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key));
+
+       if (asprintf(&tdbkey, "%s/%s", SECDESC_PREFIX, key) == -1) {
+               return WERR_NOMEM;
+       }
+       normalize_dbkey(tdbkey);
+
+        data = tdb_fetch_bystring(tdb_reg, tdbkey);
+       SAFE_FREE(tdbkey);
+
+       if (data.dptr == NULL) {
+               return WERR_BADFILE;
+       }
+
+       status = unmarshall_sec_desc(mem_ctx, (uint8 *)data.dptr, data.dsize,
+                                    psecdesc);
+
+       SAFE_FREE(data.dptr);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+               return WERR_NOMEM;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return WERR_REG_CORRUPT;
+       }
+
+       return WERR_OK;
+}
+
+static WERROR regdb_set_secdesc(const char *key,
+                               struct security_descriptor *secdesc)
+{
+       prs_struct ps;
+       TALLOC_CTX *mem_ctx;
+       char *tdbkey;
+       WERROR err = WERR_NOMEM;
+       TDB_DATA tdbdata;
+
+       if (!(mem_ctx = talloc_init("regdb_set_secdesc"))) {
+               return WERR_NOMEM;
+       }
+
+       ZERO_STRUCT(ps);
+
+       if (!(tdbkey = talloc_asprintf(mem_ctx, "%s/%s", SECDESC_PREFIX,
+                                      key))) {
+               goto done;
+       }
+       normalize_dbkey(tdbkey);
+
+       err = ntstatus_to_werror(marshall_sec_desc(mem_ctx, secdesc,
+                                                  &tdbdata.dptr,
+                                                  &tdbdata.dsize));
+       if (!W_ERROR_IS_OK(err)) {
+               goto done;
+       }
+
+       if (tdb_trans_store_bystring(tdb_reg, tdbkey, tdbdata, 0) == -1) {
+               err = ntstatus_to_werror(map_nt_error_from_unix(errno));
+               goto done;
+       }
+
+ done:
+       prs_mem_free(&ps);
+       TALLOC_FREE(mem_ctx);
+       return err;
+}
 
 /* 
  * Table of function pointers for default access
@@ -671,7 +794,7 @@ REGISTRY_OPS regdb_ops = {
        regdb_fetch_values,
        regdb_store_keys,
        regdb_store_values,
-       NULL
+       NULL,
+       regdb_get_secdesc,
+       regdb_set_secdesc
 };
-
-