r18981: * cleanup some vestiges of old cli_reg.c code and mark some TODO
[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 exhausted all the keys, then we don't need to go through everything again */
237         if ( NT_STATUS_V( hnd->status ) ==
238              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
239                 return CAC_FAILURE;
240
241         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
242                 hnd->status = NT_STATUS_INVALID_HANDLE;
243                 return CAC_FAILURE;
244         }
245
246         if ( !op || op->in.max_keys == 0 || !mem_ctx ) {
247                 hnd->status = NT_STATUS_INVALID_PARAMETER;
248                 return CAC_FAILURE;
249         }
250
251         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
252         if ( !pipe_hnd ) {
253                 hnd->status = NT_STATUS_INVALID_HANDLE;
254                 return CAC_FAILURE;
255         }
256
257    /**the only way to know how many keys to expect is to assume max_keys keys will be found*/
258         key_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
259         if ( !key_names_out ) {
260                 hnd->status = NT_STATUS_NO_MEMORY;
261                 return CAC_FAILURE;
262         }
263
264         class_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
265         if ( !class_names_out ) {
266                 hnd->status = NT_STATUS_NO_MEMORY;
267                 TALLOC_FREE( key_names_out );
268                 return CAC_FAILURE;
269         }
270
271         mod_times_out = TALLOC_ARRAY( mem_ctx, time_t, op->in.max_keys );
272         if ( !mod_times_out ) {
273                 hnd->status = NT_STATUS_NO_MEMORY;
274                 TALLOC_FREE( key_names_out );
275                 TALLOC_FREE( class_names_out );
276
277                 return CAC_FAILURE;
278         }
279
280         resume_idx = op->out.resume_idx;
281
282         do {
283 #if 0   /* FIXME!!! */
284
285                 hnd->status =
286                         rpccli_winreg_EnumKey( pipe_hnd, mem_ctx, op->in.key,
287                                                 resume_idx, key_name_in,
288                                                 class_name_in,
289                                                 &mod_times_out
290                                                 [num_keys_out] );
291
292 #endif
293                 if ( !NT_STATUS_IS_OK( hnd->status ) ) {
294                         /*don't increment any values */
295                         break;
296                 }
297
298                 key_names_out[num_keys_out] =
299                         talloc_strdup( mem_ctx, key_name_in );
300
301                 class_names_out[num_keys_out] =
302                         talloc_strdup( mem_ctx, class_name_in );
303
304                 if ( !key_names_out[num_keys_out]
305                      || !class_names_out[num_keys_out] ) {
306                         hnd->status = NT_STATUS_NO_MEMORY;
307                         break;
308                 }
309
310                 resume_idx++;
311                 num_keys_out++;
312         } while ( num_keys_out < op->in.max_keys );
313
314         if ( CAC_OP_FAILED( hnd->status ) ) {
315                 op->out.num_keys = 0;
316                 return CAC_FAILURE;
317         }
318
319         op->out.resume_idx = resume_idx;
320         op->out.num_keys = num_keys_out;
321         op->out.key_names = key_names_out;
322         op->out.class_names = class_names_out;
323         op->out.mod_times = mod_times_out;
324
325         return CAC_SUCCESS;
326 }
327
328 int cac_RegCreateKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
329                       struct RegCreateKey *op )
330 {
331         struct rpc_pipe_client *pipe_hnd = NULL;
332         POLICY_HND *key_out;
333         struct RegOpenKey rok;
334         struct winreg_String key_string, class_string;
335         enum winreg_CreateAction action = 0;
336
337         if ( !hnd )
338                 return CAC_FAILURE;
339
340         if ( !hnd->_internal.ctx ) {
341                 hnd->status = NT_STATUS_INVALID_HANDLE;
342                 return CAC_FAILURE;
343         }
344
345         if ( !op || !op->in.parent_key || !op->in.key_name || !mem_ctx ) {
346                 hnd->status = NT_STATUS_INVALID_PARAMETER;
347                 return CAC_FAILURE;
348         }
349
350         /*first try to open the key - we use cac_RegOpenKey(). this doubles as a way to ensure the winreg pipe is initialized */
351         ZERO_STRUCT( rok );
352
353         rok.in.name = op->in.key_name;
354         rok.in.access = op->in.access;
355         rok.in.parent_key = op->in.parent_key;
356
357         if ( cac_RegOpenKey( hnd, mem_ctx, &rok ) ) {
358                 /*then we got the key, return */
359                 op->out.key = rok.out.key;
360                 return CAC_SUCCESS;
361         }
362
363         /*just be ultra-safe */
364         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
365         if ( !pipe_hnd ) {
366                 hnd->status = NT_STATUS_INVALID_HANDLE;
367                 return CAC_FAILURE;
368         }
369
370         key_out = talloc( mem_ctx, POLICY_HND );
371         if ( !key_out ) {
372                 hnd->status = NT_STATUS_NO_MEMORY;
373                 return CAC_FAILURE;
374         }
375
376         key_string.name = op->in.key_name;
377         class_string.name = op->in.class_name;
378         hnd->status =
379                 rpccli_winreg_CreateKey( pipe_hnd, mem_ctx, op->in.parent_key,
380                                          key_string, class_string, 0,
381                                          op->in.access, NULL, key_out,
382                                          &action );
383
384         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
385                 return CAC_FAILURE;
386         }
387
388         op->out.key = key_out;
389
390         return CAC_SUCCESS;
391
392 }
393
394 WERROR cac_delete_subkeys_recursive( struct rpc_pipe_client * pipe_hnd,
395                                      TALLOC_CTX * mem_ctx, POLICY_HND * key )
396 {
397         /*NOTE: using cac functions might result in a big(ger) memory bloat, and would probably be far less efficient 
398          * so we use the cli_reg functions directly*/
399
400         WERROR err = WERR_OK;
401
402         POLICY_HND subkey;
403         fstring subkey_name;
404         fstring class_buf;
405         time_t mod_time_buf;
406
407         int cur_key = 0;
408
409         while ( W_ERROR_IS_OK( err ) ) {
410                 struct winreg_String key_string;
411                 NTSTATUS status;
412
413 #if 0   /* FIXME!!! */
414                 status = rpccli_winreg_enum_key( pipe_hnd, mem_ctx, key,
415                                                  cur_key, subkey_name,
416                                                  class_buf, &mod_time_buf );
417 #endif
418
419                 if ( !NT_STATUS_IS_OK( status ) )
420                         break;
421
422                 /*try to open the key with full access */
423                 key_string.name = subkey_name;
424                 status = rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, key,
425                                                 key_string, 0, REG_KEY_ALL,
426                                                 &subkey );
427
428                 if ( !NT_STATUS_IS_OK( status ) )
429                         break;
430
431                 err = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
432                                                     &subkey );
433
434                 if ( !W_ERROR_EQUAL( err, WERR_NO_MORE_ITEMS )
435                      && !W_ERROR_IS_OK( err ) )
436                         break;
437
438                 /*flush the key just to be safe */
439                 rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, key );
440
441                 /*close the key that we opened */
442                 rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, &subkey );
443
444                 /*now we delete the subkey */
445                 key_string.name = subkey_name;
446                 status = rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, key,
447                                                   key_string );
448                 err = ntstatus_to_werror( status );
449
450
451                 cur_key++;
452         }
453
454
455         return err;
456 }
457
458
459
460 int cac_RegDeleteKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
461                       struct RegDeleteKey *op )
462 {
463         struct rpc_pipe_client *pipe_hnd = NULL;
464         WERROR err;
465         struct winreg_String key_string;
466
467         if ( !hnd )
468                 return CAC_FAILURE;
469
470         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
471                 hnd->status = NT_STATUS_INVALID_HANDLE;
472                 return CAC_FAILURE;
473         }
474
475         if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
476                 hnd->status = NT_STATUS_INVALID_PARAMETER;
477                 return CAC_FAILURE;
478         }
479
480         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
481         if ( !pipe_hnd ) {
482                 hnd->status = NT_STATUS_INVALID_HANDLE;
483                 return CAC_FAILURE;
484         }
485
486         if ( op->in.recursive ) {
487                 /*first open the key, and then delete all of it's subkeys recursively */
488                 struct RegOpenKey rok;
489
490                 ZERO_STRUCT( rok );
491
492                 rok.in.parent_key = op->in.parent_key;
493                 rok.in.name = op->in.name;
494                 rok.in.access = REG_KEY_ALL;
495
496                 if ( !cac_RegOpenKey( hnd, mem_ctx, &rok ) )
497                         return CAC_FAILURE;
498
499                 err = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
500                                                     rok.out.key );
501
502                 /*close the key that we opened */
503                 cac_RegClose( hnd, mem_ctx, rok.out.key );
504
505                 hnd->status = werror_to_ntstatus( err );
506
507                 if ( NT_STATUS_V( hnd->status ) !=
508                      NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED )
509                      && !NT_STATUS_IS_OK( hnd->status ) )
510                         return CAC_FAILURE;
511
512                 /*now go on to actually delete the key */
513         }
514
515         key_string.name = op->in.name;
516         hnd->status =
517                 rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, op->in.parent_key,
518                                          key_string );
519
520         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
521                 return CAC_FAILURE;
522         }
523
524         return CAC_SUCCESS;
525 }
526
527 int cac_RegDeleteValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
528                         struct RegDeleteValue *op )
529 {
530         struct rpc_pipe_client *pipe_hnd = NULL;
531         struct winreg_String value_string;
532
533         if ( !hnd )
534                 return CAC_FAILURE;
535
536         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
537                 hnd->status = NT_STATUS_INVALID_HANDLE;
538                 return CAC_FAILURE;
539         }
540
541         if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
542                 hnd->status = NT_STATUS_INVALID_PARAMETER;
543                 return CAC_FAILURE;
544         }
545
546         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
547         if ( !pipe_hnd ) {
548                 hnd->status = NT_STATUS_INVALID_HANDLE;
549                 return CAC_FAILURE;
550         }
551
552         value_string.name = op->in.name;
553         hnd->status =
554                 rpccli_winreg_DeleteValue( pipe_hnd, mem_ctx,
555                                            op->in.parent_key, value_string );
556
557         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
558                 return CAC_FAILURE;
559         }
560
561         return CAC_SUCCESS;
562 }
563
564 #if 0
565
566 /* JRA - disabled until fix. */
567
568 /* This code is currently broken so disable it - it needs to handle the ERROR_MORE_DATA
569    cleanly and resubmit the query. */
570
571 int cac_RegQueryKeyInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
572                          struct RegQueryKeyInfo *op )
573 {
574         struct rpc_pipe_client *pipe_hnd = NULL;
575         WERROR err;
576
577         char *class_name_out = NULL;
578         uint32 class_len = 0;
579         uint32 num_subkeys_out = 0;
580         uint32 long_subkey_out = 0;
581         uint32 long_class_out = 0;
582         uint32 num_values_out = 0;
583         uint32 long_value_out = 0;
584         uint32 long_data_out = 0;
585         uint32 secdesc_size = 0;
586         NTTIME mod_time;
587
588         if ( !hnd )
589                 return CAC_FAILURE;
590
591         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
592                 hnd->status = NT_STATUS_INVALID_HANDLE;
593                 return CAC_FAILURE;
594         }
595
596         if ( !op || !op->in.key || !mem_ctx ) {
597                 hnd->status = NT_STATUS_INVALID_PARAMETER;
598                 return CAC_FAILURE;
599         }
600
601         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
602         if ( !pipe_hnd ) {
603                 hnd->status = NT_STATUS_INVALID_HANDLE;
604                 return CAC_FAILURE;
605         }
606
607         err = rpccli_reg_query_key( pipe_hnd, mem_ctx, op->in.key,
608                                     class_name_out,
609                                     &class_len,
610                                     &num_subkeys_out,
611                                     &long_subkey_out,
612                                     &long_class_out,
613                                     &num_values_out,
614                                     &long_value_out,
615                                     &long_data_out,
616                                     &secdesc_size, &mod_time );
617
618         hnd->status = werror_to_ntstatus( err );
619
620         if ( !NT_STATUS_IS_OK( hnd->status ) )
621                 return CAC_FAILURE;
622
623         if ( !class_name_out ) {
624                 op->out.class_name = talloc_strdup( mem_ctx, "" );
625         } else if ( class_len != 0 && class_name_out[class_len - 1] != '\0' ) {
626                 /*then we need to add a '\0' */
627                 op->out.class_name =
628                         talloc_size( mem_ctx,
629                                      sizeof( char ) * ( class_len + 1 ) );
630
631                 memcpy( op->out.class_name, class_name_out, class_len );
632
633                 op->out.class_name[class_len] = '\0';
634         } else {                /*then everything worked out fine in the function */
635                 op->out.class_name = talloc_strdup( mem_ctx, class_name_out );
636         }
637
638         if ( !op->out.class_name ) {
639                 hnd->status = NT_STATUS_NO_MEMORY;
640                 return CAC_FAILURE;
641         }
642
643         op->out.num_subkeys = num_subkeys_out;
644         op->out.longest_subkey = long_subkey_out;
645         op->out.longest_class = long_class_out;
646         op->out.num_values = num_values_out;
647         op->out.longest_value_name = long_value_out;
648         op->out.longest_value_data = long_data_out;
649         op->out.security_desc_size = secdesc_size;
650         op->out.last_write_time = nt_time_to_unix( &mod_time );
651
652         return CAC_FAILURE;
653 }
654 #endif
655
656 int cac_RegQueryValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
657                        struct RegQueryValue *op )
658 {
659         struct rpc_pipe_client *pipe_hnd = NULL;
660         struct winreg_String value_string;
661         REGVAL_BUFFER buffer;
662         REG_VALUE_DATA *data_out = NULL;
663         enum winreg_Type val_type;
664         uint8 *buf;
665         uint32 buf_size = 4096;
666         uint32 length = 0;
667
668         if ( !hnd )
669                 return CAC_FAILURE;
670
671         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
672                 hnd->status = NT_STATUS_INVALID_HANDLE;
673                 return CAC_FAILURE;
674         }
675
676         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
677                 hnd->status = NT_STATUS_INVALID_PARAMETER;
678                 return CAC_FAILURE;
679         }
680
681         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
682         if ( !pipe_hnd ) {
683                 hnd->status = NT_STATUS_INVALID_HANDLE;
684                 return CAC_FAILURE;
685         }
686
687         value_string.name = op->in.val_name;
688
689         if ( ( buf = TALLOC_ARRAY( mem_ctx, uint8, buf_size ) ) == NULL ) {
690                 hnd->status = NT_STATUS_NO_MEMORY;
691                 return CAC_FAILURE;
692         }
693
694         hnd->status = rpccli_winreg_QueryValue( pipe_hnd, mem_ctx, op->in.key,
695                                                 value_string, &val_type, buf,
696                                                 &buf_size, &length );
697
698         if ( !NT_STATUS_IS_OK( hnd->status ) )
699                 return CAC_FAILURE;
700
701         init_regval_buffer( &buffer, buf, length );
702
703         data_out = cac_MakeRegValueData( mem_ctx, val_type, buffer );
704         if ( !data_out ) {
705                 if ( errno == ENOMEM )
706                         hnd->status = NT_STATUS_NO_MEMORY;
707                 else
708                         hnd->status = NT_STATUS_INVALID_PARAMETER;
709
710                 return CAC_FAILURE;
711         }
712
713         op->out.type = val_type;
714         op->out.data = data_out;
715
716         return CAC_SUCCESS;
717 }
718
719
720 int cac_RegEnumValues( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
721                        struct RegEnumValues *op )
722 {
723         struct rpc_pipe_client *pipe_hnd = NULL;
724
725         /*buffers for rpccli_reg_enum_key call */
726         fstring val_name_buf;
727         REGVAL_BUFFER val_buf;
728
729         /*output buffers */
730         uint32 *types_out = NULL;
731         REG_VALUE_DATA **values_out = NULL;
732         char **val_names_out = NULL;
733         uint32 num_values_out = 0;
734         uint32 resume_idx = 0;
735
736         if ( !hnd )
737                 return CAC_FAILURE;
738
739         /*this is to avoid useless rpc calls, if the last call exhausted all the keys, then we don't need to go through everything again */
740         if ( NT_STATUS_V( hnd->status ) ==
741              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
742                 return CAC_FAILURE;
743
744         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
745                 hnd->status = NT_STATUS_INVALID_HANDLE;
746                 return CAC_FAILURE;
747         }
748
749         if ( !op || !op->in.key || op->in.max_values == 0 || !mem_ctx ) {
750                 hnd->status = NT_STATUS_INVALID_PARAMETER;
751                 return CAC_FAILURE;
752         }
753
754         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
755         if ( !pipe_hnd ) {
756                 hnd->status = NT_STATUS_INVALID_HANDLE;
757                 return CAC_FAILURE;
758         }
759
760         /*we need to assume that the max number of values will be enumerated */
761         types_out =
762                 ( uint32 * ) talloc_array( mem_ctx, int, op->in.max_values );
763         if ( !types_out ) {
764                 hnd->status = NT_STATUS_NO_MEMORY;
765                 return CAC_FAILURE;
766         }
767
768         values_out =
769                 talloc_array( mem_ctx, REG_VALUE_DATA *, op->in.max_values );
770         if ( !values_out ) {
771                 TALLOC_FREE( types_out );
772                 hnd->status = NT_STATUS_NO_MEMORY;
773                 return CAC_FAILURE;
774         }
775
776         val_names_out = talloc_array( mem_ctx, char *, op->in.max_values );
777         if ( !val_names_out ) {
778                 TALLOC_FREE( types_out );
779                 TALLOC_FREE( values_out );
780                 hnd->status = NT_STATUS_NO_MEMORY;
781                 return CAC_FAILURE;
782         }
783
784         resume_idx = op->out.resume_idx;
785         do {
786                 ZERO_STRUCT( val_buf );
787
788 #if 0
789                 hnd->status =
790                         rpccli_winreg_enum_val( pipe_hnd, mem_ctx, op->in.key,
791                                                 resume_idx, val_name_buf,
792                                                 &types_out[num_values_out],
793                                                 &val_buf );
794 #endif
795
796                 if ( !NT_STATUS_IS_OK( hnd->status ) )
797                         break;
798
799                 values_out[num_values_out] =
800                         cac_MakeRegValueData( mem_ctx,
801                                               types_out[num_values_out],
802                                               val_buf );
803                 val_names_out[num_values_out] =
804                         talloc_strdup( mem_ctx, val_name_buf );
805
806                 if ( !val_names_out[num_values_out]
807                      || !values_out[num_values_out] ) {
808                         hnd->status = NT_STATUS_NO_MEMORY;
809                         break;
810                 }
811
812                 num_values_out++;
813                 resume_idx++;
814         } while ( num_values_out < op->in.max_values );
815
816         if ( CAC_OP_FAILED( hnd->status ) )
817                 return CAC_FAILURE;
818
819         op->out.types = types_out;
820         op->out.num_values = num_values_out;
821         op->out.value_names = val_names_out;
822         op->out.values = values_out;
823         op->out.resume_idx = resume_idx;
824
825         return CAC_SUCCESS;
826 }
827
828 int cac_RegSetValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
829                      struct RegSetValue *op )
830 {
831         struct rpc_pipe_client *pipe_hnd = NULL;
832         struct winreg_String value_string;
833
834         RPC_DATA_BLOB *buffer;
835
836         if ( !hnd )
837                 return CAC_FAILURE;
838
839         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
840                 hnd->status = NT_STATUS_INVALID_HANDLE;
841                 return CAC_FAILURE;
842         }
843
844         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
845                 hnd->status = NT_STATUS_INVALID_PARAMETER;
846                 return CAC_FAILURE;
847         }
848
849         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
850         if ( !pipe_hnd ) {
851                 hnd->status = NT_STATUS_INVALID_HANDLE;
852                 return CAC_FAILURE;
853         }
854
855         buffer = cac_MakeRpcDataBlob( mem_ctx, op->in.type, op->in.value );
856
857         if ( !buffer ) {
858                 if ( errno == ENOMEM )
859                         hnd->status = NT_STATUS_NO_MEMORY;
860                 else
861                         hnd->status = NT_STATUS_INVALID_PARAMETER;
862
863                 return CAC_FAILURE;
864         }
865
866         value_string.name = op->in.val_name;
867         hnd->status =
868                 rpccli_winreg_SetValue( pipe_hnd, mem_ctx, op->in.key,
869                                         value_string, op->in.type,
870                                         buffer->buffer, buffer->buf_len );
871
872         if ( !NT_STATUS_IS_OK( hnd->status ) )
873                 return CAC_FAILURE;
874
875         /*flush */
876         hnd->status = rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, op->in.key );
877
878         if ( !NT_STATUS_IS_OK( hnd->status ) )
879                 return CAC_FAILURE;
880
881         return CAC_SUCCESS;
882 }
883
884
885
886 int cac_RegGetVersion( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
887                        struct RegGetVersion *op )
888 {
889         struct rpc_pipe_client *pipe_hnd = NULL;
890         uint32 version_out;
891
892         if ( !hnd )
893                 return CAC_FAILURE;
894
895         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
896                 hnd->status = NT_STATUS_INVALID_HANDLE;
897                 return CAC_FAILURE;
898         }
899
900         if ( !op || !op->in.key || !mem_ctx ) {
901                 hnd->status = NT_STATUS_INVALID_PARAMETER;
902                 return CAC_FAILURE;
903         }
904
905         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
906         if ( !pipe_hnd ) {
907                 hnd->status = NT_STATUS_INVALID_HANDLE;
908                 return CAC_FAILURE;
909         }
910
911         hnd->status =
912                 rpccli_winreg_GetVersion( pipe_hnd, mem_ctx, op->in.key,
913                                           &version_out );
914
915         if ( !NT_STATUS_IS_OK( hnd->status ) )
916                 return CAC_FAILURE;
917
918         op->out.version = version_out;
919
920         return CAC_SUCCESS;
921 }
922
923 int cac_RegGetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
924                            struct RegGetKeySecurity *op )
925 {
926         struct rpc_pipe_client *pipe_hnd = NULL;
927         struct KeySecurityData keysec;
928
929         ZERO_STRUCT( keysec );
930
931         if ( !hnd )
932                 return CAC_FAILURE;
933
934         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
935                 hnd->status = NT_STATUS_INVALID_HANDLE;
936                 return CAC_FAILURE;
937         }
938
939         if ( !op || !op->in.key || op->in.info_type == 0 || !mem_ctx ) {
940                 hnd->status = NT_STATUS_INVALID_PARAMETER;
941                 return CAC_FAILURE;
942         }
943
944         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
945         if ( !pipe_hnd ) {
946                 hnd->status = NT_STATUS_INVALID_HANDLE;
947                 return CAC_FAILURE;
948         }
949
950         hnd->status =
951                 rpccli_winreg_GetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
952                                               op->in.info_type, &keysec );
953
954         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
955                 return CAC_FAILURE;
956         }
957 #if 0                           /* FIX ME!!!!  unmarshall the security descriptor */
958         op->out.size = buf.sd_size;
959         op->out.descriptor = dup_sec_desc( mem_ctx, buf.sd );
960 #endif
961
962         if ( op->out.descriptor == NULL ) {
963                 return CAC_FAILURE;
964         }
965
966         return CAC_SUCCESS;
967 }
968
969 int cac_RegSetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
970                            struct RegSetKeySecurity *op )
971 {
972         struct rpc_pipe_client *pipe_hnd = NULL;
973         struct KeySecurityData keysec;
974
975         ZERO_STRUCT( keysec );
976
977         if ( !hnd )
978                 return CAC_FAILURE;
979
980         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
981                 hnd->status = NT_STATUS_INVALID_HANDLE;
982                 return CAC_FAILURE;
983         }
984
985         if ( !op || !op->in.key || op->in.info_type == 0 || op->in.size == 0
986              || !op->in.descriptor || !mem_ctx ) {
987                 hnd->status = NT_STATUS_INVALID_PARAMETER;
988                 return CAC_FAILURE;
989         }
990
991         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
992         if ( !pipe_hnd ) {
993                 hnd->status = NT_STATUS_INVALID_HANDLE;
994                 return CAC_FAILURE;
995         }
996
997         /* FIXME!!! Marshall in the input sec_desc to struct KeySecurityData */
998         hnd->status =
999                 rpccli_winreg_SetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1000                                               op->in.info_type, &keysec );
1001
1002         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1003                 return CAC_FAILURE;
1004         }
1005
1006         return CAC_SUCCESS;
1007 }
1008
1009 int cac_Shutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1010                   struct Shutdown *op )
1011 {
1012         SMBCSRV *srv = NULL;
1013         struct rpc_pipe_client *pipe_hnd = NULL;
1014         struct initshutdown_String msg_string;
1015         struct initshutdown_String_sub s;
1016
1017         char *msg;
1018
1019         if ( !hnd )
1020                 return CAC_FAILURE;
1021
1022         if ( !hnd->_internal.ctx ) {
1023                 hnd->status = NT_STATUS_INVALID_HANDLE;
1024                 return CAC_FAILURE;
1025         }
1026
1027         if ( !op || !mem_ctx ) {
1028                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1029                 return CAC_FAILURE;
1030         }
1031
1032         srv = cac_GetServer( hnd );
1033         if ( !srv ) {
1034                 hnd->status = NT_STATUS_INVALID_HANDLE;
1035                 return CAC_FAILURE;
1036         }
1037
1038         /*initialize for winreg pipe if we have to */
1039         if ( !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1040                 if ( !
1041                      ( pipe_hnd =
1042                        cli_rpc_pipe_open_noauth( srv->cli, PI_INITSHUTDOWN,
1043                                                  &( hnd->status ) ) ) ) {
1044                         return CAC_FAILURE;
1045                 }
1046
1047                 hnd->_internal.pipes[PI_INITSHUTDOWN] = True;
1048         }
1049
1050         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1051         if ( !pipe_hnd ) {
1052                 hnd->status = NT_STATUS_INVALID_HANDLE;
1053                 return CAC_FAILURE;
1054         }
1055
1056         msg = ( op->in.message !=
1057                 NULL ) ? op->in.message : talloc_strdup( mem_ctx, "" );
1058         msg_string.name = &s;
1059         msg_string.name->name = msg;
1060
1061         hnd->status = NT_STATUS_OK;
1062
1063         if ( hnd->_internal.srv_level > SRV_WIN_NT4 ) {
1064                 hnd->status =
1065                         rpccli_initshutdown_InitEx( pipe_hnd, mem_ctx, NULL,
1066                                                     &msg_string,
1067                                                     op->in.timeout,
1068                                                     op->in.reboot,
1069                                                     op->in.force,
1070                                                     op->in.reason );
1071         }
1072
1073         if ( hnd->_internal.srv_level < SRV_WIN_2K
1074              || !NT_STATUS_IS_OK( hnd->status ) ) {
1075                 hnd->status =
1076                         rpccli_initshutdown_Init( pipe_hnd, mem_ctx, NULL,
1077                                                   &msg_string, op->in.timeout,
1078                                                   op->in.reboot,
1079                                                   op->in.force );
1080
1081                 hnd->_internal.srv_level = SRV_WIN_NT4;
1082         }
1083
1084         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1085                 return CAC_FAILURE;
1086         }
1087
1088         return CAC_SUCCESS;
1089 }
1090
1091 int cac_AbortShutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx )
1092 {
1093         struct rpc_pipe_client *pipe_hnd = NULL;
1094
1095         if ( !hnd )
1096                 return CAC_FAILURE;
1097
1098         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1099                 hnd->status = NT_STATUS_INVALID_HANDLE;
1100                 return CAC_FAILURE;
1101         }
1102
1103         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1104         if ( !pipe_hnd ) {
1105                 hnd->status = NT_STATUS_INVALID_HANDLE;
1106                 return CAC_FAILURE;
1107         }
1108
1109         hnd->status = rpccli_initshutdown_Abort( pipe_hnd, mem_ctx, NULL );
1110
1111         if ( !NT_STATUS_IS_OK( hnd->status ) )
1112                 return CAC_FAILURE;
1113
1114         return CAC_SUCCESS;
1115 }