2 Unix SMB/CIFS implementation.
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
8 Copyright (C) Jeremy Allison 2006
9 Copyright (C) Simo Sorce 2003-2006
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #define DBGC_CLASS DBGC_IDMAP
32 /* High water mark keys */
33 #define HWM_GROUP "GROUP HWM"
34 #define HWM_USER "USER HWM"
36 static struct idmap_tdb_state {
38 /* User and group id pool */
39 uid_t low_uid, high_uid; /* Range of uids to allocate */
40 gid_t low_gid, high_gid; /* Range of gids to allocate */
44 /*****************************************************************************
45 For idmap conversion: convert one record to new format
46 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
48 *****************************************************************************/
49 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
51 struct winbindd_domain *domain;
58 BOOL *failed = (BOOL *)state;
60 DEBUG(10,("Converting %s\n", (const char *)key.dptr));
62 p = strchr((const char *)key.dptr, '/');
67 fstrcpy(dom_name, (const char *)key.dptr);
70 domain = find_domain_from_name(dom_name);
72 /* We must delete the old record. */
73 DEBUG(0,("Unable to find domain %s\n", dom_name ));
74 DEBUG(0,("deleting record %s\n", (const char *)key.dptr ));
76 if (tdb_delete(tdb, key) != 0) {
77 DEBUG(0, ("Unable to delete record %s\n", (const char *)key.dptr));
87 sid_copy(&sid, &domain->sid);
88 sid_append_rid(&sid, rid);
90 sid_to_string(keystr, &sid);
91 key2 = string_term_tdb_data(keystr);
93 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
94 DEBUG(0,("Unable to add record %s\n", (const char *)key2.dptr ));
99 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
100 DEBUG(0,("Unable to update record %s\n", (const char *)data.dptr ));
105 if (tdb_delete(tdb, key) != 0) {
106 DEBUG(0,("Unable to delete record %s\n", (const char *)key.dptr ));
114 /*****************************************************************************
115 Convert the idmap database from an older version.
116 *****************************************************************************/
118 static BOOL idmap_tdb_upgrade(const char *idmap_name)
121 BOOL bigendianheader;
123 TDB_CONTEXT *idmap_tdb;
125 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
127 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
130 DEBUG(0, ("Unable to open idmap database\n"));
134 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
136 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
138 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
139 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
141 * high and low records were created on a
142 * big endian machine and will need byte-reversing.
147 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
152 wm = idmap_tdb_state.low_uid;
155 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
156 DEBUG(0, ("Unable to byteswap user hwm in idmap database\n"));
157 tdb_close(idmap_tdb);
161 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
165 wm = idmap_tdb_state.low_gid;
168 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
169 DEBUG(0, ("Unable to byteswap group hwm in idmap database\n"));
170 tdb_close(idmap_tdb);
175 /* the old format stored as DOMAIN/rid - now we store the SID direct */
176 tdb_traverse(idmap_tdb, convert_fn, &failed);
179 DEBUG(0, ("Problem during conversion\n"));
180 tdb_close(idmap_tdb);
184 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
185 DEBUG(0, ("Unable to dtore idmap version in databse\n"));
186 tdb_close(idmap_tdb);
190 tdb_close(idmap_tdb);
194 /* WARNING: We can't open a tdb twice inthe same process, for that reason
195 * I'm going to use a hack with open ref counts to open the winbindd_idmap.tdb
196 * only once. We will later decide whether to split the db in multiple files
197 * or come up with a better solution to share them. */
199 static TDB_CONTEXT *idmap_tdb_common_ctx;
200 static int idmap_tdb_open_ref_count = 0;
202 static NTSTATUS idmap_tdb_open_db(TALLOC_CTX *memctx, TDB_CONTEXT **tdbctx)
206 SMB_STRUCT_STAT stbuf;
207 char *tdbfile = NULL;
209 BOOL tdb_is_new = False;
211 if (idmap_tdb_open_ref_count) { /* the tdb has already been opened */
212 idmap_tdb_open_ref_count++;
213 *tdbctx = idmap_tdb_common_ctx;
217 /* use our own context here */
218 ctx = talloc_new(memctx);
220 DEBUG(0, ("Out of memory!\n"));
221 return NT_STATUS_NO_MEMORY;
224 /* use the old database if present */
225 tdbfile = talloc_strdup(ctx, lock_path("winbindd_idmap.tdb"));
227 DEBUG(0, ("Out of memory!\n"));
228 ret = NT_STATUS_NO_MEMORY;
232 if (!file_exist(tdbfile, &stbuf)) {
236 DEBUG(10,("Opening tdbfile %s\n", tdbfile ));
238 /* Open idmap repository */
239 if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
240 DEBUG(0, ("Unable to open idmap database\n"));
241 ret = NT_STATUS_UNSUCCESSFUL;
246 /* the file didn't existed before opening it, let's
247 * store idmap version as nobody else yet opened and
248 * stored it. I do not like this method but didn't
249 * found a way to understand if an opened tdb have
250 * been just created or not --- SSS */
251 tdb_store_int32(idmap_tdb_common_ctx, "IDMAP_VERSION", IDMAP_VERSION);
254 /* check against earlier versions */
255 version = tdb_fetch_int32(idmap_tdb_common_ctx, "IDMAP_VERSION");
256 if (version != IDMAP_VERSION) {
258 /* backup_tdb expects the tdb not to be open */
259 tdb_close(idmap_tdb_common_ctx);
261 if ( ! idmap_tdb_upgrade(tdbfile)) {
263 DEBUG(0, ("Unable to open idmap database, it's in an old formati, and upgrade failed!\n"));
264 ret = NT_STATUS_INTERNAL_DB_ERROR;
268 /* Re-Open idmap repository */
269 if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
270 DEBUG(0, ("Unable to open idmap database\n"));
271 ret = NT_STATUS_UNSUCCESSFUL;
276 *tdbctx = idmap_tdb_common_ctx;
277 idmap_tdb_open_ref_count++;
285 /* NEVER use tdb_close() except for the conversion routines that are guaranteed
286 * to run only when the database is opened the first time, always use this function. */
288 BOOL idmap_tdb_tdb_close(TDB_CONTEXT *tdbctx)
290 if (tdbctx != idmap_tdb_common_ctx) {
291 DEBUG(0, ("ERROR: Invalid tdb context!"));
295 idmap_tdb_open_ref_count--;
296 if (idmap_tdb_open_ref_count) {
300 return tdb_close(idmap_tdb_common_ctx);
303 /**********************************************************************
304 IDMAP ALLOC TDB BACKEND
305 **********************************************************************/
307 static TDB_CONTEXT *idmap_alloc_tdb;
309 /**********************************
310 Initialise idmap alloc database.
311 **********************************/
313 static NTSTATUS idmap_tdb_alloc_init( const char *params )
323 /* use our own context here */
324 ctx = talloc_new(NULL);
326 DEBUG(0, ("Out of memory!\n"));
327 return NT_STATUS_NO_MEMORY;
330 ret = idmap_tdb_open_db(ctx, &idmap_alloc_tdb);
331 if ( ! NT_STATUS_IS_OK(ret)) {
339 idmap_tdb_state.low_uid = 0;
340 idmap_tdb_state.high_uid = 0;
341 idmap_tdb_state.low_gid = 0;
342 idmap_tdb_state.high_gid = 0;
344 range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL);
345 if (range && range[0]) {
346 unsigned low_id, high_id;
348 if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) {
349 if (low_id < high_id) {
350 idmap_tdb_state.low_gid = idmap_tdb_state.low_uid = low_id;
351 idmap_tdb_state.high_gid = idmap_tdb_state.high_uid = high_id;
353 DEBUG(1, ("ERROR: invalid idmap alloc range [%s]", range));
356 DEBUG(1, ("ERROR: invalid syntax for idmap alloc config:range [%s]", range));
360 /* Create high water marks for group and user id */
361 if (lp_idmap_uid(&low_uid, &high_uid)) {
362 idmap_tdb_state.low_uid = low_uid;
363 idmap_tdb_state.high_uid = high_uid;
366 if (lp_idmap_gid(&low_gid, &high_gid)) {
367 idmap_tdb_state.low_gid = low_gid;
368 idmap_tdb_state.high_gid = high_gid;
371 if (idmap_tdb_state.high_uid <= idmap_tdb_state.low_uid) {
372 DEBUG(1, ("idmap uid range missing or invalid\n"));
373 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
374 return NT_STATUS_UNSUCCESSFUL;
378 if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_USER)) == -1) ||
379 (low_id < idmap_tdb_state.low_uid)) {
380 if (tdb_store_int32(idmap_alloc_tdb, HWM_USER, idmap_tdb_state.low_uid) == -1) {
381 DEBUG(0, ("Unable to initialise user hwm in idmap database\n"));
382 return NT_STATUS_INTERNAL_DB_ERROR;
387 if (idmap_tdb_state.high_gid <= idmap_tdb_state.low_gid) {
388 DEBUG(1, ("idmap gid range missing or invalid\n"));
389 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
390 return NT_STATUS_UNSUCCESSFUL;
394 if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_GROUP)) == -1) ||
395 (low_id < idmap_tdb_state.low_gid)) {
396 if (tdb_store_int32(idmap_alloc_tdb, HWM_GROUP, idmap_tdb_state.low_gid) == -1) {
397 DEBUG(0, ("Unable to initialise group hwm in idmap database\n"));
398 return NT_STATUS_INTERNAL_DB_ERROR;
406 /**********************************
408 **********************************/
410 static NTSTATUS idmap_tdb_allocate_id(struct unixid *xid)
418 /* Get current high water mark */
424 high_hwm = idmap_tdb_state.high_uid;
430 high_hwm = idmap_tdb_state.high_gid;
434 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
435 return NT_STATUS_INVALID_PARAMETER;
438 if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
439 return NT_STATUS_INTERNAL_DB_ERROR;
442 /* check it is in the range */
443 if (hwm > high_hwm) {
444 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
445 hwmtype, (unsigned long)high_hwm));
446 return NT_STATUS_UNSUCCESSFUL;
449 /* fetch a new id and increment it */
450 ret = tdb_change_uint32_atomic(idmap_alloc_tdb, hwmkey, &hwm, 1);
452 DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype));
453 return NT_STATUS_UNSUCCESSFUL;
456 /* recheck it is in the range */
457 if (hwm > high_hwm) {
458 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
459 hwmtype, (unsigned long)high_hwm));
460 return NT_STATUS_UNSUCCESSFUL;
464 DEBUG(10,("New %s = %d\n", hwmtype, hwm));
469 /**********************************
470 Get current highest id.
471 **********************************/
473 static NTSTATUS idmap_tdb_get_hwm(struct unixid *xid)
480 /* Get current high water mark */
486 high_hwm = idmap_tdb_state.high_uid;
492 high_hwm = idmap_tdb_state.high_gid;
496 return NT_STATUS_INVALID_PARAMETER;
499 if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
500 return NT_STATUS_INTERNAL_DB_ERROR;
505 /* Warn if it is out of range */
506 if (hwm >= high_hwm) {
507 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
508 hwmtype, (unsigned long)high_hwm));
514 /**********************************
516 **********************************/
518 static NTSTATUS idmap_tdb_set_hwm(struct unixid *xid)
525 /* Get current high water mark */
531 high_hwm = idmap_tdb_state.high_uid;
537 high_hwm = idmap_tdb_state.high_gid;
541 return NT_STATUS_INVALID_PARAMETER;
546 if ((hwm = tdb_store_int32(idmap_alloc_tdb, hwmkey, hwm)) == -1) {
547 return NT_STATUS_INTERNAL_DB_ERROR;
550 /* Warn if it is out of range */
551 if (hwm >= high_hwm) {
552 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
553 hwmtype, (unsigned long)high_hwm));
559 /**********************************
561 **********************************/
563 static NTSTATUS idmap_tdb_alloc_close(void)
565 if (idmap_alloc_tdb) {
566 if (idmap_tdb_tdb_close(idmap_alloc_tdb) == 0) {
569 return NT_STATUS_UNSUCCESSFUL;
575 /**********************************************************************
576 IDMAP MAPPING TDB BACKEND
577 **********************************************************************/
579 struct idmap_tdb_context {
581 uint32_t filter_low_id;
582 uint32_t filter_high_id;
585 /*****************************
586 Initialise idmap database.
587 *****************************/
589 static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom)
592 struct idmap_tdb_context *ctx;
593 char *config_option = NULL;
596 ctx = talloc(dom, struct idmap_tdb_context);
598 DEBUG(0, ("Out of memory!\n"));
599 return NT_STATUS_NO_MEMORY;
602 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
603 if ( ! config_option) {
604 DEBUG(0, ("Out of memory!\n"));
605 ret = NT_STATUS_NO_MEMORY;
609 ret = idmap_tdb_open_db(ctx, &ctx->tdb);
610 if ( ! NT_STATUS_IS_OK(ret)) {
614 range = lp_parm_const_string(-1, config_option, "range", NULL);
616 (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
617 (ctx->filter_low_id > ctx->filter_high_id)) {
618 ctx->filter_low_id = 0;
619 ctx->filter_high_id = 0;
622 dom->private_data = ctx;
623 dom->initialized = True;
625 talloc_free(config_option);
633 /**********************************
634 Single id to sid lookup function.
635 **********************************/
637 static NTSTATUS idmap_tdb_id_to_sid(struct idmap_tdb_context *ctx, struct id_map *map)
644 return NT_STATUS_INVALID_PARAMETER;
647 /* apply filters before checking */
648 if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
649 (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
650 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
651 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
652 return NT_STATUS_NONE_MAPPED;
655 switch (map->xid.type) {
658 keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
662 keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
666 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
667 return NT_STATUS_INVALID_PARAMETER;
670 /* final SAFE_FREE safe */
673 if (keystr == NULL) {
674 DEBUG(0, ("Out of memory!\n"));
675 ret = NT_STATUS_NO_MEMORY;
679 DEBUG(10,("Fetching record %s\n", keystr));
681 /* Check if the mapping exists */
682 data = tdb_fetch_bystring(ctx->tdb, keystr);
685 DEBUG(10,("Record %s not found\n", keystr));
686 ret = NT_STATUS_NONE_MAPPED;
690 if (!string_to_sid(map->sid, (const char *)data.dptr)) {
691 DEBUG(10,("INVALID SID (%s) in record %s\n",
692 (const char *)data.dptr, keystr));
693 ret = NT_STATUS_INTERNAL_DB_ERROR;
697 DEBUG(10,("Found record %s -> %s\n", keystr, (const char *)data.dptr));
701 SAFE_FREE(data.dptr);
706 /**********************************
707 Single sid to id lookup function.
708 **********************************/
710 static NTSTATUS idmap_tdb_sid_to_id(struct idmap_tdb_context *ctx, struct id_map *map)
715 unsigned long rec_id = 0;
717 if ((keystr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
718 DEBUG(0, ("Out of memory!\n"));
719 ret = NT_STATUS_NO_MEMORY;
723 DEBUG(10,("Fetching record %s\n", keystr));
725 /* Check if sid is present in database */
726 data = tdb_fetch_bystring(ctx->tdb, keystr);
728 DEBUG(10,("Record %s not found\n", keystr));
729 ret = NT_STATUS_NONE_MAPPED;
733 /* What type of record is this ? */
734 if (sscanf((const char *)data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
735 map->xid.id = rec_id;
736 map->xid.type = ID_TYPE_UID;
737 DEBUG(10,("Found uid record %s -> %s \n", keystr, (const char *)data.dptr ));
740 } else if (sscanf((const char *)data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
741 map->xid.id = rec_id;
742 map->xid.type = ID_TYPE_GID;
743 DEBUG(10,("Found gid record %s -> %s \n", keystr, (const char *)data.dptr ));
746 } else { /* Unknown record type ! */
747 DEBUG(2, ("Found INVALID record %s -> %s\n", keystr, (const char *)data.dptr));
748 ret = NT_STATUS_INTERNAL_DB_ERROR;
751 SAFE_FREE(data.dptr);
753 /* apply filters before returning result */
754 if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
755 (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
756 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
757 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
758 ret = NT_STATUS_NONE_MAPPED;
766 /**********************************
767 lookup a set of unix ids.
768 **********************************/
770 static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
772 struct idmap_tdb_context *ctx;
776 /* make sure we initialized */
777 if ( ! dom->initialized) {
778 ret = idmap_tdb_db_init(dom);
779 if ( ! NT_STATUS_IS_OK(ret)) {
784 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
786 for (i = 0; ids[i]; i++) {
787 ret = idmap_tdb_id_to_sid(ctx, ids[i]);
788 if ( ! NT_STATUS_IS_OK(ret)) {
790 /* if it is just a failed mapping continue */
791 if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
793 /* make sure it is marked as unmapped */
794 ids[i]->status = ID_UNMAPPED;
798 /* some fatal error occurred, return immediately */
802 /* all ok, id is mapped */
803 ids[i]->status = ID_MAPPED;
812 /**********************************
813 lookup a set of sids.
814 **********************************/
816 static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
818 struct idmap_tdb_context *ctx;
822 /* make sure we initialized */
823 if ( ! dom->initialized) {
824 ret = idmap_tdb_db_init(dom);
825 if ( ! NT_STATUS_IS_OK(ret)) {
830 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
832 for (i = 0; ids[i]; i++) {
833 ret = idmap_tdb_sid_to_id(ctx, ids[i]);
834 if ( ! NT_STATUS_IS_OK(ret)) {
836 /* if it is just a failed mapping continue */
837 if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
839 /* make sure it is marked as unmapped */
840 ids[i]->status = ID_UNMAPPED;
844 /* some fatal error occurred, return immediately */
848 /* all ok, id is mapped */
849 ids[i]->status = ID_MAPPED;
858 /**********************************
860 **********************************/
862 static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_map *map)
864 struct idmap_tdb_context *ctx;
866 TDB_DATA ksid, kid, data;
867 char *ksidstr, *kidstr;
869 /* make sure we initialized */
870 if ( ! dom->initialized) {
871 ret = idmap_tdb_db_init(dom);
872 if ( ! NT_STATUS_IS_OK(ret)) {
877 if (!map || !map->sid) {
878 return NT_STATUS_INVALID_PARAMETER;
881 ksidstr = kidstr = NULL;
884 /* TODO: should we filter a set_mapping using low/high filters ? */
886 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
888 switch (map->xid.type) {
891 kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
895 kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
899 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
900 return NT_STATUS_INVALID_PARAMETER;
903 if (kidstr == NULL) {
904 DEBUG(0, ("ERROR: Out of memory!\n"));
905 ret = NT_STATUS_NO_MEMORY;
909 if ((ksidstr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
910 DEBUG(0, ("Out of memory!\n"));
911 ret = NT_STATUS_NO_MEMORY;
915 DEBUG(10, ("Storing %s <-> %s map\n", ksidstr, kidstr));
916 kid = string_term_tdb_data(kidstr);
917 ksid = string_term_tdb_data(ksidstr);
919 /* *DELETE* previous mappings if any.
920 * This is done both SID and [U|G]ID passed in */
922 /* Lock the record for this SID. */
923 if (tdb_chainlock(ctx->tdb, ksid) != 0) {
924 DEBUG(10,("Failed to lock record %s. Error %s\n",
925 ksidstr, tdb_errorstr(ctx->tdb) ));
926 return NT_STATUS_UNSUCCESSFUL;
929 data = tdb_fetch(ctx->tdb, ksid);
931 DEBUG(10, ("Deleting existing mapping %s <-> %s\n", (const char *)data.dptr, ksidstr ));
932 tdb_delete(ctx->tdb, data);
933 tdb_delete(ctx->tdb, ksid);
934 SAFE_FREE(data.dptr);
937 data = tdb_fetch(ctx->tdb, kid);
939 DEBUG(10,("Deleting existing mapping %s <-> %s\n", (const char *)data.dptr, kidstr ));
940 tdb_delete(ctx->tdb, data);
941 tdb_delete(ctx->tdb, kid);
942 SAFE_FREE(data.dptr);
945 if (tdb_store(ctx->tdb, ksid, kid, TDB_INSERT) == -1) {
946 DEBUG(0, ("Error storing SID -> ID: %s\n", tdb_errorstr(ctx->tdb)));
947 tdb_chainunlock(ctx->tdb, ksid);
948 ret = NT_STATUS_UNSUCCESSFUL;
951 if (tdb_store(ctx->tdb, kid, ksid, TDB_INSERT) == -1) {
952 DEBUG(0, ("Error stroing ID -> SID: %s\n", tdb_errorstr(ctx->tdb)));
953 /* try to remove the previous stored SID -> ID map */
954 tdb_delete(ctx->tdb, ksid);
955 tdb_chainunlock(ctx->tdb, ksid);
956 ret = NT_STATUS_UNSUCCESSFUL;
960 tdb_chainunlock(ctx->tdb, ksid);
961 DEBUG(10,("Stored %s <-> %s\n", ksidstr, kidstr));
965 talloc_free(ksidstr);
967 SAFE_FREE(data.dptr);
971 /**********************************
973 **********************************/
975 static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct id_map *map)
977 struct idmap_tdb_context *ctx;
979 TDB_DATA ksid, kid, data;
980 char *ksidstr, *kidstr;
982 /* make sure we initialized */
983 if ( ! dom->initialized) {
984 ret = idmap_tdb_db_init(dom);
985 if ( ! NT_STATUS_IS_OK(ret)) {
990 if (!map || !map->sid) {
991 return NT_STATUS_INVALID_PARAMETER;
994 ksidstr = kidstr = NULL;
997 /* TODO: should we filter a remove_mapping using low/high filters ? */
999 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
1001 switch (map->xid.type) {
1004 kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
1008 kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
1012 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
1013 return NT_STATUS_INVALID_PARAMETER;
1016 if (kidstr == NULL) {
1017 DEBUG(0, ("ERROR: Out of memory!\n"));
1018 ret = NT_STATUS_NO_MEMORY;
1022 if ((ksidstr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
1023 DEBUG(0, ("Out of memory!\n"));
1024 ret = NT_STATUS_NO_MEMORY;
1028 DEBUG(10, ("Checking %s <-> %s map\n", ksidstr, kidstr));
1029 ksid = string_term_tdb_data(ksidstr);
1030 kid = string_term_tdb_data(kidstr);
1032 /* Lock the record for this SID. */
1033 if (tdb_chainlock(ctx->tdb, ksid) != 0) {
1034 DEBUG(10,("Failed to lock record %s. Error %s\n",
1035 ksidstr, tdb_errorstr(ctx->tdb) ));
1036 return NT_STATUS_UNSUCCESSFUL;
1039 /* Check if sid is present in database */
1040 data = tdb_fetch(ctx->tdb, ksid);
1042 DEBUG(10,("Record %s not found\n", ksidstr));
1043 tdb_chainunlock(ctx->tdb, ksid);
1044 ret = NT_STATUS_NONE_MAPPED;
1048 /* Check if sid is mapped to the specified ID */
1049 if ((data.dsize != kid.dsize) ||
1050 (memcmp(data.dptr, kid.dptr, data.dsize) != 0)) {
1051 DEBUG(10,("Specified SID does not map to specified ID\n"));
1052 DEBUGADD(10,("Actual mapping is %s -> %s\n", ksidstr, (const char *)data.dptr));
1053 tdb_chainunlock(ctx->tdb, ksid);
1054 ret = NT_STATUS_NONE_MAPPED;
1058 DEBUG(10, ("Removing %s <-> %s map\n", ksidstr, kidstr));
1060 /* Delete previous mappings. */
1062 DEBUG(10, ("Deleting existing mapping %s -> %s\n", ksidstr, kidstr ));
1063 tdb_delete(ctx->tdb, ksid);
1065 DEBUG(10,("Deleting existing mapping %s -> %s\n", kidstr, ksidstr ));
1066 tdb_delete(ctx->tdb, kid);
1068 tdb_chainunlock(ctx->tdb, ksid);
1072 talloc_free(ksidstr);
1073 talloc_free(kidstr);
1074 SAFE_FREE(data.dptr);
1078 /**********************************
1079 Close the idmap tdb instance
1080 **********************************/
1082 static NTSTATUS idmap_tdb_close(struct idmap_domain *dom)
1084 struct idmap_tdb_context *ctx;
1086 if (dom->private_data) {
1087 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
1089 if (idmap_tdb_tdb_close(ctx->tdb) == 0) {
1090 return NT_STATUS_OK;
1092 return NT_STATUS_UNSUCCESSFUL;
1095 return NT_STATUS_OK;
1100 struct id_map **maps;
1105 static int idmap_tdb_dump_one_entry(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *pdata)
1107 struct dump_data *data = talloc_get_type(pdata, struct dump_data);
1108 struct id_map *maps;
1109 int num_maps = *data->num_maps;
1111 /* ignore any record but the ones with a SID as key */
1112 if (strncmp((const char *)key.dptr, "S-", 2) == 0) {
1114 maps = talloc_realloc(NULL, *data->maps, struct id_map, num_maps+1);
1116 DEBUG(0, ("Out of memory!\n"));
1117 data->ret = NT_STATUS_NO_MEMORY;
1121 maps[num_maps].sid = talloc(maps, DOM_SID);
1122 if ( ! maps[num_maps].sid) {
1123 DEBUG(0, ("Out of memory!\n"));
1124 data->ret = NT_STATUS_NO_MEMORY;
1128 if (!string_to_sid(maps[num_maps].sid, (const char *)key.dptr)) {
1129 DEBUG(10,("INVALID record %s\n", (const char *)key.dptr));
1130 /* continue even with errors */
1134 /* Try a UID record. */
1135 if (sscanf((const char *)value.dptr, "UID %u", &(maps[num_maps].xid.id)) == 1) {
1136 maps[num_maps].xid.type = ID_TYPE_UID;
1137 maps[num_maps].status = ID_MAPPED;
1138 *data->num_maps = num_maps + 1;
1140 /* Try a GID record. */
1142 if (sscanf((const char *)value.dptr, "GID %u", &(maps[num_maps].xid.id)) == 1) {
1143 maps[num_maps].xid.type = ID_TYPE_GID;
1144 maps[num_maps].status = ID_MAPPED;
1145 *data->num_maps = num_maps + 1;
1147 /* Unknown record type ! */
1149 maps[num_maps].status = ID_UNKNOWN;
1150 DEBUG(2, ("Found INVALID record %s -> %s\n",
1151 (const char *)key.dptr, (const char *)value.dptr));
1152 /* do not increment num_maps */
1159 /**********************************
1160 Dump all mappings out
1161 **********************************/
1163 static NTSTATUS idmap_tdb_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps)
1165 struct idmap_tdb_context *ctx;
1166 struct dump_data *data;
1167 NTSTATUS ret = NT_STATUS_OK;
1169 /* make sure we initialized */
1170 if ( ! dom->initialized) {
1171 ret = idmap_tdb_db_init(dom);
1172 if ( ! NT_STATUS_IS_OK(ret)) {
1177 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
1179 data = TALLOC_ZERO_P(ctx, struct dump_data);
1181 DEBUG(0, ("Out of memory!\n"));
1182 return NT_STATUS_NO_MEMORY;
1185 data->num_maps = num_maps;
1186 data->ret = NT_STATUS_OK;
1188 tdb_traverse(ctx->tdb, idmap_tdb_dump_one_entry, data);
1190 if ( ! NT_STATUS_IS_OK(data->ret)) {
1198 static struct idmap_methods db_methods = {
1200 .init = idmap_tdb_db_init,
1201 .unixids_to_sids = idmap_tdb_unixids_to_sids,
1202 .sids_to_unixids = idmap_tdb_sids_to_unixids,
1203 .set_mapping = idmap_tdb_set_mapping,
1204 .remove_mapping = idmap_tdb_remove_mapping,
1205 .dump_data = idmap_tdb_dump_data,
1206 .close_fn = idmap_tdb_close
1209 static struct idmap_alloc_methods db_alloc_methods = {
1211 .init = idmap_tdb_alloc_init,
1212 .allocate_id = idmap_tdb_allocate_id,
1213 .get_id_hwm = idmap_tdb_get_hwm,
1214 .set_id_hwm = idmap_tdb_set_hwm,
1215 .close_fn = idmap_tdb_alloc_close
1218 NTSTATUS idmap_alloc_tdb_init(void)
1220 return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_alloc_methods);
1223 NTSTATUS idmap_tdb_init(void)
1227 /* FIXME: bad hack to actually register also the alloc_tdb module without changining configure.in */
1228 ret = idmap_alloc_tdb_init();
1229 if (! NT_STATUS_IS_OK(ret)) {
1232 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);