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