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