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