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