net: add a "net registry" subcommand to locally access the registry.
[samba.git] / source / utils / net_registry.c
1 /*
2  * Samba Unix/Linux SMB client library
3  * Distributed SMB/CIFS Server Management Utility
4  * Local registry interface
5  *
6  * Copyright (C) Michael Adam 2008
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 "utils/net.h"
24
25
26 /*
27  *
28  * Helper functions
29  *
30  */
31
32 static void print_registry_key(const char *keyname, NTTIME *modtime)
33 {
34         d_printf("Keyname   = %s\n", keyname);
35         d_printf("Modtime   = %s\n",
36                  modtime
37                  ? http_timestring(nt_time_to_unix(*modtime))
38                  : "None");
39         d_printf("\n");
40 }
41
42 static void print_registry_value(const char *valname,
43                                  const struct registry_value *valvalue)
44 {
45         d_printf("Valuename  = %s\n", valname);
46         d_printf("Type       = %s\n",
47                  reg_type_lookup(valvalue->type));
48         switch(valvalue->type) {
49         case REG_DWORD:
50                 d_printf("Value      = %d\n", valvalue->v.dword);
51                 break;
52         case REG_SZ:
53         case REG_EXPAND_SZ:
54                 d_printf("Value      = \"%s\"\n", valvalue->v.sz.str);
55                 break;
56         case REG_MULTI_SZ: {
57                 uint32 j;
58                 for (j = 0; j < valvalue->v.multi_sz.num_strings; j++) {
59                         d_printf("Value[%3.3d] = \"%s\"\n", j,
60                                  valvalue->v.multi_sz.strings[j]);
61                 }
62                 break;
63         }
64         case REG_BINARY:
65                 d_printf("Value      = %d bytes\n",
66                          (int)valvalue->v.binary.length);
67                 break;
68         default:
69                 d_printf("Value      = <unprintable>\n");
70                 break;
71         }
72         d_printf("\n");
73 }
74
75 /**
76  * Split path into hive name and subkeyname
77  * normalizations performed:
78  *  - convert '/' to '\\'
79  *  - strip trailing '\\' chars
80  */
81 static WERROR split_hive_key(TALLOC_CTX *ctx, const char *path,
82                              char **hivename, const char **subkeyname)
83 {
84         char *p;
85
86         if ((path == NULL) || (hivename == NULL) || (subkeyname == NULL)) {
87                 return WERR_INVALID_PARAM;
88         }
89
90         if (strlen(path) == 0) {
91                 return WERR_INVALID_PARAM;
92         }
93
94         *hivename = talloc_string_sub(ctx, path, "/", "\\");
95         if (*hivename == NULL) {
96                 return WERR_NOMEM;
97         }
98
99         /* strip trailing '\\' chars */
100         p = strrchr(*hivename, '\\');
101         while ((p != NULL) && (p[1] == '\0')) {
102                 *p = '\0';
103                 p = strrchr(*hivename, '\\');
104         }
105
106         p = strchr(*hivename, '\\');
107
108         if ((p == NULL) || (*p == '\0')) {
109                 /* just the hive - no subkey given */
110                 *subkeyname = "";
111         } else {
112                 *p = '\0';
113                 *subkeyname = p+1;
114         }
115
116         return WERR_OK;
117 }
118
119 /**
120  * split given path into hive and remaining path and open the hive key
121  */
122 static WERROR open_hive(TALLOC_CTX *ctx, const char *path,
123                         uint32 desired_access,
124                         struct registry_key **hive,
125                         char **subkeyname)
126 {
127         WERROR werr;
128         NT_USER_TOKEN *token = NULL;
129         char *hivename = NULL;
130         const char *tmp_subkeyname = NULL;
131         TALLOC_CTX *tmp_ctx = talloc_stackframe();
132
133         if ((hive == NULL) || (subkeyname == NULL)) {
134                 werr = WERR_INVALID_PARAM;
135                 goto done;
136         }
137
138         werr = split_hive_key(tmp_ctx, path, &hivename, &tmp_subkeyname);
139         if (!W_ERROR_IS_OK(werr)) {
140                 goto done;
141         }
142         *subkeyname = talloc_strdup(ctx, tmp_subkeyname);
143         if (*subkeyname == NULL) {
144                 werr = WERR_NOMEM;
145                 goto done;
146         }
147
148         werr = ntstatus_to_werror(registry_create_admin_token(tmp_ctx, &token));
149         if (!W_ERROR_IS_OK(werr)) {
150                 goto done;
151         }
152
153         werr = reg_openhive(ctx, hivename, desired_access, token, hive);
154         if (!W_ERROR_IS_OK(werr)) {
155                 goto done;
156         }
157
158         werr = WERR_OK;
159
160 done:
161         TALLOC_FREE(tmp_ctx);
162         return werr;
163 }
164
165 static WERROR open_key(TALLOC_CTX *ctx, const char *path,
166                        uint32 desired_access,
167                        struct registry_key **key)
168 {
169         WERROR werr;
170         char *subkey_name = NULL;
171         struct registry_key *hive = NULL;
172         TALLOC_CTX *tmp_ctx = talloc_stackframe();
173
174         if ((path == NULL) || (key == NULL)) {
175                 return WERR_INVALID_PARAM;
176         }
177
178         werr = open_hive(tmp_ctx, path, desired_access, &hive, &subkey_name);
179         if (!W_ERROR_IS_OK(werr)) {
180                 d_fprintf(stderr, "open_hive failed: %s\n", dos_errstr(werr));
181                 goto done;
182         }
183
184         werr = reg_openkey(ctx, hive, subkey_name, desired_access, key);
185         if (!W_ERROR_IS_OK(werr)) {
186                 d_fprintf(stderr, "reg_openkey failed: %s\n",
187                           dos_errstr(werr));
188                 goto done;
189         }
190
191         werr = WERR_OK;
192
193 done:
194         TALLOC_FREE(tmp_ctx);
195         return werr;
196 }
197
198 /*
199  *
200  * the main "net registry" function implementations
201  *
202  */
203
204 static int net_registry_enumerate(int argc, const char **argv)
205 {
206         WERROR werr;
207         struct registry_key *key = NULL;
208         TALLOC_CTX *ctx = talloc_stackframe();
209         char *subkey_name;
210         NTTIME *modtime;
211         uint32_t count;
212         char *valname = NULL;
213         struct registry_value *valvalue = NULL;
214         int ret = -1;
215
216         if (argc != 1) {
217                 d_printf("Usage:    net registry enumerate <path>\n");
218                 d_printf("Example:  net registry enumerate "
219                          "'HKLM\\Software\\Samba'\n");
220                 goto done;
221         }
222
223         werr = open_key(ctx, argv[0], REG_KEY_READ, &key);
224         if (!W_ERROR_IS_OK(werr)) {
225                 d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
226                 goto done;
227         }
228
229         for (count = 0;
230              werr = reg_enumkey(ctx, key, count, &subkey_name, modtime),
231              W_ERROR_IS_OK(werr);
232              count++)
233         {
234                 print_registry_key(subkey_name, modtime);
235         }
236         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
237                 goto done;
238         }
239
240         for (count = 0;
241              werr = reg_enumvalue(ctx, key, count, &valname, &valvalue),
242              W_ERROR_IS_OK(werr);
243              count++)
244         {
245                 print_registry_value(valname, valvalue);
246         }
247         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
248                 goto done;
249         }
250
251         ret = 0;
252 done:
253         TALLOC_FREE(ctx);
254         return ret;
255 }
256
257 static int net_registry_createkey(int argc, const char **argv)
258 {
259         WERROR werr;
260         enum winreg_CreateAction action;
261         char *subkeyname;
262         struct registry_key *hivekey = NULL;
263         struct registry_key *subkey = NULL;
264         TALLOC_CTX *ctx = talloc_stackframe();
265         int ret = -1;
266
267         if (argc != 1) {
268                 d_printf("Usage:    net registry createkey <path>\n");
269                 d_printf("Example:  net registry createkey "
270                          "'HKLM\\Software\\Samba\\smbconf.127.0.0.1'\n");
271                 goto done;
272         }
273         if (strlen(argv[0]) == 0) {
274                 d_fprintf(stderr, "error: zero length key name given\n");
275                 goto done;
276         }
277
278         werr = open_hive(ctx, argv[0], REG_KEY_WRITE, &hivekey, &subkeyname);
279         if (!W_ERROR_IS_OK(werr)) {
280                 d_fprintf(stderr, "open_hive failed: %s\n", dos_errstr(werr));
281                 goto done;
282         }
283
284         werr = reg_createkey(ctx, hivekey, subkeyname, REG_KEY_WRITE,
285                              &subkey, &action);
286         if (!W_ERROR_IS_OK(werr)) {
287                 d_fprintf(stderr, "reg_createkey failed: %s\n",
288                           dos_errstr(werr));
289                 goto done;
290         }
291         switch (action) {
292                 case REG_ACTION_NONE:
293                         d_printf("createkey did nothing -- huh?\n");
294                         break;
295                 case REG_CREATED_NEW_KEY:
296                         d_printf("createkey created %s\n", argv[0]);
297                         break;
298                 case REG_OPENED_EXISTING_KEY:
299                         d_printf("createkey opened existing %s\n", argv[0]);
300                         break;
301         }
302
303         ret = 0;
304
305 done:
306         TALLOC_FREE(ctx);
307         return ret;
308 }
309
310 static int net_registry_deletekey(int argc, const char **argv)
311 {
312         WERROR werr;
313         char *subkeyname;
314         struct registry_key *hivekey = NULL;
315         TALLOC_CTX *ctx = talloc_stackframe();
316         int ret = -1;
317
318         if (argc != 1) {
319                 d_printf("Usage:    net registry deletekey <path>\n");
320                 d_printf("Example:  net registry deletekey "
321                          "'HKLM\\Software\\Samba\\smbconf.127.0.0.1'\n");
322                 goto done;
323         }
324         if (strlen(argv[0]) == 0) {
325                 d_fprintf(stderr, "error: zero length key name given\n");
326                 goto done;
327         }
328
329         werr = open_hive(ctx, argv[0], REG_KEY_WRITE, &hivekey, &subkeyname);
330         if (!W_ERROR_IS_OK(werr)) {
331                 d_fprintf(stderr, "open_hive failed: %s\n", dos_errstr(werr));
332                 goto done;
333         }
334
335         werr = reg_deletekey(hivekey, subkeyname);
336         if (!W_ERROR_IS_OK(werr)) {
337                 d_fprintf(stderr, "reg_deletekey failed: %s\n",
338                           dos_errstr(werr));
339                 goto done;
340         }
341
342         ret = 0;
343
344 done:
345         TALLOC_FREE(ctx);
346         return ret;
347 }
348
349 static int net_registry_setvalue(int argc, const char **argv)
350 {
351         WERROR werr;
352         struct registry_value value;
353         struct registry_key *key = NULL;
354         int ret = -1;
355         TALLOC_CTX *ctx = talloc_stackframe();
356
357         if (argc < 4) {
358                 d_fprintf(stderr, "usage: net rpc registry setvalue <key> "
359                           "<valuename> <type> [<val>]+\n");
360                 goto done;
361         }
362
363         if (!strequal(argv[2], "multi_sz") && (argc != 4)) {
364                 d_fprintf(stderr, "Too many args for type %s\n", argv[2]);
365                 goto done;
366         }
367
368         if (strequal(argv[2], "dword")) {
369                 value.type = REG_DWORD;
370                 value.v.dword = strtoul(argv[3], NULL, 10);
371         } else if (strequal(argv[2], "sz")) {
372                 value.type = REG_SZ;
373                 value.v.sz.len = strlen(argv[3])+1;
374                 value.v.sz.str = CONST_DISCARD(char *, argv[3]);
375         } else {
376                 d_fprintf(stderr, "type \"%s\" not implemented\n", argv[2]);
377                 goto done;
378         }
379
380         werr = open_key(ctx, argv[0], REG_KEY_WRITE, &key);
381         if (!W_ERROR_IS_OK(werr)) {
382                 d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
383                 goto done;
384         }
385
386         werr = reg_setvalue(key, argv[1], &value);
387         if (!W_ERROR_IS_OK(werr)) {
388                 d_fprintf(stderr, "reg_setvalue failed: %s\n",
389                           dos_errstr(werr));
390                 goto done;
391         }
392
393         ret = 0;
394
395 done:
396         TALLOC_FREE(ctx);
397         return ret;
398 }
399
400 static int net_registry_deletevalue(int argc, const char **argv)
401 {
402         WERROR werr;
403         struct registry_key *key = NULL;
404         TALLOC_CTX *ctx = talloc_stackframe();
405         int ret = -1;
406
407         if (argc != 2) {
408                 d_fprintf(stderr, "usage: net rpc registry deletevalue <key> "
409                           "<valuename>\n");
410                 goto done;
411         }
412
413         werr = open_key(ctx, argv[0], REG_KEY_WRITE, &key);
414         if (!W_ERROR_IS_OK(werr)) {
415                 d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
416                 goto done;
417         }
418
419         werr = reg_deletevalue(key, argv[1]);
420         if (!W_ERROR_IS_OK(werr)) {
421                 d_fprintf(stderr, "reg_deletekey failed: %s\n",
422                           dos_errstr(werr));
423                 goto done;
424         }
425
426         ret = 0;
427
428 done:
429         TALLOC_FREE(ctx);
430         return ret;
431 }
432
433 static int net_registry_getsd(int argc, const char **argv)
434 {
435         WERROR werr;
436         int ret = -1;
437         struct registry_key *key = NULL;
438         struct security_descriptor *secdesc = NULL;
439         TALLOC_CTX *ctx = talloc_stackframe();
440         uint32_t access_mask = REG_KEY_READ |
441                                SEC_RIGHT_MAXIMUM_ALLOWED |
442                                SEC_RIGHT_SYSTEM_SECURITY;
443
444         /*
445          * net_rpc_regsitry uses SEC_RIGHT_SYSTEM_SECURITY, but access
446          * is denied with these perms right now...
447          */
448         access_mask = REG_KEY_READ;
449
450         if (argc != 1) {
451                 d_printf("Usage:    net registry getsd <path>\n");
452                 d_printf("Example:  net registry getsd "
453                          "'HKLM\\Software\\Samba'\n");
454                 goto done;
455         }
456         if (strlen(argv[0]) == 0) {
457                 d_fprintf(stderr, "error: zero length key name given\n");
458                 goto done;
459         }
460
461         werr = open_key(ctx, argv[0], access_mask, &key);
462         if (!W_ERROR_IS_OK(werr)) {
463                 d_fprintf(stderr, "open_key failed: %s\n", dos_errstr(werr));
464                 goto done;
465         }
466
467         werr = reg_getkeysecurity(ctx, key, &secdesc);
468         if (!W_ERROR_IS_OK(werr)) {
469                 d_fprintf(stderr, "reg_getkeysecurity failed: %s\n",
470                           dos_errstr(werr));
471                 goto done;
472         }
473
474         display_sec_desc(secdesc);
475
476         ret = 0;
477
478 done:
479         TALLOC_FREE(ctx);
480         return ret;
481 }
482
483 int net_registry(int argc, const char **argv)
484 {
485         int ret = -1;
486
487         struct functable2 func[] = {
488                 {
489                         "enumerate",
490                         net_registry_enumerate,
491                         "Enumerate registry keys and values"
492                 },
493                 {
494                         "createkey",
495                         net_registry_createkey,
496                         "Create a new registry key"
497                 },
498                 {
499                         "deletekey",
500                         net_registry_deletekey,
501                         "Delete a registry key"
502                 },
503                 {
504                         "setvalue",
505                         net_registry_setvalue,
506                         "Set a new registry value"
507                 },
508                 {
509                         "deletevalue",
510                         net_registry_deletevalue,
511                         "Delete a registry value"
512                 },
513                 {
514                         "getsd",
515                         net_registry_getsd,
516                         "Get security descriptor"
517                 },
518         { NULL, NULL, NULL }
519         };
520
521         if (!registry_init_basic()) {
522                 return -1;
523         }
524
525         ret = net_run_function2(argc, argv, "net registry", func);
526
527         regdb_close();
528
529         return ret;
530 }