param: rename lp function and variable from "shortpreservecase" to "short_preserve_case"
[samba.git] / source4 / param / share_ldb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    LDB based shares configuration
5    
6    Copyright (C) Simo Sorce     2006
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 <ldb.h>
24 #include <ldb_errors.h>
25 #include "auth/auth.h"
26 #include "ldb_wrap.h"
27 #include "param/share.h"
28 #include "param/param.h"
29
30 NTSTATUS share_ldb_init(void);
31
32 static NTSTATUS sldb_init(TALLOC_CTX *mem_ctx, const struct share_ops *ops, 
33                           struct tevent_context *ev_ctx,
34                           struct loadparm_context *lp_ctx,
35                           struct share_context **ctx)
36 {
37         struct ldb_context *sdb;
38
39         *ctx = talloc(mem_ctx, struct share_context);
40         if (!*ctx) {
41                 DEBUG(0, ("ERROR: Out of memory!\n"));
42                 return NT_STATUS_NO_MEMORY;
43         }
44         
45         sdb = ldb_wrap_connect(*ctx, ev_ctx, lp_ctx,
46                                lpcfg_private_path(*ctx, lp_ctx, "share.ldb"),
47                                system_session(lp_ctx),
48                                NULL, 0);
49
50         if (!sdb) {
51                 talloc_free(*ctx);
52                 return NT_STATUS_UNSUCCESSFUL;
53         }
54
55         (*ctx)->ops = ops;
56         (*ctx)->priv_data = (void *)sdb;
57
58         return NT_STATUS_OK;
59 }
60
61 static const char *sldb_string_option(struct share_config *scfg, const char *opt_name, const char *defval)
62 {
63         struct ldb_message *msg;
64         struct ldb_message_element *el;
65         const char *colon;
66
67         if (scfg == NULL) return defval;
68
69         msg = talloc_get_type(scfg->opaque, struct ldb_message);
70
71         colon = strchr(opt_name, ':');
72         if (colon != NULL) {
73                 char *name;
74
75                 name = talloc_strdup(scfg, opt_name);
76                 if (!name) {
77                         return NULL;
78                 }
79                 name[colon-opt_name] = '-';
80
81                 el = ldb_msg_find_element(msg, name);
82                 TALLOC_FREE(name);
83         } else {
84                 el = ldb_msg_find_element(msg, opt_name);
85         }
86
87         if (el == NULL) {
88                 return defval;
89         }
90
91         return (const char *)(el->values[0].data);
92 }
93
94 static int sldb_int_option(struct share_config *scfg, const char *opt_name, int defval)
95 {
96         const char *val;
97         int ret;
98
99         val = sldb_string_option(scfg, opt_name, NULL);
100         if (val == NULL) return defval;
101
102         errno = 0;
103         ret = (int)strtol(val, NULL, 10);
104         if (errno) return -1;
105
106         return ret;
107 }
108
109 static bool sldb_bool_option(struct share_config *scfg, const char *opt_name, bool defval)
110 {
111         const char *val;
112
113         val = sldb_string_option(scfg, opt_name, NULL);
114         if (val == NULL) return defval;
115
116         if (strcasecmp(val, "true") == 0) return true;
117
118         return false;
119 }
120
121 static const char **sldb_string_list_option(TALLOC_CTX *mem_ctx, struct share_config *scfg, const char *opt_name)
122 {
123         struct ldb_message *msg;
124         struct ldb_message_element *el;
125         const char **list;
126         const char *colon;
127         int i;
128
129         if (scfg == NULL) return NULL;
130
131         msg = talloc_get_type(scfg->opaque, struct ldb_message);
132
133         colon = strchr(opt_name, ':');
134         if (colon != NULL) {
135                 char *name;
136
137                 name = talloc_strdup(scfg, opt_name);
138                 if (!name) {
139                         return NULL;
140                 }
141                 name[colon-opt_name] = '-';
142
143                 el = ldb_msg_find_element(msg, name);
144                 TALLOC_FREE(name);
145         } else {
146                 el = ldb_msg_find_element(msg, opt_name);
147         }
148
149         if (el == NULL) {
150                 return NULL;
151         }
152
153         list = talloc_array(mem_ctx, const char *, el->num_values + 1);
154         if (!list) return NULL;
155
156         for (i = 0; i < el->num_values; i++) {
157                 list[i] = (const char *)(el->values[i].data);
158         }
159         list[i] = NULL;
160
161         return list;
162 }
163
164 static NTSTATUS sldb_list_all(TALLOC_CTX *mem_ctx,
165                                  struct share_context *ctx,
166                                  int *count,
167                                  const char ***names)
168 {
169         int ret, i, j;
170         const char **n;
171         struct ldb_context *ldb;
172         struct ldb_result *res;
173         TALLOC_CTX *tmp_ctx;
174
175         tmp_ctx = talloc_new(mem_ctx);
176         if (!tmp_ctx) {
177                 DEBUG(0,("ERROR: Out of memory!\n"));
178                 return NT_STATUS_NO_MEMORY;
179         }
180
181         ldb = talloc_get_type(ctx->priv_data, struct ldb_context);
182
183         ret = ldb_search(ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, ldb, "CN=SHARES"),
184                          LDB_SCOPE_SUBTREE, NULL, "(name=*)");
185         if (ret != LDB_SUCCESS) {
186                 talloc_free(tmp_ctx);
187                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
188         }
189
190         n = talloc_array(mem_ctx, const char *, res->count);
191         if (!n) {
192                 DEBUG(0,("ERROR: Out of memory!\n"));
193                 talloc_free(tmp_ctx);
194                 return NT_STATUS_NO_MEMORY;
195         }
196
197         for (i = 0, j = 0; i < res->count; i++) {
198                 n[j] = talloc_strdup(n, ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
199                 if (!n[j]) {
200                         DEBUG(0,("WARNING: Malformed share object in share database\n!"));
201                         continue;
202                 }
203                 j++;
204         }
205
206         *names = n;
207         *count = j;
208         talloc_free(tmp_ctx);
209
210         return NT_STATUS_OK;
211 }
212
213 static NTSTATUS sldb_get_config(TALLOC_CTX *mem_ctx,
214                          struct share_context *ctx,
215                          const char *name,
216                          struct share_config **scfg)
217 {
218         int ret;
219         struct share_config *s;
220         struct ldb_context *ldb;
221         struct ldb_result *res;
222         TALLOC_CTX *tmp_ctx;
223
224         tmp_ctx = talloc_new(mem_ctx);
225         if (!tmp_ctx) {
226                 DEBUG(0,("ERROR: Out of memory!\n"));
227                 return NT_STATUS_NO_MEMORY;
228         }
229
230         ldb = talloc_get_type(ctx->priv_data, struct ldb_context);
231
232         ret = ldb_search(ldb, tmp_ctx, &res,
233                                  ldb_dn_new(tmp_ctx, ldb, "CN=SHARES"), LDB_SCOPE_SUBTREE, NULL,
234                                  "(name=%s)", name);
235         if (ret != LDB_SUCCESS || res->count > 1) {
236                 talloc_free(tmp_ctx);
237                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
238         } else if (res->count != 1) {
239                 talloc_free(tmp_ctx);
240                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
241         }
242
243         s = talloc(tmp_ctx, struct share_config);
244         if (!s) {
245                 DEBUG(0,("ERROR: Out of memory!\n"));
246                 talloc_free(tmp_ctx);
247                 return NT_STATUS_NO_MEMORY;
248         }
249
250         s->name = talloc_strdup(s, ldb_msg_find_attr_as_string(res->msgs[0], "name", NULL));
251         if (!s->name) {
252                 DEBUG(0,("ERROR: Invalid share object!\n"));
253                 talloc_free(tmp_ctx);
254                 return NT_STATUS_UNSUCCESSFUL;
255         }
256
257         s->opaque = talloc_steal(s, res->msgs[0]);
258         if (!s->opaque) {
259                 DEBUG(0,("ERROR: Invalid share object!\n"));
260                 talloc_free(tmp_ctx);
261                 return NT_STATUS_UNSUCCESSFUL;
262         }
263
264         s->ctx = ctx;
265
266         *scfg = talloc_steal(mem_ctx, s);
267
268         talloc_free(tmp_ctx);
269         return NT_STATUS_OK;
270 }
271
272 #define SHARE_ADD_STRING(name, value) do { \
273         err = ldb_msg_add_string(msg, name, value); \
274         if (err != LDB_SUCCESS) { \
275                 DEBUG(2,("ERROR: unable to add string share option %s to ldb msg\n", name)); \
276                 ret = NT_STATUS_UNSUCCESSFUL; \
277                 goto done; \
278         } } while(0)
279
280 #define SHARE_ADD_INT(name, value) do { \
281         err = ldb_msg_add_fmt(msg, name, "%d", value); \
282         if (err != LDB_SUCCESS) { \
283                 DEBUG(2,("ERROR: unable to add integer share option %s to ldb msg\n", name)); \
284                 ret = NT_STATUS_UNSUCCESSFUL; \
285                 goto done; \
286         } } while(0)
287
288 #define SHARE_ADD_BLOB(name, value) do { \
289         err = ldb_msg_add_value(msg, name, value, NULL); \
290         if (err != LDB_SUCCESS) { \
291                 DEBUG(2,("ERROR: unable to add blob share option %s to ldb msg\n", name)); \
292                 ret = NT_STATUS_UNSUCCESSFUL; \
293                 goto done; \
294         } } while(0)
295
296 static NTSTATUS sldb_create(struct share_context *ctx, const char *name, struct share_info *info, int count)
297 {
298         struct ldb_context *ldb;
299         struct ldb_message *msg;
300         TALLOC_CTX *tmp_ctx;
301         NTSTATUS ret;
302         int err, i, j;
303
304         for (i = 0, j = 0; i < count && j != 0x03; i++) {
305                 if (strcasecmp(info[i].name, SHARE_TYPE) == 0) j |= 0x02;
306                 if (strcasecmp(info[i].name, SHARE_PATH) == 0) j |= 0x01;
307                 if (strcasecmp(info[i].name, SHARE_NAME) == 0) {
308                         if (strcasecmp(name, (char *)info[i].value) != 0) {
309                                 return NT_STATUS_INVALID_PARAMETER;
310                         }
311                 }
312         }
313         if (!name || j != 0x03) {
314                 return NT_STATUS_INVALID_PARAMETER;
315         }
316         
317         tmp_ctx = talloc_new(NULL);
318         if (!tmp_ctx) {
319                 DEBUG(0,("ERROR: Out of memory!\n"));
320                 return NT_STATUS_NO_MEMORY;
321         }
322
323         ldb = talloc_get_type(ctx->priv_data, struct ldb_context);
324
325         msg = ldb_msg_new(tmp_ctx);
326         if (!msg) {
327                 DEBUG(0,("ERROR: Out of memory!\n"));
328                 ret = NT_STATUS_NO_MEMORY;
329                 goto done;
330         }
331
332         /* TODO: escape info->name */
333         msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", name);
334         if (!msg->dn) {
335                 DEBUG(0,("ERROR: Out of memory!\n"));
336                 ret = NT_STATUS_NO_MEMORY;
337                 goto done;
338         }
339
340         SHARE_ADD_STRING("objectClass", "top");
341         SHARE_ADD_STRING("objectClass", "share");
342         SHARE_ADD_STRING("cn", name);
343         SHARE_ADD_STRING(SHARE_NAME, name);
344
345         for (i = 0; i < count; i++) {
346                 if (strcasecmp(info[i].name, SHARE_NAME) == 0) continue;
347
348                 switch (info[i].type) {
349                 case SHARE_INFO_STRING:
350                         SHARE_ADD_STRING(info[i].name, (char *)info[i].value);
351                         break;
352                 case SHARE_INFO_INT:
353                         SHARE_ADD_INT(info[i].name, *((int *)info[i].value));
354                         break;
355                 case SHARE_INFO_BLOB:
356                         SHARE_ADD_BLOB(info[i].name, (DATA_BLOB *)info[i].value);
357                         break;
358                 default:
359                         DEBUG(2,("ERROR: Invalid share info type for %s\n", info[i].name));
360                         ret = NT_STATUS_INVALID_PARAMETER;
361                         goto done;
362                 }
363         }
364
365         /* TODO: Security Descriptor */
366
367         SHARE_ADD_STRING(SHARE_AVAILABLE, "true");
368         SHARE_ADD_STRING(SHARE_BROWSEABLE, "true");
369         SHARE_ADD_STRING(SHARE_READONLY, "false");
370         SHARE_ADD_STRING(SHARE_NTVFS_HANDLER, "unixuid");
371         SHARE_ADD_STRING(SHARE_NTVFS_HANDLER, "posix");
372
373         err = ldb_add(ldb, msg);
374         if (err != LDB_SUCCESS) {
375                 DEBUG(2,("ERROR: unable to add share %s to share.ldb\n"
376                          "       err=%d [%s]\n", name, err, ldb_errstring(ldb)));
377                 if (err == LDB_ERR_NO_SUCH_OBJECT) {
378                         ret = NT_STATUS_OBJECT_NAME_NOT_FOUND;
379                 } else if (err == LDB_ERR_ENTRY_ALREADY_EXISTS) {
380                         ret = NT_STATUS_OBJECT_NAME_COLLISION;
381                 } else {
382                         ret = NT_STATUS_UNSUCCESSFUL;
383                 }
384                 goto done;
385         }
386
387         ret = NT_STATUS_OK;
388 done:
389         talloc_free(tmp_ctx);
390         return ret;
391 }
392
393 #define SHARE_MOD_STRING(name, value) do { \
394         err = ldb_msg_add_empty(msg, name, LDB_FLAG_MOD_REPLACE, NULL); \
395         if (err != LDB_SUCCESS) { \
396                 DEBUG(2,("ERROR: unable to add string share option %s to ldb msg\n", name)); \
397                 ret = NT_STATUS_UNSUCCESSFUL; \
398                 goto done; \
399         } \
400         err = ldb_msg_add_string(msg, name, value); \
401         if (err != LDB_SUCCESS) { \
402                 DEBUG(2,("ERROR: unable to add string share option %s to ldb msg\n", name)); \
403                 ret = NT_STATUS_UNSUCCESSFUL; \
404                 goto done; \
405         } } while(0)
406
407 #define SHARE_MOD_INT(name, value) do { \
408         err = ldb_msg_add_empty(msg, name, LDB_FLAG_MOD_REPLACE, NULL); \
409         if (err != LDB_SUCCESS) { \
410                 DEBUG(2,("ERROR: unable to add string share option %s to ldb msg\n", name)); \
411                 ret = NT_STATUS_UNSUCCESSFUL; \
412                 goto done; \
413         } \
414         err = ldb_msg_add_fmt(msg, name, "%d", value); \
415         if (err != LDB_SUCCESS) { \
416                 DEBUG(2,("ERROR: unable to add integer share option %s to ldb msg\n", name)); \
417                 ret = NT_STATUS_UNSUCCESSFUL; \
418                 goto done; \
419         } } while(0)
420
421 #define SHARE_MOD_BLOB(name, value) do { \
422         err = ldb_msg_add_empty(msg, name, LDB_FLAG_MOD_REPLACE, NULL); \
423         if (err != LDB_SUCCESS) { \
424                 DEBUG(2,("ERROR: unable to add string share option %s to ldb msg\n", name)); \
425                 ret = NT_STATUS_UNSUCCESSFUL; \
426                 goto done; \
427         } \
428         err = ldb_msg_add_value(msg, name, value, NULL); \
429         if (err != LDB_SUCCESS) { \
430                 DEBUG(2,("ERROR: unable to add blob share option %s to ldb msg\n", name)); \
431                 ret = NT_STATUS_UNSUCCESSFUL; \
432                 goto done; \
433         } } while(0)
434
435 static NTSTATUS sldb_set(struct share_context *ctx, const char *name, struct share_info *info, int count)
436 {
437         struct ldb_context *ldb;
438         struct ldb_message *msg;
439         TALLOC_CTX *tmp_ctx;
440         NTSTATUS ret;
441         bool do_rename = false;
442         char *newname;
443         int err, i;
444
445         if (!name) {
446                 return NT_STATUS_INVALID_PARAMETER;
447         }
448         
449         tmp_ctx = talloc_new(NULL);
450         if (!tmp_ctx) {
451                 DEBUG(0,("ERROR: Out of memory!\n"));
452                 return NT_STATUS_NO_MEMORY;
453         }
454
455         ldb = talloc_get_type(ctx->priv_data, struct ldb_context);
456
457         msg = ldb_msg_new(tmp_ctx);
458         if (!msg) {
459                 DEBUG(0,("ERROR: Out of memory!\n"));
460                 ret = NT_STATUS_NO_MEMORY;
461                 goto done;
462         }
463
464         /* TODO: escape name */
465         msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", name);
466         if (!msg->dn) {
467                 DEBUG(0,("ERROR: Out of memory!\n"));
468                 ret = NT_STATUS_NO_MEMORY;
469                 goto done;
470         }
471
472         for (i = 0; i < count; i++) {
473                 if (strcasecmp(info[i].name, SHARE_NAME) == 0) {
474                         if (strcasecmp(name, (char *)info[i].value) != 0) {
475                                 do_rename = true;
476                                 newname = (char *)info[i].value;
477                                 SHARE_MOD_STRING("cn", (char *)info[i].value);
478                         }
479                 }
480
481                 switch (info[i].type) {
482                 case SHARE_INFO_STRING:
483                         SHARE_MOD_STRING(info[i].name, (char *)info[i].value);
484                         break;
485                 case SHARE_INFO_INT:
486                         SHARE_MOD_INT(info[i].name, *((int *)info[i].value));
487                         break;
488                 case SHARE_INFO_BLOB:
489                         SHARE_MOD_BLOB(info[i].name, (DATA_BLOB *)info[i].value);
490                         break;
491                 default:
492                         DEBUG(2,("ERROR: Invalid share info type for %s\n", info[i].name));
493                         ret = NT_STATUS_INVALID_PARAMETER;
494                         goto done;
495                 }
496         }
497
498         if (do_rename) {
499                 struct ldb_dn *olddn, *newdn;
500
501                 olddn = msg->dn;
502
503                 /* TODO: escape newname */
504                 newdn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", newname);
505                 if (!newdn) {
506                         DEBUG(0,("ERROR: Out of memory!\n"));
507                         ret = NT_STATUS_NO_MEMORY;
508                         goto done;
509                 }
510
511                 err = ldb_rename(ldb, olddn, newdn);
512                 if (err != LDB_SUCCESS) {
513                         DEBUG(2,("ERROR: unable to rename share %s (to %s)\n"
514                                  "       err=%d [%s]\n", name, newname, err, ldb_errstring(ldb)));
515                         if (err == LDB_ERR_NO_SUCH_OBJECT) {
516                                 ret = NT_STATUS_OBJECT_NAME_COLLISION;
517                         } else {
518                                 ret = NT_STATUS_UNSUCCESSFUL;
519                         }
520                         goto done;
521                 }
522
523                 msg->dn = newdn;
524         }
525
526         err = ldb_modify(ldb, msg);
527         if (err != LDB_SUCCESS) {
528                 DEBUG(2,("ERROR: unable to add share %s to share.ldb\n"
529                          "       err=%d [%s]\n", name, err, ldb_errstring(ldb)));
530                 if (err == LDB_ERR_NO_SUCH_OBJECT) {
531                         ret = NT_STATUS_OBJECT_NAME_COLLISION;
532                 } else {
533                         ret = NT_STATUS_UNSUCCESSFUL;
534                 }
535                 goto done;
536         }
537
538         ret = NT_STATUS_OK;
539 done:
540         talloc_free(tmp_ctx);
541         return ret;
542 }
543
544 static NTSTATUS sldb_remove(struct share_context *ctx, const char *name)
545 {
546         struct ldb_context *ldb;
547         struct ldb_dn *dn;
548         TALLOC_CTX *tmp_ctx;
549         NTSTATUS ret;
550         int err;
551
552         tmp_ctx = talloc_new(NULL);
553         if (!tmp_ctx) {
554                 DEBUG(0,("ERROR: Out of memory!\n"));
555                 return NT_STATUS_NO_MEMORY;
556         }
557
558         ldb = talloc_get_type(ctx->priv_data, struct ldb_context);
559
560         dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", name);
561         if (!dn) {
562                 DEBUG(0,("ERROR: Out of memory!\n"));
563                 ret = NT_STATUS_NO_MEMORY;
564                 goto done;
565         }
566
567         err = ldb_delete(ldb, dn);
568         if (err != LDB_SUCCESS) {
569                 DEBUG(2,("ERROR: unable to remove share %s from share.ldb\n"
570                          "       err=%d [%s]\n", name, err, ldb_errstring(ldb)));
571                 ret = NT_STATUS_UNSUCCESSFUL;
572                 goto done;
573         }
574
575         ret = NT_STATUS_OK;
576 done:
577         talloc_free(tmp_ctx);
578         return ret;
579 }
580
581 static const struct share_ops ops = {
582         .name = "ldb",
583         .init = sldb_init,
584         .string_option = sldb_string_option,
585         .int_option = sldb_int_option,
586         .bool_option = sldb_bool_option,
587         .string_list_option = sldb_string_list_option,
588         .list_all = sldb_list_all,
589         .get_config = sldb_get_config,
590         .create = sldb_create,
591         .set = sldb_set,
592         .remove = sldb_remove
593 };
594
595 NTSTATUS share_ldb_init(void)
596 {
597         return share_register(&ops);
598 }