LCOV - code coverage report
Current view: top level - source3/libsmb - samlogon_cache.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 96 186 51.6 %
Date: 2024-02-28 12:06:22 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Net_sam_logon info3 helpers
       4             :    Copyright (C) Alexander Bokovoy              2002.
       5             :    Copyright (C) Andrew Bartlett                2002.
       6             :    Copyright (C) Gerald Carter                  2003.
       7             :    Copyright (C) Tim Potter                     2003.
       8             :    Copyright (C) Guenther Deschner              2008.
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "replace.h"
      25             : #include "samlogon_cache.h"
      26             : #include "system/filesys.h"
      27             : #include "system/time.h"
      28             : #include "lib/util/debug.h"
      29             : #include "lib/util/talloc_stack.h"
      30             : #include "lib/util/memory.h" /* for SAFE_FREE() */
      31             : #include "source3/lib/util_path.h"
      32             : #include "librpc/gen_ndr/ndr_krb5pac.h"
      33             : #include "../libcli/security/security.h"
      34             : #include "util_tdb.h"
      35             : 
      36             : #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
      37             : 
      38             : static TDB_CONTEXT *netsamlogon_tdb = NULL;
      39             : 
      40             : /***********************************************************************
      41             :  open the tdb
      42             :  ***********************************************************************/
      43             : 
      44      102962 : bool netsamlogon_cache_init(void)
      45             : {
      46      102962 :         bool first_try = true;
      47      102962 :         char *path = NULL;
      48           0 :         int ret;
      49           0 :         struct tdb_context *tdb;
      50             : 
      51      102962 :         if (netsamlogon_tdb) {
      52      102899 :                 return true;
      53             :         }
      54             : 
      55          63 :         path = cache_path(talloc_tos(), NETSAMLOGON_TDB);
      56          63 :         if (path == NULL) {
      57           0 :                 return false;
      58             :         }
      59          63 : again:
      60          63 :         tdb = tdb_open_log(path, 0, TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
      61             :                            O_RDWR | O_CREAT, 0600);
      62          63 :         if (tdb == NULL) {
      63           0 :                 DEBUG(0,("tdb_open_log('%s') - failed\n", path));
      64           0 :                 goto clear;
      65             :         }
      66             : 
      67          63 :         ret = tdb_check(tdb, NULL, NULL);
      68          63 :         if (ret != 0) {
      69           0 :                 tdb_close(tdb);
      70           0 :                 DEBUG(0,("tdb_check('%s') - failed\n", path));
      71           0 :                 goto clear;
      72             :         }
      73             : 
      74          63 :         netsamlogon_tdb = tdb;
      75          63 :         talloc_free(path);
      76          63 :         return true;
      77             : 
      78           0 : clear:
      79           0 :         if (!first_try) {
      80           0 :                 talloc_free(path);
      81           0 :                 return false;
      82             :         }
      83           0 :         first_try = false;
      84             : 
      85           0 :         DEBUG(0,("retry after truncate for '%s'\n", path));
      86           0 :         ret = truncate(path, 0);
      87           0 :         if (ret == -1) {
      88           0 :                 DBG_ERR("truncate failed: %s\n", strerror(errno));
      89           0 :                 talloc_free(path);
      90           0 :                 return false;
      91             :         }
      92             : 
      93           0 :         goto again;
      94             : }
      95             : 
      96             : /***********************************************************************
      97             :  Clear cache getpwnam and getgroups entries from the winbindd cache
      98             : ***********************************************************************/
      99             : 
     100           4 : void netsamlogon_clear_cached_user(const struct dom_sid *user_sid)
     101             : {
     102           0 :         struct dom_sid_buf keystr;
     103             : 
     104           4 :         if (!netsamlogon_cache_init()) {
     105           0 :                 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
     106             :                         "%s for write!\n",
     107             :                         NETSAMLOGON_TDB));
     108           0 :                 return;
     109             :         }
     110             : 
     111             :         /* Prepare key as DOMAIN-SID/USER-RID string */
     112           4 :         dom_sid_str_buf(user_sid, &keystr);
     113             : 
     114           4 :         DBG_DEBUG("SID [%s]\n", keystr.buf);
     115             : 
     116           4 :         tdb_delete_bystring(netsamlogon_tdb, keystr.buf);
     117             : }
     118             : 
     119             : /***********************************************************************
     120             :  Store a netr_SamInfo3 structure in a tdb for later user
     121             :  username should be in UTF-8 format
     122             : ***********************************************************************/
     123             : 
     124         868 : bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3)
     125             : {
     126         868 :         uint8_t dummy = 0;
     127         868 :         TDB_DATA data = { .dptr = &dummy, .dsize = sizeof(dummy) };
     128           0 :         struct dom_sid_buf keystr;
     129         868 :         bool result = false;
     130           0 :         struct dom_sid  user_sid;
     131         868 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
     132           0 :         DATA_BLOB blob;
     133           0 :         enum ndr_err_code ndr_err;
     134           0 :         struct netsamlogoncache_entry r;
     135           0 :         int ret;
     136             : 
     137         868 :         if (!info3) {
     138           0 :                 goto fail;
     139             :         }
     140             : 
     141         868 :         if (!netsamlogon_cache_init()) {
     142           0 :                 D_WARNING("netsamlogon_cache_store: cannot open %s for write!\n",
     143             :                         NETSAMLOGON_TDB);
     144           0 :                 goto fail;
     145             :         }
     146             : 
     147             :         /*
     148             :          * First write a record with just the domain sid for
     149             :          * netsamlogon_cache_domain_known. Use TDB_INSERT to avoid
     150             :          * overwriting potentially other data. We're just interested
     151             :          * in the existence of that record.
     152             :          */
     153         868 :         dom_sid_str_buf(info3->base.domain_sid, &keystr);
     154             : 
     155         868 :         ret = tdb_store_bystring(netsamlogon_tdb, keystr.buf, data, TDB_INSERT);
     156             : 
     157         868 :         if ((ret == -1) && (tdb_error(netsamlogon_tdb) != TDB_ERR_EXISTS)) {
     158           0 :                 D_WARNING("Could not store domain marker for %s: %s\n",
     159             :                             keystr.buf, tdb_errorstr(netsamlogon_tdb));
     160           0 :                 goto fail;
     161             :         }
     162             : 
     163         868 :         sid_compose(&user_sid, info3->base.domain_sid, info3->base.rid);
     164             : 
     165             :         /* Prepare key as DOMAIN-SID/USER-RID string */
     166         868 :         dom_sid_str_buf(&user_sid, &keystr);
     167             : 
     168         868 :         DBG_DEBUG("SID [%s]\n", keystr.buf);
     169             : 
     170             :         /* Prepare data */
     171             : 
     172         868 :         if (info3->base.full_name.string == NULL) {
     173           0 :                 struct netr_SamInfo3 *cached_info3;
     174           0 :                 const char *full_name = NULL;
     175             : 
     176           0 :                 cached_info3 = netsamlogon_cache_get(tmp_ctx, &user_sid);
     177           0 :                 if (cached_info3 != NULL) {
     178           0 :                         full_name = cached_info3->base.full_name.string;
     179             :                 }
     180             : 
     181           0 :                 if (full_name != NULL) {
     182           0 :                         info3->base.full_name.string = talloc_strdup(info3, full_name);
     183           0 :                         if (info3->base.full_name.string == NULL) {
     184           0 :                                 goto fail;
     185             :                         }
     186             :                 }
     187             :         }
     188             : 
     189             :         /* only Samba fills in the username, not sure why NT doesn't */
     190             :         /* so we fill it in since winbindd_getpwnam() makes use of it */
     191             : 
     192         868 :         if (!info3->base.account_name.string) {
     193           0 :                 info3->base.account_name.string = talloc_strdup(info3, username);
     194           0 :                 if (info3->base.account_name.string == NULL) {
     195           0 :                         goto fail;
     196             :                 }
     197             :         }
     198             : 
     199         868 :         r.timestamp = time(NULL);
     200         868 :         r.info3 = *info3;
     201             : 
     202             :         /* avoid storing secret information */
     203         868 :         ZERO_STRUCT(r.info3.base.key);
     204         868 :         ZERO_STRUCT(r.info3.base.LMSessKey);
     205             : 
     206         868 :         if (DEBUGLEVEL >= 10) {
     207           0 :                 NDR_PRINT_DEBUG(netsamlogoncache_entry, &r);
     208             :         }
     209             : 
     210         868 :         ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, &r,
     211             :                                        (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry);
     212         868 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     213           0 :                 DBG_WARNING("failed to push entry to cache: %s\n",
     214             :                             ndr_errstr(ndr_err));
     215           0 :                 goto fail;
     216             :         }
     217             : 
     218         868 :         data.dsize = blob.length;
     219         868 :         data.dptr = blob.data;
     220             : 
     221         868 :         if (tdb_store_bystring(netsamlogon_tdb, keystr.buf, data, TDB_REPLACE) == 0) {
     222         868 :                 result = true;
     223             :         }
     224             : 
     225           0 : fail:
     226         868 :         TALLOC_FREE(tmp_ctx);
     227         868 :         return result;
     228             : }
     229             : 
     230             : /***********************************************************************
     231             :  Retrieves a netr_SamInfo3 structure from a tdb.  Caller must
     232             :  free the user_info struct (talloced memory)
     233             : ***********************************************************************/
     234             : 
     235      102039 : struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const struct dom_sid *user_sid)
     236             : {
     237      102039 :         struct netr_SamInfo3 *info3 = NULL;
     238           0 :         TDB_DATA data;
     239           0 :         struct dom_sid_buf keystr;
     240           0 :         enum ndr_err_code ndr_err;
     241           0 :         DATA_BLOB blob;
     242           0 :         struct netsamlogoncache_entry r;
     243             : 
     244      102039 :         if (!netsamlogon_cache_init()) {
     245           0 :                 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
     246             :                         NETSAMLOGON_TDB));
     247           0 :                 return NULL;
     248             :         }
     249             : 
     250             :         /* Prepare key as DOMAIN-SID/USER-RID string */
     251      102039 :         dom_sid_str_buf(user_sid, &keystr);
     252      102039 :         DBG_DEBUG("SID [%s]\n", keystr.buf);
     253      102039 :         data = tdb_fetch_bystring( netsamlogon_tdb, keystr.buf );
     254             : 
     255      102039 :         if (!data.dptr) {
     256        9984 :                 D_DEBUG("tdb fetch for %s is empty\n", keystr.buf);
     257        9984 :                 return NULL;
     258             :         }
     259             : 
     260       92055 :         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
     261       92055 :         if (!info3) {
     262           0 :                 goto done;
     263             :         }
     264             : 
     265       92055 :         blob = data_blob_const(data.dptr, data.dsize);
     266             : 
     267       92055 :         ndr_err = ndr_pull_struct_blob_all(
     268             :                 &blob, mem_ctx, &r,
     269             :                 (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
     270             : 
     271       92055 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     272           0 :                 D_WARNING("netsamlogon_cache_get: failed to pull entry from cache\n");
     273           0 :                 tdb_delete_bystring(netsamlogon_tdb, keystr.buf);
     274           0 :                 TALLOC_FREE(info3);
     275           0 :                 goto done;
     276             :         }
     277             : 
     278       92055 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, netsamlogoncache_entry, &r);
     279             : 
     280       92055 :         info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3,
     281             :                                                       sizeof(r.info3));
     282             : 
     283       92055 :  done:
     284       92055 :         SAFE_FREE(data.dptr);
     285             : 
     286       92055 :         return info3;
     287             : }
     288             : 
     289           0 : bool netsamlogon_cache_have(const struct dom_sid *sid)
     290             : {
     291           0 :         struct dom_sid_buf keystr;
     292           0 :         bool ok;
     293             : 
     294           0 :         if (!netsamlogon_cache_init()) {
     295           0 :                 DBG_WARNING("Cannot open %s\n", NETSAMLOGON_TDB);
     296           0 :                 return false;
     297             :         }
     298             : 
     299           0 :         dom_sid_str_buf(sid, &keystr);
     300             : 
     301           0 :         ok = tdb_exists(netsamlogon_tdb, string_term_tdb_data(keystr.buf));
     302           0 :         return ok;
     303             : }
     304             : 
     305             : struct netsamlog_cache_forall_state {
     306             :         TALLOC_CTX *mem_ctx;
     307             :         int (*cb)(const char *sid_str,
     308             :                   time_t when_cached,
     309             :                   struct netr_SamInfo3 *,
     310             :                   void *private_data);
     311             :         void *private_data;
     312             : };
     313             : 
     314          96 : static int netsamlog_cache_traverse_cb(struct tdb_context *tdb,
     315             :                                        TDB_DATA key,
     316             :                                        TDB_DATA data,
     317             :                                        void *private_data)
     318             : {
     319          96 :         struct netsamlog_cache_forall_state *state =
     320             :                 (struct netsamlog_cache_forall_state *)private_data;
     321          96 :         TALLOC_CTX *mem_ctx = NULL;
     322           0 :         DATA_BLOB blob;
     323          96 :         const char *sid_str = NULL;
     324           0 :         struct dom_sid sid;
     325           0 :         struct netsamlogoncache_entry r;
     326           0 :         enum ndr_err_code ndr_err;
     327           0 :         int ret;
     328           0 :         bool ok;
     329             : 
     330          96 :         if (key.dsize == 0) {
     331           0 :                 return 0;
     332             :         }
     333          96 :         if (key.dptr[key.dsize - 1] != '\0') {
     334           0 :                 return 0;
     335             :         }
     336          96 :         if (data.dptr == NULL) {
     337           0 :                 return 0;
     338             :         }
     339          96 :         sid_str = (char *)key.dptr;
     340             : 
     341          96 :         ok = string_to_sid(&sid, sid_str);
     342          96 :         if (!ok) {
     343           0 :                 DBG_ERR("String to SID failed for %s\n", sid_str);
     344           0 :                 return -1;
     345             :         }
     346             : 
     347          96 :         if (sid.num_auths != 5) {
     348          24 :                 return 0;
     349             :         }
     350             : 
     351          72 :         mem_ctx = talloc_new(state->mem_ctx);
     352          72 :         if (mem_ctx == NULL) {
     353           0 :                 return -1;
     354             :         }
     355             : 
     356          72 :         blob = data_blob_const(data.dptr, data.dsize);
     357             : 
     358          72 :         ndr_err = ndr_pull_struct_blob(
     359             :                 &blob, state->mem_ctx, &r,
     360             :                 (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry);
     361             : 
     362          72 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     363           0 :                 DBG_ERR("failed to pull entry from cache\n");
     364           0 :                 return -1;
     365             :         }
     366             : 
     367          72 :         ret = state->cb(sid_str, r.timestamp, &r.info3, state->private_data);
     368             : 
     369          72 :         TALLOC_FREE(mem_ctx);
     370          72 :         return ret;
     371             : }
     372             : 
     373           6 : int netsamlog_cache_for_all(int (*cb)(const char *sid_str,
     374             :                                       time_t when_cached,
     375             :                                       struct netr_SamInfo3 *,
     376             :                                       void *private_data),
     377             :                             void *private_data)
     378             : {
     379           0 :         int ret;
     380           6 :         TALLOC_CTX *mem_ctx = NULL;
     381           0 :         struct netsamlog_cache_forall_state state;
     382             : 
     383           6 :         if (!netsamlogon_cache_init()) {
     384           0 :                 DBG_ERR("Cannot open %s\n", NETSAMLOGON_TDB);
     385           0 :                 return -1;
     386             :         }
     387             : 
     388           6 :         mem_ctx = talloc_init("netsamlog_cache_for_all");
     389           6 :         if (mem_ctx == NULL) {
     390           0 :                 return -1;
     391             :         }
     392             : 
     393           6 :         state = (struct netsamlog_cache_forall_state) {
     394             :                 .mem_ctx = mem_ctx,
     395             :                 .cb = cb,
     396             :                 .private_data = private_data,
     397             :         };
     398             : 
     399           6 :         ret = tdb_traverse_read(netsamlogon_tdb,
     400             :                                 netsamlog_cache_traverse_cb,
     401             :                                 &state);
     402             : 
     403           6 :         TALLOC_FREE(state.mem_ctx);
     404           6 :         return ret;
     405             : }

Generated by: LCOV version 1.14