r23779: Change from v2 or later to v3 or later.
[samba.git] / source3 / libmsrpc / cac_winreg.c
1
2 /* 
3  *  Unix SMB/CIFS implementation.
4  *  MS-RPC client library implementation (WINREG pipe)
5  *  Copyright (C) Chris Nicholls              2005.
6  *  
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *  
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "libmsrpc.h"
23 #include "libmsrpc_internal.h"
24
25 NTSTATUS cac_delete_subkeys_recursive(struct rpc_pipe_client * pipe_hnd,
26                                       TALLOC_CTX * mem_ctx, POLICY_HND * key);
27
28 int cac_RegConnect( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
29                     struct RegConnect *op )
30 {
31         SMBCSRV *srv = NULL;
32         struct rpc_pipe_client *pipe_hnd = NULL;
33         POLICY_HND *key = NULL;
34
35         if ( !hnd )
36                 return CAC_FAILURE;
37
38         if ( !hnd->_internal.ctx ) {
39                 hnd->status = NT_STATUS_INVALID_HANDLE;
40                 return CAC_FAILURE;
41         }
42
43         if ( !op || !op->in.root || !mem_ctx ) {
44                 hnd->status = NT_STATUS_INVALID_PARAMETER;
45                 return CAC_FAILURE;
46         }
47
48         srv = cac_GetServer( hnd );
49         if ( !srv ) {
50                 hnd->status = NT_STATUS_INVALID_CONNECTION;
51                 return CAC_FAILURE;
52         }
53
54         /*initialize for winreg pipe if we have to */
55         if ( !hnd->_internal.pipes[PI_WINREG] ) {
56                 if ( !
57                      ( pipe_hnd =
58                        cli_rpc_pipe_open_noauth( srv->cli, PI_WINREG,
59                                                  &hnd->status ) ) ) {
60                         return CAC_FAILURE;
61                 }
62
63                 hnd->_internal.pipes[PI_WINREG] = True;
64         }
65
66         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
67         if ( !pipe_hnd ) {
68                 hnd->status = NT_STATUS_INVALID_HANDLE;
69                 return CAC_FAILURE;
70         }
71
72         key = talloc( mem_ctx, POLICY_HND );
73         if ( !key ) {
74                 hnd->status = NT_STATUS_NO_MEMORY;
75                 return CAC_FAILURE;
76         }
77
78         hnd->status =
79                 rpccli_winreg_Connect( pipe_hnd, mem_ctx, op->in.root,
80                                        op->in.access, key );
81
82         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
83                 return CAC_FAILURE;
84         }
85
86         op->out.key = key;
87
88         return CAC_SUCCESS;
89 }
90
91 int cac_RegClose( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
92                   POLICY_HND * key )
93 {
94         struct rpc_pipe_client *pipe_hnd = NULL;
95
96         if ( !hnd )
97                 return CAC_FAILURE;
98
99         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
100                 hnd->status = NT_STATUS_INVALID_HANDLE;
101                 return CAC_FAILURE;
102         }
103
104         if ( !key || !mem_ctx ) {
105                 hnd->status = NT_STATUS_INVALID_PARAMETER;
106                 return CAC_FAILURE;
107         }
108
109         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
110         if ( !pipe_hnd ) {
111                 hnd->status = NT_STATUS_INVALID_HANDLE;
112                 return CAC_FAILURE;
113         }
114
115         hnd->status = rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, key );
116
117         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
118                 return CAC_FAILURE;
119         }
120
121         return CAC_SUCCESS;
122 }
123
124 int cac_RegOpenKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
125                     struct RegOpenKey *op )
126 {
127         struct rpc_pipe_client *pipe_hnd = NULL;
128         struct winreg_String key_string;
129
130         POLICY_HND *key_out;
131         POLICY_HND *parent_key;
132
133         char *key_name = NULL;
134         uint32 reg_type = 0;
135
136         struct RegConnect rc;
137
138         if ( !hnd )
139                 return CAC_FAILURE;
140
141         if ( !hnd->_internal.ctx ) {
142                 hnd->status = NT_STATUS_INVALID_HANDLE;
143                 return CAC_FAILURE;
144         }
145
146         if ( !op || !op->in.name || !mem_ctx ) {
147                 hnd->status = NT_STATUS_INVALID_PARAMETER;
148                 return CAC_FAILURE;
149         }
150
151
152         key_out = talloc( mem_ctx, POLICY_HND );
153         if ( !key_out ) {
154                 hnd->status = NT_STATUS_NO_MEMORY;
155                 return CAC_FAILURE;
156         }
157
158         if ( !op->in.parent_key ) {
159                 /*then we need to connect to the registry */
160                 if ( !cac_ParseRegPath( op->in.name, &reg_type, &key_name ) ) {
161                         hnd->status = NT_STATUS_INVALID_PARAMETER;
162                         return CAC_FAILURE;
163                 }
164
165                 /*use cac_RegConnect because it handles the session setup */
166                 ZERO_STRUCT( rc );
167
168                 rc.in.access = op->in.access;
169                 rc.in.root = reg_type;
170
171                 if ( !cac_RegConnect( hnd, mem_ctx, &rc ) ) {
172                         return CAC_FAILURE;
173                 }
174
175       /**if they only specified the root key, return the key we just opened*/
176                 if ( key_name == NULL ) {
177                         op->out.key = rc.out.key;
178                         return CAC_SUCCESS;
179                 }
180
181                 parent_key = rc.out.key;
182         } else {
183                 parent_key = op->in.parent_key;
184                 key_name = op->in.name;
185         }
186
187         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
188         if ( !pipe_hnd ) {
189                 hnd->status = NT_STATUS_INVALID_HANDLE;
190                 return CAC_FAILURE;
191         }
192
193         key_string.name = key_name;
194         hnd->status =
195                 rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, parent_key,
196                                        key_string, 0, op->in.access,
197                                        key_out );
198
199         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
200                 return CAC_FAILURE;
201         }
202
203         if ( !op->in.parent_key ) {
204                 /*then close the one that we opened above */
205                 hnd->status =
206                         rpccli_winreg_CloseKey( pipe_hnd, mem_ctx,
207                                                 parent_key );
208
209                 if ( !NT_STATUS_IS_OK( hnd->status ) ) {
210                         return CAC_FAILURE;
211                 }
212         }
213
214         op->out.key = key_out;
215
216         return CAC_SUCCESS;
217 }
218
219 int cac_RegEnumKeys( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
220                      struct RegEnumKeys *op )
221 {
222         struct rpc_pipe_client *pipe_hnd = NULL;
223
224         /*buffers for rpccli_reg_enum_key call */
225         fstring key_name_in;
226         fstring class_name_in;
227
228         /*output buffers */
229         char **key_names_out = NULL;
230         char **class_names_out = NULL;
231         time_t *mod_times_out = NULL;
232         uint32 num_keys_out = 0;
233         uint32 resume_idx = 0;
234
235         if ( !hnd )
236                 return CAC_FAILURE;
237
238         /* This is to avoid useless rpc calls, if the last call 
239            exhausted all the keys, then we don't need to go 
240            through everything again */
241
242         if ( NT_STATUS_V( hnd->status ) ==
243              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
244                 return CAC_FAILURE;
245
246         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
247                 hnd->status = NT_STATUS_INVALID_HANDLE;
248                 return CAC_FAILURE;
249         }
250
251         if ( !op || op->in.max_keys == 0 || !mem_ctx ) {
252                 hnd->status = NT_STATUS_INVALID_PARAMETER;
253                 return CAC_FAILURE;
254         }
255
256         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
257         if ( !pipe_hnd ) {
258                 hnd->status = NT_STATUS_INVALID_HANDLE;
259                 return CAC_FAILURE;
260         }
261
262         /* The only way to know how many keys to expect is to 
263            assume max_keys keys will be found */
264
265         key_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
266         if ( !key_names_out ) {
267                 hnd->status = NT_STATUS_NO_MEMORY;
268                 return CAC_FAILURE;
269         }
270
271         class_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
272         if ( !class_names_out ) {
273                 hnd->status = NT_STATUS_NO_MEMORY;
274                 TALLOC_FREE( key_names_out );
275                 return CAC_FAILURE;
276         }
277
278         mod_times_out = TALLOC_ARRAY( mem_ctx, time_t, op->in.max_keys );
279         if ( !mod_times_out ) {
280                 hnd->status = NT_STATUS_NO_MEMORY;
281                 TALLOC_FREE( key_names_out );
282                 TALLOC_FREE( class_names_out );
283
284                 return CAC_FAILURE;
285         }
286
287         resume_idx = op->out.resume_idx;
288
289         do {
290 #if 0
291                 hnd->status =
292                         rpccli_winreg_EnumKey( pipe_hnd, mem_ctx, op->in.key,
293                                                 resume_idx, key_name_in,
294                                                 class_name_in,
295                                                 &mod_times_out );
296 #endif
297
298                 if ( !NT_STATUS_IS_OK( hnd->status ) ) {
299                         /*don't increment any values */
300                         break;
301                 }
302
303                 key_names_out[num_keys_out] =
304                         talloc_strdup( mem_ctx, key_name_in );
305
306                 class_names_out[num_keys_out] =
307                         talloc_strdup( mem_ctx, class_name_in );
308
309                 if ( !key_names_out[num_keys_out]
310                      || !class_names_out[num_keys_out] ) {
311                         hnd->status = NT_STATUS_NO_MEMORY;
312                         break;
313                 }
314
315                 resume_idx++;
316                 num_keys_out++;
317         } while ( num_keys_out < op->in.max_keys );
318
319         if ( CAC_OP_FAILED( hnd->status ) ) {
320                 op->out.num_keys = 0;
321                 return CAC_FAILURE;
322         }
323
324         op->out.resume_idx = resume_idx;
325         op->out.num_keys = num_keys_out;
326         op->out.key_names = key_names_out;
327         op->out.class_names = class_names_out;
328         op->out.mod_times = mod_times_out;
329
330         return CAC_SUCCESS;
331 }
332
333 int cac_RegCreateKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
334                       struct RegCreateKey *op )
335 {
336         struct rpc_pipe_client *pipe_hnd = NULL;
337         POLICY_HND *key_out;
338         struct RegOpenKey rok;
339         struct winreg_String key_string, class_string;
340         enum winreg_CreateAction action = 0;
341
342         if ( !hnd )
343                 return CAC_FAILURE;
344
345         if ( !hnd->_internal.ctx ) {
346                 hnd->status = NT_STATUS_INVALID_HANDLE;
347                 return CAC_FAILURE;
348         }
349
350         if ( !op || !op->in.parent_key || !op->in.key_name || !mem_ctx ) {
351                 hnd->status = NT_STATUS_INVALID_PARAMETER;
352                 return CAC_FAILURE;
353         }
354
355         /*first try to open the key - we use cac_RegOpenKey(). this doubles as a way to ensure the winreg pipe is initialized */
356         ZERO_STRUCT( rok );
357
358         rok.in.name = op->in.key_name;
359         rok.in.access = op->in.access;
360         rok.in.parent_key = op->in.parent_key;
361
362         if ( cac_RegOpenKey( hnd, mem_ctx, &rok ) ) {
363                 /*then we got the key, return */
364                 op->out.key = rok.out.key;
365                 return CAC_SUCCESS;
366         }
367
368         /*just be ultra-safe */
369         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
370         if ( !pipe_hnd ) {
371                 hnd->status = NT_STATUS_INVALID_HANDLE;
372                 return CAC_FAILURE;
373         }
374
375         key_out = talloc( mem_ctx, POLICY_HND );
376         if ( !key_out ) {
377                 hnd->status = NT_STATUS_NO_MEMORY;
378                 return CAC_FAILURE;
379         }
380
381         key_string.name = op->in.key_name;
382         class_string.name = op->in.class_name;
383         hnd->status =
384                 rpccli_winreg_CreateKey( pipe_hnd, mem_ctx, op->in.parent_key,
385                                          key_string, class_string, 0,
386                                          op->in.access, NULL, key_out,
387                                          &action );
388
389         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
390                 return CAC_FAILURE;
391         }
392
393         op->out.key = key_out;
394
395         return CAC_SUCCESS;
396
397 }
398
399 NTSTATUS cac_delete_subkeys_recursive( struct rpc_pipe_client * pipe_hnd,
400                                      TALLOC_CTX * mem_ctx, POLICY_HND * key )
401 {
402         POLICY_HND subkey;
403         fstring subkey_name;
404         int cur_key = 0;
405         NTSTATUS status;
406         uint32 num_subkeys, max_subkeylen, max_classlen;
407         uint32 num_values, max_valnamelen, maxvalbufsize;
408         char *name_buffer; 
409         struct winreg_String class_string;
410
411         NTTIME modtime;
412         uint32 secdescsize;
413
414         /* First get the max subkey name length */
415
416         class_string.name = NULL;
417         status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, key, 
418                                              &class_string, &num_subkeys, 
419                                              &max_subkeylen, &max_classlen,
420                                              &num_values, &max_valnamelen,
421                                              &maxvalbufsize, &secdescsize, 
422                                              &modtime );
423
424
425         if ( !NT_STATUS_IS_OK( status ) ) {
426                 return status;
427         }
428
429         if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_subkeylen )) == NULL ) {
430                 d_fprintf(stderr, "Memory allocation error.\n");
431                 return NT_STATUS_NO_MEMORY;
432         }
433
434
435         while ( NT_STATUS_IS_OK( status ) ) {
436                 struct winreg_String key_string;
437                 struct winreg_StringBuf subkey_string;
438                 fstring subkeyname;
439
440                 memset( name_buffer, 0x0, max_subkeylen );
441                 subkey_string.name = name_buffer;
442                 subkey_string.length = 0;
443                 subkey_string.size = max_subkeylen;
444
445                 status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key, cur_key, 
446                         &subkey_string, NULL, NULL);
447
448                 if ( !NT_STATUS_IS_OK( status ) )
449                         break;
450
451                 /* copy the keyname and add the terminating NULL */
452
453                 StrnCpy( subkeyname, subkey_string.name, 
454                          MIN(subkey_string.length, sizeof(subkeyname)-1) );
455                 subkeyname[MIN(subkey_string.length, sizeof(subkeyname)-1)] = '\0';
456
457                 /*try to open the key with full access */
458
459                 key_string.name = subkeyname;
460                 status = rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, key,
461                                                 key_string, 0, REG_KEY_ALL,
462                                                 &subkey );
463
464                 if ( !NT_STATUS_IS_OK( status ) )
465                         break;
466
467                 status = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
468                                                     &subkey );
469
470                 if ( !W_ERROR_EQUAL( ntstatus_to_werror(status), WERR_NO_MORE_ITEMS )
471                      && !NT_STATUS_IS_OK( status ) )
472                         break;
473
474                 /*flush the key just to be safe */
475                 rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, key );
476
477                 /*close the key that we opened */
478                 rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, &subkey );
479
480                 /*now we delete the subkey */
481                 key_string.name = subkey_name;
482                 status = rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, key,
483                                                   key_string );
484
485                 cur_key++;
486         }
487
488
489         return status;
490 }
491
492
493
494 int cac_RegDeleteKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
495                       struct RegDeleteKey *op )
496 {
497         struct rpc_pipe_client *pipe_hnd = NULL;
498         struct winreg_String key_string;
499
500         if ( !hnd )
501                 return CAC_FAILURE;
502
503         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
504                 hnd->status = NT_STATUS_INVALID_HANDLE;
505                 return CAC_FAILURE;
506         }
507
508         if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
509                 hnd->status = NT_STATUS_INVALID_PARAMETER;
510                 return CAC_FAILURE;
511         }
512
513         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
514         if ( !pipe_hnd ) {
515                 hnd->status = NT_STATUS_INVALID_HANDLE;
516                 return CAC_FAILURE;
517         }
518
519         if ( op->in.recursive ) {
520
521                 /* first open the key, and then delete all of 
522                    it's subkeys recursively */
523
524                 struct RegOpenKey rok;
525
526                 ZERO_STRUCT( rok );
527
528                 rok.in.parent_key = op->in.parent_key;
529                 rok.in.name = op->in.name;
530                 rok.in.access = REG_KEY_ALL;
531
532                 if ( !cac_RegOpenKey( hnd, mem_ctx, &rok ) )
533                         return CAC_FAILURE;
534
535                 hnd->status = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
536                                                     rok.out.key );
537
538                 /*close the key that we opened */
539                 cac_RegClose( hnd, mem_ctx, rok.out.key );
540
541                 if ( NT_STATUS_V( hnd->status ) !=
542                      NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED )
543                      && !NT_STATUS_IS_OK( hnd->status ) )
544                         return CAC_FAILURE;
545
546                 /*now go on to actually delete the key */
547         }
548
549         key_string.name = op->in.name;
550         hnd->status =
551                 rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, op->in.parent_key,
552                                          key_string );
553
554         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
555                 return CAC_FAILURE;
556         }
557
558         return CAC_SUCCESS;
559 }
560
561 int cac_RegDeleteValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
562                         struct RegDeleteValue *op )
563 {
564         struct rpc_pipe_client *pipe_hnd = NULL;
565         struct winreg_String value_string;
566
567         if ( !hnd )
568                 return CAC_FAILURE;
569
570         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
571                 hnd->status = NT_STATUS_INVALID_HANDLE;
572                 return CAC_FAILURE;
573         }
574
575         if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
576                 hnd->status = NT_STATUS_INVALID_PARAMETER;
577                 return CAC_FAILURE;
578         }
579
580         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
581         if ( !pipe_hnd ) {
582                 hnd->status = NT_STATUS_INVALID_HANDLE;
583                 return CAC_FAILURE;
584         }
585
586         value_string.name = op->in.name;
587         hnd->status =
588                 rpccli_winreg_DeleteValue( pipe_hnd, mem_ctx,
589                                            op->in.parent_key, value_string );
590
591         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
592                 return CAC_FAILURE;
593         }
594
595         return CAC_SUCCESS;
596 }
597
598 int cac_RegQueryKeyInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
599                          struct RegQueryKeyInfo *op )
600 {
601         struct rpc_pipe_client *pipe_hnd = NULL;
602         uint32 num_subkeys_out = 0;
603         uint32 long_subkey_out = 0;
604         uint32 long_class_out = 0;
605         uint32 num_values_out = 0;
606         uint32 long_value_out = 0;
607         uint32 long_data_out = 0;
608         uint32 secdesc_size = 0;
609         NTTIME mod_time;
610         struct winreg_String class_string;
611
612         if ( !hnd )
613                 return CAC_FAILURE;
614
615         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
616                 hnd->status = NT_STATUS_INVALID_HANDLE;
617                 return CAC_FAILURE;
618         }
619
620         if ( !op || !op->in.key || !mem_ctx ) {
621                 hnd->status = NT_STATUS_INVALID_PARAMETER;
622                 return CAC_FAILURE;
623         }
624
625         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
626         if ( !pipe_hnd ) {
627                 hnd->status = NT_STATUS_INVALID_HANDLE;
628                 return CAC_FAILURE;
629         }
630
631         hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, 
632                                                   op->in.key,
633                                                   &class_string,
634                                                   &num_subkeys_out,
635                                                   &long_subkey_out,
636                                                   &long_class_out,
637                                                   &num_values_out,
638                                                   &long_value_out,
639                                                   &long_data_out,
640                                                   &secdesc_size, &mod_time );
641
642         if ( !NT_STATUS_IS_OK( hnd->status ) )
643                 return CAC_FAILURE;
644
645         if ( !class_string.name ) {
646                 op->out.class_name = talloc_strdup( mem_ctx, "" );
647         } else {
648                 op->out.class_name = talloc_strdup( mem_ctx, class_string.name );
649         }
650
651         if ( !op->out.class_name ) {
652                 hnd->status = NT_STATUS_NO_MEMORY;
653                 return CAC_FAILURE;
654         }
655
656         op->out.num_subkeys = num_subkeys_out;
657         op->out.longest_subkey = long_subkey_out;
658         op->out.longest_class = long_class_out;
659         op->out.num_values = num_values_out;
660         op->out.longest_value_name = long_value_out;
661         op->out.longest_value_data = long_data_out;
662         op->out.security_desc_size = secdesc_size;
663         op->out.last_write_time = nt_time_to_unix( mod_time );
664
665         return CAC_FAILURE;
666 }
667
668 int cac_RegQueryValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
669                        struct RegQueryValue *op )
670 {
671         struct rpc_pipe_client *pipe_hnd = NULL;
672         struct winreg_String value_string;
673         REGVAL_BUFFER buffer;
674         REG_VALUE_DATA *data_out = NULL;
675         enum winreg_Type val_type;
676         uint8 *buf;
677         uint32 buf_size = 4096;
678         uint32 length = 0;
679
680         if ( !hnd )
681                 return CAC_FAILURE;
682
683         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
684                 hnd->status = NT_STATUS_INVALID_HANDLE;
685                 return CAC_FAILURE;
686         }
687
688         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
689                 hnd->status = NT_STATUS_INVALID_PARAMETER;
690                 return CAC_FAILURE;
691         }
692
693         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
694         if ( !pipe_hnd ) {
695                 hnd->status = NT_STATUS_INVALID_HANDLE;
696                 return CAC_FAILURE;
697         }
698
699         value_string.name = op->in.val_name;
700
701         if ( ( buf = TALLOC_ARRAY( mem_ctx, uint8, buf_size ) ) == NULL ) {
702                 hnd->status = NT_STATUS_NO_MEMORY;
703                 return CAC_FAILURE;
704         }
705
706         hnd->status = rpccli_winreg_QueryValue( pipe_hnd, mem_ctx, op->in.key,
707                                                 value_string, &val_type, buf,
708                                                 &buf_size, &length );
709
710         if ( !NT_STATUS_IS_OK( hnd->status ) )
711                 return CAC_FAILURE;
712
713         init_regval_buffer( &buffer, buf, length );
714
715         data_out = cac_MakeRegValueData( mem_ctx, val_type, buffer );
716         if ( !data_out ) {
717                 if ( errno == ENOMEM )
718                         hnd->status = NT_STATUS_NO_MEMORY;
719                 else
720                         hnd->status = NT_STATUS_INVALID_PARAMETER;
721
722                 return CAC_FAILURE;
723         }
724
725         op->out.type = val_type;
726         op->out.data = data_out;
727
728         return CAC_SUCCESS;
729 }
730
731
732 int cac_RegEnumValues( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
733                        struct RegEnumValues *op )
734 {
735         struct rpc_pipe_client *pipe_hnd = NULL;
736         char *name_buffer;
737         REGVAL_BUFFER val_buf;
738         uint32 *types_out = NULL;
739         REG_VALUE_DATA **values_out = NULL;
740         char **val_names_out = NULL;
741         uint32 num_values_out = 0;
742         uint32 resume_idx = 0;
743         uint32 num_subkeys, max_subkeylen, max_classlen;
744         uint32 num_values, max_valnamelen, maxvalbufsize;
745         struct winreg_String class_string;
746         NTTIME modtime;
747         uint32 secdescsize;
748         uint8 *buffer;
749
750         if ( !hnd )
751                 return CAC_FAILURE;
752
753         /* This is to avoid useless rpc calls, if the last 
754            call exhausted all the keys, then we don't need 
755            to go through everything again */
756
757         if ( NT_STATUS_V( hnd->status ) ==
758              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
759                 return CAC_FAILURE;
760
761         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
762                 hnd->status = NT_STATUS_INVALID_HANDLE;
763                 return CAC_FAILURE;
764         }
765
766         if ( !op || !op->in.key || op->in.max_values == 0 || !mem_ctx ) {
767                 hnd->status = NT_STATUS_INVALID_PARAMETER;
768                 return CAC_FAILURE;
769         }
770
771         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
772         if ( !pipe_hnd ) {
773                 hnd->status = NT_STATUS_INVALID_HANDLE;
774                 return CAC_FAILURE;
775         }
776
777         /*we need to assume that the max number of values will be enumerated */
778         types_out = TALLOC_ARRAY( mem_ctx, uint32, op->in.max_values );
779
780         if ( !types_out ) {
781                 hnd->status = NT_STATUS_NO_MEMORY;
782                 return CAC_FAILURE;
783         }
784
785         values_out = TALLOC_ARRAY( mem_ctx, REG_VALUE_DATA *, 
786                                    op->in.max_values );
787
788         if ( !values_out ) {
789                 TALLOC_FREE( types_out );
790                 hnd->status = NT_STATUS_NO_MEMORY;
791                 return CAC_FAILURE;
792         }
793
794         val_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_values );
795
796         if ( !val_names_out ) {
797                 TALLOC_FREE( types_out );
798                 TALLOC_FREE( values_out );
799                 hnd->status = NT_STATUS_NO_MEMORY;
800                 return CAC_FAILURE;
801         }
802
803         resume_idx = op->out.resume_idx;
804
805         class_string.name = NULL;
806         hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, op->in.key, 
807                                              &class_string, &num_subkeys, 
808                                              &max_subkeylen, &max_classlen,
809                                              &num_values, &max_valnamelen,
810                                              &maxvalbufsize, &secdescsize, 
811                                              &modtime );
812
813         if ( !NT_STATUS_IS_OK(hnd->status) ) {
814                 TALLOC_FREE( types_out );
815                 TALLOC_FREE( values_out );
816
817                 return CAC_FAILURE;
818         }
819
820         if ( (buffer = TALLOC_ARRAY( mem_ctx, uint8, maxvalbufsize )) == NULL ) {
821                 TALLOC_FREE( types_out );
822                 TALLOC_FREE( values_out );
823                 hnd->status = NT_STATUS_NO_MEMORY;
824
825                 return CAC_FAILURE;
826         }
827
828         if ( (name_buffer = TALLOC_ARRAY(mem_ctx, char, max_valnamelen)) == NULL ) {
829                 TALLOC_FREE( types_out );
830                 TALLOC_FREE( values_out );
831                 TALLOC_FREE( buffer );
832                 hnd->status = NT_STATUS_NO_MEMORY;
833
834                 return CAC_FAILURE;
835         }
836                 
837         do {
838                 uint32 data_size = maxvalbufsize;
839                 uint32 data_length = 0;
840                 struct winreg_ValNameBuf name_buf;
841
842                 memset( name_buffer, 0x0, max_valnamelen );
843                 name_buf.name = name_buffer;
844                 name_buf.size = max_valnamelen;
845                 name_buf.length = 0;
846                 
847                 hnd->status = rpccli_winreg_EnumValue( pipe_hnd, mem_ctx, 
848                                                        op->in.key,
849                                                        resume_idx, &name_buf,
850                                                        &types_out[num_values_out], buffer,
851                                                        &data_size,
852                                                        &data_length );
853
854                 if ( !NT_STATUS_IS_OK( hnd->status ) )
855                         break;
856
857                 ZERO_STRUCT( val_buf );
858                 init_regval_buffer(  &val_buf, buffer, data_length );
859
860                 values_out[num_values_out] = cac_MakeRegValueData( mem_ctx,
861                                                                    types_out[num_values_out],
862                                                                    val_buf );
863                 val_names_out[num_values_out] = TALLOC_ARRAY( mem_ctx, char, name_buf.length+1 );
864
865                 if ( !val_names_out[num_values_out]
866                      || !values_out[num_values_out] ) {
867                         hnd->status = NT_STATUS_NO_MEMORY;
868                         break;
869                 }
870
871                 StrnCpy( val_names_out[num_values_out], name_buf.name, name_buf.length );
872                 (val_names_out[num_values_out])[name_buf.length] = '\0';
873
874                 num_values_out++;
875                 resume_idx++;
876         } while ( num_values_out < op->in.max_values );
877
878         if ( CAC_OP_FAILED( hnd->status ) )
879                 return CAC_FAILURE;
880
881         op->out.types = types_out;
882         op->out.num_values = num_values_out;
883         op->out.value_names = val_names_out;
884         op->out.values = values_out;
885         op->out.resume_idx = resume_idx;
886
887         return CAC_SUCCESS;
888 }
889
890 int cac_RegSetValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
891                      struct RegSetValue *op )
892 {
893         struct rpc_pipe_client *pipe_hnd = NULL;
894         struct winreg_String value_string;
895
896         RPC_DATA_BLOB *buffer;
897
898         if ( !hnd )
899                 return CAC_FAILURE;
900
901         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
902                 hnd->status = NT_STATUS_INVALID_HANDLE;
903                 return CAC_FAILURE;
904         }
905
906         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
907                 hnd->status = NT_STATUS_INVALID_PARAMETER;
908                 return CAC_FAILURE;
909         }
910
911         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
912         if ( !pipe_hnd ) {
913                 hnd->status = NT_STATUS_INVALID_HANDLE;
914                 return CAC_FAILURE;
915         }
916
917         buffer = cac_MakeRpcDataBlob( mem_ctx, op->in.type, op->in.value );
918
919         if ( !buffer ) {
920                 if ( errno == ENOMEM )
921                         hnd->status = NT_STATUS_NO_MEMORY;
922                 else
923                         hnd->status = NT_STATUS_INVALID_PARAMETER;
924
925                 return CAC_FAILURE;
926         }
927
928         value_string.name = op->in.val_name;
929         hnd->status =
930                 rpccli_winreg_SetValue( pipe_hnd, mem_ctx, op->in.key,
931                                         value_string, op->in.type,
932                                         buffer->buffer, buffer->buf_len );
933
934         if ( !NT_STATUS_IS_OK( hnd->status ) )
935                 return CAC_FAILURE;
936
937         /*flush */
938         hnd->status = rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, op->in.key );
939
940         if ( !NT_STATUS_IS_OK( hnd->status ) )
941                 return CAC_FAILURE;
942
943         return CAC_SUCCESS;
944 }
945
946
947
948 int cac_RegGetVersion( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
949                        struct RegGetVersion *op )
950 {
951         struct rpc_pipe_client *pipe_hnd = NULL;
952         uint32 version_out;
953
954         if ( !hnd )
955                 return CAC_FAILURE;
956
957         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
958                 hnd->status = NT_STATUS_INVALID_HANDLE;
959                 return CAC_FAILURE;
960         }
961
962         if ( !op || !op->in.key || !mem_ctx ) {
963                 hnd->status = NT_STATUS_INVALID_PARAMETER;
964                 return CAC_FAILURE;
965         }
966
967         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
968         if ( !pipe_hnd ) {
969                 hnd->status = NT_STATUS_INVALID_HANDLE;
970                 return CAC_FAILURE;
971         }
972
973         hnd->status =
974                 rpccli_winreg_GetVersion( pipe_hnd, mem_ctx, op->in.key,
975                                           &version_out );
976
977         if ( !NT_STATUS_IS_OK( hnd->status ) )
978                 return CAC_FAILURE;
979
980         op->out.version = version_out;
981
982         return CAC_SUCCESS;
983 }
984
985 int cac_RegGetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
986                            struct RegGetKeySecurity *op )
987 {
988         struct rpc_pipe_client *pipe_hnd = NULL;
989         struct KeySecurityData keysec;
990
991         ZERO_STRUCT( keysec );
992
993         if ( !hnd )
994                 return CAC_FAILURE;
995
996         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
997                 hnd->status = NT_STATUS_INVALID_HANDLE;
998                 return CAC_FAILURE;
999         }
1000
1001         if ( !op || !op->in.key || op->in.info_type == 0 || !mem_ctx ) {
1002                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1003                 return CAC_FAILURE;
1004         }
1005
1006         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
1007         if ( !pipe_hnd ) {
1008                 hnd->status = NT_STATUS_INVALID_HANDLE;
1009                 return CAC_FAILURE;
1010         }
1011
1012         hnd->status =
1013                 rpccli_winreg_GetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1014                                               op->in.info_type, &keysec );
1015
1016         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1017                 return CAC_FAILURE;
1018         }
1019
1020 #if 0   /* FIX ME!!!!  unmarshall the security descriptor */
1021         op->out.size = buf.sd_size;
1022         op->out.descriptor = dup_sec_desc( mem_ctx, buf.sd );
1023 #endif
1024
1025         if ( op->out.descriptor == NULL ) {
1026                 return CAC_FAILURE;
1027         }
1028
1029         return CAC_SUCCESS;
1030 }
1031
1032 int cac_RegSetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1033                            struct RegSetKeySecurity *op )
1034 {
1035         struct rpc_pipe_client *pipe_hnd = NULL;
1036         struct KeySecurityData keysec;
1037
1038         ZERO_STRUCT( keysec );
1039
1040         if ( !hnd )
1041                 return CAC_FAILURE;
1042
1043         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
1044                 hnd->status = NT_STATUS_INVALID_HANDLE;
1045                 return CAC_FAILURE;
1046         }
1047
1048         if ( !op || !op->in.key || op->in.info_type == 0 || op->in.size == 0
1049              || !op->in.descriptor || !mem_ctx ) {
1050                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1051                 return CAC_FAILURE;
1052         }
1053
1054         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
1055         if ( !pipe_hnd ) {
1056                 hnd->status = NT_STATUS_INVALID_HANDLE;
1057                 return CAC_FAILURE;
1058         }
1059
1060         /* FIXME!!! Marshall in the input sec_desc to struct KeySecurityData */
1061         hnd->status =
1062                 rpccli_winreg_SetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1063                                               op->in.info_type, &keysec );
1064
1065         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1066                 return CAC_FAILURE;
1067         }
1068
1069         return CAC_SUCCESS;
1070 }
1071
1072 int cac_Shutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1073                   struct Shutdown *op )
1074 {
1075         SMBCSRV *srv = NULL;
1076         struct rpc_pipe_client *pipe_hnd = NULL;
1077         struct initshutdown_String msg_string;
1078         struct initshutdown_String_sub s;
1079
1080         char *msg;
1081
1082         if ( !hnd )
1083                 return CAC_FAILURE;
1084
1085         if ( !hnd->_internal.ctx ) {
1086                 hnd->status = NT_STATUS_INVALID_HANDLE;
1087                 return CAC_FAILURE;
1088         }
1089
1090         if ( !op || !mem_ctx ) {
1091                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1092                 return CAC_FAILURE;
1093         }
1094
1095         srv = cac_GetServer( hnd );
1096         if ( !srv ) {
1097                 hnd->status = NT_STATUS_INVALID_HANDLE;
1098                 return CAC_FAILURE;
1099         }
1100
1101         /*initialize for winreg pipe if we have to */
1102         if ( !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1103                 if ( !
1104                      ( pipe_hnd =
1105                        cli_rpc_pipe_open_noauth( srv->cli, PI_INITSHUTDOWN,
1106                                                  &( hnd->status ) ) ) ) {
1107                         return CAC_FAILURE;
1108                 }
1109
1110                 hnd->_internal.pipes[PI_INITSHUTDOWN] = True;
1111         }
1112
1113         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1114         if ( !pipe_hnd ) {
1115                 hnd->status = NT_STATUS_INVALID_HANDLE;
1116                 return CAC_FAILURE;
1117         }
1118
1119         msg = ( op->in.message !=
1120                 NULL ) ? op->in.message : talloc_strdup( mem_ctx, "" );
1121         msg_string.name = &s;
1122         msg_string.name->name = msg;
1123
1124         hnd->status = NT_STATUS_OK;
1125
1126         if ( hnd->_internal.srv_level > SRV_WIN_NT4 ) {
1127                 hnd->status =
1128                         rpccli_initshutdown_InitEx( pipe_hnd, mem_ctx, NULL,
1129                                                     &msg_string,
1130                                                     op->in.timeout,
1131                                                     op->in.reboot,
1132                                                     op->in.force,
1133                                                     op->in.reason );
1134         }
1135
1136         if ( hnd->_internal.srv_level < SRV_WIN_2K
1137              || !NT_STATUS_IS_OK( hnd->status ) ) {
1138                 hnd->status =
1139                         rpccli_initshutdown_Init( pipe_hnd, mem_ctx, NULL,
1140                                                   &msg_string, op->in.timeout,
1141                                                   op->in.reboot,
1142                                                   op->in.force );
1143
1144                 hnd->_internal.srv_level = SRV_WIN_NT4;
1145         }
1146
1147         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1148                 return CAC_FAILURE;
1149         }
1150
1151         return CAC_SUCCESS;
1152 }
1153
1154 int cac_AbortShutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx )
1155 {
1156         struct rpc_pipe_client *pipe_hnd = NULL;
1157
1158         if ( !hnd )
1159                 return CAC_FAILURE;
1160
1161         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1162                 hnd->status = NT_STATUS_INVALID_HANDLE;
1163                 return CAC_FAILURE;
1164         }
1165
1166         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1167         if ( !pipe_hnd ) {
1168                 hnd->status = NT_STATUS_INVALID_HANDLE;
1169                 return CAC_FAILURE;
1170         }
1171
1172         hnd->status = rpccli_initshutdown_Abort( pipe_hnd, mem_ctx, NULL );
1173
1174         if ( !NT_STATUS_IS_OK( hnd->status ) )
1175                 return CAC_FAILURE;
1176
1177         return CAC_SUCCESS;
1178 }