* fix seg fault caused by missing DLIST_REMOVE in free_fn()
[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) 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         void *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         void *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 -1;
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         void *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 -1;
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, uint32 index )
207 {
208         int num_subkeys, i;
209         char *subkeys = NULL;
210         char *s;
211         
212         num_subkeys = fetch_reg_keys( tdb_reg, key, &subkeys );
213         if ( num_subkeys == -1 )
214                 return False;
215
216         s = subkeys;
217         for ( i=0; i<num_subkeys; i++ ) {
218                 /* copy the key if the index matches */
219                 if ( i == index ) {
220                         fstrcpy( subkey, s );
221                         break;
222                 }
223                 
224                 /* go onto the next string */
225                 s += strlen(s) + 1;
226         }
227         
228         SAFE_FREE(subkeys);
229         
230         return True;
231 }
232
233
234 /***********************************************************************
235  Open the registry database
236  ***********************************************************************/
237  
238 static BOOL init_registry_data( TDB_CONTEXT* tdb_reg )
239 {
240         pstring keyname;
241         char *subkeys[3];
242
243         /* HKEY_LOCAL_MACHINE */
244         
245         pstrcpy( keyname, KEY_HKLM );
246         subkeys[0] = "SYSTEM";
247         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 1 ))
248                 return False;
249                 
250         pstrcpy( keyname, KEY_HKLM );
251         pstrcat( keyname, "/SYSTEM" );
252         subkeys[0] = "CurrentControlSet";
253         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 1 ))
254                 return False;
255                 
256         pstrcpy( keyname, KEY_HKLM );
257         pstrcat( keyname, "/SYSTEM/CurrentControlSet" );
258         subkeys[0] = "Control";
259         subkeys[1] = "services";
260         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 2 ))
261                 return False;
262
263         pstrcpy( keyname, KEY_HKLM );
264         pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control" );
265         subkeys[0] = "Print";
266         subkeys[1] = "ProduceOptions";
267         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 2 ))
268                 return False;
269
270         pstrcpy( keyname, KEY_HKLM );
271         pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/Print" );
272         subkeys[0] = "Environments";
273         subkeys[1] = "Forms";
274         subkeys[2] = "Printers";
275         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 3 ))
276                 return False;
277
278         pstrcpy( keyname, KEY_HKLM );
279         pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/ProductOptions" );
280         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 0 ))
281                 return False;
282
283         pstrcpy( keyname, KEY_HKLM );
284         pstrcat( keyname, "/SYSTEM/CurrentControlSet/services" );
285         subkeys[0] = "Netlogon";
286         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 1 ))
287                 return False;
288                 
289         pstrcpy( keyname, KEY_HKLM );
290         pstrcat( keyname, "/SYSTEM/CurrentControlSet/services/Netlogon" );
291         subkeys[0] = "parameters";
292         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 1 ))
293                 return False;
294                 
295         pstrcpy( keyname, KEY_HKLM );
296         pstrcat( keyname, "/SYSTEM/CurrentControlSet/services/Netlogon/parameters" );
297         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 0 ))
298                 return False;
299
300         
301         /* HKEY_USER */
302                 
303         pstrcpy( keyname, KEY_HKU );
304         if ( !store_reg_keys( tdb_reg, keyname, subkeys, 0 ) )
305                 return False;
306                 
307         return True;
308 }
309   
310 /***********************************************************************
311  Open the registry database
312  ***********************************************************************/
313  
314 BOOL init_registry( void )
315 {
316         static pid_t local_pid;
317         
318         
319         if (tdb_reg && local_pid == sys_getpid())
320                 return True;
321
322         /* 
323          * try to open first without creating so we can determine
324          * if we need to init the data in the registry
325          */
326         
327         tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
328         if ( !tdb_reg ) 
329         {
330                 tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
331                 if ( !tdb_reg ) {
332                         DEBUG(0,("init_registry: Failed to open registry %s (%s)\n",
333                                 lock_path("registry.tdb"), strerror(errno) ));
334                         return False;
335                 }
336                 
337                 DEBUG(10,("init_registry: Successfully created registry tdb\n"));
338                 
339                 /* create the registry here */
340                 if ( !init_registry_data( tdb_reg ) ) {
341                         DEBUG(0,("init_registry: Failed to initiailize data in registry!\n"));
342                         return False;
343                 }
344         }
345
346         local_pid = sys_getpid();
347         
348         return True;
349 }
350
351 /******************************************************************
352  Find a registry key handle and return a Registry_Key
353  *****************************************************************/
354
355 static Registry_Key *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
356 {
357         Registry_Key *regkey = NULL;
358
359         if(!find_policy_by_hnd(p,hnd,(void **)&regkey)) {
360                 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: "));
361                 return NULL;
362         }
363
364         return regkey;
365 }
366
367
368 /******************************************************************
369  free() function for Registry_Key
370  *****************************************************************/
371  
372 static void free_reg_info(void *ptr)
373 {
374         Registry_Key *info = (Registry_Key*)ptr;
375         
376         DLIST_REMOVE(regkeys_list, info);
377
378         SAFE_FREE(info);
379 }
380
381 /*******************************************************************
382  Function for open a new registry handle and creating a handle 
383  Note that P should be valid & hnd should already have space
384  *******************************************************************/
385  
386 static BOOL open_registry_key(pipes_struct *p, POLICY_HND *hnd, char *name, 
387                                 uint32 access_granted)
388 {
389         Registry_Key *regkey = NULL;
390
391         DEBUG(7,("open_registry_key: name = [%s]\n", name));
392
393         /* All registry keys **must** have a name of non-zero length */
394         
395         if (!name || !*name )
396                 return False;
397                         
398         if ((regkey=(Registry_Key*)malloc(sizeof(Registry_Key))) == NULL)
399                 return False;
400                 
401         ZERO_STRUCTP( regkey );
402         
403         DLIST_ADD( regkeys_list, regkey );
404
405         /* copy the name and obtain a handle */
406         
407         fstrcpy( regkey->name, name );
408         
409         DEBUG(7,("open_registry_key: exit\n"));
410         
411         return create_policy_hnd( p, hnd, free_reg_info, regkey );
412 }
413
414 /*******************************************************************
415  Function for open a new registry handle and creating a handle 
416  Note that P should be valid & hnd should already have space
417  *******************************************************************/
418
419 static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd)
420 {
421         Registry_Key *regkey = find_regkey_index_by_hnd(p, hnd);
422         
423         if ( !regkey ) {
424                 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
425                 return False;
426         }
427         
428         close_policy_hnd(p, hnd);
429         
430         return True;
431 }
432
433 /********************************************************************
434  retrieve information about the subkeys
435  *******************************************************************/
436  
437 static BOOL get_subkey_information( Registry_Key *key, uint32 *maxnum, uint32 *maxlen )
438 {
439         int num_subkeys, i;
440         uint32 max_len;
441         char *subkeys = NULL;
442         uint32 len;
443         char *s;
444         
445         if ( !key )
446                 return False;
447         
448         num_subkeys = fetch_reg_keys( tdb_reg, key->name, &subkeys );
449         if ( num_subkeys == -1 )
450                 return False;
451
452         /* find the longest string */
453         
454         max_len = 0;
455         s = subkeys;
456         for ( i=0; i<num_subkeys; i++ ) {
457                 len = strlen(s);
458                 max_len = MAX(max_len, len);
459                 s += len + 1;
460         }
461
462         *maxnum = num_subkeys;
463         *maxlen = max_len*2;
464         
465         SAFE_FREE(subkeys);
466         
467         return True;
468 }
469
470 /********************************************************************
471  retrieve information about the values.  We don't store values 
472  here.  The registry tdb is intended to be a frontend to oether 
473  Samba tdb's (such as ntdrivers.tdb).
474  *******************************************************************/
475  
476 static BOOL get_value_information( Registry_Key *key, uint32 *maxnum, 
477                                     uint32 *maxlen, uint32 *maxsize )
478 {
479         if ( !key )
480                 return False;
481
482         /* Hard coded key names first */
483         
484         if ( !strcmp(key->name, KEY_HKLM) || !strcmp(key->name, KEY_HKU) )
485         {
486                 *maxnum   = 0;
487                 *maxlen   = 0;
488                 *maxsize  = 0;
489                 return True;
490         }
491         
492         /* 
493          * FIXME!!! Need to add routines to look up values in other
494          * databases   --jerry
495          */
496
497         return False;
498 }
499
500 /********************************************************************
501  reg_close
502  ********************************************************************/
503
504 NTSTATUS _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
505 {
506         /* set up the REG unknown_1 response */
507         ZERO_STRUCT(r_u->pol);
508
509         /* close the policy handle */
510         if (!close_registry_key(p, &q_u->pol))
511                 return NT_STATUS_OBJECT_NAME_INVALID;
512
513         return NT_STATUS_OK;
514 }
515
516 /*******************************************************************
517  reg_reply_open
518  ********************************************************************/
519
520 NTSTATUS _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HKLM *q_u, REG_R_OPEN_HKLM *r_u)
521 {
522         if (!open_registry_key(p, &r_u->pol, KEY_HKLM, 0x0))
523                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
524
525         return NT_STATUS_OK;
526 }
527
528 /*******************************************************************
529  reg_reply_open
530  ********************************************************************/
531
532 NTSTATUS _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HKU *q_u, REG_R_OPEN_HKU *r_u)
533 {
534         if (!open_registry_key(p, &r_u->pol, KEY_HKU, 0x0))
535                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
536
537         return NT_STATUS_OK;
538 }
539
540 /*******************************************************************
541  reg_reply_open_entry
542  ********************************************************************/
543
544 NTSTATUS _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u)
545 {
546         POLICY_HND pol;
547         fstring name;
548         pstring path;
549         int num_subkeys;
550         Registry_Key *key = find_regkey_index_by_hnd(p, &q_u->pol);
551
552         DEBUG(5,("reg_open_entry: Enter\n"));
553
554         if ( !key )
555                 return NT_STATUS_INVALID_HANDLE;
556
557         rpcstr_pull(name,q_u->uni_name.buffer,sizeof(name),q_u->uni_name.uni_str_len*2,0);
558
559         /* store the full path in the regkey_list */
560         
561         pstrcpy( path, key->name );
562         pstrcat( path, "\\" );
563         pstrcat( path, name );
564
565         DEBUG(5,("reg_open_entry: %s\n", path));
566
567         /* do a check on the name, here */
568         
569         if ( (num_subkeys=fetch_reg_keys_count( tdb_reg, path )) == -1 )
570                 return NT_STATUS_ACCESS_DENIED;
571
572         if (!open_registry_key(p, &pol, path, 0x0))
573                 return NT_STATUS_TOO_MANY_SECRETS; 
574
575         init_reg_r_open_entry(r_u, &pol, NT_STATUS_OK);
576
577         DEBUG(5,("reg_open_entry: Exitn"));
578
579         return r_u->status;
580 }
581
582 /*******************************************************************
583  reg_reply_info
584  ********************************************************************/
585
586 NTSTATUS _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u)
587 {
588         NTSTATUS status = NT_STATUS_OK;
589         char *value = NULL;
590         uint32 type = 0x1; /* key type: REG_SZ */
591         UNISTR2 *uni_key = NULL;
592         BUFFER2 *buf = NULL;
593         fstring name;
594         Registry_Key *key = find_regkey_index_by_hnd( p, &q_u->pol );
595
596         DEBUG(5,("_reg_info: Enter\n"));
597
598         if ( !key )
599                 return NT_STATUS_INVALID_HANDLE;
600                 
601         DEBUG(7,("_reg_info: policy key name = [%s]\n", key->name));
602
603         rpcstr_pull(name, q_u->uni_type.buffer, sizeof(name), q_u->uni_type.uni_str_len*2, 0);
604
605         DEBUG(5,("reg_info: checking subkey: %s\n", name));
606
607         uni_key = (UNISTR2 *)talloc_zero(p->mem_ctx, sizeof(UNISTR2));
608         buf = (BUFFER2 *)talloc_zero(p->mem_ctx, sizeof(BUFFER2));
609
610         if (!uni_key || !buf)
611                 return NT_STATUS_NO_MEMORY;
612
613         if ( strequal(name, "RefusePasswordChange") ) {
614                 type=0xF770;
615                 status = NT_STATUS_NO_SUCH_FILE;
616                 init_unistr2(uni_key, "", 0);
617                 init_buffer2(buf, (uint8*) uni_key->buffer, uni_key->uni_str_len*2);
618                 
619                 buf->buf_max_len=4;
620
621                 goto out;
622         }
623
624         switch (lp_server_role()) {
625                 case ROLE_DOMAIN_PDC:
626                 case ROLE_DOMAIN_BDC:
627                         value = "LanmanNT";
628                         break;
629                 case ROLE_STANDALONE:
630                         value = "ServerNT";
631                         break;
632                 case ROLE_DOMAIN_MEMBER:
633                         value = "WinNT";
634                         break;
635         }
636
637         /* This makes the server look like a member server to clients */
638         /* which tells clients that we have our own local user and    */
639         /* group databases and helps with ACL support.                */
640
641         init_unistr2(uni_key, value, strlen(value)+1);
642         init_buffer2(buf, (uint8*)uni_key->buffer, uni_key->uni_str_len*2);
643   
644  out:
645         init_reg_r_info(q_u->ptr_buf, r_u, buf, type, status);
646
647         DEBUG(5,("reg_open_entry: Exit\n"));
648
649         return status;
650 }
651
652
653 /*****************************************************************************
654  Implementation of REG_QUERY_KEY
655  ****************************************************************************/
656  
657 NTSTATUS _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u)
658 {
659         NTSTATUS        status = NT_STATUS_OK;
660         Registry_Key    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
661         
662         DEBUG(5,("_reg_query_key: Enter\n"));
663         
664         if ( !regkey )
665                 return NT_STATUS_INVALID_HANDLE;        
666         
667         if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) )
668                 return NT_STATUS_ACCESS_DENIED;
669                 
670         if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) )
671                 return NT_STATUS_ACCESS_DENIED; 
672                 
673         r_u->sec_desc = 0x0;    /* size for key's sec_desc */
674         
675         /* Win9x set this to 0x0 since it does not keep timestamps.
676            Doing the same here for simplicity   --jerry */
677            
678         ZERO_STRUCT(r_u->mod_time);     
679
680         DEBUG(5,("_reg_query_key: Exit\n"));
681         
682         return status;
683 }
684
685
686 /*****************************************************************************
687  Implementation of REG_UNKNOWN_1A
688  ****************************************************************************/
689  
690 NTSTATUS _reg_unknown_1a(pipes_struct *p, REG_Q_UNKNOWN_1A *q_u, REG_R_UNKNOWN_1A *r_u)
691 {
692         NTSTATUS        status = NT_STATUS_OK;
693         Registry_Key    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
694         
695         DEBUG(5,("_reg_unknown_1a: Enter\n"));
696         
697         if ( !regkey )
698                 return NT_STATUS_INVALID_HANDLE;        
699         
700         r_u->unknown = 0x00000005;      /* seems to be consistent...no idea what it means */
701         
702         DEBUG(5,("_reg_unknown_1a: Exit\n"));
703         
704         return status;
705 }
706
707
708 /*****************************************************************************
709  Implementation of REG_ENUM_KEY
710  ****************************************************************************/
711  
712 NTSTATUS _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u)
713 {
714         NTSTATUS        status = NT_STATUS_OK;
715         Registry_Key    *regkey = find_regkey_index_by_hnd( p, &q_u->pol );
716         fstring         subkey;
717         
718         
719         DEBUG(5,("_reg_enum_key: Enter\n"));
720         
721         if ( !regkey )
722                 return NT_STATUS_INVALID_HANDLE;        
723
724         DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name));
725         
726         if ( !fetch_reg_keys_specific( tdb_reg, regkey->name, subkey, q_u->key_index ) )
727         {
728                 status = werror_to_ntstatus( WERR_NO_MORE_ITEMS );
729                 goto done;
730         }
731         
732         DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey));
733         
734         /* subkey has the string name now */
735         
736         init_reg_r_enum_key( r_u, subkey, q_u->unknown_1, q_u->unknown_2 );
737         
738         DEBUG(5,("_reg_enum_key: Exit\n"));
739         
740 done:   
741         return status;
742 }
743
744
745 /*******************************************************************
746  reg_shutdwon
747  ********************************************************************/
748
749 #define SHUTDOWN_R_STRING "-r"
750 #define SHUTDOWN_F_STRING "-f"
751
752
753 NTSTATUS _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u)
754 {
755         NTSTATUS status = NT_STATUS_OK;
756         pstring shutdown_script;
757         UNISTR2 unimsg = q_u->uni_msg;
758         pstring message;
759         pstring chkmsg;
760         fstring timeout;
761         fstring r;
762         fstring f;
763         
764         /* message */
765         rpcstr_pull (message, unimsg.buffer, sizeof(message), unimsg.uni_str_len*2,0);
766                 /* security check */
767         alpha_strcpy (chkmsg, message, NULL, sizeof(message));
768         /* timeout */
769         snprintf(timeout, sizeof(timeout), "%d", q_u->timeout);
770         /* reboot */
771         snprintf(r, sizeof(r), (q_u->flags & REG_REBOOT_ON_SHUTDOWN)?SHUTDOWN_R_STRING:"");
772         /* force */
773         snprintf(f, sizeof(f), (q_u->flags & REG_FORCE_SHUTDOWN)?SHUTDOWN_F_STRING:"");
774
775         pstrcpy(shutdown_script, lp_shutdown_script());
776
777         if(*shutdown_script) {
778                 int shutdown_ret;
779                 all_string_sub(shutdown_script, "%m", chkmsg, sizeof(shutdown_script));
780                 all_string_sub(shutdown_script, "%t", timeout, sizeof(shutdown_script));
781                 all_string_sub(shutdown_script, "%r", r, sizeof(shutdown_script));
782                 all_string_sub(shutdown_script, "%f", f, sizeof(shutdown_script));
783                 shutdown_ret = smbrun(shutdown_script,NULL);
784                 DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script,shutdown_ret));
785         }
786
787         return status;
788 }
789
790 /*******************************************************************
791  reg_abort_shutdwon
792  ********************************************************************/
793
794 NTSTATUS _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u)
795 {
796         NTSTATUS status = NT_STATUS_OK;
797         pstring abort_shutdown_script;
798
799         pstrcpy(abort_shutdown_script, lp_abort_shutdown_script());
800
801         if(*abort_shutdown_script) {
802                 int abort_shutdown_ret;
803                 abort_shutdown_ret = smbrun(abort_shutdown_script,NULL);
804                 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script,abort_shutdown_ret));
805         }
806
807         return status;
808 }
809
810