root/source3/groupdb/mapping_tdb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_group_mapping
  2. group_mapping_key
  3. add_mapping_entry
  4. get_group_map_from_sid
  5. dbrec2map
  6. find_map
  7. get_group_map_from_gid
  8. get_group_map_from_ntname
  9. group_map_remove
  10. collect_map
  11. enum_group_mapping
  12. one_alias_membership
  13. alias_memberships
  14. is_aliasmem
  15. add_aliasmem
  16. collect_aliasmem
  17. enum_aliasmem
  18. del_aliasmem
  19. groupdb_tdb_init

   1 /* 
   2  *  Unix SMB/CIFS implementation.
   3  *  RPC Pipe client / server routines
   4  *  Copyright (C) Andrew Tridgell              1992-2006,
   5  *  Copyright (C) Jean François Micouleau      1998-2001.
   6  *  Copyright (C) Volker Lendecke              2006.
   7  *  Copyright (C) Gerald Carter                2006.
   8  *  
   9  *  This program is free software; you can redistribute it and/or modify
  10  *  it under the terms of the GNU General Public License as published by
  11  *  the Free Software Foundation; either version 3 of the License, or
  12  *  (at your option) any later version.
  13  *  
  14  *  This program is distributed in the hope that it will be useful,
  15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17  *  GNU General Public License for more details.
  18  *  
  19  *  You should have received a copy of the GNU General Public License
  20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  21  */
  22 
  23 #include "includes.h"
  24 #include "groupdb/mapping.h"
  25 
  26 static struct db_context *db; /* used for driver files */
  27 
  28 static bool enum_group_mapping(const DOM_SID *domsid, enum lsa_SidType sid_name_use, GROUP_MAP **pp_rmap,
  29                                size_t *p_num_entries, bool unix_only);
  30 static bool group_map_remove(const DOM_SID *sid);
  31         
  32 /****************************************************************************
  33  Open the group mapping tdb.
  34 ****************************************************************************/
  35 static bool init_group_mapping(void)
     /* [<][>][^][v][top][bottom][index][help] */
  36 {
  37         if (db != NULL) {
  38                 return true;
  39         }
  40 
  41         db = db_open(NULL, state_path("group_mapping.tdb"), 0,
  42                            TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
  43         if (db == NULL) {
  44                 DEBUG(0, ("Failed to open group mapping database: %s\n",
  45                           strerror(errno)));
  46                 return false;
  47         }
  48 
  49 #if 0
  50         /*
  51          * This code was designed to handle a group mapping version
  52          * upgrade. mapping_tdb is not active by default anymore, so ignore
  53          * this here.
  54          */
  55         {
  56                 const char *vstring = "INFO/version";
  57                 int32 vers_id;
  58                 GROUP_MAP *map_table = NULL;
  59                 size_t num_entries = 0;
  60 
  61                 /* handle a Samba upgrade */
  62                 tdb_lock_bystring(tdb, vstring);
  63 
  64                 /* Cope with byte-reversed older versions of the db. */
  65                 vers_id = tdb_fetch_int32(tdb, vstring);
  66                 if ((vers_id == DATABASE_VERSION_V1)
  67                     || (IREV(vers_id) == DATABASE_VERSION_V1)) {
  68                         /*
  69                          * Written on a bigendian machine with old fetch_int
  70                          * code. Save as le.
  71                          */
  72                         tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
  73                         vers_id = DATABASE_VERSION_V2;
  74                 }
  75 
  76                 /* if its an unknown version we remove everthing in the db */
  77 
  78                 if (vers_id != DATABASE_VERSION_V2) {
  79                         tdb_wipe_all(tdb);
  80                         tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
  81                 }
  82 
  83                 tdb_unlock_bystring(tdb, vstring);
  84 
  85                 /* cleanup any map entries with a gid == -1 */
  86 
  87                 if ( enum_group_mapping( NULL, SID_NAME_UNKNOWN, &map_table,
  88                                          &num_entries, False ) ) {
  89                         int i;
  90 
  91                         for ( i=0; i<num_entries; i++ ) {
  92                                 if ( map_table[i].gid == -1 ) {
  93                                         group_map_remove( &map_table[i].sid );
  94                                 }
  95                         }
  96 
  97                         SAFE_FREE( map_table );
  98                 }
  99         }
 100 #endif
 101 
 102         return true;
 103 }
 104 
 105 static char *group_mapping_key(TALLOC_CTX *mem_ctx, const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 106 {
 107         char *sidstr, *result;
 108 
 109         sidstr = sid_string_talloc(talloc_tos(), sid);
 110         if (sidstr == NULL) {
 111                 return NULL;
 112         }
 113 
 114         result = talloc_asprintf(mem_ctx, "%s%s", GROUP_PREFIX, sidstr);
 115 
 116         TALLOC_FREE(sidstr);
 117         return result;
 118 }
 119 
 120 /****************************************************************************
 121 ****************************************************************************/
 122 static bool add_mapping_entry(GROUP_MAP *map, int flag)
     /* [<][>][^][v][top][bottom][index][help] */
 123 {
 124         char *key, *buf;
 125         int len;
 126         NTSTATUS status;
 127 
 128         key = group_mapping_key(talloc_tos(), &map->sid);
 129         if (key == NULL) {
 130                 return false;
 131         }
 132 
 133         len = tdb_pack(NULL, 0, "ddff",
 134                 map->gid, map->sid_name_use, map->nt_name, map->comment);
 135 
 136         buf = TALLOC_ARRAY(key, char, len);
 137         if (!buf) {
 138                 TALLOC_FREE(key);
 139                 return false;
 140         }
 141         len = tdb_pack((uint8 *)buf, len, "ddff", map->gid,
 142                        map->sid_name_use, map->nt_name, map->comment);
 143 
 144         status = dbwrap_trans_store(
 145                 db, string_term_tdb_data(key),
 146                 make_tdb_data((uint8_t *)buf, len), TDB_REPLACE);
 147 
 148         TALLOC_FREE(key);
 149 
 150         return NT_STATUS_IS_OK(status);
 151 }
 152 
 153 
 154 /****************************************************************************
 155  Return the sid and the type of the unix group.
 156 ****************************************************************************/
 157 
 158 static bool get_group_map_from_sid(DOM_SID sid, GROUP_MAP *map)
     /* [<][>][^][v][top][bottom][index][help] */
 159 {
 160         TDB_DATA dbuf;
 161         char *key;
 162         int ret = 0;
 163 
 164         /* the key is the SID, retrieving is direct */
 165 
 166         key = group_mapping_key(talloc_tos(), &sid);
 167         if (key == NULL) {
 168                 return false;
 169         }
 170 
 171         dbuf = dbwrap_fetch_bystring(db, key, key);
 172         if (dbuf.dptr == NULL) {
 173                 TALLOC_FREE(key);
 174                 return false;
 175         }
 176 
 177         ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddff",
 178                         &map->gid, &map->sid_name_use,
 179                         &map->nt_name, &map->comment);
 180 
 181         TALLOC_FREE(key);
 182 
 183         if ( ret == -1 ) {
 184                 DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
 185                 return false;
 186         }
 187 
 188         sid_copy(&map->sid, &sid);
 189 
 190         return true;
 191 }
 192 
 193 static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map)
     /* [<][>][^][v][top][bottom][index][help] */
 194 {
 195         if ((rec->key.dsize < strlen(GROUP_PREFIX))
 196             || (strncmp((char *)rec->key.dptr, GROUP_PREFIX,
 197                         GROUP_PREFIX_LEN) != 0)) {
 198                 return False;
 199         }
 200 
 201         if (!string_to_sid(&map->sid, (const char *)rec->key.dptr
 202                            + GROUP_PREFIX_LEN)) {
 203                 return False;
 204         }
 205 
 206         return tdb_unpack(rec->value.dptr, rec->value.dsize, "ddff",
 207                           &map->gid, &map->sid_name_use, &map->nt_name,
 208                           &map->comment) != -1;
 209 }
 210 
 211 struct find_map_state {
 212         bool found;
 213         const char *name;       /* If != NULL, look for name */
 214         gid_t gid;              /* valid iff name == NULL */
 215         GROUP_MAP *map;
 216 };
 217 
 218 static int find_map(struct db_record *rec, void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
 219 {
 220         struct find_map_state *state = (struct find_map_state *)private_data;
 221 
 222         if (!dbrec2map(rec, state->map)) {
 223                 DEBUG(10, ("failed to unpack map\n"));
 224                 return 0;
 225         }
 226 
 227         if (state->name != NULL) {
 228                 if (strequal(state->name, state->map->nt_name)) {
 229                         state->found = true;
 230                         return 1;
 231                 }
 232         }
 233         else {
 234                 if (state->map->gid == state->gid) {
 235                         state->found = true;
 236                         return 1;
 237                 }
 238         }
 239 
 240         return 0;
 241 }
 242 
 243 /****************************************************************************
 244  Return the sid and the type of the unix group.
 245 ****************************************************************************/
 246 
 247 static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
     /* [<][>][^][v][top][bottom][index][help] */
 248 {
 249         struct find_map_state state;
 250 
 251         state.found = false;
 252         state.name = NULL;      /* Indicate we're looking for gid */
 253         state.gid = gid;
 254         state.map = map;
 255 
 256         db->traverse_read(db, find_map, (void *)&state);
 257 
 258         return state.found;
 259 }
 260 
 261 /****************************************************************************
 262  Return the sid and the type of the unix group.
 263 ****************************************************************************/
 264 
 265 static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
     /* [<][>][^][v][top][bottom][index][help] */
 266 {
 267         struct find_map_state state;
 268 
 269         state.found = false;
 270         state.name = name;
 271         state.map = map;
 272 
 273         db->traverse_read(db, find_map, (void *)&state);
 274 
 275         return state.found;
 276 }
 277 
 278 /****************************************************************************
 279  Remove a group mapping entry.
 280 ****************************************************************************/
 281 
 282 static bool group_map_remove(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 283 {
 284         char *key;
 285         NTSTATUS status;
 286 
 287         key = group_mapping_key(talloc_tos(), sid);
 288         if (key == NULL) {
 289                 return false;
 290         }
 291 
 292         status = dbwrap_trans_delete(db, string_term_tdb_data(key));
 293 
 294         TALLOC_FREE(key);
 295         return NT_STATUS_IS_OK(status);
 296 }
 297 
 298 /****************************************************************************
 299  Enumerate the group mapping.
 300 ****************************************************************************/
 301 
 302 struct enum_map_state {
 303         const DOM_SID *domsid;
 304         enum lsa_SidType sid_name_use;
 305         bool unix_only;
 306 
 307         size_t num_maps;
 308         GROUP_MAP *maps;
 309 };
 310 
 311 static int collect_map(struct db_record *rec, void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
 312 {
 313         struct enum_map_state *state = (struct enum_map_state *)private_data;
 314         GROUP_MAP map;
 315         GROUP_MAP *tmp;
 316 
 317         if (!dbrec2map(rec, &map)) {
 318                 return 0;
 319         }
 320         /* list only the type or everything if UNKNOWN */
 321         if (state->sid_name_use != SID_NAME_UNKNOWN
 322             && state->sid_name_use != map.sid_name_use) {
 323                 DEBUG(11,("enum_group_mapping: group %s is not of the "
 324                           "requested type\n", map.nt_name));
 325                 return 0;
 326         }
 327 
 328         if ((state->unix_only == ENUM_ONLY_MAPPED) && (map.gid == -1)) {
 329                 DEBUG(11,("enum_group_mapping: group %s is non mapped\n",
 330                           map.nt_name));
 331                 return 0;
 332         }
 333 
 334         if ((state->domsid != NULL) &&
 335             (sid_compare_domain(state->domsid, &map.sid) != 0)) {
 336                 DEBUG(11,("enum_group_mapping: group %s is not in domain\n",
 337                           sid_string_dbg(&map.sid)));
 338                 return 0;
 339         }
 340 
 341         if (!(tmp = SMB_REALLOC_ARRAY(state->maps, GROUP_MAP,
 342                                       state->num_maps+1))) {
 343                 DEBUG(0,("enum_group_mapping: Unable to enlarge group "
 344                          "map!\n"));
 345                 return 1;
 346         }
 347 
 348         state->maps = tmp;
 349         state->maps[state->num_maps] = map;
 350         state->num_maps++;
 351         return 0;
 352 }
 353 
 354 static bool enum_group_mapping(const DOM_SID *domsid,
     /* [<][>][^][v][top][bottom][index][help] */
 355                                enum lsa_SidType sid_name_use,
 356                                GROUP_MAP **pp_rmap,
 357                                size_t *p_num_entries, bool unix_only)
 358 {
 359         struct enum_map_state state;
 360 
 361         state.domsid = domsid;
 362         state.sid_name_use = sid_name_use;
 363         state.unix_only = unix_only;
 364         state.num_maps = 0;
 365         state.maps = NULL;
 366 
 367         if (db->traverse_read(db, collect_map, (void *)&state) < 0) {
 368                 return false;
 369         }
 370 
 371         *pp_rmap = state.maps;
 372         *p_num_entries = state.num_maps;
 373 
 374         return true;
 375 }
 376 
 377 /* This operation happens on session setup, so it should better be fast. We
 378  * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
 379 
 380 static NTSTATUS one_alias_membership(const DOM_SID *member,
     /* [<][>][^][v][top][bottom][index][help] */
 381                                DOM_SID **sids, size_t *num)
 382 {
 383         fstring tmp;
 384         fstring key;
 385         char *string_sid;
 386         TDB_DATA dbuf;
 387         const char *p;
 388         NTSTATUS status = NT_STATUS_OK;
 389         TALLOC_CTX *frame = talloc_stackframe();
 390 
 391         slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX,
 392                  sid_to_fstring(tmp, member));
 393 
 394         dbuf = dbwrap_fetch_bystring(db, frame, key);
 395         if (dbuf.dptr == NULL) {
 396                 TALLOC_FREE(frame);
 397                 return NT_STATUS_OK;
 398         }
 399 
 400         p = (const char *)dbuf.dptr;
 401 
 402         while (next_token_talloc(frame, &p, &string_sid, " ")) {
 403                 DOM_SID alias;
 404 
 405                 if (!string_to_sid(&alias, string_sid))
 406                         continue;
 407 
 408                 status= add_sid_to_array_unique(NULL, &alias, sids, num);
 409                 if (!NT_STATUS_IS_OK(status)) {
 410                         goto done;
 411                 }
 412         }
 413 
 414 done:
 415         TALLOC_FREE(frame);
 416         return status;
 417 }
 418 
 419 static NTSTATUS alias_memberships(const DOM_SID *members, size_t num_members,
     /* [<][>][^][v][top][bottom][index][help] */
 420                                   DOM_SID **sids, size_t *num)
 421 {
 422         size_t i;
 423 
 424         *num = 0;
 425         *sids = NULL;
 426 
 427         for (i=0; i<num_members; i++) {
 428                 NTSTATUS status = one_alias_membership(&members[i], sids, num);
 429                 if (!NT_STATUS_IS_OK(status))
 430                         return status;
 431         }
 432         return NT_STATUS_OK;
 433 }
 434 
 435 static bool is_aliasmem(const DOM_SID *alias, const DOM_SID *member)
     /* [<][>][^][v][top][bottom][index][help] */
 436 {
 437         DOM_SID *sids;
 438         size_t i, num;
 439 
 440         /* This feels the wrong way round, but the on-disk data structure
 441          * dictates it this way. */
 442         if (!NT_STATUS_IS_OK(alias_memberships(member, 1, &sids, &num)))
 443                 return False;
 444 
 445         for (i=0; i<num; i++) {
 446                 if (sid_compare(alias, &sids[i]) == 0) {
 447                         TALLOC_FREE(sids);
 448                         return True;
 449                 }
 450         }
 451         TALLOC_FREE(sids);
 452         return False;
 453 }
 454 
 455 
 456 static NTSTATUS add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
     /* [<][>][^][v][top][bottom][index][help] */
 457 {
 458         GROUP_MAP map;
 459         char *key;
 460         fstring string_sid;
 461         char *new_memberstring;
 462         struct db_record *rec;
 463         NTSTATUS status;
 464 
 465         if (!get_group_map_from_sid(*alias, &map))
 466                 return NT_STATUS_NO_SUCH_ALIAS;
 467 
 468         if ( (map.sid_name_use != SID_NAME_ALIAS) &&
 469              (map.sid_name_use != SID_NAME_WKN_GRP) )
 470                 return NT_STATUS_NO_SUCH_ALIAS;
 471 
 472         if (is_aliasmem(alias, member))
 473                 return NT_STATUS_MEMBER_IN_ALIAS;
 474 
 475         sid_to_fstring(string_sid, member);
 476 
 477         key = talloc_asprintf(talloc_tos(), "%s%s", MEMBEROF_PREFIX,
 478                               string_sid);
 479         if (key == NULL) {
 480                 return NT_STATUS_NO_MEMORY;
 481         }
 482 
 483         if (db->transaction_start(db) != 0) {
 484                 DEBUG(0, ("transaction_start failed\n"));
 485                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 486         }
 487 
 488         rec = db->fetch_locked(db, key, string_term_tdb_data(key));
 489 
 490         if (rec == NULL) {
 491                 DEBUG(10, ("fetch_lock failed\n"));
 492                 TALLOC_FREE(key);
 493                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 494                 goto cancel;
 495         }
 496 
 497         sid_to_fstring(string_sid, alias);
 498 
 499         if (rec->value.dptr != NULL) {
 500                 new_memberstring = talloc_asprintf(
 501                         key, "%s %s", (char *)(rec->value.dptr), string_sid);
 502         } else {
 503                 new_memberstring = talloc_strdup(key, string_sid);
 504         }
 505 
 506         if (new_memberstring == NULL) {
 507                 TALLOC_FREE(key);
 508                 status = NT_STATUS_NO_MEMORY;
 509                 goto cancel;
 510         }
 511 
 512         status = rec->store(rec, string_term_tdb_data(new_memberstring), 0);
 513 
 514         TALLOC_FREE(key);
 515 
 516         if (!NT_STATUS_IS_OK(status)) {
 517                 DEBUG(10, ("Could not store record: %s\n", nt_errstr(status)));
 518                 goto cancel;
 519         }
 520 
 521         if (db->transaction_commit(db) != 0) {
 522                 DEBUG(0, ("transaction_commit failed\n"));
 523                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 524                 return status;
 525         }
 526 
 527         return NT_STATUS_OK;
 528 
 529  cancel:
 530         if (db->transaction_cancel(db) != 0) {
 531                 smb_panic("transaction_cancel failed");
 532         }
 533 
 534         return status;
 535 }
 536 
 537 struct aliasmem_state {
 538         const DOM_SID *alias;
 539         DOM_SID **sids;
 540         size_t *num;
 541 };
 542 
 543 static int collect_aliasmem(struct db_record *rec, void *priv)
     /* [<][>][^][v][top][bottom][index][help] */
 544 {
 545         struct aliasmem_state *state = (struct aliasmem_state *)priv;
 546         const char *p;
 547         char *alias_string;
 548         TALLOC_CTX *frame;
 549 
 550         if (strncmp((const char *)rec->key.dptr, MEMBEROF_PREFIX,
 551                     MEMBEROF_PREFIX_LEN) != 0)
 552                 return 0;
 553 
 554         p = (const char *)rec->value.dptr;
 555 
 556         frame = talloc_stackframe();
 557 
 558         while (next_token_talloc(frame, &p, &alias_string, " ")) {
 559                 DOM_SID alias, member;
 560                 const char *member_string;
 561 
 562                 if (!string_to_sid(&alias, alias_string))
 563                         continue;
 564 
 565                 if (sid_compare(state->alias, &alias) != 0)
 566                         continue;
 567 
 568                 /* Ok, we found the alias we're looking for in the membership
 569                  * list currently scanned. The key represents the alias
 570                  * member. Add that. */
 571 
 572                 member_string = strchr((const char *)rec->key.dptr, '/');
 573 
 574                 /* Above we tested for MEMBEROF_PREFIX which includes the
 575                  * slash. */
 576 
 577                 SMB_ASSERT(member_string != NULL);
 578                 member_string += 1;
 579 
 580                 if (!string_to_sid(&member, member_string))
 581                         continue;
 582 
 583                 if (!NT_STATUS_IS_OK(add_sid_to_array(NULL, &member,
 584                                                       state->sids,
 585                                                       state->num)))
 586                 {
 587                         /* talloc fail. */
 588                         break;
 589                 }
 590         }
 591 
 592         TALLOC_FREE(frame);
 593         return 0;
 594 }
 595 
 596 static NTSTATUS enum_aliasmem(const DOM_SID *alias, DOM_SID **sids, size_t *num)
     /* [<][>][^][v][top][bottom][index][help] */
 597 {
 598         GROUP_MAP map;
 599         struct aliasmem_state state;
 600 
 601         if (!get_group_map_from_sid(*alias, &map))
 602                 return NT_STATUS_NO_SUCH_ALIAS;
 603 
 604         if ( (map.sid_name_use != SID_NAME_ALIAS) &&
 605              (map.sid_name_use != SID_NAME_WKN_GRP) )
 606                 return NT_STATUS_NO_SUCH_ALIAS;
 607 
 608         *sids = NULL;
 609         *num = 0;
 610 
 611         state.alias = alias;
 612         state.sids = sids;
 613         state.num = num;
 614 
 615         db->traverse_read(db, collect_aliasmem, &state);
 616         return NT_STATUS_OK;
 617 }
 618 
 619 static NTSTATUS del_aliasmem(const DOM_SID *alias, const DOM_SID *member)
     /* [<][>][^][v][top][bottom][index][help] */
 620 {
 621         NTSTATUS status;
 622         DOM_SID *sids;
 623         size_t i, num;
 624         bool found = False;
 625         char *member_string;
 626         char *key;
 627         fstring sid_string;
 628 
 629         if (db->transaction_start(db) != 0) {
 630                 DEBUG(0, ("transaction_start failed\n"));
 631                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 632         }
 633 
 634         status = alias_memberships(member, 1, &sids, &num);
 635 
 636         if (!NT_STATUS_IS_OK(status)) {
 637                 goto cancel;
 638         }
 639 
 640         for (i=0; i<num; i++) {
 641                 if (sid_compare(&sids[i], alias) == 0) {
 642                         found = True;
 643                         break;
 644                 }
 645         }
 646 
 647         if (!found) {
 648                 TALLOC_FREE(sids);
 649                 status = NT_STATUS_MEMBER_NOT_IN_ALIAS;
 650                 goto cancel;
 651         }
 652 
 653         if (i < num)
 654                 sids[i] = sids[num-1];
 655 
 656         num -= 1;
 657 
 658         sid_to_fstring(sid_string, member);
 659 
 660         key = talloc_asprintf(sids, "%s%s", MEMBEROF_PREFIX, sid_string);
 661         if (key == NULL) {
 662                 TALLOC_FREE(sids);
 663                 status = NT_STATUS_NO_MEMORY;
 664                 goto cancel;
 665         }
 666 
 667         if (num == 0) {
 668                 status = dbwrap_delete_bystring(db, key);
 669                 goto commit;
 670         }
 671 
 672         member_string = talloc_strdup(sids, "");
 673         if (member_string == NULL) {
 674                 TALLOC_FREE(sids);
 675                 status = NT_STATUS_NO_MEMORY;
 676                 goto cancel;
 677         }
 678 
 679         for (i=0; i<num; i++) {
 680 
 681                 sid_to_fstring(sid_string, &sids[i]);
 682 
 683                 member_string = talloc_asprintf_append_buffer(
 684                         member_string, " %s", sid_string);
 685 
 686                 if (member_string == NULL) {
 687                         TALLOC_FREE(sids);
 688                         status = NT_STATUS_NO_MEMORY;
 689                         goto cancel;
 690                 }
 691         }
 692 
 693         status = dbwrap_store_bystring(
 694                 db, key, string_term_tdb_data(member_string), 0);
 695  commit:
 696         TALLOC_FREE(sids);
 697 
 698         if (!NT_STATUS_IS_OK(status)) {
 699                 DEBUG(10, ("dbwrap_store_bystring failed: %s\n",
 700                            nt_errstr(status)));
 701                 goto cancel;
 702         }
 703 
 704         if (db->transaction_commit(db) != 0) {
 705                 DEBUG(0, ("transaction_commit failed\n"));
 706                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 707                 return status;
 708         }
 709 
 710         return NT_STATUS_OK;
 711 
 712  cancel:
 713         if (db->transaction_cancel(db) != 0) {
 714                 smb_panic("transaction_cancel failed");
 715         }
 716         return status;
 717 }
 718 
 719 static const struct mapping_backend tdb_backend = {
 720         .add_mapping_entry         = add_mapping_entry,
 721         .get_group_map_from_sid    = get_group_map_from_sid,
 722         .get_group_map_from_gid    = get_group_map_from_gid,
 723         .get_group_map_from_ntname = get_group_map_from_ntname,
 724         .group_map_remove          = group_map_remove,
 725         .enum_group_mapping        = enum_group_mapping,
 726         .one_alias_membership      = one_alias_membership,
 727         .add_aliasmem              = add_aliasmem,
 728         .del_aliasmem              = del_aliasmem,
 729         .enum_aliasmem             = enum_aliasmem      
 730 };
 731 
 732 /*
 733   initialise the tdb mapping backend
 734  */
 735 const struct mapping_backend *groupdb_tdb_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 736 {
 737         if (!init_group_mapping()) {
 738                 DEBUG(0,("Failed to initialise tdb mapping backend\n"));
 739                 return NULL;
 740         }
 741 
 742         return &tdb_backend;
 743 }

/* [<][>][^][v][top][bottom][index][help] */