2 * Unix SMB/CIFS implementation.
3 * MS-RPC client library implementation (WINREG pipe)
4 * Copyright (C) Chris Nicholls 2005.
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.
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.
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.
22 #include "libmsrpc_internal.h"
25 int cac_RegConnect(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegConnect *op) {
27 struct rpc_pipe_client *pipe_hnd = NULL;
28 POLICY_HND *key = NULL;
34 if(!hnd->_internal.ctx) {
35 hnd->status = NT_STATUS_INVALID_HANDLE;
39 if(!op || !op->in.root || !mem_ctx) {
40 hnd->status = NT_STATUS_INVALID_PARAMETER;
44 srv = cac_GetServer(hnd);
46 hnd->status = NT_STATUS_INVALID_CONNECTION;
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))) {
56 hnd->_internal.pipes[PI_WINREG] = True;
59 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
61 hnd->status = NT_STATUS_INVALID_HANDLE;
65 key = talloc(mem_ctx, POLICY_HND);
67 hnd->status = NT_STATUS_NO_MEMORY;
71 err = rpccli_reg_connect( pipe_hnd, mem_ctx, op->in.root, op->in.access, key);
72 hnd->status = werror_to_ntstatus(err);
74 if(!NT_STATUS_IS_OK(hnd->status)) {
83 int cac_RegClose(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, POLICY_HND *key) {
84 struct rpc_pipe_client *pipe_hnd = NULL;
90 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
91 hnd->status = NT_STATUS_INVALID_HANDLE;
95 if(!key || !mem_ctx) {
96 hnd->status = NT_STATUS_INVALID_PARAMETER;
100 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
102 hnd->status = NT_STATUS_INVALID_HANDLE;
106 err = rpccli_reg_close(pipe_hnd, mem_ctx, key);
107 hnd->status = werror_to_ntstatus(err);
109 if(!NT_STATUS_IS_OK(hnd->status)) {
116 int cac_RegOpenKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegOpenKey *op) {
117 struct rpc_pipe_client *pipe_hnd = NULL;
121 POLICY_HND *parent_key;
123 char *key_name = NULL;
126 struct RegConnect rc;
131 if(!hnd->_internal.ctx) {
132 hnd->status = NT_STATUS_INVALID_HANDLE;
136 if(!op || !op->in.name || !mem_ctx) {
137 hnd->status = NT_STATUS_INVALID_PARAMETER;
142 key_out = talloc(mem_ctx, POLICY_HND);
144 hnd->status = NT_STATUS_NO_MEMORY;
148 if(!op->in.parent_key) {
149 /*then we need to connect to the registry*/
150 if(!cac_ParseRegPath(op->in.name, ®_type, &key_name)) {
151 hnd->status = NT_STATUS_INVALID_PARAMETER;
155 /*use cac_RegConnect because it handles the session setup*/
158 rc.in.access = op->in.access;
159 rc.in.root = reg_type;
161 if(!cac_RegConnect(hnd, mem_ctx, &rc)) {
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;
171 parent_key = rc.out.key;
174 parent_key = op->in.parent_key;
175 key_name = op->in.name;
178 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
180 hnd->status = NT_STATUS_INVALID_HANDLE;
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);
187 if(!NT_STATUS_IS_OK(hnd->status)) {
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);
196 if(!NT_STATUS_IS_OK(hnd->status)) {
201 op->out.key = key_out;
206 int cac_RegEnumKeys(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumKeys *op) {
207 struct rpc_pipe_client *pipe_hnd = NULL;
210 /*buffers for rpccli_reg_enum_key call*/
212 fstring class_name_in;
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;
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))
228 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
229 hnd->status = NT_STATUS_INVALID_HANDLE;
233 if(!op || op->in.max_keys == 0 || !mem_ctx) {
234 hnd->status = NT_STATUS_INVALID_PARAMETER;
238 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
240 hnd->status = NT_STATUS_INVALID_HANDLE;
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);
247 hnd->status = NT_STATUS_NO_MEMORY;
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);
258 mod_times_out = TALLOC_ARRAY(mem_ctx, time_t, op->in.max_keys);
260 hnd->status = NT_STATUS_NO_MEMORY;
261 TALLOC_FREE(key_names_out);
262 TALLOC_FREE(class_names_out);
267 resume_idx = op->out.resume_idx;
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);
273 if(!NT_STATUS_IS_OK(hnd->status)) {
274 /*don't increment any values*/
278 key_names_out[num_keys_out] = talloc_strdup(mem_ctx, key_name_in);
280 class_names_out[num_keys_out] = talloc_strdup(mem_ctx, class_name_in);
282 if(!key_names_out[num_keys_out] || !class_names_out[num_keys_out]) {
283 hnd->status = NT_STATUS_NO_MEMORY;
289 } while(num_keys_out < op->in.max_keys);
291 if(CAC_OP_FAILED(hnd->status)) {
292 op->out.num_keys = 0;
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;
305 int cac_RegCreateKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegCreateKey *op) {
306 struct rpc_pipe_client *pipe_hnd = NULL;
311 struct RegOpenKey rok;
316 if(!hnd->_internal.ctx) {
317 hnd->status = NT_STATUS_INVALID_HANDLE;
321 if(!op || !op->in.parent_key || !op->in.key_name || !mem_ctx) {
322 hnd->status = NT_STATUS_INVALID_PARAMETER;
326 /*first try to open the key - we use cac_RegOpenKey(). this doubles as a way to ensure the winreg pipe is initialized*/
329 rok.in.name = op->in.key_name;
330 rok.in.access = op->in.access;
331 rok.in.parent_key = op->in.parent_key;
333 if(cac_RegOpenKey(hnd, mem_ctx, &rok)) {
334 /*then we got the key, return*/
335 op->out.key = rok.out.key;
339 /*just be ultra-safe*/
340 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
342 hnd->status = NT_STATUS_INVALID_HANDLE;
346 key_out = talloc(mem_ctx, POLICY_HND);
348 hnd->status = NT_STATUS_NO_MEMORY;
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);
355 if(!NT_STATUS_IS_OK(hnd->status)) {
359 op->out.key = key_out;
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*/
369 WERROR err = WERR_OK;
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);
381 if(!W_ERROR_IS_OK(err))
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);
387 if(!W_ERROR_IS_OK(err))
390 err = cac_delete_subkeys_recursive(pipe_hnd, mem_ctx, &subkey);
392 if(!W_ERROR_EQUAL(err,WERR_NO_MORE_ITEMS) && !W_ERROR_IS_OK(err))
395 /*flush the key just to be safe*/
396 rpccli_reg_flush_key(pipe_hnd, mem_ctx, key);
398 /*close the key that we opened*/
399 rpccli_reg_close(pipe_hnd, mem_ctx, &subkey);
401 /*now we delete the subkey*/
402 err = rpccli_reg_delete_key(pipe_hnd, mem_ctx, key, subkey_name);
414 int cac_RegDeleteKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteKey *op) {
415 struct rpc_pipe_client *pipe_hnd = NULL;
421 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
422 hnd->status = NT_STATUS_INVALID_HANDLE;
426 if(!op || !op->in.parent_key || !op->in.name || !mem_ctx) {
427 hnd->status = NT_STATUS_INVALID_PARAMETER;
431 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
433 hnd->status = NT_STATUS_INVALID_HANDLE;
437 if(op->in.recursive) {
438 /*first open the key, and then delete all of it's subkeys recursively*/
439 struct RegOpenKey rok;
442 rok.in.parent_key = op->in.parent_key;
443 rok.in.name = op->in.name;
444 rok.in.access = REG_KEY_ALL;
446 if(!cac_RegOpenKey(hnd, mem_ctx, &rok))
449 err = cac_delete_subkeys_recursive(pipe_hnd, mem_ctx, rok.out.key);
451 /*close the key that we opened*/
452 cac_RegClose(hnd, mem_ctx, rok.out.key);
454 hnd->status = werror_to_ntstatus(err);
456 if(NT_STATUS_V(hnd->status) != NT_STATUS_V(NT_STATUS_GUIDS_EXHAUSTED) && !NT_STATUS_IS_OK(hnd->status))
459 /*now go on to actually delete the key*/
462 err = rpccli_reg_delete_key( pipe_hnd, mem_ctx, op->in.parent_key, op->in.name);
463 hnd->status = werror_to_ntstatus(err);
465 if(!NT_STATUS_IS_OK(hnd->status)) {
472 int cac_RegDeleteValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegDeleteValue *op) {
473 struct rpc_pipe_client *pipe_hnd = NULL;
479 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
480 hnd->status = NT_STATUS_INVALID_HANDLE;
484 if(!op || !op->in.parent_key || !op->in.name || !mem_ctx) {
485 hnd->status = NT_STATUS_INVALID_PARAMETER;
489 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
491 hnd->status = NT_STATUS_INVALID_HANDLE;
495 err = rpccli_reg_delete_val( pipe_hnd, mem_ctx, op->in.parent_key, op->in.name);
496 hnd->status = werror_to_ntstatus(err);
498 if(!NT_STATUS_IS_OK(hnd->status)) {
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. */
510 int cac_RegQueryKeyInfo(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryKeyInfo *op) {
511 struct rpc_pipe_client *pipe_hnd = NULL;
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;
528 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
529 hnd->status = NT_STATUS_INVALID_HANDLE;
533 if(!op || !op->in.key || !mem_ctx) {
534 hnd->status = NT_STATUS_INVALID_PARAMETER;
538 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
540 hnd->status = NT_STATUS_INVALID_HANDLE;
544 err = rpccli_reg_query_key( pipe_hnd, mem_ctx, op->in.key,
556 hnd->status = werror_to_ntstatus(err);
558 if(!NT_STATUS_IS_OK(hnd->status))
561 if(!class_name_out) {
562 op->out.class_name = talloc_strdup(mem_ctx, "");
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));
568 memcpy(op->out.class_name, class_name_out, class_len);
570 op->out.class_name[class_len] = '\0';
572 else { /*then everything worked out fine in the function*/
573 op->out.class_name = talloc_strdup(mem_ctx, class_name_out);
576 if(!op->out.class_name) {
577 hnd->status = NT_STATUS_NO_MEMORY;
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);
594 int cac_RegQueryValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegQueryValue *op) {
595 struct rpc_pipe_client *pipe_hnd = NULL;
599 REGVAL_BUFFER buffer;
600 REG_VALUE_DATA *data_out = NULL;
605 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
606 hnd->status = NT_STATUS_INVALID_HANDLE;
610 if(!op || !op->in.key || !op->in.val_name || !mem_ctx) {
611 hnd->status = NT_STATUS_INVALID_PARAMETER;
615 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
617 hnd->status = NT_STATUS_INVALID_HANDLE;
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);
624 if(!NT_STATUS_IS_OK(hnd->status))
627 data_out = cac_MakeRegValueData(mem_ctx, val_type, buffer);
630 hnd->status = NT_STATUS_NO_MEMORY;
632 hnd->status = NT_STATUS_INVALID_PARAMETER;
637 op->out.type = val_type;
638 op->out.data = data_out;
644 int cac_RegEnumValues(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegEnumValues *op) {
645 struct rpc_pipe_client *pipe_hnd = NULL;
648 /*buffers for rpccli_reg_enum_key call*/
649 fstring val_name_buf;
650 REGVAL_BUFFER val_buf;
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;
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))
666 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
667 hnd->status = NT_STATUS_INVALID_HANDLE;
671 if(!op || !op->in.key || op->in.max_values == 0 || !mem_ctx) {
672 hnd->status = NT_STATUS_INVALID_PARAMETER;
676 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
678 hnd->status = NT_STATUS_INVALID_HANDLE;
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);
685 hnd->status = NT_STATUS_NO_MEMORY;
689 values_out = talloc_array(mem_ctx, REG_VALUE_DATA *, op->in.max_values);
691 TALLOC_FREE(types_out);
692 hnd->status = NT_STATUS_NO_MEMORY;
696 val_names_out = talloc_array(mem_ctx, char *, op->in.max_values);
698 TALLOC_FREE(types_out);
699 TALLOC_FREE(values_out);
700 hnd->status = NT_STATUS_NO_MEMORY;
704 resume_idx = op->out.resume_idx;
706 ZERO_STRUCT(val_buf);
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);
711 if(!NT_STATUS_IS_OK(hnd->status))
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);
717 if(!val_names_out[num_values_out] || !values_out[num_values_out]) {
718 hnd->status = NT_STATUS_NO_MEMORY;
724 } while(num_values_out < op->in.max_values);
726 if(CAC_OP_FAILED(hnd->status))
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;
738 int cac_RegSetValue(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetValue *op) {
739 struct rpc_pipe_client *pipe_hnd = NULL;
742 RPC_DATA_BLOB *buffer;
747 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
748 hnd->status = NT_STATUS_INVALID_HANDLE;
752 if(!op || !op->in.key || !op->in.val_name || !mem_ctx) {
753 hnd->status = NT_STATUS_INVALID_PARAMETER;
757 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
759 hnd->status = NT_STATUS_INVALID_HANDLE;
763 buffer = cac_MakeRpcDataBlob(mem_ctx, op->in.type, op->in.value);
767 hnd->status = NT_STATUS_NO_MEMORY;
769 hnd->status = NT_STATUS_INVALID_PARAMETER;
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);
777 if(!NT_STATUS_IS_OK(hnd->status))
781 err = rpccli_reg_flush_key(pipe_hnd, mem_ctx, op->in.key);
782 hnd->status = werror_to_ntstatus(err);
784 if(!NT_STATUS_IS_OK(hnd->status))
792 int cac_RegGetVersion(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetVersion *op) {
793 struct rpc_pipe_client *pipe_hnd = NULL;
801 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
802 hnd->status = NT_STATUS_INVALID_HANDLE;
806 if(!op || !op->in.key || !mem_ctx) {
807 hnd->status = NT_STATUS_INVALID_PARAMETER;
811 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
813 hnd->status = NT_STATUS_INVALID_HANDLE;
817 err = rpccli_reg_getversion( pipe_hnd, mem_ctx, op->in.key, &version_out);
818 hnd->status = werror_to_ntstatus(err);
820 if(!NT_STATUS_IS_OK(hnd->status))
823 op->out.version = version_out;
828 int cac_RegGetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegGetKeySecurity *op) {
829 struct rpc_pipe_client *pipe_hnd = NULL;
840 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
841 hnd->status = NT_STATUS_INVALID_HANDLE;
845 if(!op || !op->in.key || op->in.info_type == 0 || !mem_ctx) {
846 hnd->status = NT_STATUS_INVALID_PARAMETER;
850 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
852 hnd->status = NT_STATUS_INVALID_HANDLE;
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);
860 if(!NT_STATUS_IS_OK(hnd->status)) {
864 op->out.size = buf.len;
865 op->out.descriptor = dup_sec_desc(mem_ctx, buf.sec);
867 if (op->out.descriptor == NULL) {
874 int cac_RegSetKeySecurity(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSetKeySecurity *op) {
875 struct rpc_pipe_client *pipe_hnd = NULL;
881 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
882 hnd->status = NT_STATUS_INVALID_HANDLE;
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;
891 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
893 hnd->status = NT_STATUS_INVALID_HANDLE;
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);
901 if(!NT_STATUS_IS_OK(hnd->status)) {
908 int cac_RegSaveKey(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct RegSaveKey *op) {
909 struct rpc_pipe_client *pipe_hnd = NULL;
915 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG]) {
916 hnd->status = NT_STATUS_INVALID_HANDLE;
920 if(!op || !op->in.key || !op->in.filename || !mem_ctx) {
921 hnd->status = NT_STATUS_INVALID_PARAMETER;
925 pipe_hnd = cac_GetPipe(hnd, PI_WINREG);
927 hnd->status = NT_STATUS_INVALID_HANDLE;
931 err = rpccli_reg_save_key( pipe_hnd, mem_ctx, op->in.key, op->in.filename);
932 hnd->status = werror_to_ntstatus(err);
935 if(!NT_STATUS_IS_OK(hnd->status)) {
942 int cac_Shutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx, struct Shutdown *op) {
944 struct rpc_pipe_client *pipe_hnd = NULL;
951 if(!hnd->_internal.ctx) {
952 hnd->status = NT_STATUS_INVALID_HANDLE;
956 if(!op || !mem_ctx) {
957 hnd->status = NT_STATUS_INVALID_PARAMETER;
961 srv = cac_GetServer(hnd);
963 hnd->status = NT_STATUS_INVALID_HANDLE;
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)))) {
973 hnd->_internal.pipes[PI_INITSHUTDOWN] = True;
976 pipe_hnd = cac_GetPipe(hnd, PI_INITSHUTDOWN);
978 hnd->status = NT_STATUS_INVALID_HANDLE;
982 msg = (op->in.message != NULL) ? op->in.message : talloc_strdup(mem_ctx, "");
984 hnd->status = NT_STATUS_OK;
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);
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);
993 hnd->_internal.srv_level = SRV_WIN_NT4;
996 if(!NT_STATUS_IS_OK(hnd->status)) {
1003 int cac_AbortShutdown(CacServerHandle *hnd, TALLOC_CTX *mem_ctx) {
1004 struct rpc_pipe_client *pipe_hnd = NULL;
1009 if(!hnd->_internal.ctx || !hnd->_internal.pipes[PI_INITSHUTDOWN]) {
1010 hnd->status = NT_STATUS_INVALID_HANDLE;
1014 pipe_hnd = cac_GetPipe(hnd, PI_INITSHUTDOWN);
1016 hnd->status = NT_STATUS_INVALID_HANDLE;
1020 hnd->status = rpccli_shutdown_abort(pipe_hnd, mem_ctx);
1022 if(!NT_STATUS_IS_OK(hnd->status))