8d131effe594cc6d7a94d41a786977dcbbed49e7
[kai/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 2 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         enum winreg_CreateAction *paction = &action;
342
343         if ( !hnd )
344                 return CAC_FAILURE;
345
346         if ( !hnd->_internal.ctx ) {
347                 hnd->status = NT_STATUS_INVALID_HANDLE;
348                 return CAC_FAILURE;
349         }
350
351         if ( !op || !op->in.parent_key || !op->in.key_name || !mem_ctx ) {
352                 hnd->status = NT_STATUS_INVALID_PARAMETER;
353                 return CAC_FAILURE;
354         }
355
356         /*first try to open the key - we use cac_RegOpenKey(). this doubles as a way to ensure the winreg pipe is initialized */
357         ZERO_STRUCT( rok );
358
359         rok.in.name = op->in.key_name;
360         rok.in.access = op->in.access;
361         rok.in.parent_key = op->in.parent_key;
362
363         if ( cac_RegOpenKey( hnd, mem_ctx, &rok ) ) {
364                 /*then we got the key, return */
365                 op->out.key = rok.out.key;
366                 return CAC_SUCCESS;
367         }
368
369         /*just be ultra-safe */
370         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
371         if ( !pipe_hnd ) {
372                 hnd->status = NT_STATUS_INVALID_HANDLE;
373                 return CAC_FAILURE;
374         }
375
376         key_out = talloc( mem_ctx, POLICY_HND );
377         if ( !key_out ) {
378                 hnd->status = NT_STATUS_NO_MEMORY;
379                 return CAC_FAILURE;
380         }
381
382         key_string.name = op->in.key_name;
383         class_string.name = op->in.class_name;
384         hnd->status =
385                 rpccli_winreg_CreateKey( pipe_hnd, mem_ctx, op->in.parent_key,
386                                          key_string, class_string, 0,
387                                          op->in.access, NULL, key_out,
388                                          &paction );
389
390         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
391                 return CAC_FAILURE;
392         }
393
394         op->out.key = key_out;
395
396         return CAC_SUCCESS;
397
398 }
399
400 NTSTATUS cac_delete_subkeys_recursive( struct rpc_pipe_client * pipe_hnd,
401                                      TALLOC_CTX * mem_ctx, POLICY_HND * key )
402 {
403         POLICY_HND subkey;
404         fstring subkey_name;
405         int cur_key = 0;
406         NTSTATUS status;
407         uint32 num_subkeys, max_subkeylen, max_classlen;
408         uint32 num_values, max_valnamelen, maxvalbufsize;
409         char *name_buffer; 
410         struct winreg_String class_string;
411
412         NTTIME modtime;
413         uint32 secdescsize;
414
415         /* First get the max subkey name length */
416
417         class_string.name = NULL;
418         status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, key, 
419                                              &class_string, &num_subkeys, 
420                                              &max_subkeylen, &max_classlen,
421                                              &num_values, &max_valnamelen,
422                                              &maxvalbufsize, &secdescsize, 
423                                              &modtime );
424
425
426         if ( !NT_STATUS_IS_OK( status ) ) {
427                 return status;
428         }
429
430         if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_subkeylen )) == NULL ) {
431                 d_fprintf(stderr, "Memory allocation error.\n");
432                 return NT_STATUS_NO_MEMORY;
433         }
434
435
436         while ( NT_STATUS_IS_OK( status ) ) {
437                 struct winreg_String key_string;
438                 struct winreg_StringBuf subkey_string;
439                 fstring subkeyname;
440
441                 memset( name_buffer, 0x0, max_subkeylen );
442                 subkey_string.name = name_buffer;
443                 subkey_string.length = 0;
444                 subkey_string.size = max_subkeylen;
445
446                 status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key, cur_key, 
447                         &subkey_string, NULL, NULL);
448
449                 if ( !NT_STATUS_IS_OK( status ) )
450                         break;
451
452                 /* copy the keyname and add the terminating NULL */
453
454                 StrnCpy( subkeyname, subkey_string.name, 
455                          MIN(subkey_string.length, sizeof(subkeyname)-1) );
456                 subkeyname[MIN(subkey_string.length, sizeof(subkeyname)-1)] = '\0';
457
458                 /*try to open the key with full access */
459
460                 key_string.name = subkeyname;
461                 status = rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, key,
462                                                 key_string, 0, REG_KEY_ALL,
463                                                 &subkey );
464
465                 if ( !NT_STATUS_IS_OK( status ) )
466                         break;
467
468                 status = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
469                                                     &subkey );
470
471                 if ( !W_ERROR_EQUAL( ntstatus_to_werror(status), WERR_NO_MORE_ITEMS )
472                      && !NT_STATUS_IS_OK( status ) )
473                         break;
474
475                 /*flush the key just to be safe */
476                 rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, key );
477
478                 /*close the key that we opened */
479                 rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, &subkey );
480
481                 /*now we delete the subkey */
482                 key_string.name = subkey_name;
483                 status = rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, key,
484                                                   key_string );
485
486                 cur_key++;
487         }
488
489
490         return status;
491 }
492
493
494
495 int cac_RegDeleteKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
496                       struct RegDeleteKey *op )
497 {
498         struct rpc_pipe_client *pipe_hnd = NULL;
499         struct winreg_String key_string;
500
501         if ( !hnd )
502                 return CAC_FAILURE;
503
504         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
505                 hnd->status = NT_STATUS_INVALID_HANDLE;
506                 return CAC_FAILURE;
507         }
508
509         if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
510                 hnd->status = NT_STATUS_INVALID_PARAMETER;
511                 return CAC_FAILURE;
512         }
513
514         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
515         if ( !pipe_hnd ) {
516                 hnd->status = NT_STATUS_INVALID_HANDLE;
517                 return CAC_FAILURE;
518         }
519
520         if ( op->in.recursive ) {
521
522                 /* first open the key, and then delete all of 
523                    it's subkeys recursively */
524
525                 struct RegOpenKey rok;
526
527                 ZERO_STRUCT( rok );
528
529                 rok.in.parent_key = op->in.parent_key;
530                 rok.in.name = op->in.name;
531                 rok.in.access = REG_KEY_ALL;
532
533                 if ( !cac_RegOpenKey( hnd, mem_ctx, &rok ) )
534                         return CAC_FAILURE;
535
536                 hnd->status = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
537                                                     rok.out.key );
538
539                 /*close the key that we opened */
540                 cac_RegClose( hnd, mem_ctx, rok.out.key );
541
542                 if ( NT_STATUS_V( hnd->status ) !=
543                      NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED )
544                      && !NT_STATUS_IS_OK( hnd->status ) )
545                         return CAC_FAILURE;
546
547                 /*now go on to actually delete the key */
548         }
549
550         key_string.name = op->in.name;
551         hnd->status =
552                 rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, op->in.parent_key,
553                                          key_string );
554
555         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
556                 return CAC_FAILURE;
557         }
558
559         return CAC_SUCCESS;
560 }
561
562 int cac_RegDeleteValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
563                         struct RegDeleteValue *op )
564 {
565         struct rpc_pipe_client *pipe_hnd = NULL;
566         struct winreg_String value_string;
567
568         if ( !hnd )
569                 return CAC_FAILURE;
570
571         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
572                 hnd->status = NT_STATUS_INVALID_HANDLE;
573                 return CAC_FAILURE;
574         }
575
576         if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
577                 hnd->status = NT_STATUS_INVALID_PARAMETER;
578                 return CAC_FAILURE;
579         }
580
581         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
582         if ( !pipe_hnd ) {
583                 hnd->status = NT_STATUS_INVALID_HANDLE;
584                 return CAC_FAILURE;
585         }
586
587         value_string.name = op->in.name;
588         hnd->status =
589                 rpccli_winreg_DeleteValue( pipe_hnd, mem_ctx,
590                                            op->in.parent_key, value_string );
591
592         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
593                 return CAC_FAILURE;
594         }
595
596         return CAC_SUCCESS;
597 }
598
599 int cac_RegQueryKeyInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
600                          struct RegQueryKeyInfo *op )
601 {
602         struct rpc_pipe_client *pipe_hnd = NULL;
603         uint32 num_subkeys_out = 0;
604         uint32 long_subkey_out = 0;
605         uint32 long_class_out = 0;
606         uint32 num_values_out = 0;
607         uint32 long_value_out = 0;
608         uint32 long_data_out = 0;
609         uint32 secdesc_size = 0;
610         NTTIME mod_time;
611         struct winreg_String class_string;
612
613         if ( !hnd )
614                 return CAC_FAILURE;
615
616         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
617                 hnd->status = NT_STATUS_INVALID_HANDLE;
618                 return CAC_FAILURE;
619         }
620
621         if ( !op || !op->in.key || !mem_ctx ) {
622                 hnd->status = NT_STATUS_INVALID_PARAMETER;
623                 return CAC_FAILURE;
624         }
625
626         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
627         if ( !pipe_hnd ) {
628                 hnd->status = NT_STATUS_INVALID_HANDLE;
629                 return CAC_FAILURE;
630         }
631
632         hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, 
633                                                   op->in.key,
634                                                   &class_string,
635                                                   &num_subkeys_out,
636                                                   &long_subkey_out,
637                                                   &long_class_out,
638                                                   &num_values_out,
639                                                   &long_value_out,
640                                                   &long_data_out,
641                                                   &secdesc_size, &mod_time );
642
643         if ( !NT_STATUS_IS_OK( hnd->status ) )
644                 return CAC_FAILURE;
645
646         if ( !class_string.name ) {
647                 op->out.class_name = talloc_strdup( mem_ctx, "" );
648         } else {
649                 op->out.class_name = talloc_strdup( mem_ctx, class_string.name );
650         }
651
652         if ( !op->out.class_name ) {
653                 hnd->status = NT_STATUS_NO_MEMORY;
654                 return CAC_FAILURE;
655         }
656
657         op->out.num_subkeys = num_subkeys_out;
658         op->out.longest_subkey = long_subkey_out;
659         op->out.longest_class = long_class_out;
660         op->out.num_values = num_values_out;
661         op->out.longest_value_name = long_value_out;
662         op->out.longest_value_data = long_data_out;
663         op->out.security_desc_size = secdesc_size;
664         op->out.last_write_time = nt_time_to_unix( mod_time );
665
666         return CAC_FAILURE;
667 }
668
669 int cac_RegQueryValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
670                        struct RegQueryValue *op )
671 {
672         struct rpc_pipe_client *pipe_hnd = NULL;
673         struct winreg_String value_string;
674         REGVAL_BUFFER buffer;
675         REG_VALUE_DATA *data_out = NULL;
676         enum winreg_Type val_type;
677         enum winreg_Type *pval_type = &val_type;
678         uint8 *buf;
679         uint32 buf_size = 4096;
680         uint32 *pbuf_size = &buf_size;
681         uint32 length = 0;
682         uint32 *plength = &length;
683
684         if ( !hnd )
685                 return CAC_FAILURE;
686
687         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
688                 hnd->status = NT_STATUS_INVALID_HANDLE;
689                 return CAC_FAILURE;
690         }
691
692         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
693                 hnd->status = NT_STATUS_INVALID_PARAMETER;
694                 return CAC_FAILURE;
695         }
696
697         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
698         if ( !pipe_hnd ) {
699                 hnd->status = NT_STATUS_INVALID_HANDLE;
700                 return CAC_FAILURE;
701         }
702
703         value_string.name = op->in.val_name;
704
705         if ( ( buf = TALLOC_ARRAY( mem_ctx, uint8, buf_size ) ) == NULL ) {
706                 hnd->status = NT_STATUS_NO_MEMORY;
707                 return CAC_FAILURE;
708         }
709
710         hnd->status = rpccli_winreg_QueryValue( pipe_hnd, mem_ctx, op->in.key,
711                                                 value_string, &pval_type, &buf,
712                                                 &pbuf_size, &plength );
713
714         if ( !NT_STATUS_IS_OK( hnd->status ) )
715                 return CAC_FAILURE;
716
717         init_regval_buffer( &buffer, buf, length );
718
719         data_out = cac_MakeRegValueData( mem_ctx, val_type, buffer );
720         if ( !data_out ) {
721                 if ( errno == ENOMEM )
722                         hnd->status = NT_STATUS_NO_MEMORY;
723                 else
724                         hnd->status = NT_STATUS_INVALID_PARAMETER;
725
726                 return CAC_FAILURE;
727         }
728
729         op->out.type = val_type;
730         op->out.data = data_out;
731
732         return CAC_SUCCESS;
733 }
734
735
736 int cac_RegEnumValues( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
737                        struct RegEnumValues *op )
738 {
739         struct rpc_pipe_client *pipe_hnd = NULL;
740         char *name_buffer;
741         REGVAL_BUFFER val_buf;
742         uint32 *types_out = NULL;
743         REG_VALUE_DATA **values_out = NULL;
744         char **val_names_out = NULL;
745         uint32 num_values_out = 0;
746         uint32 resume_idx = 0;
747         uint32 num_subkeys, max_subkeylen, max_classlen;
748         uint32 num_values, max_valnamelen, maxvalbufsize;
749         struct winreg_String class_string;
750         NTTIME modtime;
751         uint32 secdescsize;
752         uint8 *buffer;
753
754         if ( !hnd )
755                 return CAC_FAILURE;
756
757         /* This is to avoid useless rpc calls, if the last 
758            call exhausted all the keys, then we don't need 
759            to go through everything again */
760
761         if ( NT_STATUS_V( hnd->status ) ==
762              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
763                 return CAC_FAILURE;
764
765         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
766                 hnd->status = NT_STATUS_INVALID_HANDLE;
767                 return CAC_FAILURE;
768         }
769
770         if ( !op || !op->in.key || op->in.max_values == 0 || !mem_ctx ) {
771                 hnd->status = NT_STATUS_INVALID_PARAMETER;
772                 return CAC_FAILURE;
773         }
774
775         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
776         if ( !pipe_hnd ) {
777                 hnd->status = NT_STATUS_INVALID_HANDLE;
778                 return CAC_FAILURE;
779         }
780
781         /*we need to assume that the max number of values will be enumerated */
782         types_out = talloc_array( mem_ctx, uint32, op->in.max_values );
783
784         if ( !types_out ) {
785                 hnd->status = NT_STATUS_NO_MEMORY;
786                 return CAC_FAILURE;
787         }
788
789         values_out = talloc_array( mem_ctx, REG_VALUE_DATA *, 
790                                    op->in.max_values );
791
792         if ( !values_out ) {
793                 TALLOC_FREE( types_out );
794                 hnd->status = NT_STATUS_NO_MEMORY;
795                 return CAC_FAILURE;
796         }
797
798         val_names_out = talloc_array( mem_ctx, char *, op->in.max_values );
799
800         if ( !val_names_out ) {
801                 TALLOC_FREE( types_out );
802                 TALLOC_FREE( values_out );
803                 hnd->status = NT_STATUS_NO_MEMORY;
804                 return CAC_FAILURE;
805         }
806
807         resume_idx = op->out.resume_idx;
808
809         class_string.name = NULL;
810         hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, op->in.key, 
811                                              &class_string, &num_subkeys, 
812                                              &max_subkeylen, &max_classlen,
813                                              &num_values, &max_valnamelen,
814                                              &maxvalbufsize, &secdescsize, 
815                                              &modtime );
816
817         if ( !NT_STATUS_IS_OK(hnd->status) ) {
818                 TALLOC_FREE( types_out );
819                 TALLOC_FREE( values_out );
820
821                 return CAC_FAILURE;
822         }
823
824         if ( (buffer = TALLOC_ARRAY( mem_ctx, uint8, maxvalbufsize )) == NULL ) {
825                 TALLOC_FREE( types_out );
826                 TALLOC_FREE( values_out );
827                 hnd->status = NT_STATUS_NO_MEMORY;
828
829                 return CAC_FAILURE;
830         }
831
832         if ( (name_buffer = TALLOC_ARRAY(mem_ctx, char, max_valnamelen)) == NULL ) {
833                 TALLOC_FREE( types_out );
834                 TALLOC_FREE( values_out );
835                 TALLOC_FREE( buffer );
836                 hnd->status = NT_STATUS_NO_MEMORY;
837
838                 return CAC_FAILURE;
839         }
840                 
841         do {
842                 uint32 data_size = maxvalbufsize;
843                 uint32 *pdata_size = &data_size;
844                 uint32 data_length = 0;
845                 uint32 *pdata_length = &data_length;
846                 struct winreg_ValNameBuf name_buf;
847                 enum winreg_Type *ptype = &types_out[num_values_out];
848
849                 memset( name_buffer, 0x0, max_valnamelen );
850                 name_buf.name = name_buffer;
851                 name_buf.size = max_valnamelen;
852                 name_buf.length = 0;
853                 
854                 hnd->status = rpccli_winreg_EnumValue( pipe_hnd, mem_ctx, 
855                                                        op->in.key,
856                                                        resume_idx, &name_buf,
857                                                        &ptype, &buffer,
858                                                        &pdata_size,
859                                                        &pdata_length );
860
861                 if ( !NT_STATUS_IS_OK( hnd->status ) )
862                         break;
863
864                 ZERO_STRUCT( val_buf );
865                 init_regval_buffer(  &val_buf, buffer, data_length );
866
867                 values_out[num_values_out] = cac_MakeRegValueData( mem_ctx,
868                                                                    types_out[num_values_out],
869                                                                    val_buf );
870                 val_names_out[num_values_out] = TALLOC_ARRAY( mem_ctx, char, name_buf.length+1 );
871
872                 if ( !val_names_out[num_values_out]
873                      || !values_out[num_values_out] ) {
874                         hnd->status = NT_STATUS_NO_MEMORY;
875                         break;
876                 }
877
878                 StrnCpy( val_names_out[num_values_out], name_buf.name, name_buf.length );
879                 (val_names_out[num_values_out])[name_buf.length] = '\0';
880
881                 num_values_out++;
882                 resume_idx++;
883         } while ( num_values_out < op->in.max_values );
884
885         if ( CAC_OP_FAILED( hnd->status ) )
886                 return CAC_FAILURE;
887
888         op->out.types = types_out;
889         op->out.num_values = num_values_out;
890         op->out.value_names = val_names_out;
891         op->out.values = values_out;
892         op->out.resume_idx = resume_idx;
893
894         return CAC_SUCCESS;
895 }
896
897 int cac_RegSetValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
898                      struct RegSetValue *op )
899 {
900         struct rpc_pipe_client *pipe_hnd = NULL;
901         struct winreg_String value_string;
902
903         RPC_DATA_BLOB *buffer;
904
905         if ( !hnd )
906                 return CAC_FAILURE;
907
908         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
909                 hnd->status = NT_STATUS_INVALID_HANDLE;
910                 return CAC_FAILURE;
911         }
912
913         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
914                 hnd->status = NT_STATUS_INVALID_PARAMETER;
915                 return CAC_FAILURE;
916         }
917
918         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
919         if ( !pipe_hnd ) {
920                 hnd->status = NT_STATUS_INVALID_HANDLE;
921                 return CAC_FAILURE;
922         }
923
924         buffer = cac_MakeRpcDataBlob( mem_ctx, op->in.type, op->in.value );
925
926         if ( !buffer ) {
927                 if ( errno == ENOMEM )
928                         hnd->status = NT_STATUS_NO_MEMORY;
929                 else
930                         hnd->status = NT_STATUS_INVALID_PARAMETER;
931
932                 return CAC_FAILURE;
933         }
934
935         value_string.name = op->in.val_name;
936         hnd->status =
937                 rpccli_winreg_SetValue( pipe_hnd, mem_ctx, op->in.key,
938                                         value_string, op->in.type,
939                                         buffer->buffer, buffer->buf_len );
940
941         if ( !NT_STATUS_IS_OK( hnd->status ) )
942                 return CAC_FAILURE;
943
944         /*flush */
945         hnd->status = rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, op->in.key );
946
947         if ( !NT_STATUS_IS_OK( hnd->status ) )
948                 return CAC_FAILURE;
949
950         return CAC_SUCCESS;
951 }
952
953
954
955 int cac_RegGetVersion( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
956                        struct RegGetVersion *op )
957 {
958         struct rpc_pipe_client *pipe_hnd = NULL;
959         uint32 version_out;
960
961         if ( !hnd )
962                 return CAC_FAILURE;
963
964         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
965                 hnd->status = NT_STATUS_INVALID_HANDLE;
966                 return CAC_FAILURE;
967         }
968
969         if ( !op || !op->in.key || !mem_ctx ) {
970                 hnd->status = NT_STATUS_INVALID_PARAMETER;
971                 return CAC_FAILURE;
972         }
973
974         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
975         if ( !pipe_hnd ) {
976                 hnd->status = NT_STATUS_INVALID_HANDLE;
977                 return CAC_FAILURE;
978         }
979
980         hnd->status =
981                 rpccli_winreg_GetVersion( pipe_hnd, mem_ctx, op->in.key,
982                                           &version_out );
983
984         if ( !NT_STATUS_IS_OK( hnd->status ) )
985                 return CAC_FAILURE;
986
987         op->out.version = version_out;
988
989         return CAC_SUCCESS;
990 }
991
992 int cac_RegGetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
993                            struct RegGetKeySecurity *op )
994 {
995         struct rpc_pipe_client *pipe_hnd = NULL;
996         struct KeySecurityData keysec;
997
998         ZERO_STRUCT( keysec );
999
1000         if ( !hnd )
1001                 return CAC_FAILURE;
1002
1003         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
1004                 hnd->status = NT_STATUS_INVALID_HANDLE;
1005                 return CAC_FAILURE;
1006         }
1007
1008         if ( !op || !op->in.key || op->in.info_type == 0 || !mem_ctx ) {
1009                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1010                 return CAC_FAILURE;
1011         }
1012
1013         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
1014         if ( !pipe_hnd ) {
1015                 hnd->status = NT_STATUS_INVALID_HANDLE;
1016                 return CAC_FAILURE;
1017         }
1018
1019         hnd->status =
1020                 rpccli_winreg_GetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1021                                               op->in.info_type, &keysec );
1022
1023         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1024                 return CAC_FAILURE;
1025         }
1026
1027 #if 0   /* FIX ME!!!!  unmarshall the security descriptor */
1028         op->out.size = buf.sd_size;
1029         op->out.descriptor = dup_sec_desc( mem_ctx, buf.sd );
1030 #endif
1031
1032         if ( op->out.descriptor == NULL ) {
1033                 return CAC_FAILURE;
1034         }
1035
1036         return CAC_SUCCESS;
1037 }
1038
1039 int cac_RegSetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1040                            struct RegSetKeySecurity *op )
1041 {
1042         struct rpc_pipe_client *pipe_hnd = NULL;
1043         struct KeySecurityData keysec;
1044
1045         ZERO_STRUCT( keysec );
1046
1047         if ( !hnd )
1048                 return CAC_FAILURE;
1049
1050         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
1051                 hnd->status = NT_STATUS_INVALID_HANDLE;
1052                 return CAC_FAILURE;
1053         }
1054
1055         if ( !op || !op->in.key || op->in.info_type == 0 || op->in.size == 0
1056              || !op->in.descriptor || !mem_ctx ) {
1057                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1058                 return CAC_FAILURE;
1059         }
1060
1061         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
1062         if ( !pipe_hnd ) {
1063                 hnd->status = NT_STATUS_INVALID_HANDLE;
1064                 return CAC_FAILURE;
1065         }
1066
1067         /* FIXME!!! Marshall in the input sec_desc to struct KeySecurityData */
1068         hnd->status =
1069                 rpccli_winreg_SetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1070                                               op->in.info_type, &keysec );
1071
1072         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1073                 return CAC_FAILURE;
1074         }
1075
1076         return CAC_SUCCESS;
1077 }
1078
1079 int cac_Shutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1080                   struct Shutdown *op )
1081 {
1082         SMBCSRV *srv = NULL;
1083         struct rpc_pipe_client *pipe_hnd = NULL;
1084         struct initshutdown_String msg_string;
1085         struct initshutdown_String_sub s;
1086
1087         char *msg;
1088
1089         if ( !hnd )
1090                 return CAC_FAILURE;
1091
1092         if ( !hnd->_internal.ctx ) {
1093                 hnd->status = NT_STATUS_INVALID_HANDLE;
1094                 return CAC_FAILURE;
1095         }
1096
1097         if ( !op || !mem_ctx ) {
1098                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1099                 return CAC_FAILURE;
1100         }
1101
1102         srv = cac_GetServer( hnd );
1103         if ( !srv ) {
1104                 hnd->status = NT_STATUS_INVALID_HANDLE;
1105                 return CAC_FAILURE;
1106         }
1107
1108         /*initialize for winreg pipe if we have to */
1109         if ( !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1110                 if ( !
1111                      ( pipe_hnd =
1112                        cli_rpc_pipe_open_noauth( srv->cli, PI_INITSHUTDOWN,
1113                                                  &( hnd->status ) ) ) ) {
1114                         return CAC_FAILURE;
1115                 }
1116
1117                 hnd->_internal.pipes[PI_INITSHUTDOWN] = True;
1118         }
1119
1120         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1121         if ( !pipe_hnd ) {
1122                 hnd->status = NT_STATUS_INVALID_HANDLE;
1123                 return CAC_FAILURE;
1124         }
1125
1126         msg = ( op->in.message !=
1127                 NULL ) ? op->in.message : talloc_strdup( mem_ctx, "" );
1128         msg_string.name = &s;
1129         msg_string.name->name = msg;
1130
1131         hnd->status = NT_STATUS_OK;
1132
1133         if ( hnd->_internal.srv_level > SRV_WIN_NT4 ) {
1134                 hnd->status =
1135                         rpccli_initshutdown_InitEx( pipe_hnd, mem_ctx, NULL,
1136                                                     &msg_string,
1137                                                     op->in.timeout,
1138                                                     op->in.reboot,
1139                                                     op->in.force,
1140                                                     op->in.reason );
1141         }
1142
1143         if ( hnd->_internal.srv_level < SRV_WIN_2K
1144              || !NT_STATUS_IS_OK( hnd->status ) ) {
1145                 hnd->status =
1146                         rpccli_initshutdown_Init( pipe_hnd, mem_ctx, NULL,
1147                                                   &msg_string, op->in.timeout,
1148                                                   op->in.reboot,
1149                                                   op->in.force );
1150
1151                 hnd->_internal.srv_level = SRV_WIN_NT4;
1152         }
1153
1154         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1155                 return CAC_FAILURE;
1156         }
1157
1158         return CAC_SUCCESS;
1159 }
1160
1161 int cac_AbortShutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx )
1162 {
1163         struct rpc_pipe_client *pipe_hnd = NULL;
1164
1165         if ( !hnd )
1166                 return CAC_FAILURE;
1167
1168         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1169                 hnd->status = NT_STATUS_INVALID_HANDLE;
1170                 return CAC_FAILURE;
1171         }
1172
1173         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1174         if ( !pipe_hnd ) {
1175                 hnd->status = NT_STATUS_INVALID_HANDLE;
1176                 return CAC_FAILURE;
1177         }
1178
1179         hnd->status = rpccli_initshutdown_Abort( pipe_hnd, mem_ctx, NULL );
1180
1181         if ( !NT_STATUS_IS_OK( hnd->status ) )
1182                 return CAC_FAILURE;
1183
1184         return CAC_SUCCESS;
1185 }