LCOV - code coverage report
Current view: top level - source3/groupdb - mapping_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 264 576 45.8 %
Date: 2024-04-21 15:09:00 Functions: 19 22 86.4 %

          Line data    Source code
       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 "system/filesys.h"
      25             : #include "passdb.h"
      26             : #include "groupdb/mapping.h"
      27             : #include "dbwrap/dbwrap.h"
      28             : #include "dbwrap/dbwrap_open.h"
      29             : #include "util_tdb.h"
      30             : #include "../libcli/security/security.h"
      31             : #include "groupdb/mapping_tdb.h"
      32             : #include "lib/util/smb_strtox.h"
      33             : 
      34             : static struct db_context *db; /* used for driver files */
      35             : 
      36             : static bool enum_group_mapping(const struct dom_sid *domsid,
      37             :                                enum lsa_SidType sid_name_use,
      38             :                                GROUP_MAP ***pp_rmap,
      39             :                                size_t *p_num_entries,
      40             :                                bool unix_only);
      41             : static bool group_map_remove(const struct dom_sid *sid);
      42             : 
      43             : static bool mapping_switch(const char *ldb_path);
      44             : 
      45             : /****************************************************************************
      46             :  Open the group mapping tdb.
      47             : ****************************************************************************/
      48        1526 : static bool init_group_mapping(void)
      49             : {
      50           5 :         char *tdb_path;
      51           5 :         char *ldb_path;
      52             : 
      53        1526 :         if (db != NULL) {
      54           0 :                 return true;
      55             :         }
      56             : 
      57        1526 :         tdb_path = state_path(talloc_tos(), "group_mapping.tdb");
      58        1526 :         if (tdb_path == NULL) {
      59           0 :                 return false;
      60             :         }
      61        1526 :         db = db_open(NULL, tdb_path, 0,
      62             :                      TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
      63             :                      DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
      64        1526 :         if (db == NULL) {
      65           0 :                 DEBUG(0, ("Failed to open group mapping database: %s\n",
      66             :                           strerror(errno)));
      67           0 :                 talloc_free(tdb_path);
      68           0 :                 return false;
      69             :         }
      70             : 
      71        1526 :         ldb_path = state_path(talloc_tos(), "group_mapping.ldb");
      72        1526 :         if (ldb_path == NULL) {
      73           0 :                 talloc_free(tdb_path);
      74           0 :                 return false;
      75             :         }
      76        1526 :         if (file_exist(ldb_path) && !mapping_switch(ldb_path)) {
      77           0 :                 unlink(tdb_path);
      78           0 :                 talloc_free(tdb_path);
      79           0 :                 talloc_free(ldb_path);
      80           0 :                 return false;
      81             : 
      82             :         } else {
      83             :                 /* handle upgrade from old versions of the database */
      84             : #if 0 /* -- Needs conversion to dbwrap -- */
      85             :                 const char *vstring = "INFO/version";
      86             :                 int32 vers_id;
      87             :                 GROUP_MAP *map_table = NULL;
      88             :                 size_t num_entries = 0;
      89             : 
      90             :                 /* handle a Samba upgrade */
      91             :                 tdb_lock_bystring(tdb, vstring);
      92             : 
      93             :                 /* Cope with byte-reversed older versions of the db. */
      94             :                 vers_id = tdb_fetch_int32(tdb, vstring);
      95             :                 if ((vers_id == DATABASE_VERSION_V1)
      96             :                     || (IREV(vers_id) == DATABASE_VERSION_V1)) {
      97             :                         /*
      98             :                          * Written on a bigendian machine with old fetch_int
      99             :                          * code. Save as le.
     100             :                          */
     101             :                         tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
     102             :                         vers_id = DATABASE_VERSION_V2;
     103             :                 }
     104             : 
     105             :                 /* if its an unknown version we remove everything in the db */
     106             : 
     107             :                 if (vers_id != DATABASE_VERSION_V2) {
     108             :                         tdb_wipe_all(tdb);
     109             :                         tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
     110             :                 }
     111             : 
     112             :                 tdb_unlock_bystring(tdb, vstring);
     113             : 
     114             :                 /* cleanup any map entries with a gid == -1 */
     115             : 
     116             :                 if ( enum_group_mapping( NULL, SID_NAME_UNKNOWN, &map_table,
     117             :                                          &num_entries, False ) ) {
     118             :                         int i;
     119             : 
     120             :                         for ( i=0; i<num_entries; i++ ) {
     121             :                                 if ( map_table[i].gid == -1 ) {
     122             :                                         group_map_remove( &map_table[i].sid );
     123             :                                 }
     124             :                         }
     125             : 
     126             :                         SAFE_FREE( map_table );
     127             :                 }
     128             : #endif
     129           5 :         }
     130        1526 :         talloc_free(tdb_path);
     131        1526 :         talloc_free(ldb_path);
     132        1526 :         return true;
     133             : }
     134             : 
     135      104048 : static char *group_mapping_key(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
     136             : {
     137          37 :         struct dom_sid_buf sidstr;
     138             : 
     139      104048 :         return talloc_asprintf(
     140             :                 mem_ctx, "%s%s", GROUP_PREFIX, dom_sid_str_buf(sid, &sidstr));
     141             : }
     142             : 
     143             : /****************************************************************************
     144             : ****************************************************************************/
     145         800 : static bool add_mapping_entry(GROUP_MAP *map, int flag)
     146             : {
     147           0 :         char *key, *buf;
     148           0 :         int len;
     149           0 :         NTSTATUS status;
     150             : 
     151         800 :         key = group_mapping_key(talloc_tos(), &map->sid);
     152         800 :         if (key == NULL) {
     153           0 :                 return false;
     154             :         }
     155             : 
     156        1600 :         len = tdb_pack(NULL, 0, "ddff",
     157         800 :                 map->gid, map->sid_name_use, map->nt_name, map->comment);
     158             : 
     159         800 :         buf = talloc_array(key, char, len);
     160         800 :         if (!buf) {
     161           0 :                 TALLOC_FREE(key);
     162           0 :                 return false;
     163             :         }
     164        1600 :         len = tdb_pack((uint8_t *)buf, len, "ddff", map->gid,
     165         800 :                        map->sid_name_use, map->nt_name, map->comment);
     166             : 
     167         800 :         status = dbwrap_trans_store(
     168             :                 db, string_term_tdb_data(key),
     169             :                 make_tdb_data((uint8_t *)buf, len), TDB_REPLACE);
     170             : 
     171         800 :         TALLOC_FREE(key);
     172             : 
     173         800 :         return NT_STATUS_IS_OK(status);
     174             : }
     175             : 
     176             : 
     177             : /****************************************************************************
     178             :  Return the sid and the type of the unix group.
     179             : ****************************************************************************/
     180             : 
     181      103230 : static bool get_group_map_from_sid(struct dom_sid sid, GROUP_MAP *map)
     182             : {
     183          37 :         TDB_DATA dbuf;
     184          37 :         char *key;
     185      103230 :         int ret = 0;
     186          37 :         NTSTATUS status;
     187          37 :         fstring nt_name;
     188          37 :         fstring comment;
     189             : 
     190             :         /* the key is the SID, retrieving is direct */
     191             : 
     192      103230 :         key = group_mapping_key(talloc_tos(), &sid);
     193      103230 :         if (key == NULL) {
     194           0 :                 return false;
     195             :         }
     196             : 
     197      103230 :         status = dbwrap_fetch_bystring(db, key, key, &dbuf);
     198      103230 :         if (!NT_STATUS_IS_OK(status)) {
     199       70889 :                 TALLOC_FREE(key);
     200       70889 :                 return false;
     201             :         }
     202             : 
     203       32341 :         ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddff",
     204             :                         &map->gid, &map->sid_name_use,
     205             :                         &nt_name, &comment);
     206             : 
     207       32341 :         TALLOC_FREE(key);
     208             : 
     209       32341 :         if ( ret == -1 ) {
     210           0 :                 DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
     211           0 :                 return false;
     212             :         }
     213             : 
     214       32341 :         sid_copy(&map->sid, &sid);
     215             : 
     216       32341 :         map->nt_name = talloc_strdup(map, nt_name);
     217       32341 :         if (!map->nt_name) {
     218           0 :                 return false;
     219             :         }
     220       32341 :         map->comment = talloc_strdup(map, comment);
     221       32341 :         if (!map->comment) {
     222           0 :                 return false;
     223             :         }
     224             : 
     225       32308 :         return true;
     226             : }
     227             : 
     228     3417728 : static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map)
     229             : {
     230     3417728 :         TDB_DATA key = dbwrap_record_get_key(rec);
     231     3417728 :         TDB_DATA value = dbwrap_record_get_value(rec);
     232     3417728 :         int ret = 0;
     233         182 :         fstring nt_name;
     234         182 :         fstring comment;
     235             : 
     236     3417728 :         if ((key.dsize < strlen(GROUP_PREFIX))
     237     3417728 :             || (strncmp((char *)key.dptr, GROUP_PREFIX,
     238             :                         GROUP_PREFIX_LEN) != 0)) {
     239       94173 :                 return False;
     240             :         }
     241             : 
     242     3323542 :         if (!string_to_sid(&map->sid, (const char *)key.dptr
     243             :                            + GROUP_PREFIX_LEN)) {
     244           0 :                 return False;
     245             :         }
     246             : 
     247     3323542 :         ret = tdb_unpack(value.dptr, value.dsize, "ddff",
     248             :                           &map->gid, &map->sid_name_use,
     249             :                           &nt_name, &comment);
     250             : 
     251     3323542 :         if (ret == -1) {
     252           0 :                 DEBUG(3, ("dbrec2map: tdb_unpack failure\n"));
     253           0 :                 return false;
     254             :         }
     255             : 
     256     3323542 :         map->nt_name = talloc_strdup(map, nt_name);
     257     3323542 :         if (!map->nt_name) {
     258           0 :                 return false;
     259             :         }
     260     3323542 :         map->comment = talloc_strdup(map, comment);
     261     3323542 :         if (!map->comment) {
     262           0 :                 return false;
     263             :         }
     264             : 
     265     3323373 :         return true;
     266             : }
     267             : 
     268             : struct find_map_state {
     269             :         bool found;
     270             :         const char *name;       /* If != NULL, look for name */
     271             :         gid_t gid;              /* valid iff name == NULL */
     272             :         GROUP_MAP *map;
     273             : };
     274             : 
     275     3414402 : static int find_map(struct db_record *rec, void *private_data)
     276             : {
     277     3414402 :         struct find_map_state *state = (struct find_map_state *)private_data;
     278             : 
     279     3414402 :         if (!dbrec2map(rec, state->map)) {
     280       94096 :                 DEBUG(10, ("failed to unpack map\n"));
     281       94096 :                 return 0;
     282             :         }
     283             : 
     284     3320306 :         if (state->name != NULL) {
     285      222804 :                 if (strequal(state->name, state->map->nt_name)) {
     286          64 :                         state->found = true;
     287          64 :                         return 1;
     288             :                 }
     289             :         }
     290             :         else {
     291     3097502 :                 if (state->map->gid == state->gid) {
     292          14 :                         state->found = true;
     293          14 :                         return 1;
     294             :                 }
     295             :         }
     296             : 
     297     3320163 :         return 0;
     298             : }
     299             : 
     300             : /****************************************************************************
     301             :  Return the sid and the type of the unix group.
     302             : ****************************************************************************/
     303             : 
     304      220335 : static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
     305             : {
     306           5 :         struct find_map_state state;
     307             : 
     308      220335 :         state.found = false;
     309      220335 :         state.name = NULL;      /* Indicate we're looking for gid */
     310      220335 :         state.gid = gid;
     311      220335 :         state.map = map;
     312             : 
     313      220335 :         dbwrap_traverse_read(db, find_map, (void *)&state, NULL);
     314             : 
     315      220335 :         return state.found;
     316             : }
     317             : 
     318             : /****************************************************************************
     319             :  Return the sid and the type of the unix group.
     320             : ****************************************************************************/
     321             : 
     322        2156 : static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
     323             : {
     324           0 :         struct find_map_state state;
     325             : 
     326        2156 :         state.found = false;
     327        2156 :         state.name = name;
     328        2156 :         state.map = map;
     329             : 
     330        2156 :         dbwrap_traverse_read(db, find_map, (void *)&state, NULL);
     331             : 
     332        2156 :         return state.found;
     333             : }
     334             : 
     335             : /****************************************************************************
     336             :  Remove a group mapping entry.
     337             : ****************************************************************************/
     338             : 
     339          18 : static bool group_map_remove(const struct dom_sid *sid)
     340             : {
     341           0 :         char *key;
     342           0 :         NTSTATUS status;
     343             : 
     344          18 :         key = group_mapping_key(talloc_tos(), sid);
     345          18 :         if (key == NULL) {
     346           0 :                 return false;
     347             :         }
     348             : 
     349          18 :         status = dbwrap_trans_delete(db, string_term_tdb_data(key));
     350             : 
     351          18 :         TALLOC_FREE(key);
     352          18 :         return NT_STATUS_IS_OK(status);
     353             : }
     354             : 
     355             : /****************************************************************************
     356             :  Enumerate the group mapping.
     357             : ****************************************************************************/
     358             : 
     359             : struct enum_map_state {
     360             :         const struct dom_sid *domsid;
     361             :         enum lsa_SidType sid_name_use;
     362             :         bool unix_only;
     363             : 
     364             :         size_t num_maps;
     365             :         GROUP_MAP **maps;
     366             : };
     367             : 
     368        3326 : static int collect_map(struct db_record *rec, void *private_data)
     369             : {
     370        3326 :         struct enum_map_state *state = (struct enum_map_state *)private_data;
     371         112 :         GROUP_MAP *map;
     372         112 :         GROUP_MAP **tmp;
     373             : 
     374        3326 :         map = talloc_zero(NULL, GROUP_MAP);
     375        3326 :         if (!map) {
     376           0 :                 DEBUG(0, ("Unable to allocate group map!\n"));
     377           0 :                 return 1;
     378             :         }
     379             : 
     380        3326 :         if (!dbrec2map(rec, map)) {
     381          90 :                 TALLOC_FREE(map);
     382          90 :                 return 0;
     383             :         }
     384             :         /* list only the type or everything if UNKNOWN */
     385        3236 :         if (state->sid_name_use != SID_NAME_UNKNOWN
     386        3158 :             && state->sid_name_use != map->sid_name_use) {
     387        1296 :                 DEBUG(11,("enum_group_mapping: group %s is not of the "
     388             :                           "requested type\n", map->nt_name));
     389        1296 :                 TALLOC_FREE(map);
     390        1296 :                 return 0;
     391             :         }
     392             : 
     393        1940 :         if ((state->unix_only == ENUM_ONLY_MAPPED) && (map->gid == -1)) {
     394           0 :                 DEBUG(11,("enum_group_mapping: group %s is non mapped\n",
     395             :                           map->nt_name));
     396           0 :                 TALLOC_FREE(map);
     397           0 :                 return 0;
     398             :         }
     399             : 
     400        3800 :         if ((state->domsid != NULL) &&
     401        1860 :             (dom_sid_compare_domain(state->domsid, &map->sid) != 0)) {
     402           0 :                 struct dom_sid_buf buf;
     403         624 :                 DEBUG(11,("enum_group_mapping: group %s is not in domain\n",
     404             :                           dom_sid_str_buf(&map->sid, &buf)));
     405         624 :                 TALLOC_FREE(map);
     406         624 :                 return 0;
     407             :         }
     408             : 
     409        1316 :         tmp = talloc_realloc(NULL, state->maps, GROUP_MAP *,
     410             :                                         state->num_maps + 1);
     411        1316 :         if (!tmp) {
     412           0 :                 DEBUG(0,("enum_group_mapping: Unable to enlarge group "
     413             :                          "map!\n"));
     414           0 :                 TALLOC_FREE(map);
     415           0 :                 return 1;
     416             :         }
     417             : 
     418        1316 :         state->maps = tmp;
     419        1316 :         state->maps[state->num_maps] = talloc_move(state->maps, &map);
     420        1316 :         state->num_maps++;
     421        1316 :         return 0;
     422             : }
     423             : 
     424          30 : static bool enum_group_mapping(const struct dom_sid *domsid,
     425             :                                enum lsa_SidType sid_name_use,
     426             :                                GROUP_MAP ***pp_rmap,
     427             :                                size_t *p_num_entries, bool unix_only)
     428             : {
     429           8 :         struct enum_map_state state;
     430           8 :         NTSTATUS status;
     431             : 
     432          30 :         state.domsid = domsid;
     433          30 :         state.sid_name_use = sid_name_use;
     434          30 :         state.unix_only = unix_only;
     435          30 :         state.num_maps = 0;
     436          30 :         state.maps = NULL;
     437             : 
     438          30 :         status = dbwrap_traverse_read(db, collect_map, (void *)&state, NULL);
     439          30 :         if (!NT_STATUS_IS_OK(status)) {
     440           0 :                 TALLOC_FREE(state.maps);
     441           0 :                 return false;
     442             :         }
     443             : 
     444          30 :         *pp_rmap = state.maps;
     445          30 :         *p_num_entries = state.num_maps;
     446             : 
     447          30 :         return true;
     448             : }
     449             : 
     450             : /* This operation happens on session setup, so it should better be fast. We
     451             :  * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
     452             : 
     453      318244 : static NTSTATUS one_alias_membership(const struct dom_sid *member,
     454             :                                struct dom_sid **sids, size_t *num)
     455             : {
     456           0 :         struct dom_sid_buf tmp;
     457           0 :         fstring key;
     458           0 :         char *string_sid;
     459           0 :         TDB_DATA dbuf;
     460           0 :         const char *p;
     461           0 :         NTSTATUS status;
     462      318244 :         TALLOC_CTX *frame = talloc_stackframe();
     463             : 
     464      318244 :         slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX,
     465             :                  dom_sid_str_buf(member, &tmp));
     466             : 
     467      318244 :         status = dbwrap_fetch_bystring(db, frame, key, &dbuf);
     468      318244 :         if (!NT_STATUS_IS_OK(status)) {
     469      304655 :                 TALLOC_FREE(frame);
     470      304655 :                 return NT_STATUS_OK;
     471             :         }
     472             : 
     473       13589 :         p = (const char *)dbuf.dptr;
     474             : 
     475       27178 :         while (next_token_talloc(frame, &p, &string_sid, " ")) {
     476           0 :                 struct dom_sid alias;
     477           0 :                 uint32_t num_sids;
     478             : 
     479       13589 :                 if (!string_to_sid(&alias, string_sid))
     480           0 :                         continue;
     481             : 
     482       13589 :                 num_sids = *num;
     483       13589 :                 status= add_sid_to_array_unique(NULL, &alias, sids, &num_sids);
     484       13589 :                 if (!NT_STATUS_IS_OK(status)) {
     485           0 :                         goto done;
     486             :                 }
     487       13589 :                 *num = num_sids;
     488             :         }
     489             : 
     490       13589 : done:
     491       13589 :         TALLOC_FREE(frame);
     492       13589 :         return status;
     493             : }
     494             : 
     495          94 : static NTSTATUS alias_memberships(const struct dom_sid *members, size_t num_members,
     496             :                                   struct dom_sid **sids, size_t *num)
     497             : {
     498           0 :         size_t i;
     499             : 
     500          94 :         *num = 0;
     501          94 :         *sids = NULL;
     502             : 
     503         188 :         for (i=0; i<num_members; i++) {
     504          94 :                 NTSTATUS status = one_alias_membership(&members[i], sids, num);
     505          94 :                 if (!NT_STATUS_IS_OK(status))
     506           0 :                         return status;
     507             :         }
     508          94 :         return NT_STATUS_OK;
     509             : }
     510             : 
     511          74 : static bool is_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
     512             : {
     513           0 :         struct dom_sid *sids;
     514           0 :         size_t i;
     515           0 :         size_t num;
     516             : 
     517             :         /* This feels the wrong way round, but the on-disk data structure
     518             :          * dictates it this way. */
     519          74 :         if (!NT_STATUS_IS_OK(alias_memberships(member, 1, &sids, &num)))
     520           0 :                 return False;
     521             : 
     522          74 :         for (i=0; i<num; i++) {
     523          15 :                 if (dom_sid_compare(alias, &sids[i]) == 0) {
     524          15 :                         TALLOC_FREE(sids);
     525          15 :                         return True;
     526             :                 }
     527             :         }
     528          59 :         TALLOC_FREE(sids);
     529          59 :         return False;
     530             : }
     531             : 
     532             : 
     533          74 : static NTSTATUS add_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
     534             : {
     535           0 :         GROUP_MAP *map;
     536           0 :         char *key;
     537           0 :         struct dom_sid_buf string_sid;
     538           0 :         char *new_memberstring;
     539           0 :         struct db_record *rec;
     540           0 :         NTSTATUS status;
     541           0 :         TDB_DATA value;
     542             : 
     543          74 :         map = talloc_zero(talloc_tos(), GROUP_MAP);
     544          74 :         if (!map) {
     545           0 :                 return NT_STATUS_NO_MEMORY;
     546             :         }
     547             : 
     548          74 :         if (!get_group_map_from_sid(*alias, map)) {
     549           0 :                 TALLOC_FREE(map);
     550           0 :                 return NT_STATUS_NO_SUCH_ALIAS;
     551             :         }
     552             : 
     553          74 :         if ((map->sid_name_use != SID_NAME_ALIAS) &&
     554           2 :             (map->sid_name_use != SID_NAME_WKN_GRP)) {
     555           0 :                 TALLOC_FREE(map);
     556           0 :                 return NT_STATUS_NO_SUCH_ALIAS;
     557             :         }
     558             : 
     559          74 :         TALLOC_FREE(map);
     560             : 
     561          74 :         if (is_aliasmem(alias, member))
     562          15 :                 return NT_STATUS_MEMBER_IN_ALIAS;
     563             : 
     564          59 :         key = talloc_asprintf(talloc_tos(), "%s%s", MEMBEROF_PREFIX,
     565             :                               dom_sid_str_buf(member, &string_sid));
     566          59 :         if (key == NULL) {
     567           0 :                 return NT_STATUS_NO_MEMORY;
     568             :         }
     569             : 
     570          59 :         if (dbwrap_transaction_start(db) != 0) {
     571           0 :                 DEBUG(0, ("transaction_start failed\n"));
     572           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     573             :         }
     574             : 
     575          59 :         rec = dbwrap_fetch_locked(db, key, string_term_tdb_data(key));
     576             : 
     577          59 :         if (rec == NULL) {
     578           0 :                 DEBUG(10, ("fetch_lock failed\n"));
     579           0 :                 TALLOC_FREE(key);
     580           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     581           0 :                 goto cancel;
     582             :         }
     583             : 
     584          59 :         value = dbwrap_record_get_value(rec);
     585             : 
     586          59 :         dom_sid_str_buf(alias, &string_sid);
     587             : 
     588          59 :         if (value.dptr != NULL) {
     589           0 :                 new_memberstring = talloc_asprintf(
     590           0 :                         key, "%s %s", (char *)(value.dptr), string_sid.buf);
     591             :         } else {
     592          59 :                 new_memberstring = talloc_strdup(key, string_sid.buf);
     593             :         }
     594             : 
     595          59 :         if (new_memberstring == NULL) {
     596           0 :                 TALLOC_FREE(key);
     597           0 :                 status = NT_STATUS_NO_MEMORY;
     598           0 :                 goto cancel;
     599             :         }
     600             : 
     601          59 :         status = dbwrap_record_store(rec, string_term_tdb_data(new_memberstring), 0);
     602             : 
     603          59 :         TALLOC_FREE(key);
     604             : 
     605          59 :         if (!NT_STATUS_IS_OK(status)) {
     606           0 :                 DEBUG(10, ("Could not store record: %s\n", nt_errstr(status)));
     607           0 :                 goto cancel;
     608             :         }
     609             : 
     610          59 :         if (dbwrap_transaction_commit(db) != 0) {
     611           0 :                 DEBUG(0, ("transaction_commit failed\n"));
     612           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     613           0 :                 return status;
     614             :         }
     615             : 
     616          59 :         return NT_STATUS_OK;
     617             : 
     618           0 :  cancel:
     619           0 :         if (dbwrap_transaction_cancel(db) != 0) {
     620           0 :                 smb_panic("transaction_cancel failed");
     621             :         }
     622             : 
     623           0 :         return status;
     624             : }
     625             : 
     626             : struct aliasmem_state {
     627             :         TALLOC_CTX *mem_ctx;
     628             :         const struct dom_sid *alias;
     629             :         struct dom_sid **sids;
     630             :         size_t *num;
     631             : };
     632             : 
     633         520 : static int collect_aliasmem(struct db_record *rec, void *priv)
     634             : {
     635         520 :         struct aliasmem_state *state = (struct aliasmem_state *)priv;
     636         420 :         const char *p;
     637         420 :         char *alias_string;
     638         420 :         TALLOC_CTX *frame;
     639         520 :         TDB_DATA key = dbwrap_record_get_key(rec);
     640         520 :         TDB_DATA value = dbwrap_record_get_value(rec);
     641             : 
     642         520 :         if (strncmp((const char *)key.dptr, MEMBEROF_PREFIX,
     643             :                     MEMBEROF_PREFIX_LEN) != 0)
     644          52 :                 return 0;
     645             : 
     646          48 :         p = (const char *)value.dptr;
     647             : 
     648          48 :         frame = talloc_stackframe();
     649             : 
     650          96 :         while (next_token_talloc(frame, &p, &alias_string, " ")) {
     651           0 :                 struct dom_sid alias, member;
     652           0 :                 const char *member_string;
     653           0 :                 uint32_t num_sids;
     654             : 
     655          48 :                 if (!string_to_sid(&alias, alias_string))
     656          22 :                         continue;
     657             : 
     658          48 :                 if (dom_sid_compare(state->alias, &alias) != 0)
     659          22 :                         continue;
     660             : 
     661             :                 /* Ok, we found the alias we're looking for in the membership
     662             :                  * list currently scanned. The key represents the alias
     663             :                  * member. Add that. */
     664             : 
     665          26 :                 member_string = strchr((const char *)key.dptr, '/');
     666             : 
     667             :                 /* Above we tested for MEMBEROF_PREFIX which includes the
     668             :                  * slash. */
     669             : 
     670          26 :                 SMB_ASSERT(member_string != NULL);
     671          26 :                 member_string += 1;
     672             : 
     673          26 :                 if (!string_to_sid(&member, member_string))
     674           0 :                         continue;
     675             : 
     676          26 :                 num_sids = *state->num;
     677          26 :                 if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx, &member,
     678             :                                                       state->sids,
     679             :                                                       &num_sids)))
     680             :                 {
     681             :                         /* talloc fail. */
     682           0 :                         break;
     683             :                 }
     684          26 :                 *state->num = num_sids;
     685             :         }
     686             : 
     687          48 :         TALLOC_FREE(frame);
     688          48 :         return 0;
     689             : }
     690             : 
     691          38 : static NTSTATUS enum_aliasmem(const struct dom_sid *alias, TALLOC_CTX *mem_ctx,
     692             :                               struct dom_sid **sids, size_t *num)
     693             : {
     694          30 :         GROUP_MAP *map;
     695          30 :         struct aliasmem_state state;
     696             : 
     697          38 :         map = talloc_zero(talloc_tos(), GROUP_MAP);
     698          38 :         if (!map) {
     699           0 :                 return NT_STATUS_NO_MEMORY;
     700             :         }
     701             : 
     702          38 :         if (!get_group_map_from_sid(*alias, map)) {
     703           0 :                 TALLOC_FREE(map);
     704           0 :                 return NT_STATUS_NO_SUCH_ALIAS;
     705             :         }
     706             : 
     707          38 :         if ((map->sid_name_use != SID_NAME_ALIAS) &&
     708           0 :             (map->sid_name_use != SID_NAME_WKN_GRP)) {
     709           0 :                 TALLOC_FREE(map);
     710           0 :                 return NT_STATUS_NO_SUCH_ALIAS;
     711             :         }
     712             : 
     713          38 :         TALLOC_FREE(map);
     714             : 
     715          38 :         *sids = NULL;
     716          38 :         *num = 0;
     717             : 
     718          38 :         state.alias = alias;
     719          38 :         state.sids = sids;
     720          38 :         state.num = num;
     721          38 :         state.mem_ctx = mem_ctx;
     722             : 
     723          38 :         dbwrap_traverse_read(db, collect_aliasmem, &state, NULL);
     724          38 :         return NT_STATUS_OK;
     725             : }
     726             : 
     727          20 : static NTSTATUS del_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
     728             : {
     729           0 :         NTSTATUS status;
     730           0 :         struct dom_sid *sids;
     731           0 :         size_t i, num;
     732          20 :         bool found = False;
     733           0 :         char *member_string;
     734           0 :         char *key;
     735           0 :         struct dom_sid_buf sid_string;
     736             : 
     737          20 :         if (dbwrap_transaction_start(db) != 0) {
     738           0 :                 DEBUG(0, ("transaction_start failed\n"));
     739           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     740             :         }
     741             : 
     742          20 :         status = alias_memberships(member, 1, &sids, &num);
     743             : 
     744          20 :         if (!NT_STATUS_IS_OK(status)) {
     745           0 :                 goto cancel;
     746             :         }
     747             : 
     748          20 :         for (i=0; i<num; i++) {
     749          20 :                 if (dom_sid_compare(&sids[i], alias) == 0) {
     750          20 :                         found = True;
     751          20 :                         break;
     752             :                 }
     753             :         }
     754             : 
     755          20 :         if (!found) {
     756           0 :                 TALLOC_FREE(sids);
     757           0 :                 status = NT_STATUS_MEMBER_NOT_IN_ALIAS;
     758           0 :                 goto cancel;
     759             :         }
     760             : 
     761          20 :         if (i < num)
     762          20 :                 sids[i] = sids[num-1];
     763             : 
     764          20 :         num -= 1;
     765             : 
     766          20 :         key = talloc_asprintf(
     767             :                 sids,
     768             :                 "%s%s",
     769             :                 MEMBEROF_PREFIX,
     770             :                 dom_sid_str_buf(member, &sid_string));
     771          20 :         if (key == NULL) {
     772           0 :                 TALLOC_FREE(sids);
     773           0 :                 status = NT_STATUS_NO_MEMORY;
     774           0 :                 goto cancel;
     775             :         }
     776             : 
     777          20 :         if (num == 0) {
     778          20 :                 status = dbwrap_delete_bystring(db, key);
     779          20 :                 goto commit;
     780             :         }
     781             : 
     782           0 :         member_string = talloc_strdup(sids, "");
     783           0 :         if (member_string == NULL) {
     784           0 :                 TALLOC_FREE(sids);
     785           0 :                 status = NT_STATUS_NO_MEMORY;
     786           0 :                 goto cancel;
     787             :         }
     788             : 
     789           0 :         for (i=0; i<num; i++) {
     790             : 
     791           0 :                 member_string = talloc_asprintf_append_buffer(
     792             :                         member_string,
     793             :                         " %s",
     794           0 :                         dom_sid_str_buf(&sids[i], &sid_string));
     795             : 
     796           0 :                 if (member_string == NULL) {
     797           0 :                         TALLOC_FREE(sids);
     798           0 :                         status = NT_STATUS_NO_MEMORY;
     799           0 :                         goto cancel;
     800             :                 }
     801             :         }
     802             : 
     803           0 :         status = dbwrap_store_bystring(
     804             :                 db, key, string_term_tdb_data(member_string), 0);
     805          20 :  commit:
     806          20 :         TALLOC_FREE(sids);
     807             : 
     808          20 :         if (!NT_STATUS_IS_OK(status)) {
     809           0 :                 DEBUG(10, ("dbwrap_store_bystring failed: %s\n",
     810             :                            nt_errstr(status)));
     811           0 :                 goto cancel;
     812             :         }
     813             : 
     814          20 :         if (dbwrap_transaction_commit(db) != 0) {
     815           0 :                 DEBUG(0, ("transaction_commit failed\n"));
     816           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     817           0 :                 return status;
     818             :         }
     819             : 
     820          20 :         return NT_STATUS_OK;
     821             : 
     822           0 :  cancel:
     823           0 :         if (dbwrap_transaction_cancel(db) != 0) {
     824           0 :                 smb_panic("transaction_cancel failed");
     825             :         }
     826           0 :         return status;
     827             : }
     828             : 
     829             : 
     830             : /* -- ldb->tdb switching code -------------------------------------------- */
     831             : 
     832             : /* change this if the data format ever changes */
     833             : #define LTDB_PACKING_FORMAT 0x26011967
     834             : 
     835             : /* old packing formats (not supported for now,
     836             :  * it was never used for group mapping AFAIK) */
     837             : #define LTDB_PACKING_FORMAT_NODN 0x26011966
     838             : 
     839           0 : static unsigned int pull_uint32(uint8_t *p, int ofs)
     840             : {
     841           0 :         p += ofs;
     842           0 :         return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
     843             : }
     844             : 
     845             : /*
     846             :   unpack a ldb message from a linear buffer in TDB_DATA
     847             : */
     848           0 : static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
     849             :                               TDB_DATA data, void *ptr)
     850             : {
     851           0 :         TALLOC_CTX *tmp_ctx = talloc_tos();
     852           0 :         GROUP_MAP *map = NULL;
     853           0 :         uint8_t *p;
     854           0 :         uint32_t format;
     855           0 :         uint32_t num_el;
     856           0 :         unsigned int remaining;
     857           0 :         unsigned int i, j;
     858           0 :         size_t len;
     859           0 :         char *name;
     860           0 :         char *val;
     861           0 :         uint32_t num_mem = 0;
     862           0 :         struct dom_sid *members = NULL;
     863           0 :         int error = 0;
     864             : 
     865           0 :         p = (uint8_t *)data.dptr;
     866           0 :         if (data.dsize < 8) {
     867           0 :                 errno = EIO;
     868           0 :                 goto failed;
     869             :         }
     870             : 
     871           0 :         format = pull_uint32(p, 0);
     872           0 :         num_el = pull_uint32(p, 4);
     873           0 :         p += 8;
     874             : 
     875           0 :         remaining = data.dsize - 8;
     876             : 
     877           0 :         switch (format) {
     878           0 :         case LTDB_PACKING_FORMAT:
     879           0 :                 len = strnlen((char *)p, remaining);
     880           0 :                 if (len == remaining) {
     881           0 :                         errno = EIO;
     882           0 :                         goto failed;
     883             :                 }
     884             : 
     885           0 :                 if (*p == '@') {
     886             :                         /* ignore special LDB attributes */
     887           0 :                         return 0;
     888             :                 }
     889             : 
     890           0 :                 if (strncmp((char *)p, "rid=", 4)) {
     891             :                         /* unknown entry, ignore */
     892           0 :                         DEBUG(3, ("Found unknown entry in group mapping "
     893             :                                   "database named [%s]\n", (char *)p));
     894           0 :                         return 0;
     895             :                 }
     896             : 
     897           0 :                 remaining -= len + 1;
     898           0 :                 p += len + 1;
     899           0 :                 break;
     900             : 
     901           0 :         case LTDB_PACKING_FORMAT_NODN:
     902             :         default:
     903           0 :                 errno = EIO;
     904           0 :                 goto failed;
     905             :         }
     906             : 
     907           0 :         if (num_el == 0) {
     908             :                 /* bad entry, ignore */
     909           0 :                 return 0;
     910             :         }
     911             : 
     912           0 :         if (num_el > remaining / 6) {
     913           0 :                 errno = EIO;
     914           0 :                 goto failed;
     915             :         }
     916             : 
     917           0 :         map = talloc_zero(NULL, GROUP_MAP);
     918           0 :         if (!map) {
     919           0 :                 errno = ENOMEM;
     920           0 :                 goto failed;
     921             :         }
     922             : 
     923           0 :         for (i = 0; i < num_el; i++) {
     924           0 :                 uint32_t num_vals;
     925             : 
     926           0 :                 if (remaining < 10) {
     927           0 :                         errno = EIO;
     928           0 :                         goto failed;
     929             :                 }
     930           0 :                 len = strnlen((char *)p, remaining - 6);
     931           0 :                 if (len == remaining - 6) {
     932           0 :                         errno = EIO;
     933           0 :                         goto failed;
     934             :                 }
     935           0 :                 name = talloc_strndup(tmp_ctx, (char *)p, len);
     936           0 :                 if (name == NULL) {
     937           0 :                         errno = ENOMEM;
     938           0 :                         goto failed;
     939             :                 }
     940           0 :                 remaining -= len + 1;
     941           0 :                 p += len + 1;
     942             : 
     943           0 :                 num_vals = pull_uint32(p, 0);
     944           0 :                 if (strcasecmp_m(name, "member") == 0) {
     945           0 :                         num_mem = num_vals;
     946           0 :                         members = talloc_array(tmp_ctx, struct dom_sid, num_mem);
     947           0 :                         if (members == NULL) {
     948           0 :                                 errno = ENOMEM;
     949           0 :                                 goto failed;
     950             :                         }
     951           0 :                 } else if (num_vals != 1) {
     952           0 :                         errno = EIO;
     953           0 :                         goto failed;
     954             :                 }
     955             : 
     956           0 :                 p += 4;
     957           0 :                 remaining -= 4;
     958             : 
     959           0 :                 for (j = 0; j < num_vals; j++) {
     960           0 :                         len = pull_uint32(p, 0);
     961           0 :                         if (len > remaining-5) {
     962           0 :                                 errno = EIO;
     963           0 :                                 goto failed;
     964             :                         }
     965             : 
     966           0 :                         val = talloc_strndup(tmp_ctx, (char *)(p + 4), len);
     967           0 :                         if (val == NULL) {
     968           0 :                                 errno = ENOMEM;
     969           0 :                                 goto failed;
     970             :                         }
     971             : 
     972           0 :                         remaining -= len+4+1;
     973           0 :                         p += len+4+1;
     974             : 
     975             :                         /* we ignore unknown or uninteresting attributes
     976             :                          * (objectclass, etc.) */
     977           0 :                         if (strcasecmp_m(name, "gidNumber") == 0) {
     978           0 :                                 map->gid = smb_strtoul(val,
     979             :                                                        NULL,
     980             :                                                        10,
     981             :                                                        &error,
     982             :                                                        SMB_STR_FULL_STR_CONV);
     983           0 :                                 if (error != 0) {
     984           0 :                                         errno = EIO;
     985           0 :                                         goto failed;
     986             :                                 }
     987           0 :                         } else if (strcasecmp_m(name, "sid") == 0) {
     988           0 :                                 if (!string_to_sid(&map->sid, val)) {
     989           0 :                                         errno = EIO;
     990           0 :                                         goto failed;
     991             :                                 }
     992           0 :                         } else if (strcasecmp_m(name, "sidNameUse") == 0) {
     993           0 :                                 map->sid_name_use =
     994           0 :                                         smb_strtoul(val,
     995             :                                                     NULL,
     996             :                                                     10,
     997             :                                                     &error,
     998             :                                                     SMB_STR_FULL_STR_CONV);
     999           0 :                                 if (error != 0) {
    1000           0 :                                         errno = EIO;
    1001           0 :                                         goto failed;
    1002             :                                 }
    1003           0 :                         } else if (strcasecmp_m(name, "ntname") == 0) {
    1004           0 :                                 map->nt_name = talloc_strdup(map, val);
    1005           0 :                                 if (!map->nt_name) {
    1006           0 :                                         errno = ENOMEM;
    1007           0 :                                         goto failed;
    1008             :                                 }
    1009           0 :                         } else if (strcasecmp_m(name, "comment") == 0) {
    1010           0 :                                 map->comment = talloc_strdup(map, val);
    1011           0 :                                 if (!map->comment) {
    1012           0 :                                         errno = ENOMEM;
    1013           0 :                                         goto failed;
    1014             :                                 }
    1015           0 :                         } else if (strcasecmp_m(name, "member") == 0) {
    1016           0 :                                 if (!string_to_sid(&members[j], val)) {
    1017           0 :                                         errno = EIO;
    1018           0 :                                         goto failed;
    1019             :                                 }
    1020             :                         }
    1021             : 
    1022           0 :                         TALLOC_FREE(val);
    1023             :                 }
    1024             : 
    1025           0 :                 TALLOC_FREE(name);
    1026             :         }
    1027             : 
    1028           0 :         if (map->nt_name == NULL) {
    1029           0 :                 errno = EIO;
    1030           0 :                 goto failed;
    1031             :         }
    1032             : 
    1033           0 :         if (map->comment == NULL) {
    1034           0 :                 map->comment = talloc_strdup(map, "");
    1035             :         }
    1036           0 :         if (map->comment == NULL) {
    1037           0 :                 errno = ENOMEM;
    1038           0 :                 goto failed;
    1039             :         }
    1040             : 
    1041           0 :         if (!add_mapping_entry(map, 0)) {
    1042           0 :                 errno = EIO;
    1043           0 :                 goto failed;
    1044             :         }
    1045             : 
    1046           0 :         if (num_mem) {
    1047           0 :                 for (j = 0; j < num_mem; j++) {
    1048           0 :                         NTSTATUS status;
    1049           0 :                         status = add_aliasmem(&map->sid, &members[j]);
    1050           0 :                         if (!NT_STATUS_IS_OK(status)) {
    1051           0 :                                 errno = EIO;
    1052           0 :                                 goto failed;
    1053             :                         }
    1054             :                 }
    1055             :         }
    1056             : 
    1057           0 :         if (remaining != 0) {
    1058           0 :                 DEBUG(0, ("Error: %d bytes unread in ltdb_unpack_data\n",
    1059             :                           remaining));
    1060             :         }
    1061             : 
    1062           0 :         TALLOC_FREE(map);
    1063           0 :         return 0;
    1064             : 
    1065           0 : failed:
    1066           0 :         TALLOC_FREE(map);
    1067           0 :         return -1;
    1068             : }
    1069             : 
    1070           0 : static bool mapping_switch(const char *ldb_path)
    1071             : {
    1072           0 :         TDB_CONTEXT *ltdb;
    1073           0 :         TALLOC_CTX *frame;
    1074           0 :         char *new_path;
    1075           0 :         int ret;
    1076             : 
    1077           0 :         frame = talloc_stackframe();
    1078             : 
    1079           0 :         ltdb = tdb_open_log(ldb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
    1080           0 :         if (ltdb == NULL) goto failed;
    1081             : 
    1082             :         /* ldb is just a very fancy tdb, read out raw data and perform
    1083             :          * conversion */
    1084           0 :         ret = tdb_traverse(ltdb, convert_ldb_record, NULL);
    1085           0 :         if (ret < 0) goto failed;
    1086             : 
    1087           0 :         if (ltdb) {
    1088           0 :                 tdb_close(ltdb);
    1089           0 :                 ltdb = NULL;
    1090             :         }
    1091             : 
    1092             :         /* now rename the old db out of the way */
    1093           0 :         new_path = state_path(talloc_tos(), "group_mapping.ldb.replaced");
    1094           0 :         if (!new_path) {
    1095           0 :                 goto failed;
    1096             :         }
    1097           0 :         if (rename(ldb_path, new_path) != 0) {
    1098           0 :                 DEBUG(0,("Failed to rename old group mapping database\n"));
    1099           0 :                 goto failed;
    1100             :         }
    1101           0 :         TALLOC_FREE(frame);
    1102           0 :         return True;
    1103             : 
    1104           0 : failed:
    1105           0 :         DEBUG(0, ("Failed to switch to tdb group mapping database\n"));
    1106           0 :         if (ltdb) tdb_close(ltdb);
    1107           0 :         TALLOC_FREE(frame);
    1108           0 :         return False;
    1109             : }
    1110             : 
    1111             : static const struct mapping_backend tdb_backend = {
    1112             :         .add_mapping_entry         = add_mapping_entry,
    1113             :         .get_group_map_from_sid    = get_group_map_from_sid,
    1114             :         .get_group_map_from_gid    = get_group_map_from_gid,
    1115             :         .get_group_map_from_ntname = get_group_map_from_ntname,
    1116             :         .group_map_remove          = group_map_remove,
    1117             :         .enum_group_mapping        = enum_group_mapping,
    1118             :         .one_alias_membership      = one_alias_membership,
    1119             :         .add_aliasmem              = add_aliasmem,
    1120             :         .del_aliasmem              = del_aliasmem,
    1121             :         .enum_aliasmem             = enum_aliasmem      
    1122             : };
    1123             : 
    1124             : /*
    1125             :   initialise the tdb mapping backend
    1126             :  */
    1127        1526 : const struct mapping_backend *groupdb_tdb_init(void)
    1128             : {
    1129        1526 :         if (!init_group_mapping()) {
    1130           0 :                 DEBUG(0,("Failed to initialise tdb mapping backend\n"));
    1131           0 :                 return NULL;
    1132             :         }
    1133             : 
    1134        1521 :         return &tdb_backend;
    1135             : }

Generated by: LCOV version 1.14