s3-spoolss: Added a set_printer_dataex function using the winreg pipe.
[amitay/samba.git] / source3 / rpc_server / srv_spoolss_util.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  SPOOLSS RPC Pipe server / winreg client routines
5  *
6  *  Copyright (c) 2010      Andreas Schneider <asn@samba.org>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "srv_spoolss_util.h"
24 #include "../librpc/gen_ndr/srv_winreg.h"
25 #include "../librpc/gen_ndr/cli_winreg.h"
26
27 /**
28  * @internal
29  *
30  * @brief Connect to the interal winreg server and open the given printer key.
31  *
32  * The function will create the needed subkeys if they don't exist.
33  *
34  * @param[in]  mem_ctx       The memory context to use.
35  *
36  * @param[in]  server_info   The supplied server info.
37  *
38  * @param[out] winreg_pipe   A pointer for the winreg rpc client pipe.
39  *
40  * @param[in]  name          The name of the printer.
41  *
42  * @param[in]  key           The key to open.
43  *
44  * @param[in]  create_key    Set to true if the key should be created if it
45  *                           doesn't exist.
46  *
47  * @param[in]  access_mask   The access mask to open the key.
48  *
49  * @param[out] hive_handle   A policy handle for the opened hive.
50  *
51  * @param[out] key_handle    A policy handle for the opened key.
52  *
53  * @return                   WERR_OK on success, the corresponding DOS error
54  *                           code if something gone wrong.
55  */
56 static WERROR winreg_printer_openkey(TALLOC_CTX *mem_ctx,
57                               struct auth_serversupplied_info *server_info,
58                               struct rpc_pipe_client **winreg_pipe,
59                               const char *name,
60                               const char *key,
61                               bool create_key,
62                               uint32_t access_mask,
63                               struct policy_handle *hive_handle,
64                               struct policy_handle *key_handle)
65 {
66         struct rpc_pipe_client *pipe_handle;
67         struct winreg_String wkey, wkeyclass;
68         char *keyname;
69         NTSTATUS status;
70         WERROR result = WERR_OK;
71
72         /* create winreg connection */
73         status = rpc_pipe_open_internal(mem_ctx,
74                                         &ndr_table_winreg.syntax_id,
75                                         rpc_winreg_dispatch,
76                                         server_info,
77                                         &pipe_handle);
78         if (!NT_STATUS_IS_OK(status)) {
79                 DEBUG(0, ("winreg_printer_openkey: Could not connect to winreg_pipe: %s\n",
80                           nt_errstr(status)));
81                 return ntstatus_to_werror(status);
82         }
83
84         status = rpccli_winreg_OpenHKLM(pipe_handle,
85                                         mem_ctx,
86                                         NULL,
87                                         access_mask,
88                                         hive_handle,
89                                         &result);
90         if (!NT_STATUS_IS_OK(status)) {
91                 DEBUG(0, ("winreg_printer_openkey: Could not open HKLM hive: %s\n",
92                           nt_errstr(status)));
93                 talloc_free(pipe_handle);
94                 if (!W_ERROR_IS_OK(result)) {
95                         return result;
96                 }
97                 return ntstatus_to_werror(status);
98         }
99
100         if (key && *key) {
101                 keyname = talloc_asprintf(mem_ctx,
102                                     "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\%s\\%s",
103                                     name,
104                                     key);
105         } else {
106                 keyname = talloc_asprintf(mem_ctx,
107                                     "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\%s",
108                                     name);
109         }
110         if (keyname == NULL) {
111                 talloc_free(pipe_handle);
112                 return WERR_NOMEM;
113         }
114
115         ZERO_STRUCT(wkey);
116         wkey.name = keyname;
117
118         if (create_key) {
119                 enum winreg_CreateAction action = REG_ACTION_NONE;
120
121                 ZERO_STRUCT(wkeyclass);
122                 wkeyclass.name = "";
123
124                 status = rpccli_winreg_CreateKey(pipe_handle,
125                                                  mem_ctx,
126                                                  hive_handle,
127                                                  wkey,
128                                                  wkeyclass,
129                                                  0,
130                                                  access_mask,
131                                                  NULL,
132                                                  key_handle,
133                                                  &action,
134                                                  &result);
135                 switch (action) {
136                         case REG_ACTION_NONE:
137                                 DEBUG(8, ("winreg_printer_openkey:createkey did nothing -- huh?\n"));
138                                 break;
139                         case REG_CREATED_NEW_KEY:
140                                 DEBUG(8, ("winreg_printer_openkey: createkey created %s\n", keyname));
141                                 break;
142                         case REG_OPENED_EXISTING_KEY:
143                                 DEBUG(8, ("winreg_printer_openkey: createkey opened existing %s\n", keyname));
144                                 break;
145                 }
146         } else {
147                 status = rpccli_winreg_OpenKey(pipe_handle,
148                                                mem_ctx,
149                                                hive_handle,
150                                                wkey,
151                                                0,
152                                                access_mask,
153                                                key_handle,
154                                                &result);
155         }
156         if (!NT_STATUS_IS_OK(status)) {
157                 talloc_free(pipe_handle);
158                 if (!W_ERROR_IS_OK(result)) {
159                         return result;
160                 }
161                 return ntstatus_to_werror(status);
162         }
163
164         *winreg_pipe = pipe_handle;
165
166         return WERR_OK;
167 }
168
169 /* Set printer data over the winreg pipe. */
170 WERROR winreg_set_printer_dataex(struct pipes_struct *p,
171                                  const char *printer,
172                                  const char *key,
173                                  const char *value,
174                                  enum winreg_Type type,
175                                  uint8_t *data,
176                                  uint32_t data_size)
177 {
178         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
179         struct rpc_pipe_client *winreg_pipe = NULL;
180         struct policy_handle hive_hnd, key_hnd;
181         struct winreg_String wvalue;
182         WERROR result = WERR_OK;
183         NTSTATUS status;
184         TALLOC_CTX *tmp_ctx;
185
186         tmp_ctx = talloc_new(p->mem_ctx);
187         if (tmp_ctx == NULL) {
188                 return WERR_NOMEM;
189         }
190
191         ZERO_STRUCT(hive_hnd);
192         ZERO_STRUCT(key_hnd);
193
194         DEBUG(8, ("winreg_set_printer_dataex: Open printer key %s, value %s, access_mask: 0x%05x for [%s]\n",
195                         key, value, access_mask, printer));
196         result = winreg_printer_openkey(tmp_ctx,
197                                         p->server_info,
198                                         &winreg_pipe,
199                                         printer,
200                                         key,
201                                         true,
202                                         access_mask,
203                                         &hive_hnd,
204                                         &key_hnd);
205         if (!W_ERROR_IS_OK(result)) {
206                 DEBUG(0, ("winreg_set_printer_dataex: Could not open key %s: %s\n",
207                           key, win_errstr(result)));
208                 goto done;
209         }
210
211         wvalue.name = value;
212         status = rpccli_winreg_SetValue(winreg_pipe,
213                                         tmp_ctx,
214                                         &key_hnd,
215                                         wvalue,
216                                         type,
217                                         data,
218                                         data_size,
219                                         &result);
220         if (!NT_STATUS_IS_OK(status)) {
221                 DEBUG(0, ("winreg_set_printer_dataex: Could not set value %s: %s\n",
222                           value, nt_errstr(status)));
223                 if (!W_ERROR_IS_OK(result)) {
224                         goto done;
225                 }
226                 result = ntstatus_to_werror(status);
227                 goto done;
228         }
229
230         result = WERR_OK;
231 done:
232         if (winreg_pipe != NULL) {
233                 if (is_valid_policy_hnd(&key_hnd)) {
234                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
235                 }
236                 if (is_valid_policy_hnd(&hive_hnd)) {
237                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
238                 }
239         }
240
241         TALLOC_FREE(tmp_ctx);
242         return result;
243 }