s3-rpc_client: Added a winreg helper to enum keys.
[kai/samba.git] / source3 / rpc_client / cli_winreg.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  WINREG client routines
5  *
6  *  Copyright (c) 2011      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 "../librpc/gen_ndr/ndr_winreg_c.h"
24 #include "rpc_client/cli_winreg.h"
25
26 NTSTATUS dcerpc_winreg_query_dword(TALLOC_CTX *mem_ctx,
27                                    struct dcerpc_binding_handle *h,
28                                    struct policy_handle *key_handle,
29                                    const char *value,
30                                    uint32_t *data,
31                                    WERROR *pwerr)
32 {
33         struct winreg_String wvalue;
34         enum winreg_Type type;
35         uint32_t value_len = 0;
36         uint32_t data_size = 0;
37         WERROR result = WERR_OK;
38         NTSTATUS status;
39         DATA_BLOB blob;
40
41         wvalue.name = value;
42
43         status = dcerpc_winreg_QueryValue(h,
44                                           mem_ctx,
45                                           key_handle,
46                                           &wvalue,
47                                           &type,
48                                           NULL,
49                                           &data_size,
50                                           &value_len,
51                                           &result);
52         if (!NT_STATUS_IS_OK(status)) {
53                 return status;
54         }
55         if (!W_ERROR_IS_OK(result)) {
56                 *pwerr = result;
57                 return status;
58         }
59
60         if (type != REG_DWORD) {
61                 *pwerr = WERR_INVALID_DATATYPE;
62                 return status;
63         }
64
65         if (data_size != 4) {
66                 *pwerr = WERR_INVALID_DATA;
67                 return status;
68         }
69
70         blob = data_blob_talloc(mem_ctx, NULL, data_size);
71         if (blob.data == NULL) {
72                 *pwerr = WERR_NOMEM;
73                 return status;
74         }
75         value_len = 0;
76
77         status = dcerpc_winreg_QueryValue(h,
78                                           mem_ctx,
79                                           key_handle,
80                                           &wvalue,
81                                           &type,
82                                           blob.data,
83                                           &data_size,
84                                           &value_len,
85                                           &result);
86         if (!NT_STATUS_IS_OK(status)) {
87                 return status;
88         }
89         if (!W_ERROR_IS_OK(result)) {
90                 *pwerr = result;
91                 return status;
92         }
93
94         if (data) {
95                 *data = IVAL(blob.data, 0);
96         }
97
98         return status;
99 }
100
101 NTSTATUS dcerpc_winreg_query_binary(TALLOC_CTX *mem_ctx,
102                                     struct dcerpc_binding_handle *h,
103                                     struct policy_handle *key_handle,
104                                     const char *value,
105                                     DATA_BLOB *data,
106                                     WERROR *pwerr)
107 {
108         struct winreg_String wvalue;
109         enum winreg_Type type;
110         WERROR result = WERR_OK;
111         uint32_t value_len = 0;
112         uint32_t data_size = 0;
113         NTSTATUS status;
114         DATA_BLOB blob;
115
116         wvalue.name = value;
117
118         status = dcerpc_winreg_QueryValue(h,
119                                           mem_ctx,
120                                           key_handle,
121                                           &wvalue,
122                                           &type,
123                                           NULL,
124                                           &data_size,
125                                           &value_len,
126                                           &result);
127         if (!NT_STATUS_IS_OK(status)) {
128                 return status;
129         }
130         if (!W_ERROR_IS_OK(result)) {
131                 *pwerr = result;
132                 return status;
133         }
134
135         if (type != REG_BINARY) {
136                 *pwerr = WERR_INVALID_DATATYPE;
137                 return status;
138         }
139
140         blob = data_blob_talloc(mem_ctx, NULL, data_size);
141         if (blob.data == NULL) {
142                 *pwerr = WERR_NOMEM;
143                 return status;
144         }
145         value_len = 0;
146
147         status = dcerpc_winreg_QueryValue(h,
148                                           mem_ctx,
149                                           key_handle,
150                                           &wvalue,
151                                           &type,
152                                           blob.data,
153                                           &data_size,
154                                           &value_len,
155                                           &result);
156         if (!NT_STATUS_IS_OK(status)) {
157                 return status;
158         }
159         if (!W_ERROR_IS_OK(result)) {
160                 *pwerr = result;
161                 return status;
162         }
163
164         if (data) {
165                 data->data = blob.data;
166                 data->length = blob.length;
167         }
168
169         return status;
170 }
171
172 NTSTATUS dcerpc_winreg_query_multi_sz(TALLOC_CTX *mem_ctx,
173                                       struct dcerpc_binding_handle *h,
174                                       struct policy_handle *key_handle,
175                                       const char *value,
176                                       const char ***data,
177                                       WERROR *pwerr)
178 {
179         struct winreg_String wvalue;
180         enum winreg_Type type;
181         WERROR result = WERR_OK;
182         uint32_t value_len = 0;
183         uint32_t data_size = 0;
184         NTSTATUS status;
185         DATA_BLOB blob;
186
187         wvalue.name = value;
188
189         status = dcerpc_winreg_QueryValue(h,
190                                           mem_ctx,
191                                           key_handle,
192                                           &wvalue,
193                                           &type,
194                                           NULL,
195                                           &data_size,
196                                           &value_len,
197                                           &result);
198         if (!NT_STATUS_IS_OK(status)) {
199                 return status;
200         }
201         if (!W_ERROR_IS_OK(result)) {
202                 *pwerr = result;
203                 return status;
204         }
205
206         if (type != REG_MULTI_SZ) {
207                 *pwerr = WERR_INVALID_DATATYPE;
208                 return status;
209         }
210
211         blob = data_blob_talloc(mem_ctx, NULL, data_size);
212         if (blob.data == NULL) {
213                 *pwerr = WERR_NOMEM;
214                 return status;
215         }
216         value_len = 0;
217
218         status = dcerpc_winreg_QueryValue(h,
219                                           mem_ctx,
220                                           key_handle,
221                                           &wvalue,
222                                           &type,
223                                           blob.data,
224                                           &data_size,
225                                           &value_len,
226                                           &result);
227         if (!NT_STATUS_IS_OK(status)) {
228                 return status;
229         }
230         if (!W_ERROR_IS_OK(result)) {
231                 *pwerr = result;
232                 return status;
233         }
234
235         if (data) {
236                 bool ok;
237
238                 ok = pull_reg_multi_sz(mem_ctx, &blob, data);
239                 if (!ok) {
240                         *pwerr = WERR_NOMEM;
241                 }
242         }
243
244         return status;
245 }
246
247 NTSTATUS dcerpc_winreg_set_dword(TALLOC_CTX *mem_ctx,
248                                  struct dcerpc_binding_handle *h,
249                                  struct policy_handle *key_handle,
250                                  const char *value,
251                                  uint32_t data,
252                                  WERROR *pwerr)
253 {
254         struct winreg_String wvalue;
255         DATA_BLOB blob;
256         WERROR result = WERR_OK;
257         NTSTATUS status;
258
259         wvalue.name = value;
260         blob = data_blob_talloc(mem_ctx, NULL, 4);
261         SIVAL(blob.data, 0, data);
262
263         status = dcerpc_winreg_SetValue(h,
264                                         mem_ctx,
265                                         key_handle,
266                                         wvalue,
267                                         REG_DWORD,
268                                         blob.data,
269                                         blob.length,
270                                         &result);
271         if (!NT_STATUS_IS_OK(status)) {
272                 return status;
273         }
274         if (!W_ERROR_IS_OK(result)) {
275                 *pwerr = result;
276         }
277
278         return status;
279 }
280
281 NTSTATUS dcerpc_winreg_set_sz(TALLOC_CTX *mem_ctx,
282                               struct dcerpc_binding_handle *h,
283                               struct policy_handle *key_handle,
284                               const char *value,
285                               const char *data,
286                               WERROR *pwerr)
287 {
288         struct winreg_String wvalue;
289         DATA_BLOB blob;
290         WERROR result = WERR_OK;
291         NTSTATUS status;
292
293         wvalue.name = value;
294         if (data == NULL) {
295                 blob = data_blob_string_const("");
296         } else {
297                 if (!push_reg_sz(mem_ctx, &blob, data)) {
298                         DEBUG(2, ("dcerpc_winreg_set_sz: Could not marshall "
299                                   "string %s for %s\n",
300                                   data, wvalue.name));
301                         *pwerr = WERR_NOMEM;
302                         return NT_STATUS_OK;
303                 }
304         }
305
306         status = dcerpc_winreg_SetValue(h,
307                                         mem_ctx,
308                                         key_handle,
309                                         wvalue,
310                                         REG_SZ,
311                                         blob.data,
312                                         blob.length,
313                                         &result);
314         if (!NT_STATUS_IS_OK(status)) {
315                 return status;
316         }
317         if (!W_ERROR_IS_OK(result)) {
318                 *pwerr = result;
319         }
320
321         return status;
322 }
323
324 NTSTATUS dcerpc_winreg_set_expand_sz(TALLOC_CTX *mem_ctx,
325                                      struct dcerpc_binding_handle *h,
326                                      struct policy_handle *key_handle,
327                                      const char *value,
328                                      const char *data,
329                                      WERROR *pwerr)
330 {
331         struct winreg_String wvalue;
332         DATA_BLOB blob;
333         WERROR result = WERR_OK;
334         NTSTATUS status;
335
336         wvalue.name = value;
337         if (data == NULL) {
338                 blob = data_blob_string_const("");
339         } else {
340                 if (!push_reg_sz(mem_ctx, &blob, data)) {
341                         DEBUG(2, ("dcerpc_winreg_set_expand_sz: Could not marshall "
342                                   "string %s for %s\n",
343                                   data, wvalue.name));
344                         *pwerr = WERR_NOMEM;
345                         return NT_STATUS_OK;
346                 }
347         }
348
349         status = dcerpc_winreg_SetValue(h,
350                                         mem_ctx,
351                                         key_handle,
352                                         wvalue,
353                                         REG_EXPAND_SZ,
354                                         blob.data,
355                                         blob.length,
356                                         &result);
357         if (!NT_STATUS_IS_OK(status)) {
358                 return status;
359         }
360         if (!W_ERROR_IS_OK(result)) {
361                 *pwerr = result;
362         }
363
364         return status;
365 }
366
367 NTSTATUS dcerpc_winreg_set_multi_sz(TALLOC_CTX *mem_ctx,
368                                     struct dcerpc_binding_handle *h,
369                                     struct policy_handle *key_handle,
370                                     const char *value,
371                                     const char **data,
372                                     WERROR *pwerr)
373 {
374         struct winreg_String wvalue;
375         DATA_BLOB blob;
376         WERROR result = WERR_OK;
377         NTSTATUS status;
378
379         wvalue.name = value;
380         if (!push_reg_multi_sz(mem_ctx, &blob, data)) {
381                 DEBUG(2, ("dcerpc_winreg_set_multi_sz: Could not marshall "
382                           "string multi sz for %s\n",
383                           wvalue.name));
384                 *pwerr = WERR_NOMEM;
385                 return NT_STATUS_OK;
386         }
387
388         status = dcerpc_winreg_SetValue(h,
389                                         mem_ctx,
390                                         key_handle,
391                                         wvalue,
392                                         REG_MULTI_SZ,
393                                         blob.data,
394                                         blob.length,
395                                         &result);
396         if (!NT_STATUS_IS_OK(status)) {
397                 return status;
398         }
399         if (!W_ERROR_IS_OK(result)) {
400                 *pwerr = result;
401         }
402
403         return status;
404 }
405
406 NTSTATUS dcerpc_winreg_add_multi_sz(TALLOC_CTX *mem_ctx,
407                                     struct dcerpc_binding_handle *h,
408                                     struct policy_handle *key_handle,
409                                     const char *value,
410                                     const char *data,
411                                     WERROR *pwerr)
412 {
413         const char **a = NULL;
414         const char **p;
415         uint32_t i;
416         WERROR result = WERR_OK;
417         NTSTATUS status;
418
419         status = dcerpc_winreg_query_multi_sz(mem_ctx,
420                                               h,
421                                               key_handle,
422                                               value,
423                                               &a,
424                                               &result);
425
426         /* count the elements */
427         for (p = a, i = 0; p && *p; p++, i++);
428
429         p = TALLOC_REALLOC_ARRAY(mem_ctx, a, const char *, i + 2);
430         if (p == NULL) {
431                 *pwerr = WERR_NOMEM;
432                 return NT_STATUS_OK;
433         }
434
435         p[i] = data;
436         p[i + 1] = NULL;
437
438         status = dcerpc_winreg_set_multi_sz(mem_ctx,
439                                             h,
440                                             key_handle,
441                                             value,
442                                             p,
443                                             pwerr);
444
445         return status;
446 }
447
448 NTSTATUS dcerpc_winreg_enum_keys(TALLOC_CTX *mem_ctx,
449                                  struct dcerpc_binding_handle *h,
450                                  struct policy_handle *key_hnd,
451                                  uint32_t *pnum_subkeys,
452                                  const char ***psubkeys,
453                                  WERROR *pwerr)
454 {
455         const char **subkeys;
456         uint32_t num_subkeys, max_subkeylen, max_classlen;
457         uint32_t num_values, max_valnamelen, max_valbufsize;
458         uint32_t i;
459         NTTIME last_changed_time;
460         uint32_t secdescsize;
461         struct winreg_String classname;
462         WERROR result = WERR_OK;
463         NTSTATUS status;
464         TALLOC_CTX *tmp_ctx;
465
466         tmp_ctx = talloc_stackframe();
467         if (tmp_ctx == NULL) {
468                 return NT_STATUS_NO_MEMORY;
469         }
470
471         ZERO_STRUCT(classname);
472
473         status = dcerpc_winreg_QueryInfoKey(h,
474                                             tmp_ctx,
475                                             key_hnd,
476                                             &classname,
477                                             &num_subkeys,
478                                             &max_subkeylen,
479                                             &max_classlen,
480                                             &num_values,
481                                             &max_valnamelen,
482                                             &max_valbufsize,
483                                             &secdescsize,
484                                             &last_changed_time,
485                                             &result);
486         if (!NT_STATUS_IS_OK(status)) {
487                 goto error;
488         }
489         if (!W_ERROR_IS_OK(result)) {
490                 *pwerr = result;
491                 goto error;
492         }
493
494         subkeys = talloc_zero_array(tmp_ctx, const char *, num_subkeys + 2);
495         if (subkeys == NULL) {
496                 *pwerr = WERR_NOMEM;
497                 goto error;
498         }
499
500         if (num_subkeys == 0) {
501                 subkeys[0] = talloc_strdup(subkeys, "");
502                 if (subkeys[0] == NULL) {
503                         *pwerr = WERR_NOMEM;
504                         goto error;
505                 }
506                 *pnum_subkeys = 0;
507                 if (psubkeys) {
508                         *psubkeys = talloc_move(mem_ctx, &subkeys);
509                 }
510
511                 TALLOC_FREE(tmp_ctx);
512                 return NT_STATUS_OK;
513         }
514
515         for (i = 0; i < num_subkeys; i++) {
516                 char c = '\0';
517                 char n = '\0';
518                 char *name = NULL;
519                 struct winreg_StringBuf class_buf;
520                 struct winreg_StringBuf name_buf;
521                 NTTIME modtime;
522
523                 class_buf.name = &c;
524                 class_buf.size = max_classlen + 2;
525                 class_buf.length = 0;
526
527                 name_buf.name = &n;
528                 name_buf.size = max_subkeylen + 2;
529                 name_buf.length = 0;
530
531                 ZERO_STRUCT(modtime);
532
533                 status = dcerpc_winreg_EnumKey(h,
534                                                tmp_ctx,
535                                                key_hnd,
536                                                i,
537                                                &name_buf,
538                                                &class_buf,
539                                                &modtime,
540                                                &result);
541                 if (!NT_STATUS_IS_OK(status)) {
542                         DEBUG(5, ("dcerpc_winreg_enum_keys: Could not enumerate keys: %s\n",
543                                   nt_errstr(status)));
544                         goto error;
545                 }
546
547                 if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) {
548                         *pwerr = WERR_OK;
549                         break;
550                 }
551                 if (!W_ERROR_IS_OK(result)) {
552                         DEBUG(5, ("dcerpc_winreg_enum_keys: Could not enumerate keys: %s\n",
553                                   win_errstr(result)));
554                         *pwerr = result;
555                         goto error;
556                 }
557
558                 if (name_buf.name == NULL) {
559                         *pwerr = WERR_INVALID_PARAMETER;
560                         goto error;
561                 }
562
563                 name = talloc_strdup(subkeys, name_buf.name);
564                 if (name == NULL) {
565                         *pwerr = WERR_NOMEM;
566                         goto error;
567                 }
568
569                 subkeys[i] = name;
570         }
571
572         *pnum_subkeys = num_subkeys;
573         if (psubkeys) {
574                 *psubkeys = talloc_move(mem_ctx, &subkeys);
575         }
576
577  error:
578         TALLOC_FREE(tmp_ctx);
579
580         return status;
581 }
582
583 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */