s3-spoolss: Fixed winreg_printer_openkey to be used in a more generic way.
[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 #define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
28 #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
29 #define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print"
30 #define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms"
31
32 /********************************************************************
33  static helper functions
34 ********************************************************************/
35
36 /**
37  * @internal
38  *
39  * @brief Connect to the interal winreg server and open the given printer key.
40  *
41  * The function will create the needed subkeys if they don't exist.
42  *
43  * @param[in]  mem_ctx       The memory context to use.
44  *
45  * @param[in]  server_info   The supplied server info.
46  *
47  * @param[out] winreg_pipe   A pointer for the winreg rpc client pipe.
48  *
49  * @param[in]  path          The path to the key to open.
50  *
51  * @param[in]  key           The key to open.
52  *
53  * @param[in]  create_key    Set to true if the key should be created if it
54  *                           doesn't exist.
55  *
56  * @param[in]  access_mask   The access mask to open the key.
57  *
58  * @param[out] hive_handle   A policy handle for the opened hive.
59  *
60  * @param[out] key_handle    A policy handle for the opened key.
61  *
62  * @return                   WERR_OK on success, the corresponding DOS error
63  *                           code if something gone wrong.
64  */
65 static WERROR winreg_printer_openkey(TALLOC_CTX *mem_ctx,
66                               struct auth_serversupplied_info *server_info,
67                               struct rpc_pipe_client **winreg_pipe,
68                               const char *path,
69                               const char *key,
70                               bool create_key,
71                               uint32_t access_mask,
72                               struct policy_handle *hive_handle,
73                               struct policy_handle *key_handle)
74 {
75         struct rpc_pipe_client *pipe_handle;
76         struct winreg_String wkey, wkeyclass;
77         char *keyname;
78         NTSTATUS status;
79         WERROR result = WERR_OK;
80
81         /* create winreg connection */
82         status = rpc_pipe_open_internal(mem_ctx,
83                                         &ndr_table_winreg.syntax_id,
84                                         rpc_winreg_dispatch,
85                                         server_info,
86                                         &pipe_handle);
87         if (!NT_STATUS_IS_OK(status)) {
88                 DEBUG(0, ("winreg_printer_openkey: Could not connect to winreg_pipe: %s\n",
89                           nt_errstr(status)));
90                 return ntstatus_to_werror(status);
91         }
92
93         status = rpccli_winreg_OpenHKLM(pipe_handle,
94                                         mem_ctx,
95                                         NULL,
96                                         access_mask,
97                                         hive_handle,
98                                         &result);
99         if (!NT_STATUS_IS_OK(status)) {
100                 DEBUG(0, ("winreg_printer_openkey: Could not open HKLM hive: %s\n",
101                           nt_errstr(status)));
102                 talloc_free(pipe_handle);
103                 if (!W_ERROR_IS_OK(result)) {
104                         return result;
105                 }
106                 return ntstatus_to_werror(status);
107         }
108
109         if (key && *key) {
110                 keyname = talloc_asprintf(mem_ctx, "%s\\%s", path, key);
111         } else {
112                 keyname = talloc_strdup(mem_ctx, path);
113         }
114         if (keyname == NULL) {
115                 talloc_free(pipe_handle);
116                 return WERR_NOMEM;
117         }
118
119         ZERO_STRUCT(wkey);
120         wkey.name = keyname;
121
122         if (create_key) {
123                 enum winreg_CreateAction action = REG_ACTION_NONE;
124
125                 ZERO_STRUCT(wkeyclass);
126                 wkeyclass.name = "";
127
128                 status = rpccli_winreg_CreateKey(pipe_handle,
129                                                  mem_ctx,
130                                                  hive_handle,
131                                                  wkey,
132                                                  wkeyclass,
133                                                  0,
134                                                  access_mask,
135                                                  NULL,
136                                                  key_handle,
137                                                  &action,
138                                                  &result);
139                 switch (action) {
140                         case REG_ACTION_NONE:
141                                 DEBUG(8, ("winreg_printer_openkey:createkey did nothing -- huh?\n"));
142                                 break;
143                         case REG_CREATED_NEW_KEY:
144                                 DEBUG(8, ("winreg_printer_openkey: createkey created %s\n", keyname));
145                                 break;
146                         case REG_OPENED_EXISTING_KEY:
147                                 DEBUG(8, ("winreg_printer_openkey: createkey opened existing %s\n", keyname));
148                                 break;
149                 }
150         } else {
151                 status = rpccli_winreg_OpenKey(pipe_handle,
152                                                mem_ctx,
153                                                hive_handle,
154                                                wkey,
155                                                0,
156                                                access_mask,
157                                                key_handle,
158                                                &result);
159         }
160         if (!NT_STATUS_IS_OK(status)) {
161                 talloc_free(pipe_handle);
162                 if (!W_ERROR_IS_OK(result)) {
163                         return result;
164                 }
165                 return ntstatus_to_werror(status);
166         }
167
168         *winreg_pipe = pipe_handle;
169
170         return WERR_OK;
171 }
172
173 /**
174  * @brief Create the registry keyname for the given printer.
175  *
176  * @param[in]  mem_ctx  The memory context to use.
177  *
178  * @param[in]  printer  The name of the printer to get the registry key.
179  *
180  * @return     The registry key or NULL on error.
181  */
182 static char *winreg_printer_data_keyname(TALLOC_CTX *mem_ctx, const char *printer) {
183         return talloc_asprintf(mem_ctx, "%s\\%s", TOP_LEVEL_PRINT_PRINTERS_KEY, printer);
184 }
185
186 /**
187  * @internal
188  *
189  * @brief Enumerate values of an opened key handle and retrieve the data.
190  *
191  * @param[in]  mem_ctx  The memory context to use.
192  *
193  * @param[in]  pipe_handle The pipe handle for the rpc connection.
194  *
195  * @param[in]  key_hnd  The opened key handle.
196  *
197  * @param[out] pnum_values A pointer to store he number of values found.
198  *
199  * @param[out] pnum_values A pointer to store the number of values we found.
200  *
201  * @return                   WERR_OK on success, the corresponding DOS error
202  *                           code if something gone wrong.
203  */
204 static WERROR winreg_printer_enumvalues(TALLOC_CTX *mem_ctx,
205                                         struct rpc_pipe_client *pipe_handle,
206                                         struct policy_handle *key_hnd,
207                                         uint32_t *pnum_values,
208                                         struct spoolss_PrinterEnumValues **penum_values)
209 {
210         TALLOC_CTX *tmp_ctx;
211         uint32_t num_subkeys, max_subkeylen, max_classlen;
212         uint32_t num_values, max_valnamelen, max_valbufsize;
213         uint32_t secdescsize;
214         uint32_t i;
215         NTTIME last_changed_time;
216         struct winreg_String classname;
217
218         struct spoolss_PrinterEnumValues *enum_values;
219
220         WERROR result = WERR_OK;
221         NTSTATUS status;
222
223         tmp_ctx = talloc_new(mem_ctx);
224         if (tmp_ctx == NULL) {
225                 return WERR_NOMEM;
226         }
227
228         ZERO_STRUCT(classname);
229
230         status = rpccli_winreg_QueryInfoKey(pipe_handle,
231                                             tmp_ctx,
232                                             key_hnd,
233                                             &classname,
234                                             &num_subkeys,
235                                             &max_subkeylen,
236                                             &max_classlen,
237                                             &num_values,
238                                             &max_valnamelen,
239                                             &max_valbufsize,
240                                             &secdescsize,
241                                             &last_changed_time,
242                                             &result);
243         if (!NT_STATUS_IS_OK(status)) {
244                 DEBUG(0, ("winreg_printer_enumvalues: Could not query info: %s\n",
245                           nt_errstr(status)));
246                 if (!W_ERROR_IS_OK(result)) {
247                         goto error;
248                 }
249                 result = ntstatus_to_werror(status);
250                 goto error;
251         }
252
253         if (num_values == 0) {
254                 *pnum_values = 0;
255                 TALLOC_FREE(tmp_ctx);
256                 return WERR_OK;
257         }
258
259         enum_values = TALLOC_ARRAY(tmp_ctx, struct spoolss_PrinterEnumValues, num_values);
260         if (enum_values == NULL) {
261                 result = WERR_NOMEM;
262                 goto error;
263         }
264
265         for (i = 0; i < num_values; i++) {
266                 struct spoolss_PrinterEnumValues val;
267                 struct winreg_ValNameBuf name_buf;
268                 enum winreg_Type type = REG_NONE;
269                 uint8_t *data = NULL;
270                 uint32_t data_size;
271                 uint32_t length;
272                 char n = '\0';;
273
274                 name_buf.name = &n;
275                 name_buf.size = max_valnamelen + 2;
276                 name_buf.length = 0;
277
278                 data_size = max_valbufsize;
279                 data = (uint8_t *) TALLOC(tmp_ctx, data_size);
280                 length = 0;
281
282                 status = rpccli_winreg_EnumValue(pipe_handle,
283                                                  tmp_ctx,
284                                                  key_hnd,
285                                                  i,
286                                                  &name_buf,
287                                                  &type,
288                                                  data,
289                                                  &data_size,
290                                                  &length,
291                                                  &result);
292                 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) {
293                         result = WERR_OK;
294                         status = NT_STATUS_OK;
295                         break;
296                 }
297
298                 if (!NT_STATUS_IS_OK(status)) {
299                         DEBUG(0, ("winreg_printer_enumvalues: Could not enumerate values: %s\n",
300                                   nt_errstr(status)));
301                         if (!W_ERROR_IS_OK(result)) {
302                                 goto error;
303                         }
304                         result = ntstatus_to_werror(status);
305                         goto error;
306                 }
307
308                 if (name_buf.name == NULL) {
309                         result = WERR_INVALID_PARAMETER;
310                         goto error;
311                 }
312
313                 val.value_name = talloc_strdup(enum_values, name_buf.name);
314                 if (val.value_name == NULL) {
315                         result = WERR_NOMEM;
316                         goto error;
317                 }
318                 val.value_name_len = strlen_m_term(val.value_name) * 2;
319
320                 val.type = type;
321                 val.data_length = data_size;
322                 if (val.data_length) {
323                         val.data = talloc(enum_values, DATA_BLOB);
324                         if (val.data == NULL) {
325                                 result = WERR_NOMEM;
326                                 goto error;
327                         }
328                         *val.data = data_blob_talloc(enum_values, data, data_size);
329                 }
330
331                 enum_values[i] = val;
332         }
333
334         *pnum_values = num_values;
335         if (penum_values) {
336                 *penum_values = talloc_move(mem_ctx, &enum_values);
337         }
338
339         result = WERR_OK;
340
341  error:
342         TALLOC_FREE(tmp_ctx);
343         return result;
344 }
345
346 /**
347  * @internal
348  *
349  * @brief Enumerate subkeys of an opened key handle and get the names.
350  *
351  * @param[in]  mem_ctx  The memory context to use.
352  *
353  * @param[in]  pipe_handle The pipe handle for the rpc connection.
354  *
355  * @param[in]  key_hnd  The opened key handle.
356  *
357  * @param[in]  pnum_subkeys A pointer to store the number of found subkeys.
358  *
359  * @param[in]  psubkeys A pointer to an array to store the found names of
360  *                      subkeys.
361  *
362  * @return                   WERR_OK on success, the corresponding DOS error
363  *                           code if something gone wrong.
364  */
365 static WERROR winreg_printer_enumkeys(TALLOC_CTX *mem_ctx,
366                                       struct rpc_pipe_client *pipe_handle,
367                                       struct policy_handle *key_hnd,
368                                       uint32_t *pnum_subkeys,
369                                       const char ***psubkeys)
370 {
371         TALLOC_CTX *tmp_ctx;
372         const char **subkeys;
373         uint32_t num_subkeys, max_subkeylen, max_classlen;
374         uint32_t num_values, max_valnamelen, max_valbufsize;
375         uint32_t i;
376         NTTIME last_changed_time;
377         uint32_t secdescsize;
378         struct winreg_String classname;
379         WERROR result = WERR_OK;
380         NTSTATUS status;
381
382         tmp_ctx = talloc_new(mem_ctx);
383         if (tmp_ctx == NULL) {
384                 return WERR_NOMEM;
385         }
386
387         ZERO_STRUCT(classname);
388
389         status = rpccli_winreg_QueryInfoKey(pipe_handle,
390                                             tmp_ctx,
391                                             key_hnd,
392                                             &classname,
393                                             &num_subkeys,
394                                             &max_subkeylen,
395                                             &max_classlen,
396                                             &num_values,
397                                             &max_valnamelen,
398                                             &max_valbufsize,
399                                             &secdescsize,
400                                             &last_changed_time,
401                                             &result);
402         if (!NT_STATUS_IS_OK(status)) {
403                 DEBUG(0, ("winreg_printer_enumkeys: Could not query info: %s\n",
404                           nt_errstr(status)));
405                 if (!W_ERROR_IS_OK(result)) {
406                         goto error;
407                 }
408                 result = ntstatus_to_werror(status);
409                 goto error;
410         }
411
412         subkeys = talloc_zero_array(tmp_ctx, const char *, num_subkeys + 2);
413         if (subkeys == NULL) {
414                 result = WERR_NOMEM;
415                 goto error;
416         }
417
418         if (num_subkeys == 0) {
419                 subkeys[0] = talloc_strdup(subkeys, "");
420                 if (subkeys[0] == NULL) {
421                         result = WERR_NOMEM;
422                         goto error;
423                 }
424                 *pnum_subkeys = 0;
425                 if (psubkeys) {
426                         *psubkeys = talloc_move(mem_ctx, &subkeys);
427                 }
428
429                 TALLOC_FREE(tmp_ctx);
430                 return WERR_OK;
431         }
432
433         for (i = 0; i < num_subkeys; i++) {
434                 char c = '\0';
435                 char n = '\0';
436                 char *name = NULL;
437                 struct winreg_StringBuf class_buf;
438                 struct winreg_StringBuf name_buf;
439                 NTTIME modtime;
440
441                 class_buf.name = &c;
442                 class_buf.size = max_classlen + 2;
443                 class_buf.length = 0;
444
445                 name_buf.name = &n;
446                 name_buf.size = max_subkeylen + 2;
447                 name_buf.length = 0;
448
449                 ZERO_STRUCT(modtime);
450
451                 status = rpccli_winreg_EnumKey(pipe_handle,
452                                                tmp_ctx,
453                                                key_hnd,
454                                                i,
455                                                &name_buf,
456                                                &class_buf,
457                                                &modtime,
458                                                &result);
459                 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) {
460                         result = WERR_OK;
461                         status = NT_STATUS_OK;
462                         break;
463                 }
464
465                 if (!NT_STATUS_IS_OK(status)) {
466                         DEBUG(0, ("winreg_printer_enumkeys: Could not enumerate keys: %s\n",
467                                   nt_errstr(status)));
468                         if (!W_ERROR_IS_OK(result)) {
469                                 goto error;
470                         }
471                         result = ntstatus_to_werror(status);
472                         goto error;
473                 }
474
475                 if (name_buf.name == NULL) {
476                         result = WERR_INVALID_PARAMETER;
477                         goto error;
478                 }
479
480                 name = talloc_strdup(subkeys, name_buf.name);
481                 if (name == NULL) {
482                         result = WERR_NOMEM;
483                         goto error;
484                 }
485
486                 subkeys[i] = name;
487         }
488
489         *pnum_subkeys = num_subkeys;
490         if (psubkeys) {
491                 *psubkeys = talloc_move(mem_ctx, &subkeys);
492         }
493
494  error:
495         TALLOC_FREE(tmp_ctx);
496         return result;
497 }
498
499 /**
500  * @internal
501  *
502  * @brief A function to delete a key and its subkeys recurively.
503  *
504  * @param[in]  mem_ctx  The memory context to use.
505  *
506  * @param[in]  pipe_handle The pipe handle for the rpc connection.
507  *
508  * @param[in]  hive_handle A opened hive handle to the key.
509  *
510  * @param[in]  access_mask The access mask to access the key.
511  *
512  * @param[in]  key      The key to delete
513  *
514  * @return              WERR_OK on success, the corresponding DOS error
515  *                      code if something gone wrong.
516  */
517 static WERROR winreg_printer_delete_subkeys(TALLOC_CTX *mem_ctx,
518                                             struct rpc_pipe_client *pipe_handle,
519                                             struct policy_handle *hive_handle,
520                                             uint32_t access_mask,
521                                             const char *key)
522 {
523         const char **subkeys = NULL;
524         uint32_t num_subkeys = 0;
525         struct policy_handle key_hnd;
526         struct winreg_String wkey;
527         WERROR result = WERR_OK;
528         NTSTATUS status;
529         uint32_t i;
530
531         ZERO_STRUCT(key_hnd);
532         wkey.name = key;
533
534         DEBUG(2, ("winreg_printer_delete_subkeys: delete key %s\n", key));
535         /* open the key */
536         status = rpccli_winreg_OpenKey(pipe_handle,
537                                        mem_ctx,
538                                        hive_handle,
539                                        wkey,
540                                        0,
541                                        access_mask,
542                                        &key_hnd,
543                                        &result);
544         if (!NT_STATUS_IS_OK(status)) {
545                 DEBUG(0, ("winreg_printer_delete_subkeys: Could not open key %s: %s\n",
546                           wkey.name, nt_errstr(status)));
547                 if (!W_ERROR_IS_OK(result)) {
548                         return result;
549                 }
550                 return ntstatus_to_werror(status);
551         }
552
553         result = winreg_printer_enumkeys(mem_ctx,
554                                          pipe_handle,
555                                          &key_hnd,
556                                          &num_subkeys,
557                                          &subkeys);
558         if (!W_ERROR_IS_OK(result)) {
559                 goto done;
560         }
561
562         for (i = 0; i < num_subkeys; i++) {
563                 /* create key + subkey */
564                 char *subkey = talloc_asprintf(mem_ctx, "%s\\%s", key, subkeys[i]);
565                 if (subkey == NULL) {
566                         goto done;
567                 }
568
569                 DEBUG(2, ("winreg_printer_delete_subkeys: delete subkey %s\n", subkey));
570                 result = winreg_printer_delete_subkeys(mem_ctx,
571                                                        pipe_handle,
572                                                        hive_handle,
573                                                        access_mask,
574                                                        subkey);
575                 if (!W_ERROR_IS_OK(result)) {
576                         goto done;
577                 }
578         }
579
580         if (is_valid_policy_hnd(&key_hnd)) {
581                 rpccli_winreg_CloseKey(pipe_handle, mem_ctx, &key_hnd, NULL);
582         }
583
584         wkey.name = key;
585
586         status = rpccli_winreg_DeleteKey(pipe_handle,
587                                          mem_ctx,
588                                          hive_handle,
589                                          wkey,
590                                          &result);
591
592 done:
593         if (is_valid_policy_hnd(&key_hnd)) {
594                 rpccli_winreg_CloseKey(pipe_handle, mem_ctx, &key_hnd, NULL);
595         }
596
597         return result;
598 }
599
600 /********************************************************************
601  Public winreg function for spoolss
602 ********************************************************************/
603
604 /* Set printer data over the winreg pipe. */
605 WERROR winreg_set_printer_dataex(struct pipes_struct *p,
606                                  const char *printer,
607                                  const char *key,
608                                  const char *value,
609                                  enum winreg_Type type,
610                                  uint8_t *data,
611                                  uint32_t data_size)
612 {
613         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
614         struct rpc_pipe_client *winreg_pipe = NULL;
615         struct policy_handle hive_hnd, key_hnd;
616         struct winreg_String wvalue;
617         char *path;
618         WERROR result = WERR_OK;
619         NTSTATUS status;
620         TALLOC_CTX *tmp_ctx;
621
622         tmp_ctx = talloc_new(p->mem_ctx);
623         if (tmp_ctx == NULL) {
624                 return WERR_NOMEM;
625         }
626
627         path = winreg_printer_data_keyname(tmp_ctx, printer);
628         if (path == NULL) {
629                 TALLOC_FREE(tmp_ctx);
630                 return WERR_NOMEM;
631         }
632
633         ZERO_STRUCT(hive_hnd);
634         ZERO_STRUCT(key_hnd);
635
636         DEBUG(8, ("winreg_set_printer_dataex: Open printer key %s, value %s, access_mask: 0x%05x for [%s]\n",
637                         key, value, access_mask, printer));
638         result = winreg_printer_openkey(tmp_ctx,
639                                         p->server_info,
640                                         &winreg_pipe,
641                                         path,
642                                         key,
643                                         true,
644                                         access_mask,
645                                         &hive_hnd,
646                                         &key_hnd);
647         if (!W_ERROR_IS_OK(result)) {
648                 DEBUG(0, ("winreg_set_printer_dataex: Could not open key %s: %s\n",
649                           key, win_errstr(result)));
650                 goto done;
651         }
652
653         wvalue.name = value;
654         status = rpccli_winreg_SetValue(winreg_pipe,
655                                         tmp_ctx,
656                                         &key_hnd,
657                                         wvalue,
658                                         type,
659                                         data,
660                                         data_size,
661                                         &result);
662         if (!NT_STATUS_IS_OK(status)) {
663                 DEBUG(0, ("winreg_set_printer_dataex: Could not set value %s: %s\n",
664                           value, nt_errstr(status)));
665                 if (!W_ERROR_IS_OK(result)) {
666                         goto done;
667                 }
668                 result = ntstatus_to_werror(status);
669                 goto done;
670         }
671
672         result = WERR_OK;
673 done:
674         if (winreg_pipe != NULL) {
675                 if (is_valid_policy_hnd(&key_hnd)) {
676                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
677                 }
678                 if (is_valid_policy_hnd(&hive_hnd)) {
679                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
680                 }
681         }
682
683         TALLOC_FREE(tmp_ctx);
684         return result;
685 }
686
687 /* Get printer data over a winreg pipe. */
688 WERROR winreg_get_printer_dataex(struct pipes_struct *p,
689                                  const char *printer,
690                                  const char *key,
691                                  const char *value,
692                                  enum winreg_Type *type,
693                                  uint8_t **data,
694                                  uint32_t *data_size)
695 {
696         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
697         struct rpc_pipe_client *winreg_pipe = NULL;
698         struct policy_handle hive_hnd, key_hnd;
699         struct winreg_String wvalue;
700         enum winreg_Type type_in;
701         char *path;
702         uint8_t *data_in;
703         uint32_t data_in_size = 0;
704         uint32_t value_len = 0;
705         WERROR result = WERR_OK;
706         NTSTATUS status;
707         TALLOC_CTX *tmp_ctx;
708
709         tmp_ctx = talloc_new(p->mem_ctx);
710         if (tmp_ctx == NULL) {
711                 return WERR_NOMEM;
712         }
713
714         path = winreg_printer_data_keyname(tmp_ctx, printer);
715         if (path == NULL) {
716                 TALLOC_FREE(tmp_ctx);
717                 return WERR_NOMEM;
718         }
719
720         ZERO_STRUCT(hive_hnd);
721         ZERO_STRUCT(key_hnd);
722
723         result = winreg_printer_openkey(tmp_ctx,
724                                         p->server_info,
725                                         &winreg_pipe,
726                                         path,
727                                         key,
728                                         false,
729                                         access_mask,
730                                         &hive_hnd,
731                                         &key_hnd);
732         if (!W_ERROR_IS_OK(result)) {
733                 DEBUG(0, ("winreg_get_printer_dataex: Could not open key %s: %s\n",
734                           key, win_errstr(result)));
735                 goto done;
736         }
737
738         wvalue.name = value;
739
740         /*
741          * call QueryValue once with data == NULL to get the
742          * needed memory size to be allocated, then allocate
743          * data buffer and call again.
744          */
745         status = rpccli_winreg_QueryValue(winreg_pipe,
746                                           tmp_ctx,
747                                           &key_hnd,
748                                           &wvalue,
749                                           &type_in,
750                                           NULL,
751                                           &data_in_size,
752                                           &value_len,
753                                           &result);
754         if (!NT_STATUS_IS_OK(status)) {
755                 DEBUG(0, ("winreg_get_printer_dataex: Could not query value %s: %s\n",
756                           value, nt_errstr(status)));
757                 if (!W_ERROR_IS_OK(result)) {
758                         goto done;
759                 }
760                 result = ntstatus_to_werror(status);
761                 goto done;
762         }
763
764         data_in = (uint8_t *) TALLOC(tmp_ctx, data_in_size);
765         if (data_in == NULL) {
766                 result = WERR_NOMEM;
767                 goto done;
768         }
769         value_len = 0;
770
771         status = rpccli_winreg_QueryValue(winreg_pipe,
772                                           tmp_ctx,
773                                           &key_hnd,
774                                           &wvalue,
775                                           &type_in,
776                                           data_in,
777                                           &data_in_size,
778                                           &value_len,
779                                           &result);
780         if (!NT_STATUS_IS_OK(status)) {
781                 DEBUG(0, ("winreg_get_printer_dataex: Could not query value %s: %s\n",
782                           value, nt_errstr(status)));
783                 if (!W_ERROR_IS_OK(result)) {
784                         result = ntstatus_to_werror(status);
785                 }
786                 goto done;
787         }
788
789         *type = type_in;
790         *data_size = data_in_size;
791         if (data_in_size) {
792                 *data = talloc_move(p->mem_ctx, &data_in);
793         }
794
795         result = WERR_OK;
796 done:
797         if (winreg_pipe != NULL) {
798                 if (is_valid_policy_hnd(&key_hnd)) {
799                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
800                 }
801                 if (is_valid_policy_hnd(&hive_hnd)) {
802                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
803                 }
804         }
805
806         TALLOC_FREE(tmp_ctx);
807         return result;
808 }
809
810 /* Enumerate on the values of a given key and provide the data. */
811 WERROR winreg_enum_printer_dataex(struct pipes_struct *p,
812                                   const char *printer,
813                                   const char *key,
814                                   uint32_t *pnum_values,
815                                   struct spoolss_PrinterEnumValues **penum_values)
816 {
817         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
818         struct rpc_pipe_client *winreg_pipe = NULL;
819         struct policy_handle hive_hnd, key_hnd;
820
821         struct spoolss_PrinterEnumValues *enum_values = NULL;
822         uint32_t num_values = 0;
823         char *path;
824         WERROR result = WERR_OK;
825
826         TALLOC_CTX *tmp_ctx;
827
828         tmp_ctx = talloc_new(p->mem_ctx);
829         if (tmp_ctx == NULL) {
830                 return WERR_NOMEM;
831         }
832
833         path = winreg_printer_data_keyname(tmp_ctx, printer);
834         if (path == NULL) {
835                 TALLOC_FREE(tmp_ctx);
836                 return WERR_NOMEM;
837         }
838
839         result = winreg_printer_openkey(tmp_ctx,
840                                         p->server_info,
841                                         &winreg_pipe,
842                                         path,
843                                         key,
844                                         false,
845                                         access_mask,
846                                         &hive_hnd,
847                                         &key_hnd);
848         if (!W_ERROR_IS_OK(result)) {
849                 DEBUG(0, ("winreg_enum_printer_dataex: Could not open key %s: %s\n",
850                           key, win_errstr(result)));
851                 goto done;
852         }
853
854         result = winreg_printer_enumvalues(tmp_ctx,
855                                            winreg_pipe,
856                                            &key_hnd,
857                                            &num_values,
858                                            &enum_values);
859         if (!W_ERROR_IS_OK(result)) {
860                 DEBUG(0, ("winreg_enum_printer_dataex: Could not enumerate values in %s: %s\n",
861                           key, win_errstr(result)));
862                 goto done;
863         }
864
865         *pnum_values = num_values;
866         if (penum_values) {
867                 *penum_values = talloc_move(p->mem_ctx, &enum_values);
868         }
869
870         result = WERR_OK;
871 done:
872         if (winreg_pipe != NULL) {
873                 if (is_valid_policy_hnd(&key_hnd)) {
874                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
875                 }
876                 if (is_valid_policy_hnd(&hive_hnd)) {
877                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
878                 }
879         }
880
881         TALLOC_FREE(tmp_ctx);
882         return result;
883 }
884
885 /* Delete printer data over a winreg pipe. */
886 WERROR winreg_delete_printer_dataex(struct pipes_struct *p,
887                                     const char *printer,
888                                     const char *key,
889                                     const char *value)
890 {
891         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
892         struct rpc_pipe_client *winreg_pipe = NULL;
893         struct policy_handle hive_hnd, key_hnd;
894         struct winreg_String wvalue;
895         char *path;
896         WERROR result = WERR_OK;
897         NTSTATUS status;
898
899         TALLOC_CTX *tmp_ctx;
900
901         tmp_ctx = talloc_new(p->mem_ctx);
902         if (tmp_ctx == NULL) {
903                 return WERR_NOMEM;
904         }
905
906         path = winreg_printer_data_keyname(tmp_ctx, printer);
907         if (path == NULL) {
908                 TALLOC_FREE(tmp_ctx);
909                 return WERR_NOMEM;
910         }
911
912         ZERO_STRUCT(hive_hnd);
913         ZERO_STRUCT(key_hnd);
914
915         result = winreg_printer_openkey(tmp_ctx,
916                                         p->server_info,
917                                         &winreg_pipe,
918                                         path,
919                                         key,
920                                         false,
921                                         access_mask,
922                                         &hive_hnd,
923                                         &key_hnd);
924         if (!W_ERROR_IS_OK(result)) {
925                 DEBUG(0, ("winreg_delete_printer_dataex: Could not open key %s: %s\n",
926                           key, win_errstr(result)));
927                 goto done;
928         }
929
930         wvalue.name = value;
931         status = rpccli_winreg_DeleteValue(winreg_pipe,
932                                            tmp_ctx,
933                                            &key_hnd,
934                                            wvalue,
935                                            &result);
936         if (!NT_STATUS_IS_OK(status)) {
937                 DEBUG(0, ("winreg_delete_printer_dataex: Could not delete value %s: %s\n",
938                           value, nt_errstr(status)));
939                 if (!W_ERROR_IS_OK(result)) {
940                         goto done;
941                 }
942                 result = ntstatus_to_werror(status);
943                 goto done;
944         }
945
946         result = WERR_OK;
947 done:
948         if (winreg_pipe != NULL) {
949                 if (is_valid_policy_hnd(&key_hnd)) {
950                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
951                 }
952                 if (is_valid_policy_hnd(&hive_hnd)) {
953                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
954                 }
955         }
956
957         TALLOC_FREE(tmp_ctx);
958         return result;
959 }
960
961 /* Enumerate on the subkeys of a given key and provide the data. */
962 WERROR winreg_enum_printer_key(struct pipes_struct *p,
963                                const char *printer,
964                                const char *key,
965                                uint32_t *pnum_subkeys,
966                                const char ***psubkeys)
967 {
968         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
969         struct rpc_pipe_client *winreg_pipe = NULL;
970         struct policy_handle hive_hnd, key_hnd;
971         char *path;
972         const char **subkeys = NULL;
973         uint32_t num_subkeys = -1;
974
975         WERROR result = WERR_OK;
976
977         TALLOC_CTX *tmp_ctx;
978
979         tmp_ctx = talloc_new(p->mem_ctx);
980         if (tmp_ctx == NULL) {
981                 return WERR_NOMEM;
982         }
983
984         path = winreg_printer_data_keyname(tmp_ctx, printer);
985         if (path == NULL) {
986                 TALLOC_FREE(tmp_ctx);
987                 return WERR_NOMEM;
988         }
989
990         ZERO_STRUCT(hive_hnd);
991         ZERO_STRUCT(key_hnd);
992
993         result = winreg_printer_openkey(tmp_ctx,
994                                         p->server_info,
995                                         &winreg_pipe,
996                                         path,
997                                         key,
998                                         false,
999                                         access_mask,
1000                                         &hive_hnd,
1001                                         &key_hnd);
1002         if (!W_ERROR_IS_OK(result)) {
1003                 DEBUG(0, ("winreg_enum_printer_key: Could not open key %s: %s\n",
1004                           key, win_errstr(result)));
1005                 goto done;
1006         }
1007
1008         result = winreg_printer_enumkeys(tmp_ctx,
1009                                          winreg_pipe,
1010                                          &key_hnd,
1011                                          &num_subkeys,
1012                                          &subkeys);
1013         if (!W_ERROR_IS_OK(result)) {
1014                 DEBUG(0, ("winreg_enum_printer_key: Could not enumerate subkeys in %s: %s\n",
1015                           key, win_errstr(result)));
1016                 goto done;
1017         }
1018
1019         *pnum_subkeys = num_subkeys;
1020         if (psubkeys) {
1021                 *psubkeys = talloc_move(p->mem_ctx, &subkeys);
1022         }
1023
1024         result = WERR_OK;
1025 done:
1026         if (winreg_pipe != NULL) {
1027                 if (is_valid_policy_hnd(&key_hnd)) {
1028                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
1029                 }
1030                 if (is_valid_policy_hnd(&hive_hnd)) {
1031                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
1032                 }
1033         }
1034
1035         TALLOC_FREE(tmp_ctx);
1036         return result;
1037 }
1038
1039 /* Delete a key with subkeys of a given printer. */
1040 WERROR winreg_delete_printer_key(struct pipes_struct *p,
1041                                  const char *printer,
1042                                  const char *key)
1043 {
1044         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1045         struct rpc_pipe_client *winreg_pipe = NULL;
1046         struct policy_handle hive_hnd, key_hnd;
1047         char *keyname;
1048         char *path;
1049         WERROR result;
1050         TALLOC_CTX *tmp_ctx;
1051
1052         tmp_ctx = talloc_new(p->mem_ctx);
1053         if (tmp_ctx == NULL) {
1054                 return WERR_NOMEM;
1055         }
1056
1057         path = winreg_printer_data_keyname(tmp_ctx, printer);
1058         if (path == NULL) {
1059                 TALLOC_FREE(tmp_ctx);
1060                 return WERR_NOMEM;
1061         }
1062
1063         result = winreg_printer_openkey(tmp_ctx,
1064                                         p->server_info,
1065                                         &winreg_pipe,
1066                                         path,
1067                                         key,
1068                                         false,
1069                                         access_mask,
1070                                         &hive_hnd,
1071                                         &key_hnd);
1072         if (!W_ERROR_IS_OK(result)) {
1073                 /* key doesn't exist */
1074                 if (W_ERROR_EQUAL(result, WERR_BADFILE)) {
1075                         result = WERR_OK;
1076                         goto done;
1077                 }
1078
1079                 DEBUG(0, ("winreg_delete_printer_key: Could not open key %s: %s\n",
1080                           key, win_errstr(result)));
1081                 goto done;
1082         }
1083
1084         if (is_valid_policy_hnd(&key_hnd)) {
1085                 rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
1086         }
1087
1088         keyname = talloc_asprintf(tmp_ctx,
1089                                   "%s\\%s",
1090                                   path,
1091                                   key);
1092         if (keyname == NULL) {
1093                 result = WERR_NOMEM;
1094                 goto done;
1095         }
1096
1097         result = winreg_printer_delete_subkeys(tmp_ctx,
1098                                                winreg_pipe,
1099                                                &hive_hnd,
1100                                                access_mask,
1101                                                keyname);
1102         if (!W_ERROR_IS_OK(result)) {
1103                 DEBUG(0, ("winreg_delete_printer_key: Could not delete key %s: %s\n",
1104                           key, win_errstr(result)));
1105                 goto done;
1106         }
1107
1108 done:
1109         if (winreg_pipe != NULL) {
1110                 if (is_valid_policy_hnd(&key_hnd)) {
1111                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
1112                 }
1113                 if (is_valid_policy_hnd(&hive_hnd)) {
1114                         rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
1115                 }
1116         }
1117
1118         TALLOC_FREE(tmp_ctx);
1119         return result;
1120 }