LCOV - code coverage report
Current view: top level - providers/krb5 - krb5_utils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 141 459 30.7 %
Date: 2012-11-29 Functions: 7 23 30.4 %
Branches: 119 1408 8.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :     SSSD
       3                 :            : 
       4                 :            :     Kerberos 5 Backend Module -- Utilities
       5                 :            : 
       6                 :            :     Authors:
       7                 :            :         Sumit Bose <sbose@redhat.com>
       8                 :            : 
       9                 :            :     Copyright (C) 2009 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 <string.h>
      25                 :            : #include <stdlib.h>
      26                 :            : #include <libgen.h>
      27                 :            : 
      28                 :            : #include "providers/krb5/krb5_utils.h"
      29                 :            : #include "providers/krb5/krb5_auth.h"
      30                 :            : #include "src/util/find_uid.h"
      31                 :            : #include "util/util.h"
      32                 :            : 
      33                 :          0 : errno_t find_or_guess_upn(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
      34                 :            :                           struct krb5_ctx *krb5_ctx,
      35                 :            :                           const char *domain_name, const char *user,
      36                 :            :                           const char *user_dom, char **_upn)
      37                 :            : {
      38                 :            :     const char *upn;
      39                 :            :     int ret;
      40                 :            : 
      41                 :          0 :     upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);
      42         [ #  # ]:          0 :     if (upn == NULL) {
      43                 :          0 :         ret = krb5_get_simple_upn(mem_ctx, krb5_ctx, domain_name, user,
      44                 :            :                                   user_dom, _upn);
      45         [ #  # ]:          0 :         if (ret != EOK) {
      46 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_OP_FAILURE, ("krb5_get_simple_upn failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      47                 :          0 :             return ret;
      48                 :            :         }
      49                 :            :     } else {
      50                 :          0 :         *_upn = talloc_strdup(mem_ctx, upn);
      51         [ #  # ]:          0 :         if (*_upn == NULL) {
      52 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      53                 :            :             return ENOMEM;
      54                 :            :         }
      55                 :            :     }
      56                 :            : 
      57                 :            :     return EOK;
      58                 :            : }
      59                 :            : 
      60                 :          0 : errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
      61                 :            :                                          const char *user,
      62                 :            :                                          const char *upn)
      63                 :            : {
      64                 :            :     TALLOC_CTX *tmp_ctx;
      65                 :            :     int ret;
      66                 :            :     int sret;
      67                 :          0 :     const char *attrs[] = {SYSDB_UPN, NULL};
      68                 :            :     struct sysdb_attrs *new_attrs;
      69                 :            :     struct ldb_result *res;
      70                 :          0 :     bool in_transaction = false;
      71                 :            :     const char *cached_upn;
      72                 :            : 
      73 [ #  # ][ #  # ]:          0 :     if (sysdb == NULL || user == NULL || upn == NULL) {
      74                 :            :         return EINVAL;
      75                 :            :     }
      76                 :            : 
      77                 :          0 :     tmp_ctx = talloc_new(NULL);
      78         [ #  # ]:          0 :     if (tmp_ctx == NULL) {
      79 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      80                 :            :         return ENOMEM;
      81                 :            :     }
      82                 :            : 
      83                 :          0 :     ret = sysdb_get_user_attr(tmp_ctx, sysdb, user, attrs, &res);
      84         [ #  # ]:          0 :     if (ret != EOK) {
      85 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_get_user_attr failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      86                 :            :         goto done;
      87                 :            :     }
      88                 :            : 
      89         [ #  # ]:          0 :     if (res->count != 1) {
      90 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("[%d] user objects for name [%s] found, " \
         [ #  # ][ #  # ]
                 [ #  # ]
      91                 :            :                                   "expected 1.\n", res->count, user));
      92                 :            :         ret = EINVAL;
      93                 :            :         goto done;
      94                 :            :     }
      95                 :            : 
      96                 :          0 :     cached_upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL);
      97                 :            : 
      98 [ #  # ][ #  # ]:          0 :     if (cached_upn != NULL && strcmp(cached_upn, upn) == 0) {
      99 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_TRACE_ALL, ("Cached UPN and new one match, "
         [ #  # ][ #  # ]
                 [ #  # ]
     100                 :            :                                  "nothing to do.\n"));
     101                 :            :         ret = EOK;
     102                 :            :         goto done;
     103                 :            :     }
     104                 :            : 
     105 [ #  # ][ #  # ]:          0 :     DEBUG(SSSDBG_TRACE_LIBS, ("Replacing UPN [%s] with [%s] for user [%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     106                 :            :                               cached_upn, upn, user));
     107                 :            : 
     108                 :          0 :     new_attrs = sysdb_new_attrs(tmp_ctx);
     109         [ #  # ]:          0 :     if (new_attrs == NULL) {
     110 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_new_attrs failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     111                 :            :         ret = ENOMEM;
     112                 :            :         goto done;
     113                 :            :     }
     114                 :            : 
     115                 :          0 :     ret = sysdb_attrs_add_string(new_attrs, SYSDB_UPN, upn);
     116         [ #  # ]:          0 :     if (ret != EOK) {
     117 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     118                 :            :         goto done;
     119                 :            :     }
     120                 :            : 
     121                 :          0 :     ret = sysdb_transaction_start(sysdb);
     122         [ #  # ]:          0 :     if (ret != EOK) {
     123 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     124                 :            :               ("Error %d starting transaction (%s)\n", ret, strerror(ret)));
     125                 :            :         goto done;
     126                 :            :     }
     127                 :          0 :     in_transaction = true;
     128                 :            : 
     129                 :          0 :     ret = sysdb_set_entry_attr(sysdb, res->msgs[0]->dn, new_attrs,
     130                 :            :                                SYSDB_MOD_REP);
     131         [ #  # ]:          0 :     if (ret != EOK) {
     132 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_set_entry_attr failed [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     133                 :            :                                   ret, strerror(ret)));
     134                 :            :         goto done;
     135                 :            :     }
     136                 :            : 
     137                 :          0 :     ret = sysdb_transaction_commit(sysdb);
     138         [ #  # ]:          0 :     if (ret != EOK) {
     139 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Failed to commit transaction!\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     140                 :            :         goto done;
     141                 :            :     }
     142                 :            :     in_transaction = false;
     143                 :            : 
     144                 :            :     ret = EOK;
     145                 :            : 
     146                 :            : done:
     147         [ #  # ]:          0 :     if (in_transaction) {
     148                 :          0 :         sret = sysdb_transaction_cancel(sysdb);
     149         [ #  # ]:          0 :         if (sret != EOK) {
     150 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     151                 :            :         }
     152                 :            :     }
     153                 :            : 
     154                 :          0 :     talloc_free(tmp_ctx);
     155                 :            : 
     156                 :            :     return ret;
     157                 :            : }
     158                 :            : 
     159                 :         35 : char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
     160                 :            :                              const char *template, bool file_mode,
     161                 :            :                              bool case_sensitive, bool *private_path)
     162                 :            : {
     163                 :            :     char *copy;
     164                 :            :     char *p;
     165                 :            :     char *n;
     166                 :         35 :     char *result = NULL;
     167                 :            :     char *dummy;
     168                 :            :     char *name;
     169                 :         35 :     char *res = NULL;
     170                 :            :     const char *cache_dir_tmpl;
     171                 :         35 :     TALLOC_CTX *tmp_ctx = NULL;
     172                 :            : 
     173                 :         35 :     *private_path = false;
     174                 :            : 
     175         [ +  + ]:         35 :     if (template == NULL) {
     176 [ +  - ][ +  - ]:          1 :         DEBUG(1, ("Missing template.\n"));
         [ +  - ][ +  - ]
                 [ +  - ]
     177                 :            :         return NULL;
     178                 :            :     }
     179                 :            : 
     180                 :         34 :     tmp_ctx = talloc_new(NULL);
     181         [ +  - ]:         34 :     if (!tmp_ctx) return NULL;
     182                 :            : 
     183                 :         34 :     copy = talloc_strdup(tmp_ctx, template);
     184         [ -  + ]:         34 :     if (copy == NULL) {
     185 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_strdup failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     186                 :            :         goto done;
     187                 :            :     }
     188                 :            : 
     189                 :         34 :     result = talloc_strdup(tmp_ctx, "");
     190         [ +  - ]:         34 :     if (result == NULL) {
     191 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_strdup failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     192                 :            :         goto done;
     193                 :            :     }
     194                 :            : 
     195                 :            :     p = copy;
     196         [ +  + ]:         63 :     while ( (n = strchr(p, '%')) != NULL) {
     197                 :         36 :         *n = '\0';
     198                 :         36 :         n++;
     199         [ -  + ]:         36 :         if ( *n == '\0' ) {
     200 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("format error, single %% at the end of the template.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     201                 :            :             goto done;
     202                 :            :         }
     203                 :            : 
     204   [ +  +  +  +  :         36 :         switch( *n ) {
             +  +  +  +  
                      + ]
     205                 :            :             case 'u':
     206         [ -  + ]:          8 :                 if (kr->pd->user == NULL) {
     207 [ #  # ][ #  # ]:          0 :                     DEBUG(1, ("Cannot expand user name template "
         [ #  # ][ #  # ]
                 [ #  # ]
     208                 :            :                               "because user name is empty.\n"));
     209                 :            :                     goto done;
     210                 :            :                 }
     211                 :          8 :                 name = sss_get_cased_name(tmp_ctx, kr->pd->user,
     212                 :            :                                           case_sensitive);
     213         [ -  + ]:          8 :                 if (!name) {
     214 [ #  # ][ #  # ]:          0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     215                 :            :                           ("sss_get_cased_name failed\n"));
     216                 :            :                     goto done;
     217                 :            :                 }
     218                 :            : 
     219                 :          8 :                 result = talloc_asprintf_append(result, "%s%s", p,
     220                 :            :                                                 name);
     221         [ +  + ]:          8 :                 if (!file_mode) *private_path = true;
     222                 :            :                 break;
     223                 :            :             case 'U':
     224         [ -  + ]:          4 :                 if (kr->uid <= 0) {
     225 [ #  # ][ #  # ]:          0 :                     DEBUG(1, ("Cannot expand uid template "
         [ #  # ][ #  # ]
                 [ #  # ]
     226                 :            :                               "because uid is invalid.\n"));
     227                 :            :                     goto done;
     228                 :            :                 }
     229                 :          4 :                 result = talloc_asprintf_append(result, "%s%d", p,
     230                 :            :                                                 kr->uid);
     231         [ +  + ]:          4 :                 if (!file_mode) *private_path = true;
     232                 :            :                 break;
     233                 :            :             case 'p':
     234         [ -  + ]:          2 :                 if (kr->upn == NULL) {
     235 [ #  # ][ #  # ]:          0 :                     DEBUG(1, ("Cannot expand user principal name template "
         [ #  # ][ #  # ]
                 [ #  # ]
     236                 :            :                               "because upn is empty.\n"));
     237                 :            :                     goto done;
     238                 :            :                 }
     239                 :          2 :                 result = talloc_asprintf_append(result, "%s%s", p, kr->upn);
     240         [ +  + ]:          2 :                 if (!file_mode) *private_path = true;
     241                 :            :                 break;
     242                 :            :             case '%':
     243                 :          2 :                 result = talloc_asprintf_append(result, "%s%%", p);
     244                 :          2 :                 break;
     245                 :            :             case 'r':
     246                 :          2 :                 dummy = dp_opt_get_string(kr->krb5_ctx->opts, KRB5_REALM);
     247         [ -  + ]:          2 :                 if (dummy == NULL) {
     248 [ #  # ][ #  # ]:          0 :                     DEBUG(1, ("Missing kerberos realm.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     249                 :            :                     goto done;
     250                 :            :                 }
     251                 :          2 :                 result = talloc_asprintf_append(result, "%s%s", p, dummy);
     252                 :          2 :                 break;
     253                 :            :             case 'h':
     254         [ -  + ]:          2 :                 if (kr->homedir == NULL) {
     255 [ #  # ][ #  # ]:          0 :                     DEBUG(1, ("Cannot expand home directory template "
         [ #  # ][ #  # ]
                 [ #  # ]
     256                 :            :                               "because the path is not available.\n"));
     257                 :            :                     goto done;
     258                 :            :                 }
     259                 :          2 :                 result = talloc_asprintf_append(result, "%s%s", p, kr->homedir);
     260         [ +  + ]:          2 :                 if (!file_mode) *private_path = true;
     261                 :            :                 break;
     262                 :            :             case 'd':
     263         [ +  + ]:         12 :                 if (file_mode) {
     264                 :         11 :                     cache_dir_tmpl = dp_opt_get_string(kr->krb5_ctx->opts,
     265                 :            :                                                        KRB5_CCACHEDIR);
     266         [ -  + ]:         11 :                     if (cache_dir_tmpl == NULL) {
     267 [ #  # ][ #  # ]:          0 :                         DEBUG(1, ("Missing credential cache directory.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     268                 :            :                         goto done;
     269                 :            :                     }
     270                 :            : 
     271                 :         11 :                     dummy = expand_ccname_template(tmp_ctx, kr, cache_dir_tmpl,
     272                 :            :                                                    false, case_sensitive,
     273                 :            :                                                    private_path);
     274         [ +  + ]:         11 :                     if (dummy == NULL) {
     275 [ +  - ][ +  - ]:          3 :                         DEBUG(1, ("Expanding credential cache directory "
         [ +  - ][ +  - ]
                 [ +  - ]
     276                 :            :                                   "template failed.\n"));
     277                 :            :                         goto done;
     278                 :            :                     }
     279                 :          8 :                     result = talloc_asprintf_append(result, "%s%s", p, dummy);
     280                 :          8 :                     talloc_zfree(dummy);
     281                 :            :                 } else {
     282 [ +  - ][ +  - ]:          1 :                     DEBUG(1, ("'%%d' is not allowed in this template.\n"));
         [ +  - ][ +  - ]
                 [ +  - ]
     283                 :            :                     goto done;
     284                 :            :                 }
     285                 :            :                 break;
     286                 :            :             case 'P':
     287         [ +  + ]:          2 :                 if (!file_mode) {
     288 [ +  - ][ +  - ]:          1 :                     DEBUG(1, ("'%%P' is not allowed in this template.\n"));
         [ +  - ][ +  - ]
                 [ +  - ]
     289                 :            :                     goto done;
     290                 :            :                 }
     291         [ -  + ]:          1 :                 if (kr->pd->cli_pid == 0) {
     292 [ #  # ][ #  # ]:          0 :                     DEBUG(1, ("Cannot expand PID template "
         [ #  # ][ #  # ]
                 [ #  # ]
     293                 :            :                               "because PID is not available.\n"));
     294                 :            :                     goto done;
     295                 :            :                 }
     296                 :          1 :                 result = talloc_asprintf_append(result, "%s%d", p,
     297                 :            :                                                 kr->pd->cli_pid);
     298                 :          1 :                 break;
     299                 :            :             default:
     300 [ +  - ][ +  - ]:          2 :                 DEBUG(1, ("format error, unknown template [%%%c].\n", *n));
         [ +  - ][ +  - ]
                 [ +  - ]
     301                 :            :                 goto done;
     302                 :            :         }
     303                 :            : 
     304         [ -  + ]:         29 :         if (result == NULL) {
     305 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("talloc_asprintf_append failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     306                 :            :             goto done;
     307                 :            :         }
     308                 :            : 
     309                 :         29 :         p = n + 1;
     310                 :            :     }
     311                 :            : 
     312                 :         27 :     result = talloc_asprintf_append(result, "%s", p);
     313         [ -  + ]:         27 :     if (result == NULL) {
     314 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_asprintf_append failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     315                 :            :         goto done;
     316                 :            :     }
     317                 :            : 
     318                 :         27 :     res = talloc_move(mem_ctx, &result);
     319                 :            : done:
     320                 :         35 :     talloc_zfree(tmp_ctx);
     321                 :            :     return res;
     322                 :            : }
     323                 :            : 
     324                 :          2 : static errno_t check_parent_stat(bool private_path, struct stat *parent_stat,
     325                 :            :                                  uid_t uid, gid_t gid)
     326                 :            : {
     327         [ +  - ]:          2 :     if (private_path) {
     328 [ -  + ][ #  # ]:          2 :         if (!((parent_stat->st_uid == 0 && parent_stat->st_gid == 0) ||
                 [ -  + ]
     329                 :            :                parent_stat->st_uid == uid)) {
     330 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("Private directory can only be created below a "
         [ #  # ][ #  # ]
                 [ #  # ]
     331                 :            :                       "directory belonging to root or to [%d][%d].\n",
     332                 :            :                       uid, gid));
     333                 :            :             return EINVAL;
     334                 :            :         }
     335                 :            : 
     336         [ +  - ]:          2 :         if (parent_stat->st_uid == uid) {
     337         [ -  + ]:          2 :             if (!(parent_stat->st_mode & S_IXUSR)) {
     338 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("Parent directory does have the search bit set for "
         [ #  # ][ #  # ]
                 [ #  # ]
     339                 :            :                           "the owner.\n"));
     340                 :            :                 return EINVAL;
     341                 :            :             }
     342                 :            :         } else {
     343         [ #  # ]:          0 :             if (!(parent_stat->st_mode & S_IXOTH)) {
     344 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("Parent directory does have the search bit set for "
         [ #  # ][ #  # ]
                 [ #  # ]
     345                 :            :                         "others.\n"));
     346                 :            :                 return EINVAL;
     347                 :            :             }
     348                 :            :         }
     349                 :            :     } else {
     350 [ #  # ][ #  # ]:          0 :         if (parent_stat->st_uid != 0 || parent_stat->st_gid != 0) {
     351 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("Public directory cannot be created below a user "
         [ #  # ][ #  # ]
                 [ #  # ]
     352                 :            :                       "directory.\n"));
     353                 :            :             return EINVAL;
     354                 :            :         }
     355                 :            : 
     356         [ #  # ]:          0 :         if (!(parent_stat->st_mode & S_IXOTH)) {
     357 [ #  # ][ #  # ]:          2 :             DEBUG(1, ("Parent directory does have the search bit set for "
         [ #  # ][ #  # ]
                 [ #  # ]
     358                 :            :                       "others.\n"));
     359                 :            :             return EINVAL;
     360                 :            :         }
     361                 :            :     }
     362                 :            : 
     363                 :            :     return EOK;
     364                 :            : }
     365                 :            : 
     366                 :            : struct string_list {
     367                 :            :     struct string_list *next;
     368                 :            :     struct string_list *prev;
     369                 :            :     char *s;
     370                 :            : };
     371                 :            : 
     372                 :          4 : static errno_t find_ccdir_parent_data(TALLOC_CTX *mem_ctx,
     373                 :            :                                       const char *ccdirname,
     374                 :            :                                       struct stat *parent_stat,
     375                 :            :                                       struct string_list **missing_parents)
     376                 :            : {
     377                 :          4 :     int ret = EFAULT;
     378                 :          4 :     char *parent = NULL;
     379                 :            :     char *end;
     380                 :            :     struct string_list *li;
     381                 :            : 
     382                 :          4 :     ret = stat(ccdirname, parent_stat);
     383         [ +  + ]:          4 :     if (ret == EOK) {
     384         [ -  + ]:          2 :         if ( !S_ISDIR(parent_stat->st_mode) ) {
     385 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     386                 :            :                   ("[%s] is not a directory.\n", ccdirname));
     387                 :            :             return EINVAL;
     388                 :            :         }
     389                 :            :         return EOK;
     390                 :            :     } else {
     391         [ -  + ]:          2 :         if (errno != ENOENT) {
     392                 :          0 :             ret = errno;
     393 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     394                 :            :                   ("stat for [%s] failed: [%d][%s].\n", ccdirname, ret,
     395                 :            :                    strerror(ret)));
     396                 :          0 :             return ret;
     397                 :            :         }
     398                 :            :     }
     399                 :            : 
     400                 :          2 :     li = talloc_zero(mem_ctx, struct string_list);
     401         [ -  + ]:          2 :     if (li == NULL) {
     402 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     403                 :            :               ("talloc_zero failed.\n"));
     404                 :            :         return ENOMEM;
     405                 :            :     }
     406                 :            : 
     407                 :          2 :     li->s = talloc_strdup(li, ccdirname);
     408         [ -  + ]:          2 :     if (li->s == NULL) {
     409 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     410                 :            :               ("talloc_strdup failed.\n"));
     411                 :            :         return ENOMEM;
     412                 :            :     }
     413                 :            : 
     414         [ +  - ]:          2 :     DLIST_ADD(*missing_parents, li);
     415                 :            : 
     416                 :          2 :     parent = talloc_strdup(mem_ctx, ccdirname);
     417         [ -  + ]:          2 :     if (parent == NULL) {
     418 [ #  # ][ #  # ]:          2 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     419                 :            :               ("talloc_strdup failed.\n"));
     420                 :            :         return ENOMEM;
     421                 :            :     }
     422                 :            : 
     423                 :            :     /* We'll remove all trailing slashes from the back so that
     424                 :            :      * we only pass /some/path to find_ccdir_parent_data, not
     425                 :            :      * /some/path */
     426                 :            :     do {
     427                 :          2 :         end = strrchr(parent, '/');
     428         [ -  + ]:          2 :         if (end == NULL || end == parent) {
     429 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     430                 :            :                   ("Cannot find parent directory of [%s], / is not allowed.\n",
     431                 :            :                    ccdirname));
     432                 :            :             ret = EINVAL;
     433                 :            :             goto done;
     434                 :            :         }
     435                 :          2 :         *end = '\0';
     436         [ -  + ]:          2 :     } while (*(end+1) == '\0');
     437                 :            : 
     438                 :          2 :     ret = find_ccdir_parent_data(mem_ctx, parent, parent_stat, missing_parents);
     439                 :            : 
     440                 :            : done:
     441                 :          2 :     talloc_free(parent);
     442                 :          4 :     return ret;
     443                 :            : }
     444                 :            : 
     445                 :            : static errno_t
     446                 :          5 : check_ccache_re(const char *filename, pcre *illegal_re)
     447                 :            : {
     448                 :            :     errno_t ret;
     449                 :            : 
     450                 :          5 :     ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
     451                 :            :                     0, 0, NULL, 0);
     452         [ +  + ]:          5 :     if (ret == 0) {
     453 [ +  - ][ +  - ]:          3 :         DEBUG(SSSDBG_OP_FAILURE,
         [ -  + ][ #  # ]
                 [ #  # ]
     454                 :            :               ("Illegal pattern in ccache directory name [%s].\n", filename));
     455                 :            :         return EINVAL;
     456         [ +  - ]:          2 :     } else if (ret == PCRE_ERROR_NOMATCH) {
     457 [ +  - ][ +  - ]:          2 :         DEBUG(SSSDBG_TRACE_LIBS,
         [ -  + ][ #  # ]
                 [ #  # ]
     458                 :            :               ("Ccache directory name [%s] does not contain "
     459                 :            :                "illegal patterns.\n", filename));
     460                 :            :         return EOK;
     461                 :            :     }
     462                 :            : 
     463 [ #  # ][ #  # ]:          5 :     DEBUG(SSSDBG_CRIT_FAILURE, ("pcre_exec failed [%d].\n", ret));
         [ #  # ][ #  # ]
                 [ #  # ]
     464                 :            :     return EFAULT;
     465                 :            : }
     466                 :            : 
     467                 :            : errno_t
     468                 :          6 : create_ccache_dir(const char *ccdirname, pcre *illegal_re,
     469                 :            :                   uid_t uid, gid_t gid, bool private_path)
     470                 :            : {
     471                 :          6 :     int ret = EFAULT;
     472                 :            :     struct stat parent_stat;
     473                 :          6 :     struct string_list *missing_parents = NULL;
     474                 :          6 :     struct string_list *li = NULL;
     475                 :            :     mode_t old_umask;
     476                 :            :     mode_t new_dir_mode;
     477                 :          6 :     TALLOC_CTX *tmp_ctx = NULL;
     478                 :            : 
     479                 :          6 :     tmp_ctx = talloc_new(NULL);
     480         [ -  + ]:          6 :     if (tmp_ctx == NULL) {
     481 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     482                 :            :               ("talloc_new failed.\n"));
     483                 :            :         return ENOMEM;
     484                 :            :     }
     485                 :            : 
     486         [ +  + ]:          6 :     if (*ccdirname != '/') {
     487 [ +  - ][ +  - ]:          1 :         DEBUG(SSSDBG_MINOR_FAILURE,
         [ -  + ][ #  # ]
                 [ #  # ]
     488                 :            :               ("Only absolute paths are allowed, not [%s] .\n", ccdirname));
     489                 :            :         ret = EINVAL;
     490                 :            :         goto done;
     491                 :            :     }
     492                 :            : 
     493         [ +  - ]:          5 :     if (illegal_re != NULL) {
     494                 :          5 :         ret = check_ccache_re(ccdirname, illegal_re);
     495         [ +  + ]:          5 :         if (ret != EOK) {
     496                 :            :             goto done;
     497                 :            :         }
     498                 :            :     }
     499                 :            : 
     500                 :          2 :     ret = find_ccdir_parent_data(tmp_ctx, ccdirname, &parent_stat,
     501                 :            :                                  &missing_parents);
     502         [ -  + ]:          2 :     if (ret != EOK) {
     503 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     504                 :            :               ("find_ccdir_parent_data failed.\n"));
     505                 :            :         goto done;
     506                 :            :     }
     507                 :            : 
     508                 :          2 :     ret = check_parent_stat(private_path, &parent_stat, uid, gid);
     509         [ -  + ]:          2 :     if (ret != EOK) {
     510 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     511                 :            :               ("check_parent_stat failed for %s directory [%s].\n",
     512                 :            :                private_path ? "private" : "public", ccdirname));
     513                 :            :         goto done;
     514                 :            :     }
     515                 :            : 
     516         [ +  + ]:          4 :     DLIST_FOR_EACH(li, missing_parents) {
     517 [ +  - ][ +  - ]:          2 :         DEBUG(SSSDBG_TRACE_INTERNAL,
         [ -  + ][ #  # ]
                 [ #  # ]
     518                 :            :               ("Creating directory [%s].\n", li->s));
     519         [ +  - ]:          2 :         if (li->next == NULL) {
     520         [ -  + ]:          2 :             new_dir_mode = private_path ? 0700 : 01777;
     521                 :            :         } else {
     522 [ #  # ][ #  # ]:          0 :             if (private_path &&
     523         [ #  # ]:          0 :                 parent_stat.st_uid == uid && parent_stat.st_gid == gid) {
     524                 :            :                 new_dir_mode = 0700;
     525                 :            :             } else {
     526                 :          0 :                 new_dir_mode = 0755;
     527                 :            :             }
     528                 :            :         }
     529                 :            : 
     530                 :          2 :         old_umask = umask(0000);
     531                 :          2 :         ret = mkdir(li->s, new_dir_mode);
     532                 :          2 :         umask(old_umask);
     533         [ -  + ]:          2 :         if (ret != EOK) {
     534                 :          0 :             ret = errno;
     535 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     536                 :            :                   ("mkdir [%s] failed: [%d][%s].\n", li->s, ret,
     537                 :            :                    strerror(ret)));
     538                 :            :             goto done;
     539                 :            :         }
     540 [ +  - ][ +  - ]:          2 :         if (private_path &&
     541 [ -  + ][ #  # ]:          2 :             ((parent_stat.st_uid == uid && parent_stat.st_gid == gid) ||
     542                 :          0 :              li->next == NULL)) {
     543                 :          2 :             ret = chown(li->s, uid, gid);
     544         [ -  + ]:          2 :             if (ret != EOK) {
     545                 :          0 :                 ret = errno;
     546 [ #  # ][ #  # ]:          0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     547                 :            :                       ("chown failed [%d][%s].\n", ret, strerror(ret)));
     548                 :            :                 goto done;
     549                 :            :             }
     550                 :            :         }
     551                 :            :     }
     552                 :            : 
     553                 :            :     ret = EOK;
     554                 :            : 
     555                 :            : done:
     556                 :          6 :     talloc_free(tmp_ctx);
     557                 :            :     return ret;
     558                 :            : }
     559                 :            : 
     560                 :          0 : errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
     561                 :            :                              struct tgt_times *tgtt)
     562                 :            : {
     563                 :            :     krb5_error_code kerr;
     564                 :          0 :     krb5_context ctx = NULL;
     565                 :          0 :     krb5_ccache cc = NULL;
     566                 :          0 :     krb5_principal client_princ = NULL;
     567                 :          0 :     krb5_principal server_princ = NULL;
     568                 :            :     char *server_name;
     569                 :            :     krb5_creds mcred;
     570                 :            :     krb5_creds cred;
     571                 :            :     const char *realm_name;
     572                 :            :     int realm_length;
     573                 :            : 
     574                 :          0 :     kerr = krb5_init_context(&ctx);
     575         [ #  # ]:          0 :     if (kerr != 0) {
     576 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_init_context failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     577                 :            :         goto done;
     578                 :            :     }
     579                 :            : 
     580                 :          0 :     kerr = krb5_parse_name(ctx, client_name, &client_princ);
     581         [ #  # ]:          0 :     if (kerr != 0) {
     582 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     583 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     584                 :            :         goto done;
     585                 :            :     }
     586                 :            : 
     587                 :          0 :     sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
     588                 :            : 
     589                 :          0 :     server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
     590                 :            :                                   realm_length, realm_name,
     591                 :            :                                   realm_length, realm_name);
     592         [ #  # ]:          0 :     if (server_name == NULL) {
     593                 :          0 :         kerr = KRB5_CC_NOMEM;
     594 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_asprintf failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     595                 :            :         goto done;
     596                 :            :     }
     597                 :            : 
     598                 :          0 :     kerr = krb5_parse_name(ctx, server_name, &server_princ);
     599                 :          0 :     talloc_free(server_name);
     600         [ #  # ]:          0 :     if (kerr != 0) {
     601 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     602 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     603                 :            :         goto done;
     604                 :            :     }
     605                 :            : 
     606                 :          0 :     kerr = krb5_cc_resolve(ctx, ccache_file, &cc);
     607         [ #  # ]:          0 :     if (kerr != 0) {
     608 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     609 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     610                 :            :         goto done;
     611                 :            :     }
     612                 :            : 
     613                 :          0 :     memset(&mcred, 0, sizeof(mcred));
     614                 :          0 :     memset(&cred, 0, sizeof(mcred));
     615                 :            : 
     616                 :          0 :     mcred.server = server_princ;
     617                 :          0 :     mcred.client = client_princ;
     618                 :            : 
     619                 :          0 :     kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
     620         [ #  # ]:          0 :     if (kerr != 0) {
     621 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     622 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_retrieve_cred failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     623                 :            :         goto done;
     624                 :            :     }
     625                 :            : 
     626                 :          0 :     tgtt->authtime = cred.times.authtime;
     627                 :          0 :     tgtt->starttime = cred.times.starttime;
     628                 :          0 :     tgtt->endtime = cred.times.endtime;
     629                 :          0 :     tgtt->renew_till = cred.times.renew_till;
     630                 :            : 
     631                 :          0 :     krb5_free_cred_contents(ctx, &cred);
     632                 :            : 
     633                 :          0 :     kerr = krb5_cc_close(ctx, cc);
     634         [ #  # ]:          0 :     if (kerr != 0) {
     635 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     636 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_close failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     637                 :            :         goto done;
     638                 :            :     }
     639                 :          0 :     cc = NULL;
     640                 :            : 
     641                 :          0 :     kerr = 0;
     642                 :            : 
     643                 :            : done:
     644         [ #  # ]:          0 :     if (cc != NULL) {
     645                 :          0 :         krb5_cc_close(ctx, cc);
     646                 :            :     }
     647                 :            : 
     648         [ #  # ]:          0 :     if (client_princ != NULL) {
     649                 :          0 :         krb5_free_principal(ctx, client_princ);
     650                 :            :     }
     651                 :            : 
     652         [ #  # ]:          0 :     if (server_princ != NULL) {
     653                 :          0 :         krb5_free_principal(ctx, server_princ);
     654                 :            :     }
     655                 :            : 
     656         [ #  # ]:          0 :     if (ctx != NULL) {
     657                 :          0 :         krb5_free_context(ctx);
     658                 :            :     }
     659                 :            : 
     660         [ #  # ]:          0 :     if (kerr != 0) {
     661                 :            :         return EIO;
     662                 :            :     }
     663                 :            : 
     664                 :            :     return EOK;
     665                 :            : }
     666                 :            : 
     667                 :            : static errno_t
     668                 :          2 : create_ccache_dir_head(const char *parent, pcre *illegal_re,
     669                 :            :                        uid_t uid, gid_t gid, bool private_path)
     670                 :            : {
     671                 :            :     char *ccdirname;
     672                 :          2 :     TALLOC_CTX *tmp_ctx = NULL;
     673                 :            :     char *end;
     674                 :            :     errno_t ret;
     675                 :            : 
     676                 :          2 :     tmp_ctx = talloc_new(NULL);
     677         [ +  - ]:          2 :     if (!tmp_ctx) return ENOMEM;
     678                 :            : 
     679                 :          2 :     ccdirname = talloc_strdup(tmp_ctx, parent);
     680         [ -  + ]:          2 :     if (ccdirname == NULL) {
     681 [ #  # ][ #  # ]:          2 :         DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     682                 :            :         ret = ENOMEM;
     683                 :            :         goto done;
     684                 :            :     }
     685                 :            : 
     686                 :            :     /* We'll remove all trailing slashes from the back so that
     687                 :            :      * we only pass /some/path to find_ccdir_parent_data, not
     688                 :            :      * /some/path/ */
     689                 :            :     do {
     690                 :          3 :         end = strrchr(ccdirname, '/');
     691         [ -  + ]:          3 :         if (end == NULL || end == ccdirname) {
     692 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot find parent directory of [%s], "
         [ #  # ][ #  # ]
                 [ #  # ]
     693                 :            :                   "/ is not allowed.\n", ccdirname));
     694                 :            :             ret = EINVAL;
     695                 :            :             goto done;
     696                 :            :         }
     697                 :          3 :         *end = '\0';
     698         [ +  + ]:          3 :     } while (*(end+1) == '\0');
     699                 :            : 
     700                 :          2 :     ret = create_ccache_dir(ccdirname, illegal_re, uid, gid, private_path);
     701                 :            : done:
     702                 :          2 :     talloc_free(tmp_ctx);
     703                 :          2 :     return ret;
     704                 :            : }
     705                 :            : 
     706                 :            : /*======== ccache back end utilities ========*/
     707                 :            : struct sss_krb5_cc_be *
     708                 :          0 : get_cc_be_ops(enum sss_krb5_cc_type type)
     709                 :            : {
     710 [ #  # ][ #  # ]:          0 :     struct sss_krb5_cc_be *be = NULL;
     711                 :            : 
     712                 :            :     switch (type) {
     713                 :            :         case SSS_KRB5_TYPE_FILE:
     714                 :            :             be = &file_cc;
     715                 :            :             break;
     716                 :            : 
     717                 :            : #ifdef HAVE_KRB5_DIRCACHE
     718                 :            :         case SSS_KRB5_TYPE_DIR:
     719                 :            :             be = &dir_cc;
     720                 :            :             break;
     721                 :            : #endif /* HAVE_KRB5_DIRCACHE */
     722                 :            : 
     723                 :            :         case SSS_KRB5_TYPE_UNKNOWN:
     724                 :            :             be = NULL;
     725                 :            :             break;
     726                 :            :     }
     727                 :            : 
     728                 :          0 :     return be;
     729                 :            : }
     730                 :            : 
     731                 :            : struct sss_krb5_cc_be *
     732                 :          0 : get_cc_be_ops_ccache(const char *ccache)
     733                 :            : {
     734                 :            :     enum sss_krb5_cc_type type;
     735                 :            : 
     736                 :          0 :     type = sss_krb5_get_type(ccache);
     737                 :          0 :     return get_cc_be_ops(type);
     738                 :            : }
     739                 :            : 
     740                 :            : /*======== Operations on the FILE: back end ========*/
     741                 :            : errno_t
     742                 :          0 : cc_file_create(const char *location, pcre *illegal_re,
     743                 :            :                uid_t uid, gid_t gid, bool private_path)
     744                 :            : {
     745                 :            :     const char *filename;
     746                 :            : 
     747                 :          0 :     filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
     748         [ #  # ]:          0 :     if (filename == NULL) {
     749 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Bad ccache type %s\n", location));
         [ #  # ][ #  # ]
                 [ #  # ]
     750                 :            :         return EINVAL;
     751                 :            :     }
     752                 :            : 
     753                 :          0 :     return create_ccache_dir_head(filename, illegal_re, uid, gid, private_path);
     754                 :            : }
     755                 :            : 
     756                 :            : static errno_t
     757                 :          0 : cc_residual_is_used(uid_t uid, const char *ccname,
     758                 :            :                     enum sss_krb5_cc_type type, bool *result)
     759                 :            : {
     760                 :            :     int ret;
     761                 :            :     struct stat stat_buf;
     762                 :            :     bool active;
     763                 :            : 
     764                 :          0 :     *result = false;
     765                 :            : 
     766 [ #  # ][ #  # ]:          0 :     if (ccname == NULL || *ccname == '\0') {
     767                 :            :         return EINVAL;
     768                 :            :     }
     769                 :            : 
     770                 :          0 :     ret = lstat(ccname, &stat_buf);
     771                 :            : 
     772 [ #  # ][ #  # ]:          0 :     if (ret == -1 && errno != ENOENT) {
     773                 :          0 :         ret = errno;
     774 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     775                 :            :               ("stat failed [%d][%s].\n", ret, strerror(ret)));
     776                 :            :         return ret;
     777         [ #  # ]:          0 :     } else if (ret == EOK) {
     778         [ #  # ]:          0 :         if (stat_buf.st_uid != uid) {
     779 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_OP_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     780                 :            :                   ("Cache file [%s] exists, but is owned by [%d] instead of "
     781                 :            :                    "[%d].\n", ccname, stat_buf.st_uid, uid));
     782                 :            :             return EINVAL;
     783                 :            :         }
     784                 :            : 
     785      [ #  #  # ]:          0 :         switch (type) {
     786                 :            : #ifdef HAVE_KRB5_DIRCACHE
     787                 :            :             case SSS_KRB5_TYPE_DIR:
     788                 :          0 :                 ret = S_ISDIR(stat_buf.st_mode);
     789                 :          0 :                 break;
     790                 :            : #endif /* HAVE_KRB5_DIRCACHE */
     791                 :            :             case SSS_KRB5_TYPE_FILE:
     792                 :          0 :                 ret = S_ISREG(stat_buf.st_mode);
     793                 :          0 :                 break;
     794                 :            :             default:
     795 [ #  # ][ #  # ]:          0 :                 DEBUG(SSSDBG_CRIT_FAILURE, ("Unsupported ccache type\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     796                 :            :                 return EINVAL;
     797                 :            :         }
     798                 :            : 
     799         [ #  # ]:          0 :         if (ret == 0) {
     800 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_OP_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     801                 :            :                   ("Cache file [%s] exists, but is not the expected type\n",
     802                 :            :                    ccname));
     803                 :            :             return EINVAL;
     804                 :            :         }
     805                 :            :     }
     806                 :            : 
     807                 :          0 :     ret = check_if_uid_is_active(uid, &active);
     808         [ #  # ]:          0 :     if (ret != EOK) {
     809 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("check_if_uid_is_active failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     810                 :            :         return ret;
     811                 :            :     }
     812                 :            : 
     813         [ #  # ]:          0 :     if (!active) {
     814 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_TRACE_FUNC, ("User [%d] is not active\n", uid));
         [ #  # ][ #  # ]
                 [ #  # ]
     815                 :            :     } else {
     816 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_TRACE_LIBS,
         [ #  # ][ #  # ]
                 [ #  # ]
     817                 :            :               ("User [%d] is still active, reusing ccache [%s].\n",
     818                 :            :               uid, ccname));
     819                 :          0 :         *result = true;
     820                 :            :     }
     821                 :            :     return EOK;
     822                 :            : }
     823                 :            : 
     824                 :            : static void
     825                 :          0 : cc_check_template(const char *cc_template)
     826                 :            : {
     827                 :            :     size_t template_len;
     828                 :            : 
     829                 :          0 :     template_len = strlen(cc_template);
     830 [ #  # ][ #  # ]:          0 :     if (template_len >= 6 &&
     831                 :          0 :         strcmp(cc_template + (template_len - 6), "XXXXXX") != 0) {
     832 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CONF_SETTINGS, ("ccache file name template [%s] doesn't "
         [ #  # ][ #  # ]
                 [ #  # ]
     833                 :            :                    "contain randomizing characters (XXXXXX), file might not "
     834                 :            :                    "be rewritable\n", cc_template));
     835                 :            :     }
     836                 :          0 : }
     837                 :            : 
     838                 :            : errno_t
     839                 :          0 : cc_file_check_existing(const char *location, uid_t uid,
     840                 :            :                        const char *realm, const char *princ,
     841                 :            :                        const char *cc_template, bool *_active, bool *_valid)
     842                 :            : {
     843                 :            :     errno_t ret;
     844                 :            :     bool active;
     845                 :            :     bool valid;
     846                 :            :     const char *filename;
     847                 :          0 :     krb5_ccache ccache = NULL;
     848                 :          0 :     krb5_context context = NULL;
     849                 :            :     krb5_error_code kerr;
     850                 :            : 
     851                 :          0 :     filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
     852         [ #  # ]:          0 :     if (!filename) {
     853 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     854                 :            :         return EINVAL;
     855                 :            :     }
     856                 :            : 
     857         [ #  # ]:          0 :     if (filename[0] != '/') {
     858 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Only absolute path names are allowed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     859                 :            :         return EINVAL;
     860                 :            :     }
     861                 :            : 
     862                 :          0 :     ret = cc_residual_is_used(uid, filename, SSS_KRB5_TYPE_FILE, &active);
     863         [ #  # ]:          0 :     if (ret != EOK) {
     864 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Could not check if ccache is active. "
         [ #  # ][ #  # ]
                 [ #  # ]
     865                 :            :                                   "Will create a new one.\n"));
     866                 :          0 :         cc_check_template(cc_template);
     867                 :          0 :         active = false;
     868                 :            :     }
     869                 :            : 
     870                 :          0 :     kerr = krb5_init_context(&context);
     871         [ #  # ]:          0 :     if (kerr != 0) {
     872 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to init kerberos context\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     873                 :            :         return EIO;
     874                 :            :     }
     875                 :            : 
     876                 :          0 :     kerr = krb5_cc_resolve(context, location, &ccache);
     877         [ #  # ]:          0 :     if (kerr != 0) {
     878 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     879                 :          0 :         krb5_free_context(context);
     880 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     881                 :            :         return EIO;
     882                 :            :     }
     883                 :            : 
     884                 :          0 :     kerr = check_for_valid_tgt(context, ccache, realm, princ, &valid);
     885                 :          0 :     krb5_free_context(context);
     886                 :          0 :     krb5_cc_close(context, ccache);
     887         [ #  # ]:          0 :     if (kerr != EOK) {
     888 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, kerr);
         [ #  # ][ #  # ]
                 [ #  # ]
     889 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     890                 :            :               ("Could not check if ccache contains a valid principal\n"));
     891                 :            :         return EIO;
     892                 :            :     }
     893                 :            : 
     894                 :          0 :     *_active = active;
     895                 :          0 :     *_valid = valid;
     896                 :            :     return EOK;
     897                 :            : }
     898                 :            : 
     899                 :            : const char *
     900                 :          0 : cc_file_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
     901                 :            :                         const char *princ)
     902                 :            : {
     903                 :          0 :     return talloc_strdup(mem_ctx, location);
     904                 :            : }
     905                 :            : 
     906                 :            : errno_t
     907                 :          0 : cc_file_remove(const char *location)
     908                 :            : {
     909                 :            :     errno_t ret;
     910                 :            :     const char *filename;
     911                 :            : 
     912                 :          0 :     filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
     913         [ #  # ]:          0 :     if (!filename) {
     914 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     915                 :            :         return EINVAL;
     916                 :            :     }
     917                 :            : 
     918         [ #  # ]:          0 :     if (filename[0] != '/') {
     919 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     920                 :            :               ("Ccache file name [%s] is not an absolute path.\n", filename));
     921                 :            :         return EINVAL;
     922                 :            :     }
     923                 :            : 
     924                 :          0 :     errno = 0;
     925                 :          0 :     ret = unlink(filename);
     926 [ #  # ][ #  # ]:          0 :     if (ret == -1 && errno != ENOENT) {
     927                 :          0 :         ret = errno;
     928 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     929                 :            :               ("unlink [%s] failed [%d][%s].\n", filename, ret,
     930                 :            :                                                  strerror(ret)));
     931                 :          0 :         return ret;
     932                 :            :     }
     933                 :            :     return EOK;
     934                 :            : }
     935                 :            : 
     936                 :            : struct sss_krb5_cc_be file_cc = {
     937                 :            :     .type               = SSS_KRB5_TYPE_FILE,
     938                 :            :     .create             = cc_file_create,
     939                 :            :     .check_existing     = cc_file_check_existing,
     940                 :            :     .ccache_for_princ   = cc_file_cache_for_princ,
     941                 :            :     .remove             = cc_file_remove,
     942                 :            : };
     943                 :            : 
     944                 :            : #ifdef HAVE_KRB5_DIRCACHE
     945                 :            : /*======== Operations on the DIR: back end ========*/
     946                 :            : errno_t
     947                 :          2 : cc_dir_create(const char *location, pcre *illegal_re,
     948                 :            :               uid_t uid, gid_t gid, bool private_path)
     949                 :            : {
     950                 :            :     const char *dir_name;
     951                 :            : 
     952                 :          2 :     dir_name = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_DIR);
     953         [ -  + ]:          2 :     if (dir_name == NULL) {
     954 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("Bad residual type\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     955                 :            :         return EINVAL;
     956                 :            :     }
     957                 :            : 
     958                 :          2 :     return create_ccache_dir_head(dir_name, illegal_re, uid, gid, private_path);
     959                 :            : }
     960                 :            : 
     961                 :            : static krb5_error_code
     962                 :          0 : get_ccache_for_princ(krb5_context context, const char *location,
     963                 :            :                      const char *princ, krb5_ccache *_ccache)
     964                 :            : {
     965                 :            :     krb5_error_code krberr;
     966                 :          0 :     krb5_principal client_principal = NULL;
     967                 :            : 
     968                 :          0 :     krberr = krb5_cc_set_default_name(context, location);
     969         [ #  # ]:          0 :     if (krberr != 0) {
     970 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
         [ #  # ][ #  # ]
                 [ #  # ]
     971 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     972                 :            :         return krberr;
     973                 :            :     }
     974                 :            : 
     975                 :          0 :     krberr = krb5_parse_name(context, princ, &client_principal);
     976         [ #  # ]:          0 :     if (krberr != 0) {
     977 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
         [ #  # ][ #  # ]
                 [ #  # ]
     978 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     979                 :            :         return krberr;
     980                 :            :     }
     981                 :            : 
     982                 :          0 :     krberr = krb5_cc_cache_match(context, client_principal, _ccache);
     983                 :          0 :     krb5_free_principal(context, client_principal);
     984                 :            :     return krberr;
     985                 :            : }
     986                 :            : 
     987                 :            : errno_t
     988                 :          0 : cc_dir_check_existing(const char *location, uid_t uid,
     989                 :            :                       const char *realm, const char *princ,
     990                 :            :                       const char *cc_template, bool *_active, bool *_valid)
     991                 :            : {
     992                 :          0 :     bool active = false;
     993                 :          0 :     bool valid = false;
     994                 :          0 :     krb5_ccache ccache = NULL;
     995                 :          0 :     krb5_context context = NULL;
     996                 :            :     krb5_error_code krberr;
     997                 :            :     enum sss_krb5_cc_type type;
     998                 :            :     const char *filename;
     999                 :            :     const char *dir;
    1000                 :            :     char *tmp;
    1001                 :            :     errno_t ret;
    1002                 :            : 
    1003                 :          0 :     type = sss_krb5_get_type(location);
    1004         [ #  # ]:          0 :     if (type != SSS_KRB5_TYPE_DIR) {
    1005 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR:\n", location));
         [ #  # ][ #  # ]
                 [ #  # ]
    1006                 :            :         return EINVAL;
    1007                 :            :     }
    1008                 :            : 
    1009                 :          0 :     filename = sss_krb5_cc_file_path(location);
    1010         [ #  # ]:          0 :     if (!filename) {
    1011 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
    1012                 :            :               ("Existing ccname does not contain path into the collection"));
    1013                 :            :         return EINVAL;
    1014                 :            :     }
    1015                 :            : 
    1016         [ #  # ]:          0 :     if (filename[0] != '/') {
    1017 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
    1018                 :            :               ("Only absolute path names are allowed.\n"));
    1019                 :            :         return EINVAL;
    1020                 :            :     }
    1021                 :            : 
    1022                 :          0 :     tmp = talloc_strdup(NULL, filename);
    1023         [ #  # ]:          0 :     if (!tmp) return ENOMEM;
    1024                 :            : 
    1025                 :          0 :     dir = dirname(tmp);
    1026         [ #  # ]:          0 :     if (!dir) {
    1027 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
    1028                 :            :               ("Cannot base get directory of %s\n", location));
    1029                 :            :         return EINVAL;
    1030                 :            :     }
    1031                 :            : 
    1032                 :          0 :     ret = cc_residual_is_used(uid, dir, SSS_KRB5_TYPE_DIR, &active);
    1033                 :          0 :     talloc_free(tmp);
    1034         [ #  # ]:          0 :     if (ret != EOK) {
    1035 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Could not check if ccache is active. "
         [ #  # ][ #  # ]
                 [ #  # ]
    1036                 :            :                                   "Will create a new one.\n"));
    1037                 :          0 :         cc_check_template(cc_template);
    1038                 :          0 :         active = false;
    1039                 :            :     }
    1040                 :            : 
    1041                 :          0 :     krberr = krb5_init_context(&context);
    1042         [ #  # ]:          0 :     if (krberr) {
    1043 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to init kerberos context\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
    1044                 :            :         return EIO;
    1045                 :            :     }
    1046                 :            : 
    1047                 :          0 :     krberr = krb5_cc_resolve(context, location, &ccache);
    1048 [ #  # ][ #  # ]:          0 :     if (krberr == KRB5_FCC_NOFILE || ccache == NULL) {
    1049                 :            :         /* KRB5_FCC_NOFILE would be returned if the directory components
    1050                 :            :          * of the DIR cache do not exist, which is the case in /run
    1051                 :            :          * after a reboot
    1052                 :            :          */
    1053 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_TRACE_FUNC,
         [ #  # ][ #  # ]
                 [ #  # ]
    1054                 :            :               ("ccache %s is missing or empty\n", location));
    1055                 :          0 :         valid = false;
    1056                 :          0 :         ret = EOK;
    1057                 :          0 :         goto done;
    1058         [ #  # ]:          0 :     } else if (krberr != 0) {
    1059 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
         [ #  # ][ #  # ]
                 [ #  # ]
    1060 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
    1061                 :            :         ret = EIO;
    1062                 :            :         goto done;
    1063                 :            :     }
    1064                 :            : 
    1065                 :          0 :     krberr = check_for_valid_tgt(context, ccache, realm, princ, &valid);
    1066         [ #  # ]:          0 :     if (krberr != EOK) {
    1067 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
         [ #  # ][ #  # ]
                 [ #  # ]
    1068 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
    1069                 :            :               ("Could not check if ccache contains a valid principal\n"));
    1070                 :            :         ret = EIO;
    1071                 :            :         goto done;
    1072                 :            :     }
    1073                 :            : 
    1074                 :            :     ret = EOK;
    1075                 :            : done:
    1076         [ #  # ]:          0 :     if (ccache) krb5_cc_close(context, ccache);
    1077                 :          0 :     krb5_free_context(context);
    1078                 :          0 :     *_active = active;
    1079                 :          0 :     *_valid = valid;
    1080                 :            :     return ret;
    1081                 :            : }
    1082                 :            : 
    1083                 :            : const char *
    1084                 :          0 : cc_dir_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
    1085                 :            :                        const char *princ)
    1086                 :            : {
    1087                 :          0 :     krb5_context context = NULL;
    1088                 :            :     krb5_error_code krberr;
    1089                 :          0 :     krb5_ccache ccache = NULL;
    1090                 :            :     char *name;
    1091                 :            :     const char *ccname;
    1092                 :            : 
    1093                 :          0 :     ccname = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_DIR);
    1094         [ #  # ]:          0 :     if (!ccname) {
    1095 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get ccname file from %s\n",
         [ #  # ][ #  # ]
                 [ #  # ]
    1096                 :            :               location));
    1097                 :            :         return NULL;
    1098                 :            :     }
    1099                 :            : 
    1100                 :            :     /* ccname already points to a subsidiary cache */
    1101 [ #  # ][ #  # ]:          0 :     if (ccname[0] == ':' && ccname[1] && ccname[1] == '/') {
                 [ #  # ]
    1102                 :          0 :         return talloc_strdup(mem_ctx, location);
    1103                 :            :     }
    1104                 :            : 
    1105                 :          0 :     krberr = krb5_init_context(&context);
    1106         [ #  # ]:          0 :     if (krberr) {
    1107 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
    1108                 :            :         return NULL;
    1109                 :            :     }
    1110                 :            : 
    1111                 :          0 :     krberr = get_ccache_for_princ(context, location, princ, &ccache);
    1112         [ #  # ]:          0 :     if (krberr) {
    1113 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_TRACE_FUNC, ("No principal for %s in %s\n",
         [ #  # ][ #  # ]
                 [ #  # ]
    1114                 :            :               princ, location));
    1115                 :          0 :         krb5_free_context(context);
    1116                 :            :         return NULL;
    1117                 :            :     }
    1118                 :            : 
    1119                 :          0 :     krberr = krb5_cc_get_full_name(context, ccache, &name);
    1120         [ #  # ]:          0 :     if (ccache) krb5_cc_close(context, ccache);
    1121                 :          0 :     krb5_free_context(context);
    1122         [ #  # ]:          0 :     if (krberr) {
    1123 [ #  # ][ #  # ]:          0 :         KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
         [ #  # ][ #  # ]
                 [ #  # ]
    1124 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("Could not get full name of ccache\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
    1125                 :            :         return NULL;
    1126                 :            :     }
    1127                 :            : 
    1128                 :          0 :     return talloc_strdup(mem_ctx, name);
    1129                 :            : }
    1130                 :            : 
    1131                 :            : errno_t
    1132                 :          0 : cc_dir_remove(const char *location)
    1133                 :            : {
    1134                 :            :     const char *subsidiary;
    1135                 :            : 
    1136         [ #  # ]:          0 :     if (sss_krb5_get_type(location) != SSS_KRB5_TYPE_DIR) {
    1137 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR\n", location));
         [ #  # ][ #  # ]
                 [ #  # ]
    1138                 :            :         return EINVAL;
    1139                 :            :     }
    1140                 :            : 
    1141                 :          0 :     subsidiary = sss_krb5_cc_file_path(location);
    1142         [ #  # ]:          0 :     if (!subsidiary) {
    1143 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get subsidiary cache from %s\n",
         [ #  # ][ #  # ]
                 [ #  # ]
    1144                 :            :               location));
    1145                 :            :         return EINVAL;
    1146                 :            :     }
    1147                 :            : 
    1148                 :          0 :     return cc_file_remove(subsidiary);
    1149                 :            : }
    1150                 :            : 
    1151                 :            : struct sss_krb5_cc_be dir_cc = {
    1152                 :            :     .type               = SSS_KRB5_TYPE_DIR,
    1153                 :            :     .create             = cc_dir_create,
    1154                 :            :     .check_existing     = cc_dir_check_existing,
    1155                 :            :     .ccache_for_princ   = cc_dir_cache_for_princ,
    1156                 :            :     .remove             = cc_dir_remove
    1157                 :            : };
    1158                 :            : 
    1159                 :            : #endif /* HAVE_KRB5_DIRCACHE */
    1160                 :            : 
    1161                 :          0 : errno_t get_domain_or_subdomain(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
    1162                 :            :                                 char *domain_name,
    1163                 :            :                                 struct sss_domain_info **dom)
    1164                 :            : {
    1165                 :            : 
    1166 [ #  # ][ #  # ]:          0 :     if (domain_name != NULL &&
    1167                 :          0 :         strcasecmp(domain_name, be_ctx->domain->name) != 0) {
    1168                 :          0 :         *dom = new_subdomain(mem_ctx, be_ctx->domain, domain_name, NULL, NULL);
    1169         [ #  # ]:          0 :         if (*dom == NULL) {
    1170 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_OP_FAILURE, ("new_subdomain failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
    1171                 :            :             return ENOMEM;
    1172                 :            :         }
    1173                 :            :     } else {
    1174                 :          0 :         *dom = be_ctx->domain;
    1175                 :            :     }
    1176                 :            : 
    1177                 :            :     return EOK;
    1178                 :            : }

Generated by: LCOV version 1.9