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