updated the 3.0 branch from the head branch - ready for alpha18
[jra/samba/.git] / source3 / rpc_server / srv_reg_nt.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-1997,
5  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
6  *  Copyright (C) Paul Ashton                       1997.
7  *  Copyright (C) Hewlett-Packard Company           1999.
8  *  Copyright (C) Jeremy Allison                    2001.
9  *  Copyright (C) Gerald Carter                     2002.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *  
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *  
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 /* Implementation of registry functions. */
27
28 #include "includes.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
32
33 #define KEY_HKLM        "HKLM"
34 #define KEY_HKU         "HKU"
35
36 #define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
37 ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
38
39 /* structure to store the registry handles */
40
41 typedef struct _RegistryKey {
42         struct _RegistryKey *prev, *next;
43
44         fstring name; /* name of registry key */
45         POLICY_HND      hnd;
46         
47 } Registry_Key;
48
49 static Registry_Key *regkeys_list;
50 static TDB_CONTEXT *tdb_reg;
51
52 /***********************************************************************
53  Add subkey strings to the registry tdb under a defined key
54  fmt is the same format as tdb_pack except this function only supports
55  fstrings
56  ***********************************************************************/
57  
58 static BOOL store_reg_keys( TDB_CONTEXT *tdb, char *keyname, char **subkeys, uint32 num_subkeys  )
59 {
60         TDB_DATA kbuf, dbuf;
61         char *buffer, *tmpbuf;
62         int i = 0;
63         uint32 len, buflen;
64         BOOL ret = True;
65         
66         if ( !keyname )
67                 return False;
68         
69         /* allocate some initial memory */
70                 
71         buffer = malloc(sizeof(pstring));
72         buflen = sizeof(pstring);
73         len = 0;
74         
75         /* store the number of subkeys */
76         
77         len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys);
78         
79         /* pack all the strings */
80         
81         for (i=0; i<num_subkeys; i++) {
82                 len += tdb_pack(buffer+len, buflen-len, "f", subkeys[i]);
83                 if ( len > buflen ) {
84                         /* allocate some extra space */
85                         if ((tmpbuf = Realloc( buffer, len*2 )) == NULL) {
86                                 DEBUG(0,("store_reg_keys: Failed to realloc memory of size [%d]\n", len*2));
87                                 ret = False;
88                                 goto done;
89                         }
90                         buffer = tmpbuf;
91                         buflen = len*2;
92                                         
93                         len = tdb_pack(buffer+len, buflen-len, "f", subkeys[i]);
94                 }               
95         }
96         
97         /* finally write out the data */
98         
99         kbuf.dptr = keyname;
100         kbuf.dsize = strlen(keyname)+1;
101         dbuf.dptr = buffer;
102         dbuf.dsize = len;
103         if ( tdb_store( tdb, kbuf, dbuf, TDB_REPLACE ) == -1) {
104                 ret = False;
105                 goto done;
106         }
107
108 done:           
109         SAFE_FREE( buffer );
110         return ret;
111 }
112
113 /***********************************************************************
114  Retrieve an array of strings containing subkeys.  Memory should be 
115  released by the caller.  The subkeys are stored in a catenated string
116  of null terminated character strings
117  ***********************************************************************/
118
119 static int fetch_reg_keys( TDB_CONTEXT *tdb,  char* key, char **subkeys )
120 {
121         pstring path;
122         uint32 num_items;
123         TDB_DATA dbuf;
124         char *buf;
125         uint32 buflen, len;
126         int i;
127         char *s;
128
129         
130         pstrcpy( path, key );
131         
132         /* convert to key format */
133         pstring_sub( path, "\\", "/" );
134         
135         dbuf = tdb_fetch_by_string( tdb, path );
136         
137         buf = dbuf.dptr;
138         buflen = dbuf.dsize;
139         
140         if ( !buf ) {
141                 DEBUG(5,("fetch_reg_keys: Failed to fetch any subkeys for [%s]\n", key));
142                 return 0;
143         }
144         
145         len = tdb_unpack( buf, buflen, "d", &num_items);
146         if (num_items) {
147                 if ( (*subkeys = (char*)malloc(sizeof(fstring)*num_items)) == NULL ) {
148                         DEBUG(0,("fetch_reg_keys: Failed to malloc memory for subkey array containing [%d] items!\n",
149                                 num_items));
150                         num_items = -1;
151                         goto done;
152                 }
153         }
154         
155         s = *subkeys;
156         for (i=0; i<num_items; i++) {
157                 len += tdb_unpack( buf+len, buflen-len, "f", s );
158                 s += strlen(s) + 1;
159         }
160
161 done:   
162         SAFE_FREE(dbuf.dptr);
163         return num_items;
164 }
165
166 /***********************************************************************
167  count the number of subkeys dtored in the registry
168  ***********************************************************************/
169
170 static int fetch_reg_keys_count( TDB_CONTEXT *tdb,  char* key )
171 {
172         pstring path;
173         uint32 num_items;
174         TDB_DATA dbuf;
175         char *buf;
176         uint32 buflen, len;
177         
178         
179         pstrcpy( path, key );
180         
181         /* convert to key format */
182         pstring_sub( path, "\\", "/" );
183         
184         dbuf = tdb_fetch_by_string( tdb, path );
185         
186         buf = dbuf.dptr;
187         buflen = dbuf.dsize;
188         
189         if ( !buf ) {
190                 DEBUG(5,("fetch_reg_keys: Failed to fetch any subkeys for [%s]\n", key));
191                 return 0;
192         }
193         
194         len = tdb_unpack( buf, buflen, "d", &num_items);
195         
196         SAFE_FREE( buf );
197         
198         return num_items;
199 }
200
201 /***********************************************************************
202  retreive a specific subkey specified by index.  The subkey parameter
203  is assumed to be an fstring.
204  ***********************************************************************/
205
206 static BOOL fetch_reg_keys_specific( TDB_CONTEXT *tdb,  char* key, char* subkey, 
207                                      uint32 key_index )
208 {
209         int num_subkeys, i;
210         char *subkeys = NULL;
211         char *s;
212         
213         num_subkeys = fetch_reg_keys( tdb_reg, key, &subkeys );
214         if ( num_subkeys == -1 )
215                 return False;
216
217         s = subkeys;
218         for ( i=0; i<num_subkeys; i++ ) {
219                 /* copy the key if the index matches */
220                 if ( i == key_index ) {
221                         fstrcpy( subkey, s );
222                         break;
223                 }
224                 
225                 /* go onto the next string */
226                 s += strlen(s) + 1;
227         }
228         
229         SAFE_FREE(subkeys);
230         
231         return True;
232 }
233
234
235 /***********************************************************************
236  Open the registry database
237  ***********************************************************************/
238  
239 static BOOL init_registry_data( TDB_CONTEXT* registry_tdb )
240 {
241         pstring keyname;
242         char *subkeys[3];
243
244         /* HKEY_LOCAL_MACHINE */
245         
246         pstrcpy( keyname, KEY_HKLM );
247         subkeys[0] = "SYSTEM";
248         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 1 ))
249                 return False;
250                 
251         pstrcpy( keyname, KEY_HKLM );
252         pstrcat( keyname, "/SYSTEM" );
253         subkeys[0] = "CurrentControlSet";
254         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 1 ))
255                 return False;
256                 
257         pstrcpy( keyname, KEY_HKLM );
258         pstrcat( keyname, "/SYSTEM/CurrentControlSet" );
259         subkeys[0] = "Control";
260         subkeys[1] = "services";
261         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 2 ))
262                 return False;
263
264         pstrcpy( keyname, KEY_HKLM );
265         pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control" );
266         subkeys[0] = "Print";
267         subkeys[1] = "ProduceOptions";
268         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 2 ))
269                 return False;
270
271         pstrcpy( keyname, KEY_HKLM );
272         pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/Print" );
273         subkeys[0] = "Environments";
274         subkeys[1] = "Forms";
275         subkeys[2] = "Printers";
276         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 3 ))
277                 return False;
278
279         pstrcpy( keyname, KEY_HKLM );
280         pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/ProductOptions" );
281         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 0 ))
282                 return False;
283
284         pstrcpy( keyname, KEY_HKLM );
285         pstrcat( keyname, "/SYSTEM/CurrentControlSet/services" );
286         subkeys[0] = "Netlogon";
287         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 1 ))
288                 return False;
289                 
290         pstrcpy( keyname, KEY_HKLM );
291         pstrcat( keyname, "/SYSTEM/CurrentControlSet/services/Netlogon" );
292         subkeys[0] = "parameters";
293         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 1 ))
294                 return False;
295                 
296         pstrcpy( keyname, KEY_HKLM );
297         pstrcat( keyname, "/SYSTEM/CurrentControlSet/services/Netlogon/parameters" );
298         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 0 ))
299                 return False;
300
301         
302         /* HKEY_USER */
303                 
304         pstrcpy( keyname, KEY_HKU );
305         if ( !store_reg_keys( registry_tdb, keyname, subkeys, 0 ) )
306                 return False;
307                 
308         return True;
309 }
310   
311 /***********************************************************************
312  Open the registry database
313  ***********************************************************************/
314  
315 BOOL init_registry( void )
316 {
317         static pid_t local_pid;
318         
319         
320         if (tdb_reg && local_pid == sys_getpid())
321                 return True;
322
323         /* 
324          * try to open first without creating so we can determine
325          * if we need to init the data in the registry
326          */
327         
328         tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
329         if ( !tdb_reg ) 
330         {
331                 tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
332                 if ( !tdb_reg ) {
333                         DEBUG(0,("init_registry: Failed to open registry %s (%s)\n",
334                                 lock_path("registry.tdb"), strerror(errno) ));
335                         return False;
336                 }
337                 
338                 DEBUG(10,("init_registry: Successfully created registry tdb\n"));
339                 
340                 /* create the registry here */
341                 if ( !init_registry_data( tdb_reg ) ) {
342                         DEBUG(0,("init_registry: Failed to initiailize data in registry!\n"));
343                         return False;
344                 }
345         }
346
347         local_pid = sys_getpid();
348         
349         return True;
350 }
351
352 /******************************************************************
353  Find a registry key handle and return a Registry_Key
354  *****************************************************************/
355
356 static Registry_Key *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
357 {
358         Registry_Key *regkey = NULL;
359
360         if(!find_policy_by_hnd(p,hnd,(void **)&regkey)) {
361                 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
362                 return NULL;
363         }
364
365         return regkey;
366 }
367
368
369 /******************************************************************
370  free() function for Registry_Key
371  *****************************************************************/
372  
373 static void free_reg_info(void *ptr)
374 {
375         Registry_Key *info = (Registry_Key*)ptr;
376         
377         DLIST_REMOVE(regkeys_list, info);
378
379         SAFE_FREE(info);
380 }
381
382 /*******************************************************************
383  Function for open a new registry handle and creating a handle 
384  Note that P should be valid & hnd should already have space
385  *******************************************************************/
386  
387 static BOOL open_registry_key(pipes_struct *p, POLICY_HND *hnd, char *name, 
388                                 uint32 access_granted)
389 {
390         Registry_Key *regkey = NULL;
391
392         DEBUG(7,("open_registry_key: name = [%s]\n", name));
393
394         /* All registry keys **must** have a name of non-zero length */
395         
396         if (!name || !*name )
397                 return False;
398                         
399         if ((regkey=(Registry_Key*)malloc(sizeof(Registry_Key))) == NULL)
400                 return False;
401                 
402         ZERO_STRUCTP( regkey );
403         
404         DLIST_ADD( regkeys_list, regkey );
405
406         /* copy the name and obtain a handle */
407         
408         fstrcpy( regkey->name, name );
409         
410         DEBUG(7,("open_registry_key: exit\n"));
411         
412         return create_policy_hnd( p, hnd, free_reg_info, regkey );
413 }
414
415 /*******************************************************************
416  Function for open a new registry handle and creating a handle 
417  Note that P should be valid & hnd should already have space
418  *******************************************************************/
419
420 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
421 {
422         Registry_Key *regkey = find_regkey_index_by_hnd(p, hnd);
423         
424         if ( !regkey ) {
425                 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
426                 return False;
427         }
428         
429         close_policy_hnd(p, hnd);
430         
431         return True;
432 }
433
434 /********************************************************************
435  retrieve information about the subkeys
436  *******************************************************************/
437  
438 static BOOL get_subkey_information( Registry_Key *key, uint32 *maxnum, uint32 *maxlen )
439 {
440         int num_subkeys, i;
441         uint32 max_len;
442         char *subkeys = NULL;
443         uint32 len;
444         char *s;
445         
446         if ( !key )
447                 return False;
448         
449         num_subkeys = fetch_reg_keys( tdb_reg, key->name, &subkeys );
450         if ( num_subkeys == -1 )
451                 return False;
452
453         /* find the longest string */
454         
455         max_len = 0;
456         s = subkeys;
457         for ( i=0; i<num_subkeys; i++ ) {
458                 len = strlen(s);
459                 max_len = MAX(max_len, len);
460                 s += len + 1;
461         }
462
463         *maxnum = num_subkeys;
464         *maxlen = max_len*2;
465         
466         SAFE_FREE(subkeys);
467         
468         return True;
469 }
470
471 /********************************************************************
472  retrieve information about the values.  We don't store values 
473  here.  The registry tdb is intended to be a frontend to oether 
474  Samba tdb's (such as ntdrivers.tdb).
475  *******************************************************************/
476  
477 static BOOL get_value_information( Registry_Key *key, uint32 *maxnum, 
478                                     uint32 *maxlen, uint32 *maxsize )
479 {
480         if ( !key )
481                 return False;
482
483         /* Hard coded key names first */
484         /* nothing has valuies right now */
485                 
486         *maxnum   = 0;
487         *maxlen   = 0;
488         *maxsize  = 0;
489         return True;
490
491 #if 0   /* JERRY */
492         /* 
493          * FIXME!!! Need to add routines to look up values in other
494          * databases   --jerry
495          */
496
497         return False;
498 #endif
499 }
500
501 /********************************************************************
502  reg_close
503  ********************************************************************/
504
505 NTSTATUS _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
506 {
507         /* set up the REG unknown_1 response */
508         ZERO_STRUCT(r_u->pol);
509
510         /* close the policy handle */
511         if (!close_registry_key(p, &q_u->pol))
512                 return NT_STATUS_OBJECT_NAME_INVALID;
513
514         return NT_STATUS_OK;
515 }
516
517 /*******************************************************************
518  reg_reply_open
519  ********************************************************************/
520
521 NTSTATUS _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HKLM *q_u, REG_R_OPEN_HKLM *r_u)
522 {
523         if (!open_registry_key(p, &r_u->pol, KEY_HKLM, 0x0))
524                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
525
526         return NT_STATUS_OK;
527 }
528
529 /*******************************************************************
530  reg_reply_open
531  ********************************************************************/
532
533 NTSTATUS _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HKU *q_u, REG_R_OPEN_HKU *r_u)
534 {
535         if (!open_registry_key(p, &r_u->pol, KEY_HKU, 0x0))
536                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
537
538         return NT_STATUS_OK;
539 }
540
541 /*******************************************************************
542  reg_reply_open_entry
543  ********************************************************************/
544
545 NTSTATUS _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
546 {
547         POLICY_HND pol;
548         fstring name;
549         pstring path;
550         int num_subkeys;
551         Registry_Key *key = find_regkey_index_by_hnd(p, &q_u->pol);
552
553         DEBUG(5,("reg_open_entry: Enter\n"));
554
555         if ( !key )
556                 return NT_STATUS_INVALID_HANDLE;
557
558         rpcstr_pull(name,q_u->uni_name.buffer,sizeof(name),q_u->uni_name.uni_str_len*2,0);
559
560         /* store the full path in the regkey_list */
561         
562         pstrcpy( path, key->name );
563         pstrcat( path, "\\" );
564         pstrcat( path, name );
565
566         DEBUG(5,("reg_open_entry: %s\n", path));
567
568         /* do a check on the name, here */
569         
570         if ( (num_subkeys=fetch_reg_keys_count( tdb_reg, path )) == -1 )
571                 return NT_STATUS_ACCESS_DENIED;
572
573         if (!open_registry_key(p, &pol, path, 0x0))
574                 return NT_STATUS_TOO_MANY_SECRETS; 
575
576         init_reg_r_open_entry(r_u, &pol, NT_STATUS_OK);
577
578         DEBUG(5,("reg_open_entry: Exitn"));
579
580         return r_u->status;
581 }
582
583 /*******************************************************************
584  reg_reply_info
585  ********************************************************************/
586
587 NTSTATUS _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u)
588 {
589         NTSTATUS status = NT_STATUS_OK;
590         char *value = NULL;
591         uint32 type = 0x1; /* key type: REG_SZ */
592         UNISTR2 *uni_key = NULL;
593         BUFFER2 *buf = NULL;
594         fstring name;
595         Registry_Key *key = find_regkey_index_by_hnd( p, &q_u->pol );
596
597         DEBUG(5,("_reg_info: Enter\n"));
598
599         if ( !key )
600                 return NT_STATUS_INVALID_HANDLE;
601                 
602         DEBUG(7,("_reg_info: policy key name = [%s]\n", key->name));
603
604         rpcstr_pull(name, q_u->uni_type.buffer, sizeof(name), q_u->uni_type.uni_str_len*2, 0);
605
606         DEBUG(5,("reg_info: checking subkey: %s\n", name));
607
608         uni_key = (UNISTR2 *)talloc_zero(p->mem_ctx, sizeof(UNISTR2));
609         buf = (BUFFER2 *)talloc_zero(p->mem_ctx, sizeof(BUFFER2));
610
611         if (!uni_key || !buf)
612                 return NT_STATUS_NO_MEMORY;
613
614         if ( strequal(name, "RefusePasswordChange") ) {
615                 type=0xF770;
616                 status = NT_STATUS_NO_SUCH_FILE;
617                 init_unistr2(uni_key, "", 0);
618                 init_buffer2(buf, (uint8*) uni_key->buffer, uni_key->uni_str_len*2);
619                 
620                 buf->buf_max_len=4;
621
622                 goto out;
623         }
624
625         switch (lp_server_role()) {
626                 case ROLE_DOMAIN_PDC:
627                 case ROLE_DOMAIN_BDC:
628                         value = "LanmanNT";
629                         break;
630                 case ROLE_STANDALONE:
631                         value = "ServerNT";
632                         break;
633                 case ROLE_DOMAIN_MEMBER:
634                         value = "WinNT";
635                         break;
636         }
637
638         /* This makes the server look like a member server to clients */
639         /* which tells clients that we have our own local user and    */
640         /* group databases and helps with ACL support.                */
641
642         init_unistr2(uni_key, value, strlen(value)+1);
643         init_buffer2(buf, (uint8*)uni_key->buffer, uni_key->uni_str_len*2);
644   
645  out:
646         init_reg_r_info(q_u->ptr_buf, r_u, buf, type, status);
647
648         DEBUG(5,("reg_open_entry: Exit\n"));
649
650         return status;
651 }
652
653
654 /*****************************************************************************
655  Implementation of REG_QUERY_KEY
656  ****************************************************************************/
657  
658 NTSTATUS _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
659 {
660         NTSTATUS        status = NT_STATUS_OK;
661         Registry_Key    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
662         
663         DEBUG(5,("_reg_query_key: Enter\n"));
664         
665         if ( !regkey )
666                 return NT_STATUS_INVALID_HANDLE;        
667         
668         if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) )
669                 return NT_STATUS_ACCESS_DENIED;
670                 
671         if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) )
672                 return NT_STATUS_ACCESS_DENIED; 
673                 
674         r_u->sec_desc = 0x00000078;     /* size for key's sec_desc */
675         
676         /* Win9x set this to 0x0 since it does not keep timestamps.
677            Doing the same here for simplicity   --jerry */
678            
679         ZERO_STRUCT(r_u->mod_time);     
680
681         DEBUG(5,("_reg_query_key: Exit\n"));
682         
683         return status;
684 }
685
686
687 /*****************************************************************************
688  Implementation of REG_UNKNOWN_1A
689  ****************************************************************************/
690  
691 NTSTATUS _reg_unknown_1a(pipes_struct *p, REG_Q_UNKNOWN_1A *q_u, REG_R_UNKNOWN_1A *r_u)
692 {
693         NTSTATUS        status = NT_STATUS_OK;
694         Registry_Key    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
695         
696         DEBUG(5,("_reg_unknown_1a: Enter\n"));
697         
698         if ( !regkey )
699                 return NT_STATUS_INVALID_HANDLE;        
700         
701         r_u->unknown = 0x00000005;      /* seems to be consistent...no idea what it means */
702         
703         DEBUG(5,("_reg_unknown_1a: Exit\n"));
704         
705         return status;
706 }
707
708
709 /*****************************************************************************
710  Implementation of REG_ENUM_KEY
711  ****************************************************************************/
712  
713 NTSTATUS _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
714 {
715         NTSTATUS        status = NT_STATUS_OK;
716         Registry_Key    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
717         fstring         subkey;
718         
719         
720         DEBUG(5,("_reg_enum_key: Enter\n"));
721         
722         if ( !regkey )
723                 return NT_STATUS_INVALID_HANDLE;        
724
725         DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
726         
727         if ( !fetch_reg_keys_specific( tdb_reg, regkey->name, subkey, q_u->key_index ) )
728         {
729                 status = werror_to_ntstatus( WERR_NO_MORE_ITEMS );
730                 goto done;
731         }
732         
733         DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
734         
735         /* subkey has the string name now */
736         
737         init_reg_r_enum_key( r_u, subkey, q_u->unknown_1, q_u->unknown_2 );
738         
739         DEBUG(5,("_reg_enum_key: Exit\n"));
740         
741 done:   
742         return status;
743 }
744
745
746 /*******************************************************************
747  reg_shutdwon
748  ********************************************************************/
749
750 #define SHUTDOWN_R_STRING "-r"
751 #define SHUTDOWN_F_STRING "-f"
752
753
754 NTSTATUS _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
755 {
756         NTSTATUS status = NT_STATUS_OK;
757         pstring shutdown_script;
758         UNISTR2 unimsg = q_u->uni_msg;
759         pstring message;
760         pstring chkmsg;
761         fstring timeout;
762         fstring r;
763         fstring f;
764         
765         /* message */
766         rpcstr_pull (message, unimsg.buffer, sizeof(message), unimsg.uni_str_len*2,0);
767                 /* security check */
768         alpha_strcpy (chkmsg, message, NULL, sizeof(message));
769         /* timeout */
770         snprintf(timeout, sizeof(timeout), "%d", q_u->timeout);
771         /* reboot */
772         snprintf(r, sizeof(r), (q_u->flags & REG_REBOOT_ON_SHUTDOWN)?SHUTDOWN_R_STRING:"");
773         /* force */
774         snprintf(f, sizeof(f), (q_u->flags & REG_FORCE_SHUTDOWN)?SHUTDOWN_F_STRING:"");
775
776         pstrcpy(shutdown_script, lp_shutdown_script());
777
778         if(*shutdown_script) {
779                 int shutdown_ret;
780                 all_string_sub(shutdown_script, "%m", chkmsg, sizeof(shutdown_script));
781                 all_string_sub(shutdown_script, "%t", timeout, sizeof(shutdown_script));
782                 all_string_sub(shutdown_script, "%r", r, sizeof(shutdown_script));
783                 all_string_sub(shutdown_script, "%f", f, sizeof(shutdown_script));
784                 shutdown_ret = smbrun(shutdown_script,NULL);
785                 DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script,shutdown_ret));
786         }
787
788         return status;
789 }
790
791 /*******************************************************************
792  reg_abort_shutdwon
793  ********************************************************************/
794
795 NTSTATUS _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
796 {
797         NTSTATUS status = NT_STATUS_OK;
798         pstring abort_shutdown_script;
799
800         pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
801
802         if(*abort_shutdown_script) {
803                 int abort_shutdown_ret;
804                 abort_shutdown_ret = smbrun(abort_shutdown_script,NULL);
805                 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script,abort_shutdown_ret));
806         }
807
808         return status;
809 }
810
811