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