r9114: removing gratuitous debug messages
[vlendec/samba-autobuild/.git] / source3 / rpc_server / srv_reg_nt.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell               1992-1997.
5  *  Copyright (C) Luke Kenneth Casson Leighton  1996-1997.
6  *  Copyright (C) Paul Ashton                        1997.
7  *  Copyright (C) Jeremy Allison                     2001.
8  *  Copyright (C) Gerald Carter                      2002-2005.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *  
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *  
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /* Implementation of registry functions. */
26
27 #include "includes.h"
28 #include "regfio.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
32
33 #define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
34 ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
35
36
37 static struct generic_mapping reg_generic_map = { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
38
39 /********************************************************************
40 ********************************************************************/
41
42 NTSTATUS registry_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token, 
43                                      uint32 access_desired, uint32 *access_granted )
44 {
45         NTSTATUS result;
46                 
47         se_map_generic( &access_desired, &reg_generic_map );
48         se_access_check( sec_desc, token, access_desired, access_granted, &result );
49         
50         return result;
51 }
52
53 /********************************************************************
54 ********************************************************************/
55
56 SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
57 {
58         SEC_ACE ace[2]; 
59         SEC_ACCESS mask;
60         size_t i = 0;
61         SEC_DESC *sd;
62         SEC_ACL *acl;
63         uint32 sd_size;
64
65         /* basic access for Everyone */
66         
67         init_sec_access(&mask, REG_KEY_READ );
68         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
69         
70         /* Full Access 'BUILTIN\Administrators' */
71         
72         init_sec_access(&mask, REG_KEY_ALL );
73         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
74         
75         
76         /* create the security descriptor */
77         
78         if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
79                 return NULL;
80
81         if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
82                 return NULL;
83
84         return sd;
85 }
86
87 /******************************************************************
88  free() function for REGISTRY_KEY
89  *****************************************************************/
90  
91 static void free_regkey_info(void *ptr)
92 {
93         REGISTRY_KEY *info = (REGISTRY_KEY*)ptr;
94         
95         SAFE_FREE(info);
96 }
97
98 /******************************************************************
99  Find a registry key handle and return a REGISTRY_KEY
100  *****************************************************************/
101
102 static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
103 {
104         REGISTRY_KEY *regkey = NULL;
105
106         if(!find_policy_by_hnd(p,hnd,(void **)&regkey)) {
107                 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
108                 return NULL;
109         }
110
111         return regkey;
112 }
113
114
115 /*******************************************************************
116  Function for open a new registry handle and creating a handle 
117  Note that P should be valid & hnd should already have space
118  
119  When we open a key, we store the full path to the key as 
120  HK[LM|U]\<key>\<key>\...
121  *******************************************************************/
122  
123 static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY *parent,
124                                 const char *subkeyname, uint32 access_granted  )
125 {
126         REGISTRY_KEY    *regkey = NULL;
127         WERROR          result = WERR_OK;
128         REGSUBKEY_CTR   subkeys;
129         pstring         subkeyname2;
130         int             subkey_len;
131         
132         DEBUG(7,("open_registry_key: name = [%s][%s]\n", 
133                 parent ? parent->name : "NULL", subkeyname));
134
135         /* strip any trailing '\'s */
136         pstrcpy( subkeyname2, subkeyname );
137         subkey_len = strlen ( subkeyname2 );
138         if ( subkey_len && subkeyname2[subkey_len-1] == '\\' )
139                 subkeyname2[subkey_len-1] = '\0';
140
141         if ((regkey=SMB_MALLOC_P(REGISTRY_KEY)) == NULL)
142                 return WERR_NOMEM;
143                 
144         ZERO_STRUCTP( regkey );
145         
146         /* 
147          * very crazy, but regedit.exe on Win2k will attempt to call 
148          * REG_OPEN_ENTRY with a keyname of "".  We should return a new 
149          * (second) handle here on the key->name.  regedt32.exe does 
150          * not do this stupidity.   --jerry
151          */
152         
153         if ( !subkey_len ) {
154                 pstrcpy( regkey->name, parent->name );  
155         }
156         else {
157                 pstrcpy( regkey->name, "" );
158                 if ( parent ) {
159                         pstrcat( regkey->name, parent->name );
160                         pstrcat( regkey->name, "\\" );
161                 }
162                 pstrcat( regkey->name, subkeyname2 );
163         }
164         
165         /* Look up the table of registry I/O operations */
166
167         if ( !(regkey->hook = reghook_cache_find( regkey->name )) ) {
168                 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
169                         regkey->name ));
170                 return WERR_BADFILE;
171         }
172         
173         /* check if the path really exists; failed is indicated by -1 */
174         /* if the subkey count failed, bail out */
175
176         regsubkey_ctr_init( &subkeys );
177         
178         if ( fetch_reg_keys( regkey, &subkeys ) == -1 )  {
179                 result = WERR_BADFILE;
180                 goto done;
181         }
182                 
183         if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) {
184                         result = WERR_BADFILE; 
185                 goto done;
186         }
187         
188         /* save the access mask */
189
190         regkey->access_granted = access_granted;
191         
192 done:
193         /* clean up */
194
195         regsubkey_ctr_destroy( &subkeys );
196         
197         if ( ! NT_STATUS_IS_OK(result) )
198                 SAFE_FREE( regkey );
199         
200         DEBUG(7,("open_registry_key: exit\n"));
201
202         return result;
203 }
204
205 /*******************************************************************
206  Function for open a new registry handle and creating a handle 
207  Note that P should be valid & hnd should already have space
208  *******************************************************************/
209
210 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
211 {
212         REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd);
213         
214         if ( !regkey ) {
215                 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
216                 return False;
217         }
218         
219         close_policy_hnd(p, hnd);
220         
221         return True;
222 }
223
224 /********************************************************************
225  retrieve information about the subkeys
226  *******************************************************************/
227  
228 static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen )
229 {
230         int             num_subkeys, i;
231         uint32          max_len;
232         REGSUBKEY_CTR   subkeys;
233         uint32          len;
234         
235         if ( !key )
236                 return False;
237
238         regsubkey_ctr_init( &subkeys ); 
239            
240         if ( fetch_reg_keys( key, &subkeys ) == -1 )
241                 return False;
242
243         /* find the longest string */
244         
245         max_len = 0;
246         num_subkeys = regsubkey_ctr_numkeys( &subkeys );
247         
248         for ( i=0; i<num_subkeys; i++ ) {
249                 len = strlen( regsubkey_ctr_specific_key(&subkeys, i) );
250                 max_len = MAX(max_len, len);
251         }
252
253         *maxnum = num_subkeys;
254         *maxlen = max_len*2;
255         
256         regsubkey_ctr_destroy( &subkeys );
257         
258         return True;
259 }
260
261 /********************************************************************
262  retrieve information about the values.  
263  *******************************************************************/
264  
265 static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum, 
266                                     uint32 *maxlen, uint32 *maxsize )
267 {
268         REGVAL_CTR      values;
269         REGISTRY_VALUE  *val;
270         uint32          sizemax, lenmax;
271         int             i, num_values;
272         
273         if ( !key )
274                 return False;
275
276         regval_ctr_init( &values );
277         
278         if ( fetch_reg_values( key, &values ) == -1 )
279                 return False;
280         
281         lenmax = sizemax = 0;
282         num_values = regval_ctr_numvals( &values );
283         
284         val = regval_ctr_specific_value( &values, 0 );
285         
286         for ( i=0; i<num_values && val; i++ ) 
287         {
288                 lenmax  = MAX(lenmax,  val->valuename ? strlen(val->valuename)+1 : 0 );
289                 sizemax = MAX(sizemax, val->size );
290                 
291                 val = regval_ctr_specific_value( &values, i );
292         }
293
294         *maxnum   = num_values;
295         *maxlen   = lenmax;
296         *maxsize  = sizemax;
297         
298         regval_ctr_destroy( &values );
299         
300         return True;
301 }
302
303
304 /********************************************************************
305  reg_close
306  ********************************************************************/
307
308 WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
309 {
310         /* close the policy handle */
311
312         if (!close_registry_key(p, &q_u->pol))
313                 return WERR_BADFID; 
314
315         return WERR_OK;
316 }
317
318 /*******************************************************************
319  ********************************************************************/
320
321 WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
322 {
323         SEC_DESC *sec_desc;
324         uint32 access_granted = 0;
325         NTSTATUS status;
326         
327         /* perform access checks */
328         /* top level keys are done here without passing through the REGISTRY_HOOK api */
329         
330         if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
331                 return WERR_NOMEM;
332                 
333         status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
334         if ( !NT_STATUS_IS_OK(status) )
335                 return ntstatus_to_werror( status );
336                 
337         return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, access_granted );
338 }
339
340 /*******************************************************************
341  ********************************************************************/
342
343 WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
344 {
345         SEC_DESC *sec_desc;
346         uint32 access_granted = 0;
347         NTSTATUS status;
348         
349         /* perform access checks */
350         /* top level keys are done here without passing through the REGISTRY_HOOK api */
351         
352         if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
353                 return WERR_NOMEM;
354                 
355         status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
356         if ( !NT_STATUS_IS_OK(status) )
357                 return ntstatus_to_werror( status );
358                 
359         return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, access_granted );
360 }
361
362 /*******************************************************************
363  ********************************************************************/
364
365 WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
366 {
367         SEC_DESC *sec_desc;
368         uint32 access_granted = 0;
369         NTSTATUS status;
370         
371         /* perform access checks */
372         /* top level keys are done here without passing through the REGISTRY_HOOK api */
373         
374         if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
375                 return WERR_NOMEM;
376                 
377         status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
378         if ( !NT_STATUS_IS_OK(status) )
379                 return ntstatus_to_werror( status );
380                 
381         return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, access_granted );
382 }
383
384 /*******************************************************************
385  reg_reply_open_entry
386  ********************************************************************/
387
388 WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
389 {
390         fstring name;
391         REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->pol);
392         REGISTRY_KEY *newkey;
393         uint32 access_granted;
394         WERROR result;
395
396         if ( !parent )
397                 return WERR_BADFID;
398
399         rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
400         
401         /* check granted access first; what is the correct mask here? */
402
403         if ( !(parent->access_granted & (SEC_RIGHTS_ENUM_SUBKEYS|SEC_RIGHTS_CREATE_SUBKEY)) )
404                 return WERR_ACCESS_DENIED;
405         
406         /* open the key first to get the appropriate REGISTRY_HOOK 
407            and then check the premissions */
408
409         if ( !W_ERROR_IS_OK(result = open_registry_key( p, &r_u->handle, parent, name, 0 )) )
410                 return result;
411
412         newkey = find_regkey_index_by_hnd(p, &r_u->handle);
413
414         /* finally allow the backend to check the access for the requested key */
415
416         if ( !regkey_access_check( newkey, q_u->access, &access_granted, p->pipe_user.nt_user_token ) ) {
417                 close_registry_key( p, &r_u->handle );
418                 return WERR_ACCESS_DENIED;
419         }
420
421         /* if successful, save the granted access mask */
422
423         newkey->access_granted = access_granted;
424         
425         return WERR_OK;
426 }
427
428 /*******************************************************************
429  reg_reply_info
430  ********************************************************************/
431
432 WERROR _reg_query_value(pipes_struct *p, REG_Q_QUERY_VALUE *q_u, REG_R_QUERY_VALUE *r_u)
433 {
434         WERROR                  status = WERR_BADFILE;
435         fstring                 name;
436         REGISTRY_KEY            *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
437         REGISTRY_VALUE          *val = NULL;
438         REGVAL_CTR              regvals;
439         int                     i;
440
441         if ( !regkey )
442                 return WERR_BADFID;
443                 
444         DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
445         
446         rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
447
448         DEBUG(5,("reg_info: looking up value: [%s]\n", name));
449
450         regval_ctr_init( &regvals );
451         
452         for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ ) 
453         {
454                 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
455                 if ( strequal( val->valuename, name ) ) {
456                         DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
457                         status = WERR_OK;
458                         break;
459                 }
460                 
461                 free_registry_value( val );
462         }
463
464         init_reg_r_query_value(q_u->ptr_buf, r_u, val, status);
465         
466         regval_ctr_destroy( &regvals );
467         free_registry_value( val );
468
469         return status;
470 }
471
472
473 /*****************************************************************************
474  Implementation of REG_QUERY_KEY
475  ****************************************************************************/
476  
477 WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
478 {
479         WERROR  status = WERR_OK;
480         REGISTRY_KEY    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
481         
482         if ( !regkey )
483                 return WERR_BADFID; 
484         
485         if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) ) {
486                 DEBUG(0,("_reg_query_key: get_subkey_information() failed!\n"));
487                 return WERR_ACCESS_DENIED;
488         }
489                 
490         if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) ) {
491                 DEBUG(0,("_reg_query_key: get_value_information() failed!\n"));
492                 return WERR_ACCESS_DENIED;      
493         }
494
495                 
496         r_u->sec_desc = 0x00000078;     /* size for key's sec_desc */
497         
498         /* Win9x set this to 0x0 since it does not keep timestamps.
499            Doing the same here for simplicity   --jerry */
500            
501         ZERO_STRUCT(r_u->mod_time);     
502
503         return status;
504 }
505
506
507 /*****************************************************************************
508  Implementation of REG_GETVERSION
509  ****************************************************************************/
510  
511 WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u)
512 {
513         WERROR  status = WERR_OK;
514         REGISTRY_KEY    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
515         
516         if ( !regkey )
517                 return WERR_BADFID;
518         
519         r_u->win_version = 0x00000005;  /* Windows 2000 registry API version */
520         
521         return status;
522 }
523
524
525 /*****************************************************************************
526  Implementation of REG_ENUM_KEY
527  ****************************************************************************/
528  
529 WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
530 {
531         WERROR  status = WERR_OK;
532         REGISTRY_KEY    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
533         char            *subkey = NULL;
534         
535         
536         if ( !regkey )
537                 return WERR_BADFID; 
538
539         DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
540         
541         if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) )
542         {
543                 status = WERR_NO_MORE_ITEMS;
544                 goto done;
545         }
546         
547         DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
548         
549         /* subkey has the string name now */
550         
551         init_reg_r_enum_key( r_u, subkey );
552         
553 done:   
554         SAFE_FREE( subkey );
555         return status;
556 }
557
558 /*****************************************************************************
559  Implementation of REG_ENUM_VALUE
560  ****************************************************************************/
561  
562 WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u)
563 {
564         WERROR  status = WERR_OK;
565         REGISTRY_KEY    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
566         REGISTRY_VALUE  *val;
567         
568         
569         if ( !regkey )
570                 return WERR_BADFID; 
571
572         DEBUG(8,("_reg_enum_value: enumerating values for key [%s]\n", regkey->name));
573
574         if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) {
575                 status = WERR_NO_MORE_ITEMS;
576                 goto done;
577         }
578         
579         DEBUG(10,("_reg_enum_value: retrieved value named  [%s]\n", val->valuename));
580         
581         /* subkey has the string name now */
582         
583         init_reg_r_enum_val( r_u, val );
584
585 done:   
586         free_registry_value( val );
587         
588         return status;
589 }
590
591
592 /*******************************************************************
593  reg_shutdwon
594  ********************************************************************/
595
596 WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
597 {
598         REG_Q_SHUTDOWN_EX q_u_ex;
599         REG_R_SHUTDOWN_EX r_u_ex;
600         
601         /* copy fields (including stealing memory) */
602         
603         q_u_ex.server  = q_u->server;
604         q_u_ex.message = q_u->message;
605         q_u_ex.timeout = q_u->timeout;
606         q_u_ex.force   = q_u->force;
607         q_u_ex.reboot  = q_u->reboot;
608         q_u_ex.reason  = 0x0;   /* don't care for now */
609         
610         /* thunk down to _reg_shutdown_ex() (just returns a status) */
611         
612         return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex );
613 }
614
615 /*******************************************************************
616  reg_shutdown_ex
617  ********************************************************************/
618
619 #define SHUTDOWN_R_STRING "-r"
620 #define SHUTDOWN_F_STRING "-f"
621
622
623 WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u)
624 {
625         pstring shutdown_script;
626         pstring message;
627         pstring chkmsg;
628         fstring timeout;
629         fstring reason;
630         fstring r;
631         fstring f;
632         int ret;
633         BOOL can_shutdown;
634         
635
636         pstrcpy(shutdown_script, lp_shutdown_script());
637         
638         if ( !*shutdown_script )
639                 return WERR_ACCESS_DENIED;
640
641         /* pull the message string and perform necessary sanity checks on it */
642
643         pstrcpy( message, "" );
644         if ( q_u->message ) {
645                 UNISTR2 *msg_string = q_u->message->string;
646                 
647                 rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 );
648         }
649         alpha_strcpy (chkmsg, message, NULL, sizeof(message));
650                 
651         fstr_sprintf(timeout, "%d", q_u->timeout);
652         fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : "");
653         fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : "");
654         fstr_sprintf( reason, "%d", q_u->reason );
655
656         all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) );
657         all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) );
658         all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) );
659         all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) );
660         all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) );
661
662         can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
663                 
664         /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root
665            Take the error return from the script and provide it as the Windows return code. */
666            
667         /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
668         
669         if ( can_shutdown ) 
670                 become_root();
671
672         ret = smbrun( shutdown_script, NULL );
673                 
674         if ( can_shutdown )
675                 unbecome_root();
676
677         /********** END SeRemoteShutdownPrivilege BLOCK **********/
678         
679         DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n",
680                 shutdown_script, ret));
681                 
682
683         return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
684 }
685
686
687
688
689 /*******************************************************************
690  reg_abort_shutdwon
691  ********************************************************************/
692
693 WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
694 {
695         pstring abort_shutdown_script;
696         int ret;
697         BOOL can_shutdown;
698
699         pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
700
701         if ( !*abort_shutdown_script )
702                 return WERR_ACCESS_DENIED;
703                 
704         can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown );
705                 
706         /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/
707         
708         if ( can_shutdown )
709                 become_root();
710                 
711         ret = smbrun( abort_shutdown_script, NULL );
712         
713         if ( can_shutdown )
714                 unbecome_root();
715                 
716         /********** END SeRemoteShutdownPrivilege BLOCK **********/
717
718         DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",
719                 abort_shutdown_script, ret));
720                 
721
722         return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED;
723 }
724
725 /*******************************************************************
726  ********************************************************************/
727
728 static int validate_reg_filename( pstring fname )
729 {
730         char *p;
731         int num_services = lp_numservices();
732         int snum;
733         pstring share_path;
734         pstring unix_fname;
735         
736         /* convert to a unix path, stripping the C:\ along the way */
737         
738         if ( !(p = valid_share_pathname( fname ) ))
739                 return -1;
740
741         /* has to exist within a valid file share */
742                         
743         for ( snum=0; snum<num_services; snum++ ) {
744         
745                 if ( !lp_snum_ok(snum) || lp_print_ok(snum) )
746                         continue;
747                 
748                 pstrcpy( share_path, lp_pathname(snum) );
749
750                 /* make sure we have a path (e.g. [homes] ) */
751
752                 if ( strlen( share_path ) == 0 )
753                         continue;
754
755                 if ( strncmp( share_path, p, strlen( share_path )) == 0 )
756                         break;
757         }
758         
759         /* p and fname are overlapping memory so copy out and back in again */
760         
761         pstrcpy( unix_fname, p );
762         pstrcpy( fname, unix_fname );
763         
764         return (snum < num_services) ? snum : -1;
765 }
766
767 /*******************************************************************
768  Note: topkeypat is the *full* path that this *key will be 
769  loaded into (including the name of the key)
770  ********************************************************************/
771
772 static WERROR reg_load_tree( REGF_FILE *regfile, const char *topkeypath,
773                              REGF_NK_REC *key )
774 {
775         REGF_NK_REC *subkey;
776         REGISTRY_KEY registry_key;
777         REGVAL_CTR values;
778         REGSUBKEY_CTR subkeys;
779         int i;
780         pstring path;
781         WERROR result = WERR_OK;
782         
783         /* initialize the REGISTRY_KEY structure */
784         
785         if ( !(registry_key.hook = reghook_cache_find(topkeypath)) ) {
786                 DEBUG(0,("reg_load_tree: Failed to assigned a REGISTRY_HOOK to [%s]\n",
787                         topkeypath ));
788                 return WERR_BADFILE;
789         }
790         pstrcpy( registry_key.name, topkeypath );
791         
792         /* now start parsing the values and subkeys */
793
794         regsubkey_ctr_init( &subkeys );
795         regval_ctr_init( &values );
796         
797         /* copy values into the REGVAL_CTR */
798         
799         for ( i=0; i<key->num_values; i++ ) {
800                 regval_ctr_addvalue( &values, key->values[i].valuename, key->values[i].type,
801                         key->values[i].data, (key->values[i].data_size & ~VK_DATA_IN_OFFSET) );
802         }
803
804         /* copy subkeys into the REGSUBKEY_CTR */
805         
806         key->subkey_index = 0;
807         while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
808                 regsubkey_ctr_addkey( &subkeys, subkey->keyname );
809         }
810         
811         /* write this key and values out */
812         
813         if ( !store_reg_values( &registry_key, &values ) 
814                 || !store_reg_keys( &registry_key, &subkeys ) )
815         {
816                 DEBUG(0,("reg_load_tree: Failed to load %s!\n", topkeypath));
817                 result = WERR_REG_IO_FAILURE;
818         }
819         
820         regval_ctr_destroy( &values );
821         regsubkey_ctr_destroy( &subkeys );
822         
823         if ( !W_ERROR_IS_OK(result) )
824                 return result;
825         
826         /* now continue to load each subkey registry tree */
827
828         key->subkey_index = 0;
829         while ( (subkey = regfio_fetch_subkey( regfile, key )) ) {
830                 pstr_sprintf( path, "%s%s%s", topkeypath, "\\", subkey->keyname );
831                 result = reg_load_tree( regfile, path, subkey );
832                 if ( !W_ERROR_IS_OK(result) )
833                         break;
834         }
835
836         return result;
837 }
838
839 /*******************************************************************
840  ********************************************************************/
841
842 static WERROR restore_registry_key ( REGISTRY_KEY *krecord, const char *fname )
843 {
844         REGF_FILE *regfile;
845         REGF_NK_REC *rootkey;
846         WERROR result;
847                 
848         /* open the registry file....fail if the file already exists */
849         
850         if ( !(regfile = regfio_open( fname, (O_RDONLY), 0 )) ) {
851                 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n", 
852                         fname, strerror(errno) ));
853                 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
854         }
855         
856         /* get the rootkey from the regf file and then load the tree
857            via recursive calls */
858            
859         if ( !(rootkey = regfio_rootkey( regfile )) )
860                 return WERR_REG_FILE_INVALID;
861         
862         result = reg_load_tree( regfile, krecord->name, rootkey );
863                 
864         /* cleanup */
865         
866         regfio_close( regfile );
867         
868         return result;
869 }
870
871 /*******************************************************************
872  ********************************************************************/
873
874 WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY  *q_u, REG_R_RESTORE_KEY *r_u)
875 {
876         REGISTRY_KEY    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
877         pstring         filename;
878         int             snum;
879         
880         if ( !regkey )
881                 return WERR_BADFID; 
882
883         rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
884
885         DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename));
886
887         if ( (snum = validate_reg_filename( filename )) == -1 )
888                 return WERR_OBJECT_PATH_INVALID;
889                 
890         /* user must posses SeRestorePrivilege for this this proceed */
891         
892         if ( !user_has_privileges( p->pipe_user.nt_user_token, &se_restore ) )
893                 return WERR_ACCESS_DENIED;
894                 
895         DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
896
897         return restore_registry_key( regkey, filename );
898 }
899
900 /********************************************************************
901 ********************************************************************/
902
903 static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath,
904                               REGF_NK_REC *parent, SEC_DESC *sec_desc )
905 {
906         REGF_NK_REC *key;
907         REGVAL_CTR values;
908         REGSUBKEY_CTR subkeys;
909         int i, num_subkeys;
910         pstring key_tmp;
911         char *keyname, *parentpath;
912         pstring subkeypath;
913         char *subkeyname;
914         REGISTRY_KEY registry_key;
915         WERROR result = WERR_OK;
916         
917         if ( !regfile )
918                 return WERR_GENERAL_FAILURE;
919                 
920         if ( !keypath )
921                 return WERR_OBJECT_PATH_INVALID;
922                 
923         /* split up the registry key path */
924         
925         pstrcpy( key_tmp, keypath );
926         if ( !reg_split_key( key_tmp, &parentpath, &keyname ) )
927                 return WERR_OBJECT_PATH_INVALID;
928
929         if ( !keyname )
930                 keyname = parentpath;
931
932         /* we need a REGISTRY_KEY object here to enumerate subkeys and values */
933         
934         ZERO_STRUCT( registry_key );
935         pstrcpy( registry_key.name, keypath );
936         if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) )
937                 return WERR_BADFILE;
938
939         
940         /* lookup the values and subkeys */
941         
942         regsubkey_ctr_init( &subkeys );
943         regval_ctr_init( &values );
944         
945         fetch_reg_keys( &registry_key, &subkeys );
946         fetch_reg_values( &registry_key, &values );
947
948         /* write out this key */
949                 
950         if ( !(key = regfio_write_key( regfile, keyname, &values, &subkeys, sec_desc, parent )) ) {
951                 result = WERR_CAN_NOT_COMPLETE;
952                 goto done;
953         }
954
955         /* write each one of the subkeys out */
956
957         num_subkeys = regsubkey_ctr_numkeys( &subkeys );
958         for ( i=0; i<num_subkeys; i++ ) {
959                 subkeyname = regsubkey_ctr_specific_key( &subkeys, i );
960                 pstr_sprintf( subkeypath, "%s\\%s", keypath, subkeyname );
961                 result = reg_write_tree( regfile, subkeypath, key, sec_desc );
962                 if ( !W_ERROR_IS_OK(result) )
963                         goto done;
964         }
965
966         DEBUG(6,("reg_write_tree: wrote key [%s]\n", keypath ));
967
968 done:
969         regval_ctr_destroy( &values );
970         regsubkey_ctr_destroy( &subkeys );
971
972         return result;
973 }
974
975 /*******************************************************************
976  ********************************************************************/
977
978 static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
979 {
980         DOM_SID adm_sid, owner_sid;
981         SEC_ACE ace[2];         /* at most 2 entries */
982         SEC_ACCESS mask;
983         SEC_ACL *psa = NULL;
984         uint32 sd_size;
985
986         /* set the owner to BUILTIN\Administrator */
987
988         sid_copy(&owner_sid, &global_sid_Builtin);
989         sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
990         
991
992         /* basic access for Everyone */
993
994         init_sec_access(&mask, reg_generic_map.generic_execute | reg_generic_map.generic_read );
995         init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
996
997         /* add Full Access 'BUILTIN\Administrators' */
998
999         init_sec_access(&mask, reg_generic_map.generic_all);
1000         sid_copy(&adm_sid, &global_sid_Builtin);
1001         sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
1002         init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
1003
1004         /* create the security descriptor */
1005
1006         if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace)) == NULL)
1007                 return WERR_NOMEM;
1008
1009         if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, &owner_sid, NULL, NULL, psa, &sd_size)) == NULL)
1010                 return WERR_NOMEM;
1011
1012         return WERR_OK;
1013 }
1014
1015 /*******************************************************************
1016  ********************************************************************/
1017
1018 static WERROR backup_registry_key ( REGISTRY_KEY *krecord, const char *fname )
1019 {
1020         REGF_FILE *regfile;
1021         WERROR result;
1022         SEC_DESC *sd = NULL;
1023         
1024         /* open the registry file....fail if the file already exists */
1025         
1026         if ( !(regfile = regfio_open( fname, (O_RDWR|O_CREAT|O_EXCL), (S_IREAD|S_IWRITE) )) ) {
1027                 DEBUG(0,("backup_registry_key: failed to open \"%s\" (%s)\n", 
1028                         fname, strerror(errno) ));
1029                 return ( ntstatus_to_werror(map_nt_error_from_unix( errno )) );
1030         }
1031         
1032         if ( !W_ERROR_IS_OK(result = make_default_reg_sd( regfile->mem_ctx, &sd )) ) {
1033                 regfio_close( regfile );
1034                 return result;
1035         }
1036                 
1037         /* write the registry tree to the file  */
1038         
1039         result = reg_write_tree( regfile, krecord->name, NULL, sd );
1040                 
1041         /* cleanup */
1042         
1043         regfio_close( regfile );
1044         
1045         return result;
1046 }
1047
1048 /*******************************************************************
1049  ********************************************************************/
1050
1051 WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY  *q_u, REG_R_SAVE_KEY *r_u)
1052 {
1053         REGISTRY_KEY    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
1054         pstring         filename;
1055         int             snum;
1056         
1057         if ( !regkey )
1058                 return WERR_BADFID; 
1059
1060         rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE);
1061
1062         DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename));
1063         
1064         if ( (snum = validate_reg_filename( filename )) == -1 )
1065                 return WERR_OBJECT_PATH_INVALID;
1066                 
1067         DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) ));
1068                 
1069         return backup_registry_key( regkey, filename );
1070
1071         return WERR_OK;
1072 }
1073
1074 /*******************************************************************
1075  ********************************************************************/
1076
1077 WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREATE_KEY_EX *r_u)
1078 {
1079         REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1080         REGISTRY_KEY *newparent;
1081         POLICY_HND newparent_handle;
1082         REGSUBKEY_CTR subkeys;
1083         BOOL write_result;
1084         pstring name;
1085         WERROR result;
1086
1087         if ( !parent )
1088                 return WERR_BADFID;
1089                 
1090         rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1091         
1092         /* ok.  Here's what we do.  */
1093
1094         if ( strrchr( name, '\\' ) ) {
1095                 pstring newkeyname;
1096                 char *ptr;
1097                 uint32 access_granted;
1098                 
1099                 /* (1) check for enumerate rights on the parent handle.  CLients can try 
1100                        create things like 'SOFTWARE\Samba' on the HKLM handle. 
1101                    (2) open the path to the child parent key if necessary */
1102         
1103                 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1104                         return WERR_ACCESS_DENIED;
1105                 
1106                 pstrcpy( newkeyname, name );
1107                 ptr = strrchr( newkeyname, '\\' );
1108                 *ptr = '\0';
1109
1110                 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1111                 if ( !W_ERROR_IS_OK(result) )
1112                         return result;
1113                 
1114                 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1115                 SMB_ASSERT( newparent != NULL );
1116                         
1117                 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1118                         result = WERR_ACCESS_DENIED;
1119                         goto done;
1120                 }
1121
1122                 newparent->access_granted = access_granted;
1123
1124                 /* copy the new key name (just the lower most keyname) */
1125
1126                 pstrcpy( name, ptr+1 );
1127         }
1128         else {
1129                 /* use the existing open key information */
1130                 newparent = parent;
1131                 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1132         }
1133         
1134         /* (3) check for create subkey rights on the correct parent */
1135         
1136         if ( !(newparent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
1137                 result = WERR_ACCESS_DENIED;
1138                 goto done;
1139         }       
1140                 
1141         regsubkey_ctr_init( &subkeys );
1142         
1143         /* (4) lookup the current keys and add the new one */
1144         
1145         fetch_reg_keys( newparent, &subkeys );
1146         regsubkey_ctr_addkey( &subkeys, name );
1147         
1148         /* now write to the registry backend */
1149         
1150         write_result = store_reg_keys( newparent, &subkeys );
1151         
1152         regsubkey_ctr_destroy( &subkeys );
1153         
1154         if ( !write_result )
1155                 return WERR_REG_IO_FAILURE;
1156                 
1157         /* (5) open the new key and return the handle.  Note that it is probably 
1158            not correct to grant full access on this open handle.  We should pass
1159            the new open through the regkey_access_check() like we do for 
1160            _reg_open_entry() but this is ok for now. */
1161         
1162         result = open_registry_key( p, &r_u->handle, newparent, name, REG_KEY_ALL );
1163
1164 done:
1165         /* close any intermediate key handles */
1166         
1167         if ( newparent != parent )
1168                 close_registry_key( p, &newparent_handle );
1169                 
1170         return result;
1171 }
1172
1173
1174 /*******************************************************************
1175  ********************************************************************/
1176
1177 WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE  *q_u, REG_R_SET_VALUE *r_u)
1178 {
1179         REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1180         REGVAL_CTR values;
1181         BOOL write_result;
1182         fstring valuename;
1183
1184         if ( !key )
1185                 return WERR_BADFID;
1186                 
1187         /* access checks first */
1188         
1189         if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1190                 return WERR_ACCESS_DENIED;
1191                 
1192         rpcstr_pull( valuename, q_u->name.string->buffer, sizeof(valuename), q_u->name.string->uni_str_len*2, 0 );
1193
1194         /* verify the name */
1195
1196         if ( !*valuename )
1197                 return WERR_INVALID_PARAM;
1198
1199         DEBUG(8,("_reg_set_value: Setting value for [%s:%s]\n", key->name, valuename));
1200                 
1201         regval_ctr_init( &values );
1202         
1203         /* lookup the current values and add the new one */
1204         
1205         fetch_reg_values( key, &values );
1206         
1207         regval_ctr_addvalue( &values, valuename, q_u->type, q_u->value.buffer, q_u->value.buf_len );
1208         
1209         /* now write to the registry backend */
1210         
1211         write_result = store_reg_values( key, &values );
1212         
1213         regval_ctr_destroy( &values );
1214         
1215         if ( !write_result )
1216                 return WERR_REG_IO_FAILURE;
1217                 
1218         return WERR_OK;
1219 }
1220
1221 /*******************************************************************
1222  ********************************************************************/
1223
1224 WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY  *q_u, REG_R_DELETE_KEY *r_u)
1225 {
1226         REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
1227         REGISTRY_KEY *newparent;
1228         POLICY_HND newparent_handle;
1229         REGSUBKEY_CTR subkeys;
1230         BOOL write_result;
1231         pstring name;
1232         WERROR result;
1233
1234         if ( !parent )
1235                 return WERR_BADFID;
1236                 
1237         rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
1238                 
1239         /* ok.  Here's what we do.  */
1240
1241         if ( strrchr( name, '\\' ) ) {
1242                 pstring newkeyname;
1243                 char *ptr;
1244                 uint32 access_granted;
1245                 
1246                 /* (1) check for enumerate rights on the parent handle.  CLients can try 
1247                        create things like 'SOFTWARE\Samba' on the HKLM handle. 
1248                    (2) open the path to the child parent key if necessary */
1249         
1250                 if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
1251                         return WERR_ACCESS_DENIED;
1252                 
1253                 pstrcpy( newkeyname, name );
1254                 ptr = strrchr( newkeyname, '\\' );
1255                 *ptr = '\0';
1256
1257                 result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
1258                 if ( !W_ERROR_IS_OK(result) )
1259                         return result;
1260                 
1261                 newparent = find_regkey_index_by_hnd(p, &newparent_handle);
1262                 SMB_ASSERT( newparent != NULL );
1263                         
1264                 if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
1265                         result = WERR_ACCESS_DENIED;
1266                         goto done;
1267                 }
1268
1269                 newparent->access_granted = access_granted;
1270
1271                 /* copy the new key name (just the lower most keyname) */
1272
1273                 pstrcpy( name, ptr+1 );
1274         }
1275         else {
1276                 /* use the existing open key information */
1277                 newparent = parent;
1278                 memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
1279         }
1280         
1281         /* (3) check for create subkey rights on the correct parent */
1282         
1283         if ( !(newparent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
1284                 result = WERR_ACCESS_DENIED;
1285                 goto done;
1286         }
1287
1288         regsubkey_ctr_init( &subkeys );
1289         
1290         /* lookup the current keys and delete the new one */
1291         
1292         fetch_reg_keys( newparent, &subkeys );
1293         
1294         regsubkey_ctr_delkey( &subkeys, name );
1295         
1296         /* now write to the registry backend */
1297         
1298         write_result = store_reg_keys( newparent, &subkeys );
1299         
1300         regsubkey_ctr_destroy( &subkeys );
1301
1302         result = write_result ? WERR_OK : WERR_REG_IO_FAILURE;
1303         
1304 done:
1305         /* close any intermediate key handles */
1306         
1307         if ( newparent != parent )
1308                 close_registry_key( p, &newparent_handle );
1309
1310         return result;
1311 }
1312
1313
1314 /*******************************************************************
1315  ********************************************************************/
1316
1317 WERROR _reg_delete_value(pipes_struct *p, REG_Q_DELETE_VALUE  *q_u, REG_R_DELETE_VALUE *r_u)
1318 {
1319         REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1320         REGVAL_CTR values;
1321         BOOL write_result;
1322         fstring valuename;
1323         
1324         if ( !key )
1325                 return WERR_BADFID;
1326                 
1327         /* access checks first */
1328         
1329         if ( !(key->access_granted & SEC_RIGHTS_SET_VALUE) )
1330                 return WERR_ACCESS_DENIED;
1331
1332         rpcstr_pull( valuename, q_u->name.string->buffer, sizeof(valuename), q_u->name.string->uni_str_len*2, 0 );
1333
1334         if ( !*valuename )
1335                 return WERR_INVALID_PARAM;
1336
1337         DEBUG(8,("_reg_delete_value: Setting value for [%s:%s]\n", key->name, valuename));
1338
1339         regval_ctr_init( &values );
1340         
1341         /* lookup the current values and add the new one */
1342         
1343         fetch_reg_values( key, &values );
1344         
1345         regval_ctr_delvalue( &values, valuename );
1346         
1347         /* now write to the registry backend */
1348         
1349         write_result = store_reg_values( key, &values );
1350         
1351         regval_ctr_destroy( &values );
1352         
1353         if ( !write_result )
1354                 return WERR_REG_IO_FAILURE;
1355                 
1356         return WERR_OK;
1357 }
1358
1359 /*******************************************************************
1360  ********************************************************************/
1361
1362 WERROR _reg_get_key_sec(pipes_struct *p, REG_Q_GET_KEY_SEC  *q_u, REG_R_GET_KEY_SEC *r_u)
1363 {
1364         REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1365
1366         if ( !key )
1367                 return WERR_BADFID;
1368                 
1369         /* access checks first */
1370         
1371         if ( !(key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) )
1372                 return WERR_ACCESS_DENIED;
1373                 
1374         return WERR_ACCESS_DENIED;
1375 }
1376
1377 /*******************************************************************
1378  ********************************************************************/
1379
1380 WERROR _reg_set_key_sec(pipes_struct *p, REG_Q_SET_KEY_SEC  *q_u, REG_R_SET_KEY_SEC *r_u)
1381 {
1382         REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->handle);
1383
1384         if ( !key )
1385                 return WERR_BADFID;
1386                 
1387         /* access checks first */
1388         
1389         if ( !(key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) )
1390                 return WERR_ACCESS_DENIED;
1391                 
1392         return WERR_ACCESS_DENIED;
1393 }
1394
1395