r25598: Add missing become_root/unbecome_root around calls of add_aliases.
[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 3 of the License, or
10  *  (at your option) any later version.
11  *  
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "libmsrpc.h"
22 #include "libmsrpc_internal.h"
23
24 NTSTATUS cac_delete_subkeys_recursive(struct rpc_pipe_client * pipe_hnd,
25                                       TALLOC_CTX * mem_ctx, POLICY_HND * key);
26
27 int cac_RegConnect( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
28                     struct RegConnect *op )
29 {
30         SMBCSRV *srv = NULL;
31         struct rpc_pipe_client *pipe_hnd = NULL;
32         POLICY_HND *key = NULL;
33
34         if ( !hnd )
35                 return CAC_FAILURE;
36
37         if ( !hnd->_internal.ctx ) {
38                 hnd->status = NT_STATUS_INVALID_HANDLE;
39                 return CAC_FAILURE;
40         }
41
42         if ( !op || !op->in.root || !mem_ctx ) {
43                 hnd->status = NT_STATUS_INVALID_PARAMETER;
44                 return CAC_FAILURE;
45         }
46
47         srv = cac_GetServer( hnd );
48         if ( !srv ) {
49                 hnd->status = NT_STATUS_INVALID_CONNECTION;
50                 return CAC_FAILURE;
51         }
52
53         /*initialize for winreg pipe if we have to */
54         if ( !hnd->_internal.pipes[PI_WINREG] ) {
55                 if ( !
56                      ( pipe_hnd =
57                        cli_rpc_pipe_open_noauth( srv->cli, PI_WINREG,
58                                                  &hnd->status ) ) ) {
59                         return CAC_FAILURE;
60                 }
61
62                 hnd->_internal.pipes[PI_WINREG] = True;
63         }
64
65         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
66         if ( !pipe_hnd ) {
67                 hnd->status = NT_STATUS_INVALID_HANDLE;
68                 return CAC_FAILURE;
69         }
70
71         key = talloc( mem_ctx, POLICY_HND );
72         if ( !key ) {
73                 hnd->status = NT_STATUS_NO_MEMORY;
74                 return CAC_FAILURE;
75         }
76
77         hnd->status =
78                 rpccli_winreg_Connect( pipe_hnd, mem_ctx, op->in.root,
79                                        op->in.access, key );
80
81         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
82                 return CAC_FAILURE;
83         }
84
85         op->out.key = key;
86
87         return CAC_SUCCESS;
88 }
89
90 int cac_RegClose( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
91                   POLICY_HND * key )
92 {
93         struct rpc_pipe_client *pipe_hnd = NULL;
94
95         if ( !hnd )
96                 return CAC_FAILURE;
97
98         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
99                 hnd->status = NT_STATUS_INVALID_HANDLE;
100                 return CAC_FAILURE;
101         }
102
103         if ( !key || !mem_ctx ) {
104                 hnd->status = NT_STATUS_INVALID_PARAMETER;
105                 return CAC_FAILURE;
106         }
107
108         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
109         if ( !pipe_hnd ) {
110                 hnd->status = NT_STATUS_INVALID_HANDLE;
111                 return CAC_FAILURE;
112         }
113
114         hnd->status = rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, key );
115
116         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
117                 return CAC_FAILURE;
118         }
119
120         return CAC_SUCCESS;
121 }
122
123 int cac_RegOpenKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
124                     struct RegOpenKey *op )
125 {
126         struct rpc_pipe_client *pipe_hnd = NULL;
127         struct winreg_String key_string;
128
129         POLICY_HND *key_out;
130         POLICY_HND *parent_key;
131
132         char *key_name = NULL;
133         uint32 reg_type = 0;
134
135         struct RegConnect rc;
136
137         if ( !hnd )
138                 return CAC_FAILURE;
139
140         if ( !hnd->_internal.ctx ) {
141                 hnd->status = NT_STATUS_INVALID_HANDLE;
142                 return CAC_FAILURE;
143         }
144
145         if ( !op || !op->in.name || !mem_ctx ) {
146                 hnd->status = NT_STATUS_INVALID_PARAMETER;
147                 return CAC_FAILURE;
148         }
149
150
151         key_out = talloc( mem_ctx, POLICY_HND );
152         if ( !key_out ) {
153                 hnd->status = NT_STATUS_NO_MEMORY;
154                 return CAC_FAILURE;
155         }
156
157         if ( !op->in.parent_key ) {
158                 /*then we need to connect to the registry */
159                 if ( !cac_ParseRegPath( op->in.name, &reg_type, &key_name ) ) {
160                         hnd->status = NT_STATUS_INVALID_PARAMETER;
161                         return CAC_FAILURE;
162                 }
163
164                 /*use cac_RegConnect because it handles the session setup */
165                 ZERO_STRUCT( rc );
166
167                 rc.in.access = op->in.access;
168                 rc.in.root = reg_type;
169
170                 if ( !cac_RegConnect( hnd, mem_ctx, &rc ) ) {
171                         return CAC_FAILURE;
172                 }
173
174       /**if they only specified the root key, return the key we just opened*/
175                 if ( key_name == NULL ) {
176                         op->out.key = rc.out.key;
177                         return CAC_SUCCESS;
178                 }
179
180                 parent_key = rc.out.key;
181         } else {
182                 parent_key = op->in.parent_key;
183                 key_name = op->in.name;
184         }
185
186         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
187         if ( !pipe_hnd ) {
188                 hnd->status = NT_STATUS_INVALID_HANDLE;
189                 return CAC_FAILURE;
190         }
191
192         key_string.name = key_name;
193         hnd->status =
194                 rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, parent_key,
195                                        key_string, 0, op->in.access,
196                                        key_out );
197
198         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
199                 return CAC_FAILURE;
200         }
201
202         if ( !op->in.parent_key ) {
203                 /*then close the one that we opened above */
204                 hnd->status =
205                         rpccli_winreg_CloseKey( pipe_hnd, mem_ctx,
206                                                 parent_key );
207
208                 if ( !NT_STATUS_IS_OK( hnd->status ) ) {
209                         return CAC_FAILURE;
210                 }
211         }
212
213         op->out.key = key_out;
214
215         return CAC_SUCCESS;
216 }
217
218 int cac_RegEnumKeys( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
219                      struct RegEnumKeys *op )
220 {
221         struct rpc_pipe_client *pipe_hnd = NULL;
222
223         /*buffers for rpccli_reg_enum_key call */
224         fstring key_name_in;
225         fstring class_name_in;
226
227         /*output buffers */
228         char **key_names_out = NULL;
229         char **class_names_out = NULL;
230         time_t *mod_times_out = NULL;
231         uint32 num_keys_out = 0;
232         uint32 resume_idx = 0;
233
234         if ( !hnd )
235                 return CAC_FAILURE;
236
237         /* This is to avoid useless rpc calls, if the last call 
238            exhausted all the keys, then we don't need to go 
239            through everything again */
240
241         if ( NT_STATUS_V( hnd->status ) ==
242              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
243                 return CAC_FAILURE;
244
245         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
246                 hnd->status = NT_STATUS_INVALID_HANDLE;
247                 return CAC_FAILURE;
248         }
249
250         if ( !op || op->in.max_keys == 0 || !mem_ctx ) {
251                 hnd->status = NT_STATUS_INVALID_PARAMETER;
252                 return CAC_FAILURE;
253         }
254
255         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
256         if ( !pipe_hnd ) {
257                 hnd->status = NT_STATUS_INVALID_HANDLE;
258                 return CAC_FAILURE;
259         }
260
261         /* The only way to know how many keys to expect is to 
262            assume max_keys keys will be found */
263
264         key_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
265         if ( !key_names_out ) {
266                 hnd->status = NT_STATUS_NO_MEMORY;
267                 return CAC_FAILURE;
268         }
269
270         class_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
271         if ( !class_names_out ) {
272                 hnd->status = NT_STATUS_NO_MEMORY;
273                 TALLOC_FREE( key_names_out );
274                 return CAC_FAILURE;
275         }
276
277         mod_times_out = TALLOC_ARRAY( mem_ctx, time_t, op->in.max_keys );
278         if ( !mod_times_out ) {
279                 hnd->status = NT_STATUS_NO_MEMORY;
280                 TALLOC_FREE( key_names_out );
281                 TALLOC_FREE( class_names_out );
282
283                 return CAC_FAILURE;
284         }
285
286         resume_idx = op->out.resume_idx;
287
288         do {
289 #if 0
290                 hnd->status =
291                         rpccli_winreg_EnumKey( pipe_hnd, mem_ctx, op->in.key,
292                                                 resume_idx, key_name_in,
293                                                 class_name_in,
294                                                 &mod_times_out );
295 #endif
296
297                 if ( !NT_STATUS_IS_OK( hnd->status ) ) {
298                         /*don't increment any values */
299                         break;
300                 }
301
302                 key_names_out[num_keys_out] =
303                         talloc_strdup( mem_ctx, key_name_in );
304
305                 class_names_out[num_keys_out] =
306                         talloc_strdup( mem_ctx, class_name_in );
307
308                 if ( !key_names_out[num_keys_out]
309                      || !class_names_out[num_keys_out] ) {
310                         hnd->status = NT_STATUS_NO_MEMORY;
311                         break;
312                 }
313
314                 resume_idx++;
315                 num_keys_out++;
316         } while ( num_keys_out < op->in.max_keys );
317
318         if ( CAC_OP_FAILED( hnd->status ) ) {
319                 op->out.num_keys = 0;
320                 return CAC_FAILURE;
321         }
322
323         op->out.resume_idx = resume_idx;
324         op->out.num_keys = num_keys_out;
325         op->out.key_names = key_names_out;
326         op->out.class_names = class_names_out;
327         op->out.mod_times = mod_times_out;
328
329         return CAC_SUCCESS;
330 }
331
332 int cac_RegCreateKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
333                       struct RegCreateKey *op )
334 {
335         struct rpc_pipe_client *pipe_hnd = NULL;
336         POLICY_HND *key_out;
337         struct RegOpenKey rok;
338         struct winreg_String key_string, class_string;
339         enum winreg_CreateAction action = 0;
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                                          &action );
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         uint8 *buf;
676         uint32 buf_size = 4096;
677         uint32 length = 0;
678
679         if ( !hnd )
680                 return CAC_FAILURE;
681
682         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
683                 hnd->status = NT_STATUS_INVALID_HANDLE;
684                 return CAC_FAILURE;
685         }
686
687         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
688                 hnd->status = NT_STATUS_INVALID_PARAMETER;
689                 return CAC_FAILURE;
690         }
691
692         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
693         if ( !pipe_hnd ) {
694                 hnd->status = NT_STATUS_INVALID_HANDLE;
695                 return CAC_FAILURE;
696         }
697
698         value_string.name = op->in.val_name;
699
700         if ( ( buf = TALLOC_ARRAY( mem_ctx, uint8, buf_size ) ) == NULL ) {
701                 hnd->status = NT_STATUS_NO_MEMORY;
702                 return CAC_FAILURE;
703         }
704
705         hnd->status = rpccli_winreg_QueryValue( pipe_hnd, mem_ctx, op->in.key,
706                                                 value_string, &val_type, buf,
707                                                 &buf_size, &length );
708
709         if ( !NT_STATUS_IS_OK( hnd->status ) )
710                 return CAC_FAILURE;
711
712         init_regval_buffer( &buffer, buf, length );
713
714         data_out = cac_MakeRegValueData( mem_ctx, val_type, buffer );
715         if ( !data_out ) {
716                 if ( errno == ENOMEM )
717                         hnd->status = NT_STATUS_NO_MEMORY;
718                 else
719                         hnd->status = NT_STATUS_INVALID_PARAMETER;
720
721                 return CAC_FAILURE;
722         }
723
724         op->out.type = val_type;
725         op->out.data = data_out;
726
727         return CAC_SUCCESS;
728 }
729
730
731 int cac_RegEnumValues( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
732                        struct RegEnumValues *op )
733 {
734         struct rpc_pipe_client *pipe_hnd = NULL;
735         char *name_buffer;
736         REGVAL_BUFFER val_buf;
737         uint32 *types_out = NULL;
738         REG_VALUE_DATA **values_out = NULL;
739         char **val_names_out = NULL;
740         uint32 num_values_out = 0;
741         uint32 resume_idx = 0;
742         uint32 num_subkeys, max_subkeylen, max_classlen;
743         uint32 num_values, max_valnamelen, maxvalbufsize;
744         struct winreg_String class_string;
745         NTTIME modtime;
746         uint32 secdescsize;
747         uint8 *buffer;
748
749         if ( !hnd )
750                 return CAC_FAILURE;
751
752         /* This is to avoid useless rpc calls, if the last 
753            call exhausted all the keys, then we don't need 
754            to go through everything again */
755
756         if ( NT_STATUS_V( hnd->status ) ==
757              NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
758                 return CAC_FAILURE;
759
760         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
761                 hnd->status = NT_STATUS_INVALID_HANDLE;
762                 return CAC_FAILURE;
763         }
764
765         if ( !op || !op->in.key || op->in.max_values == 0 || !mem_ctx ) {
766                 hnd->status = NT_STATUS_INVALID_PARAMETER;
767                 return CAC_FAILURE;
768         }
769
770         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
771         if ( !pipe_hnd ) {
772                 hnd->status = NT_STATUS_INVALID_HANDLE;
773                 return CAC_FAILURE;
774         }
775
776         /*we need to assume that the max number of values will be enumerated */
777         types_out = TALLOC_ARRAY( mem_ctx, uint32, op->in.max_values );
778
779         if ( !types_out ) {
780                 hnd->status = NT_STATUS_NO_MEMORY;
781                 return CAC_FAILURE;
782         }
783
784         values_out = TALLOC_ARRAY( mem_ctx, REG_VALUE_DATA *, 
785                                    op->in.max_values );
786
787         if ( !values_out ) {
788                 TALLOC_FREE( types_out );
789                 hnd->status = NT_STATUS_NO_MEMORY;
790                 return CAC_FAILURE;
791         }
792
793         val_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_values );
794
795         if ( !val_names_out ) {
796                 TALLOC_FREE( types_out );
797                 TALLOC_FREE( values_out );
798                 hnd->status = NT_STATUS_NO_MEMORY;
799                 return CAC_FAILURE;
800         }
801
802         resume_idx = op->out.resume_idx;
803
804         class_string.name = NULL;
805         hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, op->in.key, 
806                                              &class_string, &num_subkeys, 
807                                              &max_subkeylen, &max_classlen,
808                                              &num_values, &max_valnamelen,
809                                              &maxvalbufsize, &secdescsize, 
810                                              &modtime );
811
812         if ( !NT_STATUS_IS_OK(hnd->status) ) {
813                 TALLOC_FREE( types_out );
814                 TALLOC_FREE( values_out );
815
816                 return CAC_FAILURE;
817         }
818
819         if ( (buffer = TALLOC_ARRAY( mem_ctx, uint8, maxvalbufsize )) == NULL ) {
820                 TALLOC_FREE( types_out );
821                 TALLOC_FREE( values_out );
822                 hnd->status = NT_STATUS_NO_MEMORY;
823
824                 return CAC_FAILURE;
825         }
826
827         if ( (name_buffer = TALLOC_ARRAY(mem_ctx, char, max_valnamelen)) == NULL ) {
828                 TALLOC_FREE( types_out );
829                 TALLOC_FREE( values_out );
830                 TALLOC_FREE( buffer );
831                 hnd->status = NT_STATUS_NO_MEMORY;
832
833                 return CAC_FAILURE;
834         }
835                 
836         do {
837                 uint32 data_size = maxvalbufsize;
838                 uint32 data_length = 0;
839                 struct winreg_ValNameBuf name_buf;
840
841                 memset( name_buffer, 0x0, max_valnamelen );
842                 name_buf.name = name_buffer;
843                 name_buf.size = max_valnamelen;
844                 name_buf.length = 0;
845                 
846                 hnd->status = rpccli_winreg_EnumValue( pipe_hnd, mem_ctx, 
847                                                        op->in.key,
848                                                        resume_idx, &name_buf,
849                                                        &types_out[num_values_out], buffer,
850                                                        &data_size,
851                                                        &data_length );
852
853                 if ( !NT_STATUS_IS_OK( hnd->status ) )
854                         break;
855
856                 ZERO_STRUCT( val_buf );
857                 init_regval_buffer(  &val_buf, buffer, data_length );
858
859                 values_out[num_values_out] = cac_MakeRegValueData( mem_ctx,
860                                                                    types_out[num_values_out],
861                                                                    val_buf );
862                 val_names_out[num_values_out] = TALLOC_ARRAY( mem_ctx, char, name_buf.length+1 );
863
864                 if ( !val_names_out[num_values_out]
865                      || !values_out[num_values_out] ) {
866                         hnd->status = NT_STATUS_NO_MEMORY;
867                         break;
868                 }
869
870                 StrnCpy( val_names_out[num_values_out], name_buf.name, name_buf.length );
871                 (val_names_out[num_values_out])[name_buf.length] = '\0';
872
873                 num_values_out++;
874                 resume_idx++;
875         } while ( num_values_out < op->in.max_values );
876
877         if ( CAC_OP_FAILED( hnd->status ) )
878                 return CAC_FAILURE;
879
880         op->out.types = types_out;
881         op->out.num_values = num_values_out;
882         op->out.value_names = val_names_out;
883         op->out.values = values_out;
884         op->out.resume_idx = resume_idx;
885
886         return CAC_SUCCESS;
887 }
888
889 int cac_RegSetValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
890                      struct RegSetValue *op )
891 {
892         struct rpc_pipe_client *pipe_hnd = NULL;
893         struct winreg_String value_string;
894
895         RPC_DATA_BLOB *buffer;
896
897         if ( !hnd )
898                 return CAC_FAILURE;
899
900         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
901                 hnd->status = NT_STATUS_INVALID_HANDLE;
902                 return CAC_FAILURE;
903         }
904
905         if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
906                 hnd->status = NT_STATUS_INVALID_PARAMETER;
907                 return CAC_FAILURE;
908         }
909
910         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
911         if ( !pipe_hnd ) {
912                 hnd->status = NT_STATUS_INVALID_HANDLE;
913                 return CAC_FAILURE;
914         }
915
916         buffer = cac_MakeRpcDataBlob( mem_ctx, op->in.type, op->in.value );
917
918         if ( !buffer ) {
919                 if ( errno == ENOMEM )
920                         hnd->status = NT_STATUS_NO_MEMORY;
921                 else
922                         hnd->status = NT_STATUS_INVALID_PARAMETER;
923
924                 return CAC_FAILURE;
925         }
926
927         value_string.name = op->in.val_name;
928         hnd->status =
929                 rpccli_winreg_SetValue( pipe_hnd, mem_ctx, op->in.key,
930                                         value_string, op->in.type,
931                                         buffer->buffer, buffer->buf_len );
932
933         if ( !NT_STATUS_IS_OK( hnd->status ) )
934                 return CAC_FAILURE;
935
936         /*flush */
937         hnd->status = rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, op->in.key );
938
939         if ( !NT_STATUS_IS_OK( hnd->status ) )
940                 return CAC_FAILURE;
941
942         return CAC_SUCCESS;
943 }
944
945
946
947 int cac_RegGetVersion( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
948                        struct RegGetVersion *op )
949 {
950         struct rpc_pipe_client *pipe_hnd = NULL;
951         uint32 version_out;
952
953         if ( !hnd )
954                 return CAC_FAILURE;
955
956         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
957                 hnd->status = NT_STATUS_INVALID_HANDLE;
958                 return CAC_FAILURE;
959         }
960
961         if ( !op || !op->in.key || !mem_ctx ) {
962                 hnd->status = NT_STATUS_INVALID_PARAMETER;
963                 return CAC_FAILURE;
964         }
965
966         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
967         if ( !pipe_hnd ) {
968                 hnd->status = NT_STATUS_INVALID_HANDLE;
969                 return CAC_FAILURE;
970         }
971
972         hnd->status =
973                 rpccli_winreg_GetVersion( pipe_hnd, mem_ctx, op->in.key,
974                                           &version_out );
975
976         if ( !NT_STATUS_IS_OK( hnd->status ) )
977                 return CAC_FAILURE;
978
979         op->out.version = version_out;
980
981         return CAC_SUCCESS;
982 }
983
984 int cac_RegGetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
985                            struct RegGetKeySecurity *op )
986 {
987         struct rpc_pipe_client *pipe_hnd = NULL;
988         struct KeySecurityData keysec;
989
990         ZERO_STRUCT( keysec );
991
992         if ( !hnd )
993                 return CAC_FAILURE;
994
995         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
996                 hnd->status = NT_STATUS_INVALID_HANDLE;
997                 return CAC_FAILURE;
998         }
999
1000         if ( !op || !op->in.key || op->in.info_type == 0 || !mem_ctx ) {
1001                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1002                 return CAC_FAILURE;
1003         }
1004
1005         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
1006         if ( !pipe_hnd ) {
1007                 hnd->status = NT_STATUS_INVALID_HANDLE;
1008                 return CAC_FAILURE;
1009         }
1010
1011         hnd->status =
1012                 rpccli_winreg_GetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1013                                               op->in.info_type, &keysec );
1014
1015         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1016                 return CAC_FAILURE;
1017         }
1018
1019 #if 0   /* FIX ME!!!!  unmarshall the security descriptor */
1020         op->out.size = buf.sd_size;
1021         op->out.descriptor = dup_sec_desc( mem_ctx, buf.sd );
1022 #endif
1023
1024         if ( op->out.descriptor == NULL ) {
1025                 return CAC_FAILURE;
1026         }
1027
1028         return CAC_SUCCESS;
1029 }
1030
1031 int cac_RegSetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1032                            struct RegSetKeySecurity *op )
1033 {
1034         struct rpc_pipe_client *pipe_hnd = NULL;
1035         struct KeySecurityData keysec;
1036
1037         ZERO_STRUCT( keysec );
1038
1039         if ( !hnd )
1040                 return CAC_FAILURE;
1041
1042         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
1043                 hnd->status = NT_STATUS_INVALID_HANDLE;
1044                 return CAC_FAILURE;
1045         }
1046
1047         if ( !op || !op->in.key || op->in.info_type == 0 || op->in.size == 0
1048              || !op->in.descriptor || !mem_ctx ) {
1049                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1050                 return CAC_FAILURE;
1051         }
1052
1053         pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
1054         if ( !pipe_hnd ) {
1055                 hnd->status = NT_STATUS_INVALID_HANDLE;
1056                 return CAC_FAILURE;
1057         }
1058
1059         /* FIXME!!! Marshall in the input sec_desc to struct KeySecurityData */
1060         hnd->status =
1061                 rpccli_winreg_SetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
1062                                               op->in.info_type, &keysec );
1063
1064         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1065                 return CAC_FAILURE;
1066         }
1067
1068         return CAC_SUCCESS;
1069 }
1070
1071 int cac_Shutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1072                   struct Shutdown *op )
1073 {
1074         SMBCSRV *srv = NULL;
1075         struct rpc_pipe_client *pipe_hnd = NULL;
1076         struct initshutdown_String msg_string;
1077         struct initshutdown_String_sub s;
1078
1079         char *msg;
1080
1081         if ( !hnd )
1082                 return CAC_FAILURE;
1083
1084         if ( !hnd->_internal.ctx ) {
1085                 hnd->status = NT_STATUS_INVALID_HANDLE;
1086                 return CAC_FAILURE;
1087         }
1088
1089         if ( !op || !mem_ctx ) {
1090                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1091                 return CAC_FAILURE;
1092         }
1093
1094         srv = cac_GetServer( hnd );
1095         if ( !srv ) {
1096                 hnd->status = NT_STATUS_INVALID_HANDLE;
1097                 return CAC_FAILURE;
1098         }
1099
1100         /*initialize for winreg pipe if we have to */
1101         if ( !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1102                 if ( !
1103                      ( pipe_hnd =
1104                        cli_rpc_pipe_open_noauth( srv->cli, PI_INITSHUTDOWN,
1105                                                  &( hnd->status ) ) ) ) {
1106                         return CAC_FAILURE;
1107                 }
1108
1109                 hnd->_internal.pipes[PI_INITSHUTDOWN] = True;
1110         }
1111
1112         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1113         if ( !pipe_hnd ) {
1114                 hnd->status = NT_STATUS_INVALID_HANDLE;
1115                 return CAC_FAILURE;
1116         }
1117
1118         msg = ( op->in.message !=
1119                 NULL ) ? op->in.message : talloc_strdup( mem_ctx, "" );
1120         msg_string.name = &s;
1121         msg_string.name->name = msg;
1122
1123         hnd->status = NT_STATUS_OK;
1124
1125         if ( hnd->_internal.srv_level > SRV_WIN_NT4 ) {
1126                 hnd->status =
1127                         rpccli_initshutdown_InitEx( pipe_hnd, mem_ctx, NULL,
1128                                                     &msg_string,
1129                                                     op->in.timeout,
1130                                                     op->in.reboot,
1131                                                     op->in.force,
1132                                                     op->in.reason );
1133         }
1134
1135         if ( hnd->_internal.srv_level < SRV_WIN_2K
1136              || !NT_STATUS_IS_OK( hnd->status ) ) {
1137                 hnd->status =
1138                         rpccli_initshutdown_Init( pipe_hnd, mem_ctx, NULL,
1139                                                   &msg_string, op->in.timeout,
1140                                                   op->in.reboot,
1141                                                   op->in.force );
1142
1143                 hnd->_internal.srv_level = SRV_WIN_NT4;
1144         }
1145
1146         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1147                 return CAC_FAILURE;
1148         }
1149
1150         return CAC_SUCCESS;
1151 }
1152
1153 int cac_AbortShutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx )
1154 {
1155         struct rpc_pipe_client *pipe_hnd = NULL;
1156
1157         if ( !hnd )
1158                 return CAC_FAILURE;
1159
1160         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
1161                 hnd->status = NT_STATUS_INVALID_HANDLE;
1162                 return CAC_FAILURE;
1163         }
1164
1165         pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
1166         if ( !pipe_hnd ) {
1167                 hnd->status = NT_STATUS_INVALID_HANDLE;
1168                 return CAC_FAILURE;
1169         }
1170
1171         hnd->status = rpccli_initshutdown_Abort( pipe_hnd, mem_ctx, NULL );
1172
1173         if ( !NT_STATUS_IS_OK( hnd->status ) )
1174                 return CAC_FAILURE;
1175
1176         return CAC_SUCCESS;
1177 }