LCOV - code coverage report
Current view: top level - providers/krb5 - krb5_renew_tgt.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 285 0.0 %
Date: 2015-10-19 Functions: 0 12 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Kerberos 5 Backend Module -- Renew a TGT automatically
       5             : 
       6             :     Authors:
       7             :         Sumit Bose <sbose@redhat.com>
       8             : 
       9             :     Copyright (C) 2010 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : #include <security/pam_modules.h>
      25             : 
      26             : #include "util/util.h"
      27             : #include "providers/krb5/krb5_common.h"
      28             : #include "providers/krb5/krb5_auth.h"
      29             : #include "providers/krb5/krb5_utils.h"
      30             : #include "providers/krb5/krb5_ccache.h"
      31             : 
      32             : #define INITIAL_TGT_TABLE_SIZE 10
      33             : 
      34             : struct renew_tgt_ctx {
      35             :     hash_table_t *tgt_table;
      36             :     struct be_ctx *be_ctx;
      37             :     struct tevent_context *ev;
      38             :     struct krb5_ctx *krb5_ctx;
      39             :     time_t timer_interval;
      40             :     struct tevent_timer *te;
      41             : };
      42             : 
      43             : struct renew_data {
      44             :     const char *ccfile;
      45             :     time_t start_time;
      46             :     time_t lifetime;
      47             :     time_t start_renew_at;
      48             :     struct pam_data *pd;
      49             : };
      50             : 
      51             : struct auth_data {
      52             :     struct be_ctx *be_ctx;
      53             :     struct krb5_ctx *krb5_ctx;
      54             :     struct pam_data *pd;
      55             :     struct renew_data *renew_data;
      56             :     hash_table_t *table;
      57             :     hash_key_t key;
      58             : };
      59             : 
      60             : 
      61             : static void renew_tgt_done(struct tevent_req *req);
      62           0 : static void renew_tgt(struct tevent_context *ev, struct tevent_timer *te,
      63             :                       struct timeval current_time, void *private_data)
      64             : {
      65           0 :     struct auth_data *auth_data = talloc_get_type(private_data,
      66             :                                                   struct auth_data);
      67             :     struct tevent_req *req;
      68             : 
      69           0 :     req = krb5_auth_queue_send(auth_data, ev, auth_data->be_ctx, auth_data->pd,
      70             :                                auth_data->krb5_ctx);
      71           0 :     if (req == NULL) {
      72           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth_send failed.\n");
      73             : /* Give back the pam data to the renewal item to be able to retry at the next
      74             :  * time the renewals re run. */
      75           0 :         auth_data->renew_data->pd = talloc_steal(auth_data->renew_data,
      76             :                                                  auth_data->pd);
      77           0 :         talloc_free(auth_data);
      78           0 :         return;
      79             :     }
      80             : 
      81           0 :     tevent_req_set_callback(req, renew_tgt_done, auth_data);
      82             : }
      83             : 
      84           0 : static void renew_tgt_done(struct tevent_req *req)
      85             : {
      86           0 :     struct auth_data *auth_data = tevent_req_callback_data(req,
      87             :                                                            struct auth_data);
      88             :     int ret;
      89           0 :     int pam_status = PAM_SYSTEM_ERR;
      90             :     int dp_err;
      91             :     hash_value_t value;
      92             : 
      93           0 :     ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
      94           0 :     talloc_free(req);
      95           0 :     if (ret) {
      96           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth request failed.\n");
      97           0 :         if (auth_data->renew_data != NULL) {
      98           0 :             DEBUG(SSSDBG_FUNC_DATA, "Giving back pam data.\n");
      99           0 :             auth_data->renew_data->pd = talloc_steal(auth_data->renew_data,
     100             :                                                      auth_data->pd);
     101             :         }
     102             :     } else {
     103           0 :         switch (pam_status) {
     104             :             case PAM_SUCCESS:
     105           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     106             :                       "Successfully renewed TGT for user [%s].\n",
     107             :                           auth_data->pd->user);
     108             : /* In general a successful renewal will update the renewal item and free the
     109             :  * old data. But if the TGT has reached the end of his renewable lifetime it
     110             :  * will not be put into the list of renewable tickets again. In this case the
     111             :  * renewal item is not updated and the value from the hash and the one we have
     112             :  * stored are the same. Since the TGT cannot be renewed anymore we want to
     113             :  * remove it from the list of renewable tickets. */
     114           0 :                 ret = hash_lookup(auth_data->table, &auth_data->key, &value);
     115           0 :                 if (ret == HASH_SUCCESS) {
     116           0 :                     if (value.type == HASH_VALUE_PTR &&
     117           0 :                         auth_data->renew_data == talloc_get_type(value.ptr,
     118             :                                                            struct renew_data)) {
     119           0 :                         DEBUG(SSSDBG_FUNC_DATA,
     120             :                               "New TGT was not added for renewal, "
     121             :                                   "removing list entry for user [%s].\n",
     122             :                                   auth_data->pd->user);
     123           0 :                         ret = hash_delete(auth_data->table, &auth_data->key);
     124           0 :                         if (ret != HASH_SUCCESS) {
     125           0 :                             DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed.\n");
     126             :                         }
     127             :                     }
     128             :                 }
     129           0 :                 break;
     130             :             case PAM_AUTHINFO_UNAVAIL:
     131             :             case PAM_AUTHTOK_LOCK_BUSY:
     132           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     133             :                       "Cannot renewed TGT for user [%s] while offline, "
     134             :                           "will retry later.\n",
     135             :                           auth_data->pd->user);
     136           0 :                 if (auth_data->renew_data != NULL) {
     137           0 :                     DEBUG(SSSDBG_FUNC_DATA, "Giving back pam data.\n");
     138           0 :                     auth_data->renew_data->pd = talloc_steal(auth_data->renew_data,
     139             :                                                              auth_data->pd);
     140             :                 }
     141           0 :                 break;
     142             :             default:
     143           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     144             :                       "Failed to renew TGT for user [%s].\n",
     145             :                           auth_data->pd->user);
     146           0 :                 ret = hash_delete(auth_data->table, &auth_data->key);
     147           0 :                 if (ret != HASH_SUCCESS) {
     148           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed.\n");
     149             :                 }
     150             :         }
     151             :     }
     152             : 
     153           0 :     talloc_zfree(auth_data);
     154           0 : }
     155             : 
     156           0 : static errno_t renew_all_tgts(struct renew_tgt_ctx *renew_tgt_ctx)
     157             : {
     158             :     int ret;
     159             :     hash_entry_t *entries;
     160             :     unsigned long count;
     161             :     size_t c;
     162             :     time_t now;
     163             :     struct auth_data *auth_data;
     164             :     struct renew_data *renew_data;
     165           0 :     struct tevent_timer *te = NULL;
     166             : 
     167           0 :     ret = hash_entries(renew_tgt_ctx->tgt_table, &count, &entries);
     168           0 :     if (ret != HASH_SUCCESS) {
     169           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "hash_entries failed.\n");
     170           0 :         return ENOMEM;
     171             :     }
     172             : 
     173           0 :     now = time(NULL);
     174             : 
     175           0 :     for (c = 0; c < count; c++) {
     176           0 :         renew_data = talloc_get_type(entries[c].value.ptr, struct renew_data);
     177           0 :         DEBUG(SSSDBG_TRACE_ALL,
     178             :               "Checking [%s] for renewal at [%.24s].\n", renew_data->ccfile,
     179             :                   ctime(&renew_data->start_renew_at));
     180             :         /* If renew_data->pd == NULL a renewal request for this data is
     181             :          * currently running so we skip it. */
     182           0 :         if (renew_data->start_renew_at < now && renew_data->pd != NULL) {
     183           0 :             auth_data = talloc_zero(renew_tgt_ctx, struct auth_data);
     184           0 :             if (auth_data == NULL) {
     185           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
     186             :             } else {
     187             : /* We need to steal the pam_data here, because a successful renewal of the
     188             :  * ticket might add a new renewal item to the list with the same key (upn).
     189             :  * This would delete renew_data and all its children. But we cannot be sure
     190             :  * that adding the new renewal item is the last operation of the renewal
     191             :  * process with access the pam_data. To be on the safe side we steal the
     192             :  * pam_data and make it a child of auth_data which is only freed after the
     193             :  * renewal process is finished. In the case of an error during renewal we
     194             :  * might want to steal the pam_data back to renew_data before freeing
     195             :  * auth_data to allow a new renewal attempt. */
     196           0 :                 auth_data->pd = talloc_move(auth_data, &renew_data->pd);
     197           0 :                 auth_data->krb5_ctx = renew_tgt_ctx->krb5_ctx;
     198           0 :                 auth_data->be_ctx = renew_tgt_ctx->be_ctx;
     199           0 :                 auth_data->table = renew_tgt_ctx->tgt_table;
     200           0 :                 auth_data->renew_data = renew_data;
     201           0 :                 auth_data->key.type = entries[c].key.type;
     202           0 :                 auth_data->key.str = talloc_strdup(auth_data,
     203           0 :                                                    entries[c].key.str);
     204           0 :                 if (auth_data->key.str == NULL) {
     205           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
     206             :                 } else {
     207           0 :                     te = tevent_add_timer(renew_tgt_ctx->ev,
     208             :                                           auth_data, tevent_timeval_current(),
     209             :                                           renew_tgt, auth_data);
     210           0 :                     if (te == NULL) {
     211           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
     212             :                               "tevent_add_timer failed.\n");
     213             :                     }
     214             :                 }
     215             :             }
     216             : 
     217           0 :             if (auth_data == NULL || te == NULL) {
     218           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     219             :                       "Failed to renew TGT in [%s].\n", renew_data->ccfile);
     220           0 :                 ret = hash_delete(renew_tgt_ctx->tgt_table, &entries[c].key);
     221           0 :                 if (ret != HASH_SUCCESS) {
     222           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed.\n");
     223             :                 }
     224             :             }
     225             :         }
     226             :     }
     227             : 
     228           0 :     talloc_free(entries);
     229             : 
     230           0 :     return EOK;
     231             : }
     232             : 
     233             : static void renew_handler(struct renew_tgt_ctx *renew_tgt_ctx);
     234             : 
     235           0 : static void renew_tgt_offline_callback(void *private_data)
     236             : {
     237           0 :     struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(private_data,
     238             :                                                           struct renew_tgt_ctx);
     239             : 
     240           0 :     talloc_zfree(renew_tgt_ctx->te);
     241           0 : }
     242             : 
     243           0 : static void renew_tgt_online_callback(void *private_data)
     244             : {
     245           0 :     struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(private_data,
     246             :                                                           struct renew_tgt_ctx);
     247             : 
     248           0 :     renew_handler(renew_tgt_ctx);
     249           0 : }
     250             : 
     251           0 : static void renew_tgt_timer_handler(struct tevent_context *ev,
     252             :                                     struct tevent_timer *te,
     253             :                                     struct timeval current_time, void *data)
     254             : {
     255           0 :     struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(data,
     256             :                                                           struct renew_tgt_ctx);
     257             : 
     258             :     /* forget the timer event, it will be freed by the tevent timer loop */
     259           0 :     renew_tgt_ctx->te = NULL;
     260             : 
     261           0 :     renew_handler(renew_tgt_ctx);
     262           0 : }
     263             : 
     264           0 : static void renew_handler(struct renew_tgt_ctx *renew_tgt_ctx)
     265             : {
     266             :     struct timeval next;
     267             :     int ret;
     268             : 
     269           0 :     if (be_is_offline(renew_tgt_ctx->be_ctx)) {
     270           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Offline, disable renew timer.\n");
     271           0 :         return;
     272             :     }
     273             : 
     274           0 :     ret = renew_all_tgts(renew_tgt_ctx);
     275           0 :     if (ret != EOK) {
     276           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "renew_all_tgts failed. "
     277             :                   "Disabling automatic TGT renewal\n");
     278           0 :         sss_log(SSS_LOG_ERR, "Disabling automatic TGT renewal.");
     279           0 :         talloc_zfree(renew_tgt_ctx);
     280           0 :         return;
     281             :     }
     282             : 
     283           0 :     if (renew_tgt_ctx->te != NULL) {
     284           0 :         DEBUG(SSSDBG_TRACE_LIBS,
     285             :               "There is an active renewal timer, doing nothing.\n");
     286           0 :         return;
     287             :     }
     288             : 
     289           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Adding new renew timer.\n");
     290             : 
     291           0 :     next = tevent_timeval_current_ofs(renew_tgt_ctx->timer_interval,
     292             :                                       0);
     293           0 :     renew_tgt_ctx->te = tevent_add_timer(renew_tgt_ctx->ev, renew_tgt_ctx,
     294             :                                          next, renew_tgt_timer_handler,
     295             :                                          renew_tgt_ctx);
     296           0 :     if (renew_tgt_ctx->te == NULL) {
     297           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
     298           0 :         sss_log(SSS_LOG_ERR, "Disabling automatic TGT renewal.");
     299           0 :         talloc_zfree(renew_tgt_ctx);
     300             :     }
     301             : 
     302           0 :     return;
     303             : }
     304             : 
     305           0 : static void renew_del_cb(hash_entry_t *entry, hash_destroy_enum type, void *pvt)
     306             : {
     307             :     struct renew_data *renew_data;
     308             : 
     309           0 :     if (entry->value.type == HASH_VALUE_PTR) {
     310           0 :         renew_data = talloc_get_type(entry->value.ptr, struct renew_data);
     311           0 :         talloc_zfree(renew_data);
     312           0 :         return;
     313             :     }
     314             : 
     315           0 :     DEBUG(SSSDBG_CRIT_FAILURE,
     316             :           "Unexpected value type [%d].\n", entry->value.type);
     317             : }
     318             : 
     319           0 : static errno_t check_ccache_file(struct renew_tgt_ctx *renew_tgt_ctx,
     320             :                                  const char *ccache_file, const char *upn,
     321             :                                  const char *user_name)
     322             : {
     323             :     int ret;
     324             :     struct stat stat_buf;
     325             :     struct tgt_times tgtt;
     326             :     struct pam_data pd;
     327             :     time_t now;
     328             :     const char *filename;
     329             : 
     330           0 :     if (ccache_file == NULL || upn == NULL || user_name == NULL) {
     331           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     332             :               "Missing one of the needed attributes: [%s][%s][%s].\n",
     333             :                   ccache_file == NULL ? "cache file missing" : ccache_file,
     334             :                   upn == NULL ? "principal missing" : upn,
     335             :                   user_name == NULL ? "user name missing" : user_name);
     336           0 :         return EINVAL;
     337             :     }
     338             : 
     339           0 :     if (strncmp(ccache_file, "FILE:", 5) == 0) {
     340           0 :         filename = ccache_file + 5;
     341             :     } else {
     342           0 :         filename = ccache_file;
     343             :     }
     344             : 
     345           0 :     ret = stat(filename, &stat_buf);
     346           0 :     if (ret != EOK) {
     347           0 :         if (ret == ENOENT) {
     348           0 :             return EOK;
     349             :         }
     350           0 :         return ret;
     351             :     }
     352             : 
     353           0 :     DEBUG(SSSDBG_TRACE_ALL, "Found ccache file [%s].\n", ccache_file);
     354             : 
     355           0 :     memset(&tgtt, 0, sizeof(tgtt));
     356           0 :     ret = get_ccache_file_data(ccache_file, upn, &tgtt);
     357           0 :     if (ret != EOK) {
     358           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "get_ccache_file_data failed.\n");
     359           0 :         return ret;
     360             :     }
     361             : 
     362           0 :     memset(&pd, 0, sizeof(pd));
     363           0 :     pd.cmd = SSS_CMD_RENEW;
     364           0 :     pd.user = discard_const_p(char, user_name);
     365           0 :     now = time(NULL);
     366           0 :     if (tgtt.renew_till > tgtt.endtime && tgtt.renew_till > now &&
     367           0 :         tgtt.endtime > now) {
     368           0 :         DEBUG(SSSDBG_TRACE_LIBS,
     369             :               "Adding [%s] for automatic renewal.\n", ccache_file);
     370           0 :         ret = add_tgt_to_renew_table(renew_tgt_ctx->krb5_ctx, ccache_file,
     371             :                                      &tgtt, &pd, upn);
     372           0 :         if (ret != EOK) {
     373           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "add_tgt_to_renew_table failed, "
     374             :                       "automatic renewal not possible.\n");
     375             :         }
     376             :     } else {
     377           0 :         DEBUG(SSSDBG_TRACE_ALL,
     378             :               "TGT in [%s] for [%s] is too old.\n", ccache_file, upn);
     379             :     }
     380             : 
     381           0 :     return EOK;
     382             : }
     383             : 
     384           0 : static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx)
     385             : {
     386             :     TALLOC_CTX *tmp_ctx;
     387             :     int ret;
     388           0 :     const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)" \
     389             :                                   "("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS"))";
     390           0 :     const char *ccache_attrs[] = { SYSDB_CCACHE_FILE, SYSDB_UPN, SYSDB_NAME,
     391             :                                    SYSDB_CANONICAL_UPN, NULL };
     392           0 :     size_t msgs_count = 0;
     393           0 :     struct ldb_message **msgs = NULL;
     394             :     size_t c;
     395             :     const char *ccache_file;
     396             :     char *upn;
     397             :     const char *user_name;
     398             :     struct ldb_dn *base_dn;
     399             :     const struct ldb_val *user_dom_val;
     400             :     char *user_dom;
     401             : 
     402           0 :     tmp_ctx = talloc_new(NULL);
     403           0 :     if (tmp_ctx == NULL) {
     404           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
     405           0 :         return ENOMEM;
     406             :     }
     407             : 
     408           0 :     base_dn = sysdb_base_dn(renew_tgt_ctx->be_ctx->domain->sysdb, tmp_ctx);
     409           0 :     if (base_dn == NULL) {
     410           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_base_dn failed.\n");
     411           0 :         ret = ENOMEM;
     412           0 :         goto done;
     413             :     }
     414             : 
     415           0 :     ret = sysdb_search_entry(tmp_ctx, renew_tgt_ctx->be_ctx->domain->sysdb, base_dn,
     416             :                              LDB_SCOPE_SUBTREE, ccache_filter, ccache_attrs,
     417             :                              &msgs_count, &msgs);
     418           0 :     if (ret != EOK) {
     419           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry failed.\n");
     420           0 :         goto done;
     421             :     }
     422             : 
     423           0 :     if (msgs_count == 0) {
     424           0 :         DEBUG(SSSDBG_TRACE_ALL,
     425             :               "No entries with ccache file found in cache.\n");
     426           0 :         ret = EOK;
     427           0 :         goto done;
     428             :     }
     429           0 :     DEBUG(SSSDBG_TRACE_ALL,
     430             :           "Found [%zu] entries with ccache file in cache.\n", msgs_count);
     431             : 
     432           0 :     for (c = 0; c < msgs_count; c++) {
     433           0 :         user_name = ldb_msg_find_attr_as_string(msgs[c], SYSDB_NAME, NULL);
     434           0 :         if (user_name == NULL) {
     435           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     436             :                   "No user name found, this is a severe error, "
     437             :                       "but we ignore it here.\n");
     438           0 :             continue;
     439             :         }
     440             : 
     441             :         /* The DNs of users in sysdb looks like
     442             :          * name=username,cn=users,cn=domain.name,cn=sysdb
     443             :          * the value of the third component (index 2) is the domain name. */
     444             : 
     445           0 :         user_dom_val = ldb_dn_get_component_val(msgs[c]->dn, 2);
     446           0 :         if (user_dom_val == NULL) {
     447           0 :             DEBUG(SSSDBG_OP_FAILURE, "Invalid user DN [%s].\n",
     448             :                                       ldb_dn_get_linearized(msgs[c]->dn));
     449           0 :             ret = EINVAL;
     450           0 :             goto done;
     451             :         }
     452           0 :         user_dom = talloc_strndup(tmp_ctx, (char *) user_dom_val->data,
     453             :                                  user_dom_val->length);
     454           0 :         if (user_dom == NULL) {
     455           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed,\n");
     456           0 :             ret = ENOMEM;
     457           0 :             goto done;
     458             :         }
     459             : 
     460           0 :         ret = find_or_guess_upn(tmp_ctx, msgs[c], renew_tgt_ctx->krb5_ctx,
     461           0 :                                 renew_tgt_ctx->be_ctx->domain,
     462             :                                 user_name, user_dom, &upn);
     463           0 :         if (ret != EOK) {
     464           0 :             DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
     465           0 :             goto done;
     466             :         }
     467             : 
     468           0 :         ccache_file = ldb_msg_find_attr_as_string(msgs[c], SYSDB_CCACHE_FILE,
     469             :                                                   NULL);
     470             : 
     471           0 :         ret = check_ccache_file(renew_tgt_ctx, ccache_file, upn, user_name);
     472           0 :         if (ret != EOK) {
     473           0 :             DEBUG(SSSDBG_FUNC_DATA,
     474             :                   "Failed to check ccache file [%s].\n", ccache_file);
     475             :         }
     476             :     }
     477             : 
     478           0 :     ret = EOK;
     479             : 
     480             : done:
     481           0 :     talloc_free(tmp_ctx);
     482             : 
     483           0 :     return ret;
     484             : }
     485             : 
     486           0 : errno_t init_renew_tgt(struct krb5_ctx *krb5_ctx, struct be_ctx *be_ctx,
     487             :                        struct tevent_context *ev, time_t renew_intv)
     488             : {
     489             :     int ret;
     490             :     struct timeval next;
     491             : 
     492           0 :     krb5_ctx->renew_tgt_ctx = talloc_zero(krb5_ctx, struct renew_tgt_ctx);
     493           0 :     if (krb5_ctx->renew_tgt_ctx == NULL) {
     494           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
     495           0 :         return ENOMEM;
     496             :     }
     497             : 
     498           0 :     ret = sss_hash_create_ex(krb5_ctx->renew_tgt_ctx, INITIAL_TGT_TABLE_SIZE,
     499           0 :                              &krb5_ctx->renew_tgt_ctx->tgt_table, 0, 0, 0, 0,
     500             :                              renew_del_cb, NULL);
     501           0 :     if (ret != EOK) {
     502           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sss_hash_create failed.\n");
     503           0 :         goto fail;
     504             :     }
     505             : 
     506           0 :     krb5_ctx->renew_tgt_ctx->be_ctx = be_ctx;
     507           0 :     krb5_ctx->renew_tgt_ctx->krb5_ctx = krb5_ctx;
     508           0 :     krb5_ctx->renew_tgt_ctx->ev = ev;
     509           0 :     krb5_ctx->renew_tgt_ctx->timer_interval = renew_intv;
     510             : 
     511           0 :     ret = check_ccache_files(krb5_ctx->renew_tgt_ctx);
     512           0 :     if (ret != EOK) {
     513           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     514             :               "Failed to read ccache files, continuing ...\n");
     515             :     }
     516             : 
     517           0 :     next = tevent_timeval_current_ofs(krb5_ctx->renew_tgt_ctx->timer_interval,
     518             :                                       0);
     519           0 :     krb5_ctx->renew_tgt_ctx->te = tevent_add_timer(ev, krb5_ctx->renew_tgt_ctx,
     520             :                                                    next, renew_tgt_timer_handler,
     521             :                                                    krb5_ctx->renew_tgt_ctx);
     522           0 :     if (krb5_ctx->renew_tgt_ctx->te == NULL) {
     523           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
     524           0 :         ret = ENOMEM;
     525           0 :         goto fail;
     526             :     }
     527             : 
     528           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     529             :           "Adding offline callback to remove renewal timer.\n");
     530           0 :     ret = be_add_offline_cb(krb5_ctx->renew_tgt_ctx, be_ctx,
     531           0 :                             renew_tgt_offline_callback, krb5_ctx->renew_tgt_ctx,
     532             :                             NULL);
     533           0 :     if (ret != EOK) {
     534           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add offline callback.\n");
     535           0 :         goto fail;
     536             :     }
     537             : 
     538           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Adding renewal task to online callbacks.\n");
     539           0 :     ret = be_add_online_cb(krb5_ctx->renew_tgt_ctx, be_ctx,
     540           0 :                            renew_tgt_online_callback, krb5_ctx->renew_tgt_ctx,
     541             :                            NULL);
     542           0 :     if (ret != EOK) {
     543           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     544             :               "Failed to add renewal task to online callbacks.\n");
     545           0 :         goto fail;
     546             :     }
     547             : 
     548           0 :     return EOK;
     549             : 
     550             : fail:
     551           0 :     talloc_zfree(krb5_ctx->renew_tgt_ctx);
     552           0 :     return ret;
     553             : }
     554             : 
     555           0 : errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile,
     556             :                                struct tgt_times *tgtt, struct pam_data *pd,
     557             :                                const char *upn)
     558             : {
     559             :     int ret;
     560             :     hash_key_t key;
     561             :     hash_value_t value;
     562           0 :     struct renew_data *renew_data = NULL;
     563             : 
     564           0 :     if (krb5_ctx->renew_tgt_ctx == NULL) {
     565           0 :         DEBUG(SSSDBG_TRACE_LIBS ,"Renew context not initialized, "
     566             :                   "automatic renewal not available.\n");
     567           0 :         return EOK;
     568             :     }
     569             : 
     570           0 :     if (pd->cmd != SSS_PAM_AUTHENTICATE && pd->cmd != SSS_CMD_RENEW &&
     571           0 :         pd->cmd != SSS_PAM_CHAUTHTOK) {
     572           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected pam task [%d].\n", pd->cmd);
     573           0 :         return EINVAL;
     574             :     }
     575             : 
     576           0 :     if (upn == NULL) {
     577           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing user principal name.\n");
     578           0 :         return EINVAL;
     579             :     }
     580             : 
     581             :     /* hash_enter copies the content of the hash string, so it is safe to use
     582             :      * discard_const_p here. */
     583           0 :     key.type = HASH_KEY_STRING;
     584           0 :     key.str = discard_const_p(char, upn);
     585             : 
     586           0 :     renew_data = talloc_zero(krb5_ctx->renew_tgt_ctx, struct renew_data);
     587           0 :     if (renew_data == NULL) {
     588           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
     589           0 :         ret = ENOMEM;
     590           0 :         goto done;
     591             :     }
     592             : 
     593           0 :     if (ccfile[0] == '/') {
     594           0 :         renew_data->ccfile = talloc_asprintf(renew_data, "FILE:%s", ccfile);
     595           0 :         if (renew_data->ccfile == NULL) {
     596           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
     597           0 :             ret = ENOMEM;
     598           0 :             goto done;
     599             :         }
     600             :     } else {
     601           0 :         renew_data->ccfile = talloc_strdup(renew_data, ccfile);
     602             :     }
     603             : 
     604           0 :     renew_data->start_time = tgtt->starttime;
     605           0 :     renew_data->lifetime = tgtt->endtime;
     606           0 :     renew_data->start_renew_at = (time_t) (tgtt->starttime +
     607           0 :                                         0.5 *(tgtt->endtime - tgtt->starttime));
     608             : 
     609           0 :     ret = copy_pam_data(renew_data, pd, &renew_data->pd);
     610           0 :     if (ret != EOK) {
     611           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "copy_pam_data failed.\n");
     612           0 :         goto done;
     613             :     }
     614             : 
     615           0 :     sss_authtok_set_empty(renew_data->pd->newauthtok);
     616             : 
     617           0 :     ret = sss_authtok_set_ccfile(renew_data->pd->authtok, renew_data->ccfile, 0);
     618           0 :     if (ret) {
     619           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to store ccfile in auth token.\n");
     620           0 :         goto done;
     621             :     }
     622             : 
     623           0 :     renew_data->pd->cmd = SSS_CMD_RENEW;
     624             : 
     625           0 :     value.type = HASH_VALUE_PTR;
     626           0 :     value.ptr = renew_data;
     627             : 
     628           0 :     ret = hash_enter(krb5_ctx->renew_tgt_ctx->tgt_table, &key, &value);
     629           0 :     if (ret != HASH_SUCCESS) {
     630           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n");
     631           0 :         ret = EFAULT;
     632           0 :         goto done;
     633             :     }
     634             : 
     635           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     636             :           "Added [%s] for renewal at [%.24s].\n", renew_data->ccfile,
     637             :                                            ctime(&renew_data->start_renew_at));
     638             : 
     639           0 :     ret = EOK;
     640             : 
     641             : done:
     642           0 :     if (ret != EOK) {
     643           0 :         talloc_free(renew_data);
     644             :     }
     645           0 :     return ret;
     646             : }

Generated by: LCOV version 1.10