Rename libnet_smbconf_key_exists() to libnet_smbconf_share_exists()
[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 static bool libnet_smbconf_value_exists(struct registry_key *key,
104                                         const char *param)
105 {
106         bool ret = false;
107         WERROR werr = WERR_OK;
108         TALLOC_CTX *ctx = talloc_stackframe();
109         struct registry_value *value = NULL;
110
111         werr = reg_queryvalue(ctx, key, param, &value);
112         if (W_ERROR_IS_OK(werr)) {
113                 ret = true;
114         }
115
116         TALLOC_FREE(ctx);
117         return ret;
118 }
119
120 /*
121  * create a subkey of KEY_SMBCONF
122  */
123 WERROR libnet_smbconf_reg_createkey_internal(TALLOC_CTX *ctx,
124                                              const char * subkeyname,
125                                              struct registry_key **newkey)
126 {
127         WERROR werr = WERR_OK;
128         struct registry_key *create_parent = NULL;
129         TALLOC_CTX *create_ctx;
130         enum winreg_CreateAction action = REG_ACTION_NONE;
131
132         /* create a new talloc ctx for creation. it will hold
133          * the intermediate parent key (SMBCONF) for creation
134          * and will be destroyed when leaving this function... */
135         if (!(create_ctx = talloc_new(ctx))) {
136                 werr = WERR_NOMEM;
137                 goto done;
138         }
139
140         werr = libnet_smbconf_reg_open_basepath(create_ctx, REG_KEY_WRITE,
141                                                 &create_parent);
142         if (!W_ERROR_IS_OK(werr)) {
143                 goto done;
144         }
145
146         werr = reg_createkey(ctx, create_parent, subkeyname,
147                              REG_KEY_WRITE, newkey, &action);
148         if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
149                 DEBUG(10, ("Key '%s' already exists.\n", subkeyname));
150                 werr = WERR_ALREADY_EXISTS;
151         }
152         if (!W_ERROR_IS_OK(werr)) {
153                 DEBUG(5, ("Error creating key %s: %s\n",
154                          subkeyname, dos_errstr(werr)));
155         }
156
157 done:
158         TALLOC_FREE(create_ctx);
159         return werr;
160 }
161
162 /*
163  * add a value to a key.
164  */
165 WERROR libnet_smbconf_reg_setvalue_internal(struct registry_key *key,
166                                                    const char *valname,
167                                                    const char *valstr)
168 {
169         struct registry_value val;
170         WERROR werr = WERR_OK;
171         char *subkeyname;
172         const char *canon_valname;
173         const char *canon_valstr;
174
175         if (!lp_canonicalize_parameter_with_value(valname, valstr,
176                                                   &canon_valname,
177                                                   &canon_valstr))
178         {
179                 if (canon_valname == NULL) {
180                         DEBUG(5, ("invalid parameter '%s' given\n",
181                                   valname));
182                 } else {
183                         DEBUG(5, ("invalid value '%s' given for "
184                                   "parameter '%s'\n", valstr, valname));
185                 }
186                 werr = WERR_INVALID_PARAM;
187                 goto done;
188         }
189
190         ZERO_STRUCT(val);
191
192         val.type = REG_SZ;
193         val.v.sz.str = CONST_DISCARD(char *, canon_valstr);
194         val.v.sz.len = strlen(canon_valstr) + 1;
195
196         if (registry_smbconf_valname_forbidden(canon_valname)) {
197                 DEBUG(5, ("Parameter '%s' not allowed in registry.\n",
198                           canon_valname));
199                 werr = WERR_INVALID_PARAM;
200                 goto done;
201         }
202
203         subkeyname = strrchr_m(key->key->name, '\\');
204         if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) {
205                 DEBUG(5, ("Invalid registry key '%s' given as "
206                           "smbconf section.\n", key->key->name));
207                 werr = WERR_INVALID_PARAM;
208                 goto done;
209         }
210         subkeyname++;
211         if (!strequal(subkeyname, GLOBAL_NAME) &&
212             lp_parameter_is_global(valname))
213         {
214                 DEBUG(5, ("Global paramter '%s' not allowed in "
215                           "service definition ('%s').\n", canon_valname,
216                           subkeyname));
217                 werr = WERR_INVALID_PARAM;
218                 goto done;
219         }
220
221         werr = reg_setvalue(key, canon_valname, &val);
222         if (!W_ERROR_IS_OK(werr)) {
223                 DEBUG(5, ("Error adding value '%s' to "
224                           "key '%s': %s\n",
225                           canon_valname, key->key->name, dos_errstr(werr)));
226         }
227
228 done:
229         return werr;
230 }
231
232 /**
233  * format a registry_value into a string.
234  *
235  * This is intended to be used for smbconf registry values,
236  * which are ar stored as REG_SZ values, so the incomplete
237  * handling should be ok.
238  */
239 static char *libnet_smbconf_format_registry_value(TALLOC_CTX *mem_ctx,
240                                                   struct registry_value *value)
241 {
242         char *result = NULL;
243
244         /* alternatively, create a new talloc context? */
245         if (mem_ctx == NULL) {
246                 return result;
247         }
248
249         switch (value->type) {
250         case REG_DWORD:
251                 result = talloc_asprintf(mem_ctx, "%d", value->v.dword);
252                 break;
253         case REG_SZ:
254         case REG_EXPAND_SZ:
255                 result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str);
256                 break;
257         case REG_MULTI_SZ: {
258                 uint32 j;
259                 for (j = 0; j < value->v.multi_sz.num_strings; j++) {
260                         result = talloc_asprintf(mem_ctx, "\"%s\" ",
261                                                  value->v.multi_sz.strings[j]);
262                 }
263                 break;
264         }
265         case REG_BINARY:
266                 result = talloc_asprintf(mem_ctx, "binary (%d bytes)",
267                                          (int)value->v.binary.length);
268                 break;
269         default:
270                 result = talloc_asprintf(mem_ctx, "<unprintable>");
271                 break;
272         }
273         return result;
274 }
275
276 /**
277  * Get the values of a key as a list of value names
278  * and a list of value strings (ordered)
279  */
280 static WERROR libnet_smbconf_reg_get_values(TALLOC_CTX *mem_ctx,
281                                             struct registry_key *key,
282                                             uint32_t *num_values,
283                                             char ***value_names,
284                                             char ***value_strings)
285 {
286         TALLOC_CTX *tmp_ctx = NULL;
287         WERROR werr = WERR_OK;
288         uint32_t count;
289         struct registry_value *valvalue = NULL;
290         char *valname = NULL;
291         char **tmp_valnames = NULL;
292         char **tmp_valstrings = NULL;
293
294         if ((num_values == NULL) || (value_names == NULL) ||
295             (value_strings == NULL))
296         {
297                 werr = WERR_INVALID_PARAM;
298                 goto done;
299         }
300
301         tmp_ctx = talloc_new(mem_ctx);
302         if (tmp_ctx == NULL) {
303                 werr = WERR_NOMEM;
304                 goto done;
305         }
306
307         for (count = 0;
308              W_ERROR_IS_OK(werr = reg_enumvalue(tmp_ctx, key, count, &valname,
309                                                 &valvalue));
310              count++)
311         {
312                 char *valstring;
313
314                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
315                                                           &tmp_valnames,
316                                                           count, valname);
317                 if (!W_ERROR_IS_OK(werr)) {
318                         goto done;
319                 }
320
321                 valstring = libnet_smbconf_format_registry_value(tmp_ctx,
322                                                                  valvalue);
323                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
324                                                           &tmp_valstrings,
325                                                           count,
326                                                           valstring);
327                 if (!W_ERROR_IS_OK(werr)) {
328                         goto done;
329                 }
330         }
331         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
332                 goto done;
333         }
334
335         werr = WERR_OK;
336
337         *num_values = count;
338         if (count > 0) {
339                 *value_names = talloc_move(mem_ctx, &tmp_valnames);
340                 *value_strings = talloc_move(mem_ctx, &tmp_valstrings);
341         } else {
342                 *value_names = NULL;
343                 *value_strings = NULL;
344         }
345
346 done:
347         TALLOC_FREE(tmp_ctx);
348         return werr;
349 }
350
351 /**********************************************************************
352  *
353  * The actual net conf api functions, that are exported.
354  *
355  **********************************************************************/
356
357 /**
358  * Drop the whole configuration (restarting empty).
359  */
360 WERROR libnet_smbconf_drop(void)
361 {
362         char *path, *p;
363         WERROR werr = WERR_OK;
364         NT_USER_TOKEN *token;
365         struct registry_key *parent_key = NULL;
366         struct registry_key *new_key = NULL;
367         TALLOC_CTX* mem_ctx = talloc_stackframe();
368         enum winreg_CreateAction action;
369
370         if (!(token = registry_create_admin_token(mem_ctx))) {
371                 /* what is the appropriate error code here? */
372                 werr = WERR_CAN_NOT_COMPLETE;
373                 goto done;
374         }
375
376         path = talloc_strdup(mem_ctx, KEY_SMBCONF);
377         if (path == NULL) {
378                 werr = WERR_NOMEM;
379                 goto done;
380         }
381         p = strrchr(path, '\\');
382         *p = '\0';
383         werr = reg_open_path(mem_ctx, path, REG_KEY_WRITE, token, &parent_key);
384
385         if (!W_ERROR_IS_OK(werr)) {
386                 goto done;
387         }
388
389         werr = reg_deletekey_recursive(mem_ctx, parent_key, p+1);
390
391         if (!W_ERROR_IS_OK(werr)) {
392                 goto done;
393         }
394
395         werr = reg_createkey(mem_ctx, parent_key, p+1, REG_KEY_WRITE,
396                              &new_key, &action);
397
398 done:
399         TALLOC_FREE(mem_ctx);
400         return werr;
401 }
402
403 /**
404  * Get the whole configuration as lists of strings with counts:
405  *
406  *  num_shares   : number of shares
407  *  share_names  : list of length num_shares of share names
408  *  num_params   : list of length num_shares of parameter counts for each share
409  *  param_names  : list of lists of parameter names for each share
410  *  param_values : list of lists of parameter values for each share
411  */
412 WERROR libnet_smbconf_get_config(TALLOC_CTX *mem_ctx, uint32_t *num_shares,
413                                  char ***share_names, uint32_t **num_params,
414                                  char ****param_names, char ****param_values)
415 {
416         WERROR werr = WERR_OK;
417         TALLOC_CTX *tmp_ctx = NULL;
418         uint32_t tmp_num_shares;
419         char **tmp_share_names;
420         uint32_t *tmp_num_params;
421         char ***tmp_param_names;
422         char ***tmp_param_values;
423         uint32_t count;
424
425         if ((num_shares == NULL) || (share_names == NULL) ||
426             (num_params == NULL) || (param_names == NULL) ||
427             (param_values == NULL))
428         {
429                 werr = WERR_INVALID_PARAM;
430                 goto done;
431         }
432
433         tmp_ctx = talloc_new(mem_ctx);
434         if (tmp_ctx == NULL) {
435                 werr = WERR_NOMEM;
436                 goto done;
437         }
438
439         werr = libnet_smbconf_get_share_names(tmp_ctx, &tmp_num_shares,
440                                               &tmp_share_names);
441         if (!W_ERROR_IS_OK(werr)) {
442                 goto done;
443         }
444
445         tmp_num_params   = TALLOC_ARRAY(tmp_ctx, uint32_t, tmp_num_shares);
446         tmp_param_names  = TALLOC_ARRAY(tmp_ctx, char **, tmp_num_shares);
447         tmp_param_values = TALLOC_ARRAY(tmp_ctx, char **, tmp_num_shares);
448
449         if ((tmp_num_params == NULL) || (tmp_param_names == NULL) ||
450             (tmp_param_values == NULL))
451         {
452                 werr = WERR_NOMEM;
453                 goto done;
454         }
455
456         for (count = 0; count < tmp_num_shares; count++) {
457                 werr = libnet_smbconf_getshare(mem_ctx, tmp_share_names[count],
458                                                &tmp_num_params[count],
459                                                &tmp_param_names[count],
460                                                &tmp_param_values[count]);
461                 if (!W_ERROR_IS_OK(werr)) {
462                         goto done;
463                 }
464         }
465
466         werr = WERR_OK;
467
468         *num_shares = tmp_num_shares;
469         if (tmp_num_shares > 0) {
470                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
471                 *num_params = talloc_move(mem_ctx, &tmp_num_params);
472                 *param_names = talloc_move(mem_ctx, &tmp_param_names);
473                 *param_values = talloc_move(mem_ctx, &tmp_param_values);
474         } else {
475                 *share_names = NULL;
476                 *num_params = NULL;
477                 *param_names = NULL;
478                 *param_values = NULL;
479         }
480
481 done:
482         TALLOC_FREE(tmp_ctx);
483         return werr;
484 }
485
486
487 /**
488  * get the list of share names defined in the configuration.
489  */
490 WERROR libnet_smbconf_get_share_names(TALLOC_CTX *mem_ctx, uint32_t *num_shares,
491                                       char ***share_names)
492 {
493         uint32_t count;
494         uint32_t added_count = 0;
495         TALLOC_CTX *tmp_ctx = NULL;
496         WERROR werr = WERR_OK;
497         struct registry_key *key = NULL;
498         char *subkey_name = NULL;
499         char **tmp_share_names = NULL;
500
501         if ((num_shares == NULL) || (share_names == NULL)) {
502                 werr = WERR_INVALID_PARAM;
503                 goto done;
504         }
505
506         tmp_ctx = talloc_new(mem_ctx);
507         if (tmp_ctx == NULL) {
508                 werr = WERR_NOMEM;
509                 goto done;
510         }
511
512         /* make sure "global" is always listed first */
513         if (libnet_smbconf_share_exists(GLOBAL_NAME)) {
514                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
515                                                           &tmp_share_names,
516                                                           0, GLOBAL_NAME);
517                 if (!W_ERROR_IS_OK(werr)) {
518                         goto done;
519                 }
520                 added_count++;
521         }
522
523         werr = libnet_smbconf_reg_open_basepath(tmp_ctx,
524                                                 SEC_RIGHTS_ENUM_SUBKEYS,
525                                                 &key);
526         if (!W_ERROR_IS_OK(werr)) {
527                 goto done;
528         }
529
530         for (count = 0;
531              W_ERROR_IS_OK(werr = reg_enumkey(tmp_ctx, key, count,
532                                               &subkey_name, NULL));
533              count++)
534         {
535                 if (strequal(subkey_name, GLOBAL_NAME)) {
536                         continue;
537                 }
538
539                 werr = libnet_smbconf_add_string_to_array(tmp_ctx,
540                                                           &tmp_share_names,
541                                                           added_count,
542                                                           subkey_name);
543                 if (!W_ERROR_IS_OK(werr)) {
544                         goto done;
545                 }
546                 added_count++;
547         }
548         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
549                 goto done;
550         }
551         werr = WERR_OK;
552
553         *num_shares = added_count;
554         if (added_count > 0) {
555                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
556         } else {
557                 *share_names = NULL;
558         }
559
560 done:
561         TALLOC_FREE(tmp_ctx);
562         return werr;
563 }
564
565 /**
566  * check if a share/service of a given name exists
567  */
568 bool libnet_smbconf_share_exists(const char *subkeyname)
569 {
570         bool ret = false;
571         WERROR werr = WERR_OK;
572         TALLOC_CTX *mem_ctx = talloc_stackframe();
573         struct registry_key *key = NULL;
574
575         werr = libnet_smbconf_reg_open_path(mem_ctx, subkeyname, REG_KEY_READ,
576                                             &key);
577         if (W_ERROR_IS_OK(werr)) {
578                 ret = true;
579         }
580
581         TALLOC_FREE(mem_ctx);
582         return ret;
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_share_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_share_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_share_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