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