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", key.dptr));
62 p = strchr(key.dptr, '/');
67 fstrcpy(dom_name, 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", key.dptr ));
76 if (tdb_delete(tdb, key) != 0) {
77 DEBUG(0, ("Unable to delete record %s\n", key.dptr));
87 sid_copy(&sid, &domain->sid);
88 sid_append_rid(&sid, rid);
90 sid_to_string(keystr, &sid);
92 key2.dsize = strlen(keystr) + 1;
94 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
95 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
100 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
101 DEBUG(0,("Unable to update record %s\n", data.dptr ));
106 if (tdb_delete(tdb, key) != 0) {
107 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
115 /*****************************************************************************
116 Convert the idmap database from an older version.
117 *****************************************************************************/
119 static BOOL idmap_tdb_convert(const char *idmap_name)
122 BOOL bigendianheader;
124 TDB_CONTEXT *idmap_tdb;
126 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
129 DEBUG(0, ("Unable to open idmap database\n"));
133 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
135 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
137 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
138 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
140 * high and low records were created on a
141 * big endian machine and will need byte-reversing.
146 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
151 wm = idmap_tdb_state.low_uid;
154 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
155 DEBUG(0, ("Unable to byteswap user hwm in idmap database\n"));
156 tdb_close(idmap_tdb);
160 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
164 wm = idmap_tdb_state.low_gid;
167 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
168 DEBUG(0, ("Unable to byteswap group hwm in idmap database\n"));
169 tdb_close(idmap_tdb);
174 /* the old format stored as DOMAIN/rid - now we store the SID direct */
175 tdb_traverse(idmap_tdb, convert_fn, &failed);
178 DEBUG(0, ("Problem during conversion\n"));
179 tdb_close(idmap_tdb);
183 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
184 DEBUG(0, ("Unable to dtore idmap version in databse\n"));
185 tdb_close(idmap_tdb);
189 tdb_close(idmap_tdb);
193 /*****************************************************************************
194 Convert the idmap database from an older version if necessary
195 *****************************************************************************/
197 BOOL idmap_tdb_upgrade(TALLOC_CTX *ctx, const char *tdbfile)
201 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
203 backup_name = talloc_asprintf(ctx, "%s.bak", tdbfile);
204 if ( ! backup_name) {
205 DEBUG(0, ("Out of memory!\n"));
209 if (backup_tdb(tdbfile, backup_name, 0) != 0) {
210 DEBUG(0, ("Could not backup idmap database\n"));
211 talloc_free(backup_name);
215 talloc_free(backup_name);
216 return idmap_tdb_convert(tdbfile);
219 /* WARNING: We can't open a tdb twice inthe same process, for that reason
220 * I'm going to use a hack with open ref counts to open the winbindd_idmap.tdb
221 * only once. We will later decide whether to split the db in multiple files
222 * or come up with a better solution to share them. */
224 static TDB_CONTEXT *idmap_tdb_common_ctx;
225 static int idmap_tdb_open_ref_count = 0;
227 static NTSTATUS idmap_tdb_open_db(TALLOC_CTX *memctx, TDB_CONTEXT **tdbctx)
231 SMB_STRUCT_STAT stbuf;
232 char *tdbfile = NULL;
234 BOOL tdb_is_new = False;
236 if (idmap_tdb_open_ref_count) { /* the tdb has already been opened */
237 idmap_tdb_open_ref_count++;
238 *tdbctx = idmap_tdb_common_ctx;
242 /* use our own context here */
243 ctx = talloc_new(memctx);
245 DEBUG(0, ("Out of memory!\n"));
246 return NT_STATUS_NO_MEMORY;
249 /* use the old database if present */
250 tdbfile = talloc_strdup(ctx, lock_path("winbindd_idmap.tdb"));
252 DEBUG(0, ("Out of memory!\n"));
253 ret = NT_STATUS_NO_MEMORY;
257 if (!file_exist(tdbfile, &stbuf)) {
261 DEBUG(10,("Opening tdbfile %s\n", tdbfile ));
263 /* Open idmap repository */
264 if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
265 DEBUG(0, ("Unable to open idmap database\n"));
266 ret = NT_STATUS_UNSUCCESSFUL;
271 /* the file didn't existed before opening it, let's
272 * store idmap version as nobody else yet opened and
273 * stored it. I do not like this method but didn't
274 * found a way to understand if an opened tdb have
275 * been just created or not --- SSS */
276 tdb_store_int32(idmap_tdb_common_ctx, "IDMAP_VERSION", IDMAP_VERSION);
279 /* check against earlier versions */
280 version = tdb_fetch_int32(idmap_tdb_common_ctx, "IDMAP_VERSION");
281 if (version != IDMAP_VERSION) {
283 /* backup_tdb expects the tdb not to be open */
284 tdb_close(idmap_tdb_common_ctx);
286 if ( ! idmap_tdb_upgrade(ctx, tdbfile)) {
288 DEBUG(0, ("Unable to open idmap database, it's in an old formati, and upgrade failed!\n"));
289 ret = NT_STATUS_INTERNAL_DB_ERROR;
293 /* Re-Open idmap repository */
294 if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
295 DEBUG(0, ("Unable to open idmap database\n"));
296 ret = NT_STATUS_UNSUCCESSFUL;
301 *tdbctx = idmap_tdb_common_ctx;
302 idmap_tdb_open_ref_count++;
310 /* NEVER use tdb_close() except for the conversion routines that are guaranteed
311 * to run only when the database is opened the first time, always use this function. */
313 BOOL idmap_tdb_tdb_close(TDB_CONTEXT *tdbctx)
315 if (tdbctx != idmap_tdb_common_ctx) {
316 DEBUG(0, ("ERROR: Invalid tdb context!"));
320 idmap_tdb_open_ref_count--;
321 if (idmap_tdb_open_ref_count) {
325 return tdb_close(idmap_tdb_common_ctx);
328 /**********************************************************************
329 IDMAP ALLOC TDB BACKEND
330 **********************************************************************/
332 static TDB_CONTEXT *idmap_alloc_tdb;
334 /**********************************
335 Initialise idmap alloc database.
336 **********************************/
338 static NTSTATUS idmap_tdb_alloc_init( const char *params )
344 uint32_t high_id = 0;
346 /* use our own context here */
347 ctx = talloc_new(NULL);
349 DEBUG(0, ("Out of memory!\n"));
350 return NT_STATUS_NO_MEMORY;
353 ret = idmap_tdb_open_db(ctx, &idmap_alloc_tdb);
354 if ( ! NT_STATUS_IS_OK(ret)) {
362 idmap_tdb_state.low_uid = 0;
363 idmap_tdb_state.high_uid = 0;
364 idmap_tdb_state.low_gid = 0;
365 idmap_tdb_state.high_gid = 0;
367 range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL);
368 if (range && range[0]) {
369 if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) {
370 if (low_id < high_id) {
371 idmap_tdb_state.low_gid = idmap_tdb_state.low_uid = low_id;
372 idmap_tdb_state.high_gid = idmap_tdb_state.high_uid = high_id;
374 DEBUG(1, ("ERROR: invalid idmap alloc range [%s]", range));
377 DEBUG(1, ("ERROR: invalid syntax for idmap alloc config:range [%s]", range));
381 /* Create high water marks for group and user id */
382 if (lp_idmap_uid(&low_id, &high_id)) {
383 idmap_tdb_state.low_uid = low_id;
384 idmap_tdb_state.high_uid = high_id;
387 if (lp_idmap_gid(&low_id, &high_id)) {
388 idmap_tdb_state.low_gid = low_id;
389 idmap_tdb_state.high_gid = high_id;
392 if (idmap_tdb_state.high_uid <= idmap_tdb_state.low_uid) {
393 DEBUG(1, ("idmap uid range missing or invalid\n"));
394 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
395 return NT_STATUS_UNSUCCESSFUL;
397 if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_USER)) == -1) ||
398 (low_id < idmap_tdb_state.low_uid)) {
399 if (tdb_store_int32(idmap_alloc_tdb, HWM_USER, idmap_tdb_state.low_uid) == -1) {
400 DEBUG(0, ("Unable to initialise user hwm in idmap database\n"));
401 return NT_STATUS_INTERNAL_DB_ERROR;
406 if (idmap_tdb_state.high_gid <= idmap_tdb_state.low_gid) {
407 DEBUG(1, ("idmap gid range missing or invalid\n"));
408 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
409 return NT_STATUS_UNSUCCESSFUL;
411 if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_GROUP)) == -1) ||
412 (low_id < idmap_tdb_state.low_gid)) {
413 if (tdb_store_int32(idmap_alloc_tdb, HWM_GROUP, idmap_tdb_state.low_gid) == -1) {
414 DEBUG(0, ("Unable to initialise group hwm in idmap database\n"));
415 return NT_STATUS_INTERNAL_DB_ERROR;
423 /**********************************
425 **********************************/
427 static NTSTATUS idmap_tdb_allocate_id(struct unixid *xid)
435 /* Get current high water mark */
441 high_hwm = idmap_tdb_state.high_uid;
447 high_hwm = idmap_tdb_state.high_gid;
451 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
452 return NT_STATUS_INVALID_PARAMETER;
455 if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
456 return NT_STATUS_INTERNAL_DB_ERROR;
459 /* check it is in the range */
460 if (hwm > high_hwm) {
461 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
462 hwmtype, (unsigned long)high_hwm));
463 return NT_STATUS_UNSUCCESSFUL;
466 /* fetch a new id and increment it */
467 ret = tdb_change_uint32_atomic(idmap_alloc_tdb, hwmkey, &hwm, 1);
469 DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype));
470 return NT_STATUS_UNSUCCESSFUL;
473 /* recheck it is in the range */
474 if (hwm > high_hwm) {
475 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n",
476 hwmtype, (unsigned long)high_hwm));
477 return NT_STATUS_UNSUCCESSFUL;
481 DEBUG(10,("New %s = %d\n", hwmtype, hwm));
486 /**********************************
487 Get current highest id.
488 **********************************/
490 static NTSTATUS idmap_tdb_get_hwm(struct unixid *xid)
497 /* Get current high water mark */
503 high_hwm = idmap_tdb_state.high_uid;
509 high_hwm = idmap_tdb_state.high_gid;
513 return NT_STATUS_INVALID_PARAMETER;
516 if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
517 return NT_STATUS_INTERNAL_DB_ERROR;
522 /* Warn if it is out of range */
523 if (hwm >= high_hwm) {
524 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
525 hwmtype, (unsigned long)high_hwm));
531 /**********************************
533 **********************************/
535 static NTSTATUS idmap_tdb_set_hwm(struct unixid *xid)
542 /* Get current high water mark */
548 high_hwm = idmap_tdb_state.high_uid;
554 high_hwm = idmap_tdb_state.high_gid;
558 return NT_STATUS_INVALID_PARAMETER;
563 if ((hwm = tdb_store_int32(idmap_alloc_tdb, hwmkey, hwm)) == -1) {
564 return NT_STATUS_INTERNAL_DB_ERROR;
567 /* Warn if it is out of range */
568 if (hwm >= high_hwm) {
569 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n",
570 hwmtype, (unsigned long)high_hwm));
576 /**********************************
578 **********************************/
580 static NTSTATUS idmap_tdb_alloc_close(void)
582 if (idmap_alloc_tdb) {
583 if (idmap_tdb_tdb_close(idmap_alloc_tdb) == 0) {
586 return NT_STATUS_UNSUCCESSFUL;
592 /**********************************************************************
593 IDMAP MAPPING TDB BACKEND
594 **********************************************************************/
596 struct idmap_tdb_context {
598 uint32_t filter_low_id;
599 uint32_t filter_high_id;
602 /*****************************
603 Initialise idmap database.
604 *****************************/
606 static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom, const char *compat_params)
609 struct idmap_tdb_context *ctx;
610 char *config_option = NULL;
613 ctx = talloc(dom, struct idmap_tdb_context);
615 DEBUG(0, ("Out of memory!\n"));
616 return NT_STATUS_NO_MEMORY;
619 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
620 if ( ! config_option) {
621 DEBUG(0, ("Out of memory!\n"));
622 ret = NT_STATUS_NO_MEMORY;
626 ret = idmap_tdb_open_db(ctx, &ctx->tdb);
627 if ( ! NT_STATUS_IS_OK(ret)) {
631 range = lp_parm_const_string(-1, config_option, "range", NULL);
633 (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
634 (ctx->filter_low_id > ctx->filter_high_id)) {
635 ctx->filter_low_id = 0;
636 ctx->filter_high_id = 0;
639 dom->private_data = ctx;
641 talloc_free(config_option);
649 /**********************************
650 Single id to sid lookup function.
651 **********************************/
653 static NTSTATUS idmap_tdb_id_to_sid(struct idmap_tdb_context *ctx, struct id_map *map)
659 return NT_STATUS_INVALID_PARAMETER;
662 /* apply filters before checking */
663 if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
664 (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
665 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
666 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
667 return NT_STATUS_NONE_MAPPED;
670 switch (map->xid.type) {
673 key.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
677 key.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
681 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
682 return NT_STATUS_INVALID_PARAMETER;
685 /* final SAFE_FREE safe */
688 if (key.dptr == NULL) {
689 DEBUG(0, ("Out of memory!\n"));
690 ret = NT_STATUS_NO_MEMORY;
694 key.dsize = strlen(key.dptr) + 1;
696 DEBUG(10,("Fetching record %s\n", key.dptr));
698 /* Check if the mapping exists */
699 data = tdb_fetch(ctx->tdb, key);
702 DEBUG(10,("Record %s not found\n", key.dptr));
703 ret = NT_STATUS_NONE_MAPPED;
707 if (!string_to_sid(map->sid, data.dptr)) {
708 DEBUG(10,("INVALID SID (%s) in record %s\n",
709 data.dptr, key.dptr));
710 ret = NT_STATUS_INTERNAL_DB_ERROR;
714 DEBUG(10,("Found record %s -> %s\n", key.dptr, data.dptr));
718 SAFE_FREE(data.dptr);
719 talloc_free(key.dptr);
723 /**********************************
724 Single sid to id lookup function.
725 **********************************/
727 static NTSTATUS idmap_tdb_sid_to_id(struct idmap_tdb_context *ctx, struct id_map *map)
731 unsigned long rec_id = 0;
733 if ((key.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
734 DEBUG(0, ("Out of memory!\n"));
735 ret = NT_STATUS_NO_MEMORY;
739 key.dsize = strlen(key.dptr) + 1;
741 DEBUG(10,("Fetching record %s\n", key.dptr));
743 /* Check if sid is present in database */
744 data = tdb_fetch(ctx->tdb, key);
746 DEBUG(10,("Record %s not found\n", key.dptr));
747 ret = NT_STATUS_NONE_MAPPED;
751 /* What type of record is this ? */
752 if (sscanf(data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
753 map->xid.id = rec_id;
754 map->xid.type = ID_TYPE_UID;
755 DEBUG(10,("Found uid record %s -> %s \n", key.dptr, data.dptr ));
758 } else if (sscanf(data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
759 map->xid.id = rec_id;
760 map->xid.type = ID_TYPE_GID;
761 DEBUG(10,("Found gid record %s -> %s \n", key.dptr, data.dptr ));
764 } else { /* Unknown record type ! */
765 DEBUG(2, ("Found INVALID record %s -> %s\n", key.dptr, data.dptr));
766 ret = NT_STATUS_INTERNAL_DB_ERROR;
769 SAFE_FREE(data.dptr);
771 /* apply filters before returning result */
772 if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
773 (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
774 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
775 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
776 ret = NT_STATUS_NONE_MAPPED;
780 talloc_free(key.dptr);
784 /**********************************
785 lookup a set of unix ids.
786 **********************************/
788 static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
790 struct idmap_tdb_context *ctx;
794 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
796 for (i = 0; ids[i]; i++) {
797 ret = idmap_tdb_id_to_sid(ctx, ids[i]);
798 if ( ! NT_STATUS_IS_OK(ret)) {
800 /* if it is just a failed mapping continue */
801 if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
803 /* make sure it is marked as unmapped */
804 ids[i]->mapped = False;
808 /* some fatal error occurred, return immediately */
812 /* all ok, id is mapped */
813 ids[i]->mapped = True;
822 /**********************************
823 lookup a set of sids.
824 **********************************/
826 static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
828 struct idmap_tdb_context *ctx;
832 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
834 for (i = 0; ids[i]; i++) {
835 ret = idmap_tdb_sid_to_id(ctx, ids[i]);
836 if ( ! NT_STATUS_IS_OK(ret)) {
838 /* if it is just a failed mapping continue */
839 if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
841 /* make sure it is marked as unmapped */
842 ids[i]->mapped = False;
846 /* some fatal error occurred, return immediately */
850 /* all ok, id is mapped */
851 ids[i]->mapped = True;
860 /**********************************
862 **********************************/
864 static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_map *map)
866 struct idmap_tdb_context *ctx;
868 TDB_DATA ksid, kid, data;
870 if (!map || !map->sid) {
871 return NT_STATUS_INVALID_PARAMETER;
874 ksid.dptr = kid.dptr = data.dptr = NULL;
876 /* TODO: should we filter a set_mapping using low/high filters ? */
878 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
880 switch (map->xid.type) {
883 kid.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
887 kid.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
891 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
892 return NT_STATUS_INVALID_PARAMETER;
895 if (kid.dptr == NULL) {
896 DEBUG(0, ("ERROR: Out of memory!\n"));
897 ret = NT_STATUS_NO_MEMORY;
900 kid.dsize = strlen(kid.dptr) + 1;
902 if ((ksid.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
903 DEBUG(0, ("Out of memory!\n"));
904 ret = NT_STATUS_NO_MEMORY;
907 ksid.dsize = strlen(ksid.dptr) + 1;
909 DEBUG(10, ("Storing %s <-> %s map\n", ksid.dptr, kid.dptr));
911 /* *DELETE* previous mappings if any.
912 * This is done both SID and [U|G]ID passed in */
914 /* Lock the record for this SID. */
915 if (tdb_chainlock(ctx->tdb, ksid) != 0) {
916 DEBUG(10,("Failed to lock record %s. Error %s\n",
917 ksid.dptr, tdb_errorstr(ctx->tdb) ));
918 return NT_STATUS_UNSUCCESSFUL;
921 data = tdb_fetch(ctx->tdb, ksid);
923 DEBUG(10, ("Deleting existing mapping %s <-> %s\n", data.dptr, ksid.dptr ));
924 tdb_delete(ctx->tdb, data);
925 tdb_delete(ctx->tdb, ksid);
926 SAFE_FREE(data.dptr);
929 data = tdb_fetch(ctx->tdb, kid);
931 DEBUG(10,("Deleting existing mapping %s <-> %s\n", data.dptr, kid.dptr ));
932 tdb_delete(ctx->tdb, data);
933 tdb_delete(ctx->tdb, kid);
934 SAFE_FREE(data.dptr);
937 if (tdb_store(ctx->tdb, ksid, kid, TDB_INSERT) == -1) {
938 DEBUG(0, ("Error storing SID -> ID: %s\n", tdb_errorstr(ctx->tdb)));
939 tdb_chainunlock(ctx->tdb, ksid);
940 ret = NT_STATUS_UNSUCCESSFUL;
943 if (tdb_store(ctx->tdb, kid, ksid, TDB_INSERT) == -1) {
944 DEBUG(0, ("Error stroing ID -> SID: %s\n", tdb_errorstr(ctx->tdb)));
945 /* try to remove the previous stored SID -> ID map */
946 tdb_delete(ctx->tdb, ksid);
947 tdb_chainunlock(ctx->tdb, ksid);
948 ret = NT_STATUS_UNSUCCESSFUL;
952 tdb_chainunlock(ctx->tdb, ksid);
953 DEBUG(10,("Stored %s <-> %s\n", ksid.dptr, kid.dptr));
957 talloc_free(ksid.dptr);
958 talloc_free(kid.dptr);
959 SAFE_FREE(data.dptr);
963 /**********************************
965 **********************************/
967 static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct id_map *map)
969 struct idmap_tdb_context *ctx;
971 TDB_DATA ksid, kid, data;
973 if (!map || !map->sid) {
974 return NT_STATUS_INVALID_PARAMETER;
977 ksid.dptr = kid.dptr = data.dptr = NULL;
979 /* TODO: should we filter a remove_mapping using low/high filters ? */
981 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
983 switch (map->xid.type) {
986 kid.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
990 kid.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
994 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
995 return NT_STATUS_INVALID_PARAMETER;
998 if (kid.dptr == NULL) {
999 DEBUG(0, ("ERROR: Out of memory!\n"));
1000 ret = NT_STATUS_NO_MEMORY;
1003 kid.dsize = strlen(kid.dptr) + 1;
1005 if ((ksid.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
1006 DEBUG(0, ("Out of memory!\n"));
1007 ret = NT_STATUS_NO_MEMORY;
1010 ksid.dsize = strlen(ksid.dptr) + 1;
1012 DEBUG(10, ("Checking %s <-> %s map\n", ksid.dptr, kid.dptr));
1014 /* Lock the record for this SID. */
1015 if (tdb_chainlock(ctx->tdb, ksid) != 0) {
1016 DEBUG(10,("Failed to lock record %s. Error %s\n",
1017 ksid.dptr, tdb_errorstr(ctx->tdb) ));
1018 return NT_STATUS_UNSUCCESSFUL;
1021 /* Check if sid is present in database */
1022 data = tdb_fetch(ctx->tdb, ksid);
1024 DEBUG(10,("Record %s not found\n", ksid.dptr));
1025 tdb_chainunlock(ctx->tdb, ksid);
1026 ret = NT_STATUS_NONE_MAPPED;
1030 /* Check if sid is mapped to the specified ID */
1031 if ((data.dsize != kid.dsize) ||
1032 (memcmp(data.dptr, kid.dptr, data.dsize) != 0)) {
1033 DEBUG(10,("Specified SID does not map to specified ID\n"));
1034 DEBUGADD(10,("Actual mapping is %s -> %s\n", ksid.dptr, data.dptr));
1035 tdb_chainunlock(ctx->tdb, ksid);
1036 ret = NT_STATUS_NONE_MAPPED;
1040 DEBUG(10, ("Removing %s <-> %s map\n", ksid.dptr, kid.dptr));
1042 /* Delete previous mappings. */
1044 data = tdb_fetch(ctx->tdb, ksid);
1046 DEBUG(10, ("Deleting existing mapping %s -> %s\n", ksid.dptr, kid.dptr ));
1047 tdb_delete(ctx->tdb, ksid);
1048 SAFE_FREE(data.dptr);
1051 data = tdb_fetch(ctx->tdb, kid);
1053 DEBUG(10,("Deleting existing mapping %s -> %s\n", kid.dptr, ksid.dptr ));
1054 tdb_delete(ctx->tdb, kid);
1055 SAFE_FREE(data.dptr);
1058 tdb_chainunlock(ctx->tdb, ksid);
1062 talloc_free(ksid.dptr);
1063 talloc_free(kid.dptr);
1064 SAFE_FREE(data.dptr);
1068 /**********************************
1069 Close the idmap tdb instance
1070 **********************************/
1072 static NTSTATUS idmap_tdb_close(struct idmap_domain *dom)
1074 struct idmap_tdb_context *ctx;
1076 if (dom->private_data) {
1077 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
1079 if (idmap_tdb_tdb_close(ctx->tdb) == 0) {
1080 return NT_STATUS_OK;
1082 return NT_STATUS_UNSUCCESSFUL;
1085 return NT_STATUS_OK;
1090 struct id_map **maps;
1095 static int idmap_tdb_dump_one_entry(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *pdata)
1097 struct dump_data *data = talloc_get_type(pdata, struct dump_data);
1098 struct id_map *maps;
1099 int num_maps = *data->num_maps;
1101 /* ignore any record but the ones with a SID as key */
1102 if (strncmp(key.dptr, "S-", 2) == 0) {
1104 maps = talloc_realloc(NULL, *data->maps, struct id_map, num_maps+1);
1106 DEBUG(0, ("Out of memory!\n"));
1107 data->ret = NT_STATUS_NO_MEMORY;
1111 maps[num_maps].sid = talloc(maps, DOM_SID);
1112 if ( ! maps[num_maps].sid) {
1113 DEBUG(0, ("Out of memory!\n"));
1114 data->ret = NT_STATUS_NO_MEMORY;
1118 if (!string_to_sid(maps[num_maps].sid, key.dptr)) {
1119 DEBUG(10,("INVALID record %s\n", key.dptr));
1120 /* continue even with errors */
1124 /* Try a UID record. */
1125 if (sscanf(value.dptr, "UID %u", &(maps[num_maps].xid.id)) == 1) {
1126 maps[num_maps].xid.type = ID_TYPE_UID;
1127 maps[num_maps].mapped = True;
1128 *data->num_maps = num_maps + 1;
1130 /* Try a GID record. */
1132 if (sscanf(value.dptr, "GID %u", &(maps[num_maps].xid.id)) == 1) {
1133 maps[num_maps].xid.type = ID_TYPE_GID;
1134 maps[num_maps].mapped = True;
1135 *data->num_maps = num_maps + 1;
1137 /* Unknown record type ! */
1139 DEBUG(2, ("Found INVALID record %s -> %s\n", key.dptr, value.dptr));
1140 /* do not increment num_maps */
1147 /**********************************
1148 Dump all mappings out
1149 **********************************/
1151 static NTSTATUS idmap_tdb_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps)
1153 struct idmap_tdb_context *ctx;
1154 struct dump_data *data;
1155 NTSTATUS ret = NT_STATUS_OK;
1157 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
1159 data = talloc_zero(ctx, struct dump_data);
1161 DEBUG(0, ("Out of memory!\n"));
1162 return NT_STATUS_NO_MEMORY;
1165 data->num_maps = num_maps;
1166 data->ret = NT_STATUS_OK;
1168 tdb_traverse(ctx->tdb, idmap_tdb_dump_one_entry, data);
1170 if ( ! NT_STATUS_IS_OK(data->ret)) {
1178 static struct idmap_methods db_methods = {
1180 .init = idmap_tdb_db_init,
1181 .unixids_to_sids = idmap_tdb_unixids_to_sids,
1182 .sids_to_unixids = idmap_tdb_sids_to_unixids,
1183 .set_mapping = idmap_tdb_set_mapping,
1184 .remove_mapping = idmap_tdb_remove_mapping,
1185 .dump_data = idmap_tdb_dump_data,
1186 .close_fn = idmap_tdb_close
1189 static struct idmap_alloc_methods db_alloc_methods = {
1191 .init = idmap_tdb_alloc_init,
1192 .allocate_id = idmap_tdb_allocate_id,
1193 .get_id_hwm = idmap_tdb_get_hwm,
1194 .set_id_hwm = idmap_tdb_set_hwm,
1195 .close_fn = idmap_tdb_alloc_close
1198 NTSTATUS idmap_alloc_tdb_init(void)
1200 return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_alloc_methods);
1203 NTSTATUS idmap_tdb_init(void)
1207 /* FIXME: bad hack to actually register also the alloc_tdb module without changining configure.in */
1208 ret = idmap_alloc_tdb_init();
1209 if (! NT_STATUS_IS_OK(ret)) {
1212 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);