LCOV - code coverage report
Current view: top level - tests - krb5_child-test.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 242 0.0 %
Date: 2015-10-19 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Unit tests - exercise the krb5 child
       5             : 
       6             :     Authors:
       7             :         Jakub Hrozek <jhrozek@redhat.com>
       8             : 
       9             :     Copyright (C) 2012 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             : 
      25             : #include <stdio.h>
      26             : #include <stdlib.h>
      27             : #include <talloc.h>
      28             : #include <popt.h>
      29             : #include <errno.h>
      30             : #include <unistd.h>
      31             : #include <limits.h>
      32             : 
      33             : #include "util/util.h"
      34             : #include "src/tools/tools_util.h"
      35             : 
      36             : /* Interfaces being tested */
      37             : #include "providers/krb5/krb5_auth.h"
      38             : #include "providers/krb5/krb5_common.h"
      39             : #include "providers/krb5/krb5_utils.h"
      40             : #include "providers/krb5/krb5_ccache.h"
      41             : 
      42             : extern struct dp_option default_krb5_opts[];
      43             : 
      44             : static krb5_context krb5_error_ctx;
      45             : #define KRB5_CHILD_TEST_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
      46             : 
      47             : #define CHECK_KRET_L(kret, err, label) do {     \
      48             :     if (kret) {                                 \
      49             :         KRB5_CHILD_TEST_DEBUG(SSSDBG_OP_FAILURE, kret);    \
      50             :         goto label;                             \
      51             :     }                                           \
      52             : } while(0)                                      \
      53             : 
      54             : struct krb5_child_test_ctx {
      55             :     struct tevent_context *ev;
      56             :     struct krb5child_req *kr;
      57             : 
      58             :     bool done;
      59             :     errno_t child_ret;
      60             : 
      61             :     uint8_t *buf;
      62             :     ssize_t len;
      63             :     struct krb5_child_response *res;
      64             : };
      65             : 
      66             : static errno_t
      67           0 : setup_krb5_child_test(TALLOC_CTX *mem_ctx, struct krb5_child_test_ctx **_ctx)
      68             : {
      69             :     struct krb5_child_test_ctx *ctx;
      70             : 
      71           0 :     ctx = talloc_zero(mem_ctx, struct krb5_child_test_ctx);
      72           0 :     if (!ctx) return ENOMEM;
      73             : 
      74           0 :     ctx->ev = tevent_context_init(ctx);
      75           0 :     if (ctx->ev == NULL) {
      76           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tevent context\n");
      77           0 :         talloc_free(ctx);
      78           0 :         return EFAULT;
      79             :     }
      80             : 
      81           0 :     *_ctx = ctx;
      82           0 :     return EOK;
      83             : }
      84             : 
      85           0 : int re_destructor(void *memctx)
      86             : {
      87           0 :     struct krb5_ctx *ctx = (struct krb5_ctx *) memctx;
      88             : 
      89           0 :     if (ctx->illegal_path_re) {
      90           0 :         pcre_free(ctx->illegal_path_re);
      91           0 :         ctx->illegal_path_re = NULL;
      92             :     }
      93           0 :     return 0;
      94             : }
      95             : 
      96             : static struct krb5_ctx *
      97           0 : create_dummy_krb5_ctx(TALLOC_CTX *mem_ctx, const char *realm)
      98             : {
      99             :     struct krb5_ctx *krb5_ctx;
     100             :     const char *errstr;
     101             :     int errval;
     102             :     int errpos;
     103             :     int i;
     104             :     errno_t ret;
     105             : 
     106           0 :     krb5_ctx = talloc_zero(mem_ctx, struct krb5_ctx);
     107           0 :     if (!krb5_ctx) return NULL;
     108             : 
     109           0 :     krb5_ctx->illegal_path_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
     110             :                                         &errval, &errstr, &errpos, NULL);
     111           0 :     if (krb5_ctx->illegal_path_re == NULL) {
     112           0 :         DEBUG(SSSDBG_OP_FAILURE,
     113             :               "Invalid Regular Expression pattern at position %d. "
     114             :                "(Error: %d [%s])\n", errpos, errval, errstr);
     115           0 :         goto fail;
     116             :     }
     117           0 :     talloc_set_destructor((TALLOC_CTX *) krb5_ctx, re_destructor);
     118             : 
     119             :     /* Kerberos options */
     120           0 :     krb5_ctx->opts = talloc_zero_array(krb5_ctx, struct dp_option, KRB5_OPTS);
     121           0 :     if (!krb5_ctx->opts) goto fail;
     122           0 :     for (i = 0; i < KRB5_OPTS; i++) {
     123           0 :         krb5_ctx->opts[i].opt_name = default_krb5_opts[i].opt_name;
     124           0 :         krb5_ctx->opts[i].type = default_krb5_opts[i].type;
     125           0 :         krb5_ctx->opts[i].def_val = default_krb5_opts[i].def_val;
     126           0 :         switch (krb5_ctx->opts[i].type) {
     127             :             case DP_OPT_STRING:
     128           0 :                 ret = dp_opt_set_string(krb5_ctx->opts, i,
     129             :                                         default_krb5_opts[i].def_val.string);
     130           0 :                 break;
     131             :             case DP_OPT_BLOB:
     132           0 :                 ret = dp_opt_set_blob(krb5_ctx->opts, i,
     133             :                                       default_krb5_opts[i].def_val.blob);
     134           0 :                 break;
     135             :             case DP_OPT_NUMBER:
     136           0 :                 ret = dp_opt_set_int(krb5_ctx->opts, i,
     137             :                                      default_krb5_opts[i].def_val.number);
     138           0 :                 break;
     139             :             case DP_OPT_BOOL:
     140           0 :                 ret = dp_opt_set_bool(krb5_ctx->opts, i,
     141             :                                       default_krb5_opts[i].def_val.boolean);
     142           0 :                 break;
     143             :         }
     144           0 :         if (ret) goto fail;
     145             :     }
     146             : 
     147           0 :     ret = dp_opt_set_string(krb5_ctx->opts, KRB5_REALM, realm);
     148           0 :     if (ret) goto fail;
     149             : 
     150           0 :     return krb5_ctx;
     151             : 
     152             : fail:
     153           0 :     talloc_free(krb5_ctx);
     154           0 :     return NULL;
     155             : }
     156             : 
     157             : static struct pam_data *
     158           0 : create_dummy_pam_data(TALLOC_CTX *mem_ctx, const char *user,
     159             :                       const char *password)
     160             : {
     161             :     struct pam_data *pd;
     162             :     const char *authtok;
     163             :     size_t authtok_len;
     164             :     errno_t ret;
     165             : 
     166           0 :     pd = create_pam_data(mem_ctx);
     167           0 :     if (!pd) goto fail;
     168             : 
     169           0 :     pd->cmd = SSS_PAM_AUTHENTICATE;
     170           0 :     pd->user = talloc_strdup(pd, user);
     171           0 :     if (!pd->user) goto fail;
     172             : 
     173           0 :     ret = sss_authtok_set_password(pd->authtok, password, 0);
     174           0 :     if (ret) goto fail;
     175             : 
     176           0 :     (void)sss_authtok_get_password(pd->authtok, &authtok, &authtok_len);
     177           0 :     DEBUG(SSSDBG_FUNC_DATA, "Authtok [%s] len [%d]\n",
     178             :                              authtok, (int)authtok_len);
     179             : 
     180           0 :     return pd;
     181             : 
     182             : fail:
     183           0 :     talloc_free(pd);
     184           0 :     return NULL;
     185             : }
     186             : 
     187             : static struct krb5child_req *
     188           0 : create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
     189             :                  const char *password, const char *realm,
     190             :                  const char *ccname, const char *ccname_template,
     191             :                  int timeout)
     192             : {
     193             :     struct krb5child_req *kr;
     194             :     struct passwd *pwd;
     195             :     errno_t ret;
     196             : 
     197             :     /* The top level child request */
     198           0 :     kr = talloc_zero(mem_ctx, struct krb5child_req);
     199           0 :     if (!kr) return NULL;
     200             : 
     201           0 :     pwd = getpwnam(user);
     202           0 :     if (!pwd) {
     203           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     204             :               "Cannot get info on user [%s]\n", user);
     205           0 :         goto fail;
     206             :     }
     207             : 
     208           0 :     kr->uid = pwd->pw_uid;
     209           0 :     kr->gid = pwd->pw_gid;
     210             : 
     211             :     /* The Kerberos context */
     212           0 :     kr->krb5_ctx = create_dummy_krb5_ctx(kr, realm);
     213             :     /* PAM Data structure */
     214           0 :     kr->pd = create_dummy_pam_data(kr, user, password);
     215             : 
     216           0 :     ret = krb5_get_simple_upn(kr, kr->krb5_ctx, NULL, kr->pd->user, NULL,
     217             :                               &kr->upn);
     218           0 :     if (ret != EOK) {
     219           0 :         DEBUG(SSSDBG_OP_FAILURE, "krb5_get_simple_upn failed.\n");
     220           0 :         goto fail;
     221             :     }
     222             : 
     223             :     /* Override options with what was provided by the user */
     224           0 :     if (ccname_template) {
     225           0 :         ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL,
     226             :                                 ccname_template);
     227           0 :         if (ret != EOK) goto fail;
     228             :     }
     229             : 
     230           0 :     if (timeout) {
     231           0 :         ret = dp_opt_set_int(kr->krb5_ctx->opts, KRB5_AUTH_TIMEOUT, timeout);
     232           0 :         if (ret != EOK) {
     233           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set value for krb5_auth_timeout\n");
     234           0 :             goto fail;
     235             :         }
     236             :     }
     237             : 
     238           0 :     if (!ccname) {
     239           0 :         kr->ccname = expand_ccname_template(kr, kr,
     240           0 :                                         dp_opt_get_cstring(kr->krb5_ctx->opts,
     241             :                                                            KRB5_CCNAME_TMPL),
     242           0 :                                             kr->krb5_ctx->illegal_path_re, true, true);
     243           0 :         if (!kr->ccname) goto fail;
     244             : 
     245           0 :         DEBUG(SSSDBG_FUNC_DATA, "ccname [%s] uid [%llu] gid [%llu]\n",
     246             :               kr->ccname, (unsigned long long) kr->uid,
     247             :               (unsigned long long) kr->gid);
     248             :     } else {
     249           0 :         kr->ccname = talloc_strdup(kr, ccname);
     250             :     }
     251           0 :     if (!kr->ccname) goto fail;
     252             : 
     253           0 :     DEBUG(SSSDBG_FUNC_DATA, "ccname [%s] uid [%u] gid [%u]\n",
     254             :             kr->ccname, kr->uid, kr->gid);
     255             : 
     256           0 :     ret = sss_krb5_precreate_ccache(kr->ccname,
     257             :                                     kr->uid, kr->gid);
     258           0 :     if (ret != EOK) {
     259           0 :         DEBUG(SSSDBG_OP_FAILURE, "create_ccache_dir failed.\n");
     260           0 :         goto fail;
     261             :     }
     262             : 
     263           0 :     return kr;
     264             : 
     265             : fail:
     266           0 :     talloc_free(kr);
     267           0 :     return NULL;
     268             : }
     269             : 
     270             : static void
     271           0 : child_done(struct tevent_req *req)
     272             : {
     273           0 :     struct krb5_child_test_ctx *ctx = tevent_req_callback_data(req,
     274             :                                     struct krb5_child_test_ctx);
     275             :     errno_t ret;
     276             : 
     277           0 :     ret = handle_child_recv(req, ctx, &ctx->buf, &ctx->len);
     278           0 :     talloc_free(req);
     279           0 :     ctx->done = true;
     280           0 :     ctx->child_ret = ret;
     281           0 : }
     282             : 
     283             : static void
     284           0 : printtime(krb5_timestamp ts)
     285             : {
     286             :     krb5_error_code kret;
     287             :     char timestring[BUFSIZ];
     288           0 :     char fill = '\0';
     289             : 
     290             : #ifdef HAVE_KRB5_TIMESTAMP_TO_SFSTRING
     291           0 :     kret = krb5_timestamp_to_sfstring(ts, timestring, BUFSIZ, &fill);
     292           0 :     if (kret) {
     293           0 :         KRB5_CHILD_TEST_DEBUG(SSSDBG_OP_FAILURE, kret);
     294             :     }
     295           0 :     printf("%s", timestring);
     296             : #else
     297             :     printf("%s", ctime(&ts));
     298             : #endif /* HAVE_KRB5_TIMESTAMP_TO_SFSTRING */
     299           0 : }
     300             : 
     301             : static void
     302           0 : print_creds(krb5_context kcontext, krb5_creds *cred, const char *defname)
     303             : {
     304             :     krb5_error_code kret;
     305           0 :     char *name = NULL;
     306           0 :     char *sname = NULL;
     307             : 
     308           0 :     kret = krb5_unparse_name(kcontext, cred->client, &name);
     309           0 :     CHECK_KRET_L(kret, EIO, done);
     310             : 
     311           0 :     kret = krb5_unparse_name(kcontext, cred->server, &sname);
     312           0 :     CHECK_KRET_L(kret, EIO, done);
     313             : 
     314           0 :     if (!cred->times.starttime) {
     315           0 :         cred->times.starttime = cred->times.authtime;
     316             :     }
     317             : 
     318             : 
     319           0 :     printf("\t\t%s\n", sname);
     320           0 :     printf("\t\tValid from\t");  printtime(cred->times.starttime);
     321           0 :     printf("\n\t\tValid until\t"); printtime(cred->times.endtime);
     322           0 :     printf("\n");
     323             : 
     324           0 :     if (strcmp(name, defname)) {
     325           0 :         printf("\t\tfor client %s", name);
     326             :     }
     327             : 
     328             : done:
     329           0 :     krb5_free_unparsed_name(kcontext, name);
     330           0 :     krb5_free_unparsed_name(kcontext, sname);
     331           0 : }
     332             : 
     333             : static errno_t
     334           0 : print_ccache(const char *cc)
     335             : {
     336             :     krb5_cc_cursor cur;
     337           0 :     krb5_ccache cache = NULL;
     338             :     krb5_error_code kret;
     339           0 :     krb5_context kcontext = NULL;
     340           0 :     krb5_principal_data *princ = NULL;
     341             :     krb5_creds creds;
     342           0 :     char *defname = NULL;
     343           0 :     int i = 1;
     344           0 :     errno_t ret = EIO;
     345             : 
     346           0 :     kret = krb5_init_context(&kcontext);
     347           0 :     CHECK_KRET_L(kret, EIO, done);
     348             : 
     349           0 :     kret = krb5_cc_resolve(kcontext, cc, &cache);
     350           0 :     CHECK_KRET_L(kret, EIO, done);
     351             : 
     352           0 :     kret = krb5_cc_get_principal(kcontext, cache, &princ);
     353           0 :     CHECK_KRET_L(kret, EIO, done);
     354             : 
     355           0 :     kret = krb5_unparse_name(kcontext, princ, &defname);
     356           0 :     CHECK_KRET_L(kret, EIO, done);
     357             : 
     358           0 :     printf("\nTicket cache: %s:%s\nDefault principal: %s\n\n",
     359             :            krb5_cc_get_type(kcontext, cache),
     360             :            krb5_cc_get_name(kcontext, cache), defname);
     361             : 
     362           0 :     kret = krb5_cc_start_seq_get(kcontext, cache, &cur);
     363           0 :     CHECK_KRET_L(kret, EIO, done);
     364             : 
     365           0 :     while (!(kret = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
     366           0 :         printf("Ticket #%d:\n", i);
     367           0 :         print_creds(kcontext, &creds, defname);
     368           0 :         krb5_free_cred_contents(kcontext, &creds);
     369             :     }
     370             : 
     371           0 :     kret = krb5_cc_end_seq_get(kcontext, cache, &cur);
     372           0 :     CHECK_KRET_L(kret, EIO, done);
     373             : 
     374           0 :     ret = EOK;
     375             : done:
     376           0 :     krb5_cc_close(kcontext, cache);
     377           0 :     krb5_free_unparsed_name(kcontext, defname);
     378           0 :     krb5_free_principal(kcontext, princ);
     379           0 :     krb5_free_context(kcontext);
     380           0 :     return ret;
     381             : }
     382             : 
     383             : int
     384           0 : main(int argc, const char *argv[])
     385             : {
     386             :     int opt;
     387             :     errno_t ret;
     388           0 :     struct krb5_child_test_ctx *ctx = NULL;
     389             :     struct tevent_req *req;
     390             : 
     391           0 :     int pc_debug = 0;
     392           0 :     int pc_timeout = 0;
     393           0 :     const char *pc_user = NULL;;
     394           0 :     const char *pc_passwd = NULL;;
     395           0 :     const char *pc_realm = NULL;;
     396           0 :     const char *pc_ccname = NULL;;
     397           0 :     const char *pc_ccname_tp = NULL;;
     398           0 :     char *password = NULL;
     399           0 :     bool rm_ccache = true;
     400             : 
     401             :     poptContext pc;
     402           0 :     struct poptOption long_options[] = {
     403             :         POPT_AUTOHELP
     404             :         { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0,
     405             :           "The debug level to run with", NULL },
     406             :         { "user", 'u', POPT_ARG_STRING, &pc_user, 0,
     407             :           "The user to log in as", NULL },
     408             :         { "password", 'w', POPT_ARG_STRING, &pc_passwd, 0,
     409             :           "The authtok to use", NULL },
     410             :         { "ask-password", 'W', POPT_ARG_NONE, NULL, 'W',
     411             :           "Ask interactively for authtok", NULL },
     412             :         { "ccname", 'c', POPT_ARG_STRING, &pc_ccname, 0,
     413             :            "Force usage of a certain credential cache", NULL },
     414             :         { "ccname-template", 't', POPT_ARG_STRING, &pc_ccname_tp, 0,
     415             :            "Specify the credential cache template", NULL },
     416             :         { "realm", 'r', POPT_ARG_STRING, &pc_realm, 0,
     417             :           "The Kerberos realm to use", NULL },
     418             :         { "keep-ccache", 'k', POPT_ARG_NONE, NULL, 'k',
     419             :           "Do not delete the ccache when the tool finishes", NULL },
     420             :         { "timeout", '\0', POPT_ARG_INT, &pc_timeout, 0,
     421             :           "The timeout for the child, in seconds", NULL },
     422             :         POPT_TABLEEND
     423             :     };
     424             : 
     425           0 :     debug_prg_name = argv[0];
     426           0 :     pc = poptGetContext(NULL, argc, argv, long_options, 0);
     427             : 
     428           0 :     while ((opt = poptGetNextOpt(pc)) > 0) {
     429           0 :         switch(opt) {
     430             :         case 'W':
     431           0 :             errno = 0;
     432           0 :             password = getpass("Enter password:");
     433           0 :             if (!password) {
     434           0 :                 return 1;
     435             :             }
     436           0 :             break;
     437             :         case 'k':
     438           0 :             rm_ccache = false;
     439           0 :             break;
     440             :         default:
     441           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected option\n");
     442           0 :             return 1;
     443             :         }
     444             :     }
     445             : 
     446           0 :     DEBUG_CLI_INIT(pc_debug);
     447             : 
     448           0 :     if (opt != -1) {
     449           0 :         poptPrintUsage(pc, stderr, 0);
     450           0 :         fprintf(stderr, "%s", poptStrerror(opt));
     451           0 :         return 1;
     452             :     }
     453             : 
     454           0 :     if (!pc_user) {
     455           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Please specify the user\n");
     456           0 :         poptPrintUsage(pc, stderr, 0);
     457           0 :         return 1;
     458             :     }
     459             : 
     460           0 :     if (!pc_realm) {
     461           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Please specify the realm\n");
     462           0 :         poptPrintUsage(pc, stderr, 0);
     463           0 :         return 1;
     464             :     }
     465             : 
     466           0 :     if (!password && !pc_passwd) {
     467           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     468             :               "Password was not provided or asked for\n");
     469           0 :         poptPrintUsage(pc, stderr, 0);
     470           0 :         return 1;
     471             :     }
     472             : 
     473           0 :     if (pc_ccname && pc_ccname_tp) {
     474           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     475             :               "Both ccname and ccname template specified, "
     476             :                "will prefer ccname\n");
     477             :     }
     478             : 
     479           0 :     ret = setup_krb5_child_test(NULL, &ctx);
     480           0 :     if (ret != EOK) {
     481           0 :         poptPrintUsage(pc, stderr, 0);
     482           0 :         fprintf(stderr, "%s", poptStrerror(opt));
     483           0 :         return 3;
     484             :     }
     485             : 
     486           0 :     ctx->kr = create_dummy_req(ctx, pc_user, password ? password : pc_passwd,
     487             :                                pc_realm, pc_ccname, pc_ccname_tp, pc_timeout);
     488           0 :     if (!ctx->kr) {
     489           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Cannot create Kerberos request\n");
     490           0 :         ret = 4;
     491           0 :         goto done;
     492             :     }
     493             : 
     494           0 :     req = handle_child_send(ctx, ctx->ev, ctx->kr);
     495           0 :     if (!req) {
     496           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Cannot create child request\n");
     497           0 :         ret = 4;
     498           0 :         goto done;
     499             :     }
     500           0 :     tevent_req_set_callback(req, child_done, ctx);
     501             : 
     502           0 :     while (ctx->done == false) {
     503           0 :          tevent_loop_once(ctx->ev);
     504             :     }
     505             : 
     506           0 :     printf("Child returned %d\n", ctx->child_ret);
     507             : 
     508           0 :     ret = parse_krb5_child_response(ctx, ctx->buf, ctx->len,
     509           0 :                                     ctx->kr->pd, 0, &ctx->res);
     510           0 :     if (ret != EOK) {
     511           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Could not parse child response\n");
     512           0 :         ret = 5;
     513           0 :         goto done;
     514             :     }
     515             : 
     516           0 :     if (!ctx->res->ccname) {
     517           0 :         fprintf(stderr, "No ccname returned\n");
     518           0 :         ret = 6;
     519           0 :         goto done;
     520             :     }
     521             : 
     522           0 :     print_ccache(ctx->res->ccname);
     523             : 
     524           0 :     ret = 0;
     525             : done:
     526           0 :     if (rm_ccache && ctx->res
     527           0 :             && ctx->res->ccname
     528           0 :             && ctx->kr) {
     529           0 :         sss_krb5_cc_destroy(ctx->res->ccname, ctx->kr->uid, ctx->kr->gid);
     530             :     }
     531           0 :     free(password);
     532           0 :     talloc_free(ctx);
     533           0 :     poptFreeContext(pc);
     534           0 :     return ret;
     535             : }

Generated by: LCOV version 1.10