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