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