8fe2c76ea3eebdf8bed7303043005f969d2b43c7
[ira/wip.git] / source3 / libnet / libnet_conf.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libnet smbconf registry Support
4  *  Copyright (C) Michael Adam 2007
5  *  Copyright (C) Guenther Deschner 2007
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "libnet/libnet.h"
23
24 /**********************************************************************
25  *
26  * Helper functions (mostly registry related)
27  * TODO: These should be eventually static.
28
29  **********************************************************************/
30
31 /**
32  * add a string to a talloced array of strings.
33  */
34 static WERROR libnet_smbconf_add_string_to_array(TALLOC_CTX *mem_ctx,
35                                                 char ***array,
36                                                 uint32_t count,
37                                                 const char *string)
38 {
39         char **new_array = NULL;
40
41         if ((array == NULL) || (string == NULL)) {
42                 return WERR_INVALID_PARAM;
43         }
44
45         new_array = TALLOC_REALLOC_ARRAY(mem_ctx, *array, char *, count + 1);
46         if (new_array == NULL) {
47                 return WERR_NOMEM;
48         }
49
50         new_array[count] = talloc_strdup(new_array, string);
51
52         *array = new_array;
53
54         return WERR_OK;
55 }
56
57 /*
58  * Open a subkey of KEY_SMBCONF (i.e a service)
59  */
60 static WERROR libnet_smbconf_reg_open_path(TALLOC_CTX *ctx,
61                                            const char *subkeyname,
62                                            uint32 desired_access,
63                                            struct registry_key **key)
64 {
65         WERROR werr = WERR_OK;
66         char *path = NULL;
67         NT_USER_TOKEN *token;
68
69         if (!(token = registry_create_admin_token(ctx))) {
70                 DEBUG(1, ("Error creating admin token\n"));
71                 goto done;
72         }
73
74         if (subkeyname == NULL) {
75                 path = talloc_strdup(ctx, KEY_SMBCONF);
76         } else {
77                 path = talloc_asprintf(ctx, "%s\\%s", KEY_SMBCONF, subkeyname);
78         }
79
80         werr = reg_open_path(ctx, path, desired_access,
81                              token, key);
82
83         if (!W_ERROR_IS_OK(werr)) {
84                 DEBUG(1, ("Error opening registry path '%s': %s\n",
85                           path, dos_errstr(werr)));
86         }
87
88 done:
89         TALLOC_FREE(path);
90         return werr;
91 }
92
93 /*
94  * open the base key KEY_SMBCONF
95  */
96 static WERROR libnet_smbconf_reg_open_basepath(TALLOC_CTX *ctx,
97                                                uint32 desired_access,
98                                                struct registry_key **key)
99 {
100         return libnet_smbconf_reg_open_path(ctx, NULL, desired_access, key);
101 }
102
103 /*
104  * check if a subkey of KEY_SMBCONF of a given name exists
105  */
106 bool libnet_smbconf_key_exists(const char *subkeyname)
107 {
108         bool ret = false;
109         WERROR werr = WERR_OK;
110         TALLOC_CTX *mem_ctx = talloc_stackframe();
111         struct registry_key *key = NULL;
112
113         werr = libnet_smbconf_reg_open_path(mem_ctx, subkeyname, REG_KEY_READ,
114                                             &key);
115         if (W_ERROR_IS_OK(werr)) {
116                 ret = true;
117         }
118
119         TALLOC_FREE(mem_ctx);
120         return ret;
121 }
122
123 static bool libnet_smbconf_value_exists(struct registry_key *key,
124                                         const char *param)
125 {
126         bool ret = false;
127         WERROR werr = WERR_OK;
128         TALLOC_CTX *ctx = talloc_stackframe();
129         struct registry_value *value = NULL;
130
131         werr = reg_queryvalue(ctx, key, param, &value);
132         if (W_ERROR_IS_OK(werr)) {
133                 ret = true;
134         }
135
136         TALLOC_FREE(ctx);
137         return ret;
138 }
139
140 /*
141  * create a subkey of KEY_SMBCONF
142  */
143 WERROR libnet_smbconf_reg_createkey_internal(TALLOC_CTX *ctx,
144                                              const char * subkeyname,
145                                              struct registry_key **newkey)
146 {
147         WERROR werr = WERR_OK;
148         struct registry_key *create_parent = NULL;
149         TALLOC_CTX *create_ctx;
150         enum winreg_CreateAction action = REG_ACTION_NONE;
151
152         /* create a new talloc ctx for creation. it will hold
153          * the intermediate parent key (SMBCONF) for creation
154          * and will be destroyed when leaving this function... */
155         if (!(create_ctx = talloc_new(ctx))) {
156                 werr = WERR_NOMEM;
157                 goto done;
158         }
159
160         werr = libnet_smbconf_reg_open_basepath(create_ctx, REG_KEY_WRITE,
161                                                 &create_parent);
162         if (!W_ERROR_IS_OK(werr)) {
163                 goto done;
164         }
165
166         werr = reg_createkey(ctx, create_parent, subkeyname,
167                              REG_KEY_WRITE, newkey, &action);
168         if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
169                 DEBUG(10, ("Key '%s' already exists.\n", subkeyname));
170                 werr = WERR_ALREADY_EXISTS;
171         }
172         if (!W_ERROR_IS_OK(werr)) {
173                 DEBUG(5, ("Error creating key %s: %s\n",
174                          subkeyname, dos_errstr(werr)));
175         }
176
177 done:
178         TALLOC_FREE(create_ctx);
179         return werr;
180 }
181
182 /*
183  * add a value to a key.
184  */
185 WERROR libnet_smbconf_reg_setvalue_internal(struct registry_key *key,
186                                                    const char *valname,
187                                                    const char *valstr)
188 {
189         struct registry_value val;
190         WERROR werr = WERR_OK;
191         char *subkeyname;
192         const char *canon_valname;
193         const char *canon_valstr;
194
195         if (!lp_canonicalize_parameter_with_value(valname, valstr,
196                                                   &canon_valname,
197                                                   &canon_valstr))
198         {
199                 if (canon_valname == NULL) {
200                         DEBUG(5, ("invalid parameter '%s' given\n",
201                                   valname));
202                 } else {
203                         DEBUG(5, ("invalid value '%s' given for "
204                                   "parameter '%s'\n", valstr, valname));
205                 }
206                 werr = WERR_INVALID_PARAM;
207                 goto done;
208         }
209
210         ZERO_STRUCT(val);
211
212         val.type = REG_SZ;
213         val.v.sz.str = CONST_DISCARD(char *, canon_valstr);
214         val.v.sz.len = strlen(canon_valstr) + 1;
215
216         if (registry_smbconf_valname_forbidden(canon_valname)) {
217                 DEBUG(5, ("Parameter '%s' not allowed in registry.\n",
218                           canon_valname));
219                 werr = WERR_INVALID_PARAM;
220                 goto done;
221         }
222
223         subkeyname = strrchr_m(key->key->name, '\\');
224         if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) {
225                 DEBUG(5, ("Invalid registry key '%s' given as "
226                           "smbconf section.\n", key->key->name));
227                 werr = WERR_INVALID_PARAM;
228                 goto done;
229         }
230         subkeyname++;
231         if (!strequal(subkeyname, GLOBAL_NAME) &&
232             lp_parameter_is_global(valname))
233         {
234                 DEBUG(5, ("Global paramter '%s' not allowed in "
235                           "service definition ('%s').\n", canon_valname,
236                           subkeyname));
237                 werr = WERR_INVALID_PARAM;
238                 goto done;
239         }
240
241         werr = reg_setvalue(key, canon_valname, &val);
242         if (!W_ERROR_IS_OK(werr)) {
243                 DEBUG(5, ("Error adding value '%s' to "
244                           "key '%s': %s\n",
245                           canon_valname, key->key->name, dos_errstr(werr)));
246         }
247
248 done:
249         return werr;
250 }
251
252 /**
253  * format a registry_value into a string.
254  *
255  * This is intended to be used for smbconf registry values,
256  * which are ar stored as REG_SZ values, so the incomplete
257  * handling should be ok.
258  */
259 static char *libnet_smbconf_format_registry_value(TALLOC_CTX *mem_ctx,
260                                                   struct registry_value *value)
261 {
262         char *result = NULL;
263
264         /* alternatively, create a new talloc context? */
265         if (mem_ctx == NULL) {
266                 return result;
267         }
268
269         switch (value->type) {
270         case REG_DWORD:
271                 result = talloc_asprintf(mem_ctx, "%d", value->v.dword);
272                 break;
273         case REG_SZ:
274         case REG_EXPAND_SZ:
275                 result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str);
276                 break;
277         case REG_MULTI_SZ: {
278                 uint32 j;
279                 for (j = 0; j < value->v.multi_sz.num_strings; j++) {
280                         result = talloc_asprintf(mem_ctx, "\"%s\" ",
281                                                  value->v.multi_sz.strings[j]);
282                 }
283                 break;
284         }
285         case REG_BINARY:
286                 result = talloc_asprintf(mem_ctx, "binary (%d bytes)",
287                                          (int)value->v.binary.length);
288                 break;
289         default:
290                 result = talloc_asprintf(mem_ctx, "<unprintable>");
291                 break;
292         }
293         return result;
294 }
295
296 /**
297  * Get the values of a key as a list of value names
298  * and a list of value strings (ordered)
299  */
300 static WERROR libnet_smbconf_reg_get_values(TALLOC_CTX *mem_ctx,
301                                             struct registry_key *key,
302                                             uint32_t *num_values,
303                                             char ***value_names,
304                                             char ***value_strings)
305 {
306         TALLOC_CTX *tmp_ctx = NULL;
307         WERROR werr = WERR_OK;
308         uint32_t count;
309         struct registry_value *valvalue = NULL;
310         char *valname = NULL;
311         char **tmp_valnames = NULL;
312         char **tmp_valstrings = NULL;
313
314         if ((num_values == NULL) || (value_names == NULL) ||
315             (value_strings == NULL))
316         {
317                 werr = WERR_INVALID_PARAM;
318                 goto done;
319         }
320
321         tmp_ctx = talloc_new(mem_ctx);
322         if (tmp_ctx == NULL) {
323                 werr = WERR_NOMEM;
324                 goto done;
325         }
326
327         for (count = 0;
328              W_ERROR_IS_OK(werr = reg_enumvalue(tmp_ctx, key, count, &valname,
329                                                 &valvalue));
330              count++)
331         {
332                 char *valstring;
333
334                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
335                                                           &tmp_valnames,
336                                                           count, valname);
337                 if (!W_ERROR_IS_OK(werr)) {
338                         goto done;
339                 }
340
341                 valstring = libnet_smbconf_format_registry_value(tmp_ctx,
342                                                                  valvalue);
343                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
344                                                           &tmp_valstrings,
345                                                           count,
346                                                           valstring);
347                 if (!W_ERROR_IS_OK(werr)) {
348                         goto done;
349                 }
350         }
351         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
352                 goto done;
353         }
354
355         werr = WERR_OK;
356
357         *num_values = count;
358         if (count > 0) {
359                 *value_names = talloc_move(mem_ctx, &tmp_valnames);
360                 *value_strings = talloc_move(mem_ctx, &tmp_valstrings);
361         } else {
362                 *value_names = NULL;
363                 *value_strings = NULL;
364         }
365
366 done:
367         TALLOC_FREE(tmp_ctx);
368         return werr;
369 }
370
371 /**********************************************************************
372  *
373  * The actual net conf api functions, that are exported.
374  *
375  **********************************************************************/
376
377 /**
378  * Drop the whole configuration (restarting empty).
379  */
380 WERROR libnet_smbconf_drop(void)
381 {
382         char *path, *p;
383         WERROR werr = WERR_OK;
384         NT_USER_TOKEN *token;
385         struct registry_key *parent_key = NULL;
386         struct registry_key *new_key = NULL;
387         TALLOC_CTX* mem_ctx = talloc_stackframe();
388         enum winreg_CreateAction action;
389
390         if (!(token = registry_create_admin_token(mem_ctx))) {
391                 /* what is the appropriate error code here? */
392                 werr = WERR_CAN_NOT_COMPLETE;
393                 goto done;
394         }
395
396         path = talloc_strdup(mem_ctx, KEY_SMBCONF);
397         if (path == NULL) {
398                 werr = WERR_NOMEM;
399                 goto done;
400         }
401         p = strrchr(path, '\\');
402         *p = '\0';
403         werr = reg_open_path(mem_ctx, path, REG_KEY_WRITE, token, &parent_key);
404
405         if (!W_ERROR_IS_OK(werr)) {
406                 goto done;
407         }
408
409         werr = reg_deletekey_recursive(mem_ctx, parent_key, p+1);
410
411         if (!W_ERROR_IS_OK(werr)) {
412                 goto done;
413         }
414
415         werr = reg_createkey(mem_ctx, parent_key, p+1, REG_KEY_WRITE,
416                              &new_key, &action);
417
418 done:
419         TALLOC_FREE(mem_ctx);
420         return werr;
421 }
422
423 /**
424  * Get the whole configuration as lists of strings with counts:
425  *
426  *  num_shares   : number of shares
427  *  share_names  : list of length num_shares of share names
428  *  num_params   : list of length num_shares of parameter counts for each share
429  *  param_names  : list of lists of parameter names for each share
430  *  param_values : list of lists of parameter values for each share
431  */
432 WERROR libnet_smbconf_get_config(TALLOC_CTX *mem_ctx, uint32_t *num_shares,
433                                  char ***share_names, uint32_t **num_params,
434                                  char ****param_names, char ****param_values)
435 {
436         WERROR werr = WERR_OK;
437         TALLOC_CTX *tmp_ctx = NULL;
438         uint32_t tmp_num_shares;
439         char **tmp_share_names;
440         uint32_t *tmp_num_params;
441         char ***tmp_param_names;
442         char ***tmp_param_values;
443         uint32_t count;
444
445         if ((num_shares == NULL) || (share_names == NULL) ||
446             (num_params == NULL) || (param_names == NULL) ||
447             (param_values == NULL))
448         {
449                 werr = WERR_INVALID_PARAM;
450                 goto done;
451         }
452
453         tmp_ctx = talloc_new(mem_ctx);
454         if (tmp_ctx == NULL) {
455                 werr = WERR_NOMEM;
456                 goto done;
457         }
458
459         werr = libnet_smbconf_get_share_names(tmp_ctx, &tmp_num_shares,
460                                               &tmp_share_names);
461         if (!W_ERROR_IS_OK(werr)) {
462                 goto done;
463         }
464
465         tmp_num_params   = TALLOC_ARRAY(tmp_ctx, uint32_t, tmp_num_shares);
466         tmp_param_names  = TALLOC_ARRAY(tmp_ctx, char **, tmp_num_shares);
467         tmp_param_values = TALLOC_ARRAY(tmp_ctx, char **, tmp_num_shares);
468
469         if ((tmp_num_params == NULL) || (tmp_param_names == NULL) ||
470             (tmp_param_values == NULL))
471         {
472                 werr = WERR_NOMEM;
473                 goto done;
474         }
475
476         for (count = 0; count < tmp_num_shares; count++) {
477                 werr = libnet_smbconf_getshare(mem_ctx, tmp_share_names[count],
478                                                &tmp_num_params[count],
479                                                &tmp_param_names[count],
480                                                &tmp_param_values[count]);
481                 if (!W_ERROR_IS_OK(werr)) {
482                         goto done;
483                 }
484         }
485
486         werr = WERR_OK;
487
488         *num_shares = tmp_num_shares;
489         if (tmp_num_shares > 0) {
490                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
491                 *num_params = talloc_move(mem_ctx, &tmp_num_params);
492                 *param_names = talloc_move(mem_ctx, &tmp_param_names);
493                 *param_values = talloc_move(mem_ctx, &tmp_param_values);
494         } else {
495                 *share_names = NULL;
496                 *num_params = NULL;
497                 *param_names = NULL;
498                 *param_values = NULL;
499         }
500
501 done:
502         TALLOC_FREE(tmp_ctx);
503         return werr;
504 }
505
506
507 /**
508  * get the list of share names defined in the configuration.
509  */
510 WERROR libnet_smbconf_get_share_names(TALLOC_CTX *mem_ctx, uint32_t *num_shares,
511                                       char ***share_names)
512 {
513         uint32_t count;
514         uint32_t added_count = 0;
515         TALLOC_CTX *tmp_ctx = NULL;
516         WERROR werr = WERR_OK;
517         struct registry_key *key = NULL;
518         char *subkey_name = NULL;
519         char **tmp_share_names = NULL;
520
521         if ((num_shares == NULL) || (share_names == NULL)) {
522                 werr = WERR_INVALID_PARAM;
523                 goto done;
524         }
525
526         tmp_ctx = talloc_new(mem_ctx);
527         if (tmp_ctx == NULL) {
528                 werr = WERR_NOMEM;
529                 goto done;
530         }
531
532         /* make sure "global" is always listed first */
533         if (libnet_smbconf_key_exists(GLOBAL_NAME)) {
534                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
535                                                           &tmp_share_names,
536                                                           0, GLOBAL_NAME);
537                 if (!W_ERROR_IS_OK(werr)) {
538                         goto done;
539                 }
540                 added_count++;
541         }
542
543         werr = libnet_smbconf_reg_open_basepath(tmp_ctx,
544                                                 SEC_RIGHTS_ENUM_SUBKEYS,
545                                                 &key);
546         if (!W_ERROR_IS_OK(werr)) {
547                 goto done;
548         }
549
550         for (count = 0;
551              W_ERROR_IS_OK(werr = reg_enumkey(tmp_ctx, key, count,
552                                               &subkey_name, NULL));
553              count++)
554         {
555                 if (strequal(subkey_name, GLOBAL_NAME)) {
556                         continue;
557                 }
558
559                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
560                                                           &tmp_share_names,
561                                                           added_count,
562                                                           subkey_name);
563                 if (!W_ERROR_IS_OK(werr)) {
564                         goto done;
565                 }
566                 added_count++;
567         }
568         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
569                 goto done;
570         }
571         werr = WERR_OK;
572
573         *num_shares = added_count;
574         if (added_count > 0) {
575                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
576         } else {
577                 *share_names = NULL;
578         }
579
580 done:
581         TALLOC_FREE(tmp_ctx);
582         return werr;
583 }
584
585 /**
586  * get a definition of a share (service) from configuration.
587  */
588 WERROR libnet_smbconf_getshare(TALLOC_CTX *mem_ctx, const char *servicename,
589                                uint32_t *num_params, char ***param_names,
590                                char ***param_values)
591 {
592         WERROR werr = WERR_OK;
593         struct registry_key *key = NULL;
594
595         werr = libnet_smbconf_reg_open_path(mem_ctx, servicename, REG_KEY_READ,
596                                             &key);
597         if (!W_ERROR_IS_OK(werr)) {
598                 goto done;
599         }
600
601         werr = libnet_smbconf_reg_get_values(mem_ctx, key, num_params,
602                                              param_names, param_values);
603
604 done:
605         TALLOC_FREE(key);
606         return werr;
607 }
608
609 /**
610  * delete a service from configuration
611  */
612 WERROR libnet_smbconf_delshare(const char *servicename)
613 {
614         WERROR werr = WERR_OK;
615         struct registry_key *key = NULL;
616         TALLOC_CTX *ctx = talloc_stackframe();
617
618         werr = libnet_smbconf_reg_open_basepath(ctx, REG_KEY_WRITE, &key);
619         if (!W_ERROR_IS_OK(werr)) {
620                 goto done;
621         }
622
623         werr = reg_deletekey_recursive(key, key, servicename);
624
625 done:
626         TALLOC_FREE(ctx);
627         return werr;
628 }
629
630 /**
631  * set a configuration parameter to the value provided.
632  */
633 WERROR libnet_smbconf_setparm(const char *service,
634                               const char *param,
635                               const char *valstr)
636 {
637         WERROR werr;
638         struct registry_key *key = NULL;
639         TALLOC_CTX *mem_ctx = talloc_stackframe();
640
641         if (!libnet_smbconf_key_exists(service)) {
642                 werr = libnet_smbconf_reg_createkey_internal(mem_ctx, service,
643                                                              &key);
644         } else {
645                 werr = libnet_smbconf_reg_open_path(mem_ctx, service,
646                                                     REG_KEY_WRITE, &key);
647         }
648         if (!W_ERROR_IS_OK(werr)) {
649                 goto done;
650         }
651
652         werr = libnet_smbconf_reg_setvalue_internal(key, param, valstr);
653
654 done:
655         TALLOC_FREE(mem_ctx);
656         return werr;
657 }
658
659 /**
660  * get the value of a configuration parameter as a string
661  */
662 WERROR libnet_smbconf_getparm(TALLOC_CTX *mem_ctx,
663                               const char *service,
664                               const char *param,
665                               char **valstr)
666 {
667         WERROR werr = WERR_OK;
668         struct registry_key *key = NULL;
669         struct registry_value *value = NULL;
670
671         if (valstr == NULL) {
672                 werr = WERR_INVALID_PARAM;
673                 goto done;
674         }
675
676         if (!libnet_smbconf_key_exists(service)) {
677                 werr = WERR_NO_SUCH_SERVICE;
678                 goto done;
679         }
680
681         werr = libnet_smbconf_reg_open_path(mem_ctx, service, REG_KEY_READ,
682                                             &key);
683         if (!W_ERROR_IS_OK(werr)) {
684                 goto done;
685         }
686
687         if (!libnet_smbconf_value_exists(key, param)) {
688                 werr = WERR_INVALID_PARAM;
689                 goto done;
690         }
691
692         werr = reg_queryvalue(mem_ctx, key, param, &value);
693         if (!W_ERROR_IS_OK(werr)) {
694                 goto done;
695         }
696
697         *valstr = libnet_smbconf_format_registry_value(mem_ctx, value);
698
699         if (*valstr == NULL) {
700                 werr = WERR_NOMEM;
701         }
702
703 done:
704         TALLOC_FREE(key);
705         TALLOC_FREE(value);
706         return werr;
707 }
708
709 /**
710  * delete a parameter from configuration
711  */
712 WERROR libnet_smbconf_delparm(const char *service,
713                               const char *param)
714 {
715         struct registry_key *key = NULL;
716         WERROR werr = WERR_OK;
717         TALLOC_CTX *mem_ctx = talloc_stackframe();
718
719         if (!libnet_smbconf_key_exists(service)) {
720                 return WERR_NO_SUCH_SERVICE;
721         }
722
723         werr = libnet_smbconf_reg_open_path(mem_ctx, service, REG_KEY_ALL, &key);
724         if (!W_ERROR_IS_OK(werr)) {
725                 goto done;
726         }
727
728         if (!libnet_smbconf_value_exists(key, param)) {
729                 werr = WERR_INVALID_PARAM;
730                 goto done;
731         }
732
733         werr = reg_deletevalue(key, param);
734
735 done:
736         TALLOC_FREE(mem_ctx);
737         return werr;
738 }
739
740
741 /**********************************************************************
742  *
743  * Convenience functions that are also exported.
744  *
745  **********************************************************************/
746
747 WERROR libnet_smbconf_set_global_param(const char *param,
748                                        const char *val)
749 {
750         return libnet_smbconf_setparm(GLOBAL_NAME, param, val);
751 }
752