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