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