From 2129d3c711a109b47c3c1596a6a639520d2f72d2 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 17 Jun 2005 15:35:31 +0000 Subject: r7691: * add .gdbinit to the svn:ignore files * start adding write support to the Samba registry Flesh out the server implementations of RegCreateKey(), RegSetValue(), RegDeleteKey() and RegDeleteValue() I can create a new key using regedit.exe now but the 'New Key #1' key cannot be deleted yet. (This used to be commit e188fdbef8f0ad202b0ecf3c30be2941ebe6d5b1) --- source3/include/rpc_reg.h | 4 +- source3/include/rpc_secdes.h | 2 +- source3/printing/nt_printing.c | 2 - source3/registry/reg_db.c | 44 +++++++- source3/registry/reg_frontend.c | 2 - source3/registry/reg_objects.c | 10 +- source3/rpc_client/cli_reg.c | 2 +- source3/rpc_client/cli_spoolss.c | 1 - source3/rpc_parse/parse_reg.c | 8 +- source3/rpc_server/srv_reg_nt.c | 228 +++++++++++++++++++++++++++++++++------ source3/utils/net_rpc_registry.c | 3 - 11 files changed, 248 insertions(+), 58 deletions(-) diff --git a/source3/include/rpc_reg.h b/source3/include/rpc_reg.h index 270ba32f4b..f89571484c 100644 --- a/source3/include/rpc_reg.h +++ b/source3/include/rpc_reg.h @@ -179,7 +179,7 @@ typedef struct { /***********************************************/ typedef struct { - POLICY_HND pol; + POLICY_HND handle; UNISTR4 name; uint32 type; RPC_DATA_BLOB value; @@ -228,7 +228,7 @@ typedef struct { } REG_Q_CREATE_KEY; typedef struct { - POLICY_HND key_pol; + POLICY_HND handle; uint32 unknown; WERROR status; } REG_R_CREATE_KEY; diff --git a/source3/include/rpc_secdes.h b/source3/include/rpc_secdes.h index a14caf36c1..b2b97e391e 100644 --- a/source3/include/rpc_secdes.h +++ b/source3/include/rpc_secdes.h @@ -547,7 +547,7 @@ typedef struct standard_mapping { #define REG_KEY_EXECUTE REG_KEY_READ #define REG_KEY_WRITE \ - ( STANDARD_RIGHTS_READ_ACCESS |\ + ( STANDARD_RIGHTS_WRITE_ACCESS |\ SEC_RIGHTS_SET_VALUE |\ SEC_RIGHTS_CREATE_SUBKEY ) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 8fd28d8cfe..75473c39f2 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -2543,8 +2543,6 @@ static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name ) data->num_keys++; data->keys[key_index].name = SMB_STRDUP( name ); - ZERO_STRUCTP( &data->keys[key_index].values ); - regval_ctr_init( &data->keys[key_index].values ); DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name )); diff --git a/source3/registry/reg_db.c b/source3/registry/reg_db.c index 7efa032e39..a459aa5f5f 100644 --- a/source3/registry/reg_db.c +++ b/source3/registry/reg_db.c @@ -68,8 +68,6 @@ static BOOL init_registry_data( void ) int i; const char *p, *p2; - ZERO_STRUCTP( &subkeys ); - /* loop over all of the predefined paths and add each component */ for ( i=0; builtin_registry_paths[i] != NULL; i++ ) { @@ -168,10 +166,10 @@ BOOL init_registry_db( void ) The full path to the registry key is used as database after the \'s are converted to /'s. Key string is also normalized to UPPER - case. + case. ***********************************************************************/ -static BOOL regdb_store_reg_keys( char *key, REGSUBKEY_CTR *ctr ) +static BOOL regdb_store_reg_keys_internal( char *key, REGSUBKEY_CTR *ctr ) { TDB_DATA kbuf, dbuf; char *buffer, *tmpbuf; @@ -236,6 +234,44 @@ done: return ret; } +/*********************************************************************** + Store the new subkey record and create any child key records that + do not currently exist + ***********************************************************************/ + +static BOOL regdb_store_reg_keys( char *key, REGSUBKEY_CTR *ctr ) +{ + int num_subkeys, i; + pstring path; + REGSUBKEY_CTR subkeys; + + /* store the subkey list for the parent */ + + if ( !regdb_store_reg_keys_internal( key, ctr ) ) { + DEBUG(0,("regdb_store_reg_keys: Failed to store new subkey list for parent [%s}\n", key )); + return False; + } + + /* now create records for any subkeys that don't already exist */ + + num_subkeys = regsubkey_ctr_numkeys( ctr ); + for ( i=0; iname)); - ZERO_STRUCTP( &ctr ); regsubkey_ctr_init( &ctr ); pstrcpy( save_path, key->name ); @@ -202,7 +201,6 @@ BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 if ( !ctr_init ) { DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name)); - ZERO_STRUCTP( &ctr ); regval_ctr_init( &ctr ); pstrcpy( save_path, key->name ); diff --git a/source3/registry/reg_objects.c b/source3/registry/reg_objects.c index add82ae0d4..2dd61f515f 100644 --- a/source3/registry/reg_objects.c +++ b/source3/registry/reg_objects.c @@ -28,12 +28,13 @@ /*********************************************************************** Init the talloc context held by a REGSUBKEY_CTR structure + This now zero's the structure **********************************************************************/ void regsubkey_ctr_init( REGSUBKEY_CTR *ctr ) { - if ( !ctr->ctx ) - ctr->ctx = talloc_init("regsubkey_ctr_init for ctr %p", ctr); + ZERO_STRUCTP( ctr ); + ctr->ctx = talloc_init("regsubkey_ctr_init for ctr %p", ctr); } /*********************************************************************** @@ -117,12 +118,13 @@ void regsubkey_ctr_destroy( REGSUBKEY_CTR *ctr ) /*********************************************************************** Init the talloc context held by a REGSUBKEY_CTR structure + This now zero's the structure **********************************************************************/ void regval_ctr_init( REGVAL_CTR *ctr ) { - if ( ctr && !ctr->ctx ) - ctr->ctx = talloc_init("regval_ctr_init for ctr %p", ctr); + ZERO_STRUCTP( ctr ); + ctr->ctx = talloc_init("regval_ctr_init for ctr %p", ctr); } /*********************************************************************** diff --git a/source3/rpc_client/cli_reg.c b/source3/rpc_client/cli_reg.c index 3f5b7652ac..ca4b63c282 100644 --- a/source3/rpc_client/cli_reg.c +++ b/source3/rpc_client/cli_reg.c @@ -474,7 +474,7 @@ WERROR cli_reg_create_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, if ( !W_ERROR_IS_OK( out.status ) ) return out.status; - memcpy( key, &out.key_pol, sizeof(POLICY_HND) ); + memcpy( key, &out.handle, sizeof(POLICY_HND) ); return out.status; } diff --git a/source3/rpc_client/cli_spoolss.c b/source3/rpc_client/cli_spoolss.c index 518c20ff9b..8ed29f50fb 100644 --- a/source3/rpc_client/cli_spoolss.c +++ b/source3/rpc_client/cli_spoolss.c @@ -2270,7 +2270,6 @@ WERROR cli_spoolss_enumprinterdataex(struct cli_state *cli, TALLOC_CTX *mem_ctx, /* Return data */ - ZERO_STRUCTP(ctr); regval_ctr_init(ctr); for (i = 0; i < r.returned; i++) { diff --git a/source3/rpc_parse/parse_reg.c b/source3/rpc_parse/parse_reg.c index 5eed245a28..5cc4d06f4f 100644 --- a/source3/rpc_parse/parse_reg.c +++ b/source3/rpc_parse/parse_reg.c @@ -297,7 +297,7 @@ BOOL reg_io_r_create_key(const char *desc, REG_R_CREATE_KEY *r_u, if(!prs_align(ps)) return False; - if(!smb_io_pol_hnd("", &r_u->key_pol, ps, depth)) + if(!smb_io_pol_hnd("", &r_u->handle, ps, depth)) return False; if(!prs_uint32("unknown", ps, depth, &r_u->unknown)) return False; @@ -407,8 +407,6 @@ BOOL reg_io_q_delete_key(const char *desc, REG_Q_DELETE_KEY *q_u, if(!prs_unistr4("", ps, depth, &q_u->name)) return False; - if(!prs_align(ps)) - return False; return True; } @@ -1219,7 +1217,7 @@ void init_reg_q_set_val(REG_Q_SET_VALUE *q_u, POLICY_HND *pol, { ZERO_STRUCTP(q_u); - memcpy(&q_u->pol, pol, sizeof(q_u->pol)); + memcpy(&q_u->handle, pol, sizeof(q_u->handle)); init_unistr4(&q_u->name, val_name, UNI_STR_TERMINATE); @@ -1243,7 +1241,7 @@ BOOL reg_io_q_set_value(const char *desc, REG_Q_SET_VALUE *q_u, prs_struct *ps, if(!prs_align(ps)) return False; - if(!smb_io_pol_hnd("", &q_u->pol, ps, depth)) + if(!smb_io_pol_hnd("", &q_u->handle, ps, depth)) return False; if(!prs_unistr4("name", ps, depth, &q_u->name )) diff --git a/source3/rpc_server/srv_reg_nt.c b/source3/rpc_server/srv_reg_nt.c index 95af6c15c9..3491cc2c76 100644 --- a/source3/rpc_server/srv_reg_nt.c +++ b/source3/rpc_server/srv_reg_nt.c @@ -179,29 +179,23 @@ static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY * /* check if the path really exists; failed is indicated by -1 */ /* if the subkey count failed, bail out */ - ZERO_STRUCTP( &subkeys ); - regsubkey_ctr_init( &subkeys ); if ( fetch_reg_keys( regkey, &subkeys ) == -1 ) { - - /* don't really know what to return here */ result = WERR_BADFILE; + goto done; } - else { - /* - * This would previously return NT_STATUS_TOO_MANY_SECRETS - * that doesn't sound quite right to me --jerry - */ - - if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) - result = WERR_BADFILE; + + if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) { + result = WERR_BADFILE; + goto done; } /* save the access mask */ regkey->access_granted = access_granted; +done: /* clean up */ regsubkey_ctr_destroy( &subkeys ); @@ -247,8 +241,6 @@ static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *m if ( !key ) return False; - ZERO_STRUCTP( &subkeys ); - regsubkey_ctr_init( &subkeys ); if ( fetch_reg_keys( key, &subkeys ) == -1 ) @@ -289,9 +281,6 @@ static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum, if ( !key ) return False; - - ZERO_STRUCTP( &values ); - regval_ctr_init( &values ); if ( fetch_reg_values( key, &values ) == -1 ) @@ -407,27 +396,27 @@ WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u) { fstring name; - REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->pol); + REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->pol); REGISTRY_KEY *newkey; uint32 access_granted; WERROR result; DEBUG(5,("reg_open_entry: Enter\n")); - if ( !key ) + if ( !parent ) return WERR_BADFID; rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 ); /* check granted access first; what is the correct mask here? */ - if ( !(key->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) ) + if ( !(parent->access_granted & (SEC_RIGHTS_ENUM_SUBKEYS|SEC_RIGHTS_CREATE_SUBKEY)) ) return WERR_ACCESS_DENIED; /* open the key first to get the appropriate REGISTRY_HOOK and then check the premissions */ - if ( !W_ERROR_IS_OK(result = open_registry_key( p, &r_u->handle, key, name, 0 )) ) + if ( !W_ERROR_IS_OK(result = open_registry_key( p, &r_u->handle, parent, name, 0 )) ) return result; newkey = find_regkey_index_by_hnd(p, &r_u->handle); @@ -473,8 +462,6 @@ WERROR _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u) DEBUG(5,("reg_info: looking up value: [%s]\n", name)); - ZERO_STRUCTP( ®vals ); - regval_ctr_init( ®vals ); /* couple of hard coded registry values */ @@ -891,9 +878,6 @@ static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath, /* now start parsing the values and subkeys */ - ZERO_STRUCT( values ); - ZERO_STRUCT( subkeys ); - regsubkey_ctr_init( &subkeys ); regval_ctr_init( &values ); @@ -1044,9 +1028,6 @@ static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath, /* lookup the values and subkeys */ - ZERO_STRUCT( values ); - ZERO_STRUCT( subkeys ); - regsubkey_ctr_init( &subkeys ); regval_ctr_init( &values ); @@ -1186,7 +1167,98 @@ WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u) WERROR _reg_create_key(pipes_struct *p, REG_Q_CREATE_KEY *q_u, REG_R_CREATE_KEY *r_u) { - return WERR_ACCESS_DENIED; + REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle); + REGISTRY_KEY *newparent; + POLICY_HND newparent_handle; + REGSUBKEY_CTR subkeys; + BOOL write_result; + pstring name; + WERROR result; + + if ( !parent ) + return WERR_BADFID; + + rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 ); + + /* ok. Here's what we do. */ + + if ( strrchr( name, '\\' ) ) { + pstring newkeyname; + char *ptr; + uint32 access_granted; + + /* (1) check for enumerate rights on the parent handle. CLients can try + create things like 'SOFTWARE\Samba' on the HKLM handle. + (2) open the path to the child parent key if necessary */ + + if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) ) + return WERR_ACCESS_DENIED; + + pstrcpy( newkeyname, name ); + ptr = strrchr( newkeyname, '\\' ); + *ptr = '\0'; + + result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 ); + if ( !W_ERROR_IS_OK(result) ) + return result; + + newparent = find_regkey_index_by_hnd(p, &newparent_handle); + SMB_ASSERT( newparent != NULL ); + + if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) { + result = WERR_ACCESS_DENIED; + goto done; + } + + newparent->access_granted = access_granted; + + /* copy the new key name (just the lower most keyname) */ + + pstrcpy( name, ptr+1 ); + } + else { + /* use the existing open key information */ + newparent = parent; + memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) ); + } + + /* (3) check for create subkey rights on the correct parent */ + + if ( !(newparent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) { + result = WERR_ACCESS_DENIED; + goto done; + } + + regsubkey_ctr_init( &subkeys ); + + /* (4) lookup the current keys and add the new one */ + + fetch_reg_keys( newparent, &subkeys ); + regsubkey_ctr_addkey( &subkeys, name ); + + /* now write to the registry backend */ + + write_result = store_reg_keys( newparent, &subkeys ); + + regsubkey_ctr_destroy( &subkeys ); + + if ( !write_result ) + return WERR_REG_IO_FAILURE; + + /* (5) open the new key and return the handle. Note that it is probably + not correct to grant full access on this open handle. We should pass + the new open through the regkey_access_check() like we do for + _reg_open_entry() but this is ok for now. */ + + result = open_registry_key( p, &r_u->handle, newparent, name, REG_KEY_ALL ); + +done: + /* close any intermediate key handles */ + + if ( newparent != parent ) + close_registry_key( p, &newparent_handle ); + + return result; } @@ -1195,7 +1267,35 @@ WERROR _reg_create_key(pipes_struct *p, REG_Q_CREATE_KEY *q_u, REG_R_CREATE_KEY WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r_u) { - return WERR_ACCESS_DENIED; + REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle); + REGVAL_CTR values; + BOOL write_result; + + if ( !key ) + return WERR_BADFID; + + /* access checks first */ + + if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) ) + return WERR_ACCESS_DENIED; + + regval_ctr_init( &values ); + + /* lookup the current values and add the new one */ + + fetch_reg_values( key, &values ); + /* FIXME!!!! regval_ctr_addvalue( &values, .... ); */ + + /* now write to the registry backend */ + + write_result = store_reg_values( key, &values ); + + regval_ctr_destroy( &values ); + + if ( !write_result ) + return WERR_REG_IO_FAILURE; + + return WERR_OK; } /******************************************************************* @@ -1203,7 +1303,41 @@ WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY *r_u) { - return WERR_ACCESS_DENIED; + REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle); + REGSUBKEY_CTR subkeys; + BOOL write_result; + fstring name; + + if ( !parent ) + return WERR_BADFID; + + rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 ); + + /* access checks first */ + + if ( !(parent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) + return WERR_ACCESS_DENIED; + + regsubkey_ctr_init( &subkeys ); + + /* lookup the current keys and add the new one */ + + fetch_reg_keys( parent, &subkeys ); + + /* FIXME!!! regsubkey_ctr_delkey( &subkeys, name ); */ + + /* now write to the registry backend */ + + write_result = store_reg_keys( parent, &subkeys ); + + regsubkey_ctr_destroy( &subkeys ); + + if ( !write_result ) + return WERR_REG_IO_FAILURE; + + /* rpc_reg.h says there is a POLICY_HDN in the reply...no idea if that is correct */ + + return WERR_OK; } @@ -1212,6 +1346,34 @@ WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY WERROR _reg_delete_value(pipes_struct *p, REG_Q_DELETE_VALUE *q_u, REG_R_DELETE_VALUE *r_u) { - return WERR_ACCESS_DENIED; + REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle); + REGVAL_CTR values; + BOOL write_result; + + if ( !key ) + return WERR_BADFID; + + /* access checks first */ + + if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) ) + return WERR_ACCESS_DENIED; + + regval_ctr_init( &values ); + + /* lookup the current values and add the new one */ + + fetch_reg_values( key, &values ); + /* FIXME!!!! regval_ctr_delval( &values, .... ); */ + + /* now write to the registry backend */ + + write_result = store_reg_values( key, &values ); + + regval_ctr_destroy( &values ); + + if ( !write_result ) + return WERR_REG_IO_FAILURE; + + return WERR_OK; } diff --git a/source3/utils/net_rpc_registry.c b/source3/utils/net_rpc_registry.c index f97f67a13b..8a97f64584 100644 --- a/source3/utils/net_rpc_registry.c +++ b/source3/utils/net_rpc_registry.c @@ -336,9 +336,6 @@ static BOOL write_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk, int i; pstring path; - ZERO_STRUCT( values ); - ZERO_STRUCT( subkeys ); - regsubkey_ctr_init( &subkeys ); regval_ctr_init( &values ); -- cgit