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