krb5_child.c revision d6c2ee96f5f181f21b0003aa8f3506e82522291d
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose Kerberos 5 Backend Module -- tgt_req and changepw child
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose Sumit Bose <sbose@redhat.com>
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose Copyright (C) 2009-2010 Red Hat
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose This program is free software; you can redistribute it and/or modify
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose it under the terms of the GNU General Public License as published by
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose the Free Software Foundation; either version 3 of the License, or
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose (at your option) any later version.
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose This program is distributed in the hope that it will be useful,
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose but WITHOUT ANY WARRANTY; without even the implied warranty of
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose GNU General Public License for more details.
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose You should have received a copy of the GNU General Public License
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose along with this program. If not, see <http://www.gnu.org/licenses/>.
5e60c73cb91d1659755fb5ea829837db68d46163Sumit Bose#define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const char *upn;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny#define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenystatic krb5_error_code get_changepw_options(krb5_context ctx,
87ed72b47859e673b636c85f35b85f1546c7ed3dSimo Sorce kerr = sss_krb5_get_init_creds_opt_alloc(ctx, &options);
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorce sss_krb5_get_init_creds_opt_set_canonicalize(options, 0);
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose krb5_get_init_creds_opt_set_forwardable(options, 0);
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose krb5_get_init_creds_opt_set_proxiable(options, 0);
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose krb5_get_init_creds_opt_set_renew_life(options, 0);
87ed72b47859e673b636c85f35b85f1546c7ed3dSimo Sorce krb5_get_init_creds_opt_set_tkt_life(options, 5*60);
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bosestatic errno_t sss_send_pac(krb5_authdata **pac_authdata)
b1829e54acbc8a010aca7f14b9ffa9625f8c102cSumit Bose ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
b1829e54acbc8a010aca7f14b9ffa9625f8c102cSumit Bose DEBUG(SSSDBG_OP_FAILURE, ("sss_pac_make_request failed [%d][%d].\n",
d2a8b08561e6700bdd4feb988becae4e8f5368ddJakub Hrozekstatic void sss_krb5_expire_callback_func(krb5_context context, void *data,
4fa184e2c60b377fd71e0115a618bd68dc73627dSumit Bose struct krb5_req *kr = talloc_get_type(data, struct krb5_req);
d2a8b08561e6700bdd4feb988becae4e8f5368ddJakub Hrozek DEBUG(SSSDBG_TRACE_INTERNAL, ("exp_time: [%d]\n", exp_time));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov blob = talloc_array(kr->pd, uint32_t, 2);
d2a8b08561e6700bdd4feb988becae4e8f5368ddJakub Hrozek ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t),
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose * TODO: These features generally would requires a significant refactoring
096a9678919fae460342469989b97fd47d812823Sumit Bose * of SSSD and MIT krb5 doesn't support them anyway. They are listed here
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose * simply as a reminder of things that might become future feature potential.
096a9678919fae460342469989b97fd47d812823Sumit Bose * 1. tokeninfo selection
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose * 2. challenge
096a9678919fae460342469989b97fd47d812823Sumit Bose * 3. discreet token/pin prompting
096a9678919fae460342469989b97fd47d812823Sumit Bose * 4. interactive otp format correction
096a9678919fae460342469989b97fd47d812823Sumit Bose * 5. nextOTP
096a9678919fae460342469989b97fd47d812823Sumit Bosetypedef int (*checker)(int c);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov case KRB5_RESPONDER_OTP_FORMAT_ALPHANUMERIC:
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic int token_pin_destructor(char *mem)
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bosestatic krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx,
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_NEXTOTP) {
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* This is a non-sensical value. */
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_COLLECT_TOKEN) {
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* ASSUMPTION: authtok has one of the following formats:
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose * 1. TokenValue
096a9678919fae460342469989b97fd47d812823Sumit Bose * 2. PIN+TokenValue
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov token = talloc_strndup(mem_ctx, pwd, len);
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose talloc_set_destructor(token, token_pin_destructor);
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_COLLECT_PIN) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* If the server desires a separate pin, we will split it.
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose * ASSUMPTION: Format of authtok is PIN+TokenValue. */
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_SEPARATE_PIN) {
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* Copy the PIN from the front of the value. */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov pin = talloc_strndup(NULL, pwd, len - ti->length);
5e60c73cb91d1659755fb5ea829837db68d46163Sumit Bose talloc_set_destructor(pin, token_pin_destructor);
096a9678919fae460342469989b97fd47d812823Sumit Bose /* Remove the PIN from the front of the token value. */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov memmove(token, token + len - ti->length, ti->length + 1);
096a9678919fae460342469989b97fd47d812823Sumit Bose talloc_set_destructor(pin, token_pin_destructor);
096a9678919fae460342469989b97fd47d812823Sumit Bose /* If check is set, we need to verify the contents of the token. */
096a9678919fae460342469989b97fd47d812823Sumit Bose for (i = 0; check != NULL && token[i] != '\0'; i++) {
096a9678919fae460342469989b97fd47d812823Sumit Bosestatic krb5_error_code answer_otp(krb5_context ctx,
096a9678919fae460342469989b97fd47d812823Sumit Bose ret = krb5_responder_otp_get_challenge(ctx, rctx, &chl);
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* Either an error, or nothing to do. */
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose if (chl->tokeninfo == NULL || chl->tokeninfo[0] == NULL) {
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* No tokeninfos? Absurd! */
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* Validate our assumptions about the contents of authtok. */
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose ret = sss_authtok_get_password(kr->pd->authtok, &pwd, &len);
31dd31b00ad759f256282ef0f7054e60672161ceJakub Hrozek /* Find the first supported tokeninfo which matches our authtoken. */
31dd31b00ad759f256282ef0f7054e60672161ceJakub Hrozek ret = tokeninfo_matches(kr, chl->tokeninfo[i], pwd, len, &token, &pin);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ("No tokeninfos found which match our credentials.\n"));
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (chl->tokeninfo[i]->flags & KRB5_RESPONDER_OTP_FLAGS_COLLECT_TOKEN) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose /* Don't let SSSD cache the OTP authtok since it is single-use. */
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ret = pam_add_response(kr->pd, SSS_OTP, 0, NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose /* Respond with the appropriate answer. */
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek ret = krb5_responder_otp_set_answer(ctx, rctx, i, token, pin);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose krb5_responder_otp_challenge_free(ctx, rctx, chl);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic krb5_error_code sss_krb5_responder(krb5_context ctx,
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose struct krb5_req *kr = talloc_get_type(data, struct krb5_req);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bosestatic krb5_error_code sss_krb5_prompter(krb5_context context, void *data,
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek struct krb5_req *kr = talloc_get_type(data, struct krb5_req);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek DEBUG(1, ("Cannot handle password prompts.\n"));
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek DEBUG(5, ("Prompter called with empty banner, nothing to do.\n"));
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek DEBUG(SSSDBG_FUNC_DATA, ("Prompter called with [%s].\n", banner));
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek ret = pam_add_response(kr->pd, SSS_PAM_TEXT_MSG, strlen(banner)+1,
81165faf5d951aca69f410713730c26ff048ec44Sumit Bosestatic krb5_error_code create_empty_cred(krb5_context ctx, krb5_principal princ,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce kerr = krb5_copy_principal(ctx, princ, &cred->client);
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose kerr = krb5_build_principal_ext(ctx, &cred->server,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov krb5_realm->length, krb5_realm->data, 0);
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce DEBUG(1, ("krb5_build_principal_ext failed.\n"));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_TRACE_INTERNAL, ("Created empty krb5_creds.\n"));
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozekstatic bool need_switch_to_principal(krb5_context ctx, krb5_principal princ)
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek bool ret = false;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov kerr = krb5_cc_get_principal(ctx, default_cc, &default_princ);
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce /* There is not any default cache. */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce } else if (kerr != 0) {
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek kerr = krb5_unparse_name(ctx, default_princ, &default_full_name);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek kerr = krb5_unparse_name(ctx, princ, &full_name);
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek ("Comparing default principal [%s] and new principal [%s].\n",
05d935cc9d04f03522d0bb44598d22d99b085926Jakub Hrozek if (0 == strcmp(default_full_name, full_name)) {
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce /* all functions can be safely called with NULL. */
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce#endif /* HAVE_KRB5_DIRCACHE */
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorcestore_creds_in_ccache(krb5_context ctx, krb5_principal princ,
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce#endif /* HAVE_KRB5_DIRCACHE */
81165faf5d951aca69f410713730c26ff048ec44Sumit Bosestatic krb5_error_code create_ccache_file(krb5_context ctx,
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_FUNC_DATA, ("Creating ccache at [%s]\n", ccname));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(1, ("Ccache filename is not an absolute path.\n"));
ad9ca94d0c793c2e30e77f4cc385bf10e42e382fJakub Hrozek tmp_ccname = talloc_strndup(tmp_ctx, cc_file_name,
5ea449b18d2597f2581627de80bcaf2bc70b0fd3Simo Sorce tmp_ccname = talloc_asprintf_append(tmp_ccname, "/.krb5cc_dummy_XXXXXX");
5e60c73cb91d1659755fb5ea829837db68d46163Sumit Bose ("mkstemp failed [%d][%s].\n", kerr, strerror(kerr)));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose kerr = krb5_cc_resolve(ctx, tmp_ccname, &tmp_cc);
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose kerr = store_creds_in_ccache(ctx, princ, tmp_cc, creds);
4c20fe34346919cf676c3e1b54b7701069e2aac6Simo Sorce if (ccname_len >= 6 && strcmp(cc_file_name + (ccname_len - 6), "XXXXXX") == 0) {
dcb44c39dda9699cdd6488fd116a51ced0687de3Jakub Hrozek ("mkstemp failed [%d][%s].\n", kerr, strerror(kerr)));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(1, ("rename failed [%d][%s].\n", kerr, strerror(kerr)));
4c20fe34346919cf676c3e1b54b7701069e2aac6Simo Sorce DEBUG(SSSDBG_TRACE_LIBS, ("Created ccache file: [%s]\n", ccname));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bosecreate_ccdir(const char *dirname, uid_t uid, gid_t gid)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* Failing the mkdir is only OK if the directory already
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov * exists AND it is owned by the same user and group and
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose * has the correct permissions.
ad9ca94d0c793c2e30e77f4cc385bf10e42e382fJakub Hrozek ("stat failed [%d]: %s\n", ret, strerror(ret)));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose if (statbuf.st_uid != uid || statbuf.st_gid != gid) {
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose ("The directory %s is owned by %d/%d, expected %d/%d\n",
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose dirname, statbuf.st_uid, statbuf.st_gid, uid, gid));
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ("The directory %s has wrong permissions %o, expected 0700\n",
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("mkdir [%s] failed [%d]: %s\n",
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_FUNC_DATA, ("Creating ccache at [%s]\n", ccname));
6a81cb8c3424dbe9f764af3738299cbbe5874a15Simo Sorce dirname = sss_krb5_residual_check_type(ccname, SSS_KRB5_TYPE_DIR);
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("become_user failed.\n"));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose /* Cache name in the form of DIR::filepath represents a single
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * ccache in a collection that we are trying to reuse.
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose * See src/lib/krb5/ccache/cc_dir.c in the MIT Kerberos tree.
ad9ca94d0c793c2e30e77f4cc385bf10e42e382fJakub Hrozek /* An absolute path denotes that krb5_child should create a new
ad9ca94d0c793c2e30e77f4cc385bf10e42e382fJakub Hrozek * ccache. We can afford to just call mkdir(dirname) because we
ad9ca94d0c793c2e30e77f4cc385bf10e42e382fJakub Hrozek * only want the last component to be created.
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose kerr = krb5_cc_new_unique(ctx, "DIR", NULL, &tmp_cc);
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose ("Wrong residual format for DIR in ccache %s\n", ccname));
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose kerr = store_creds_in_ccache(ctx, princ, tmp_cc, creds);
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose#endif /* HAVE_KRB5_DIRCACHE */
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bosecreate_ccache(uid_t uid, gid_t gid, krb5_context ctx,
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose krb5_principal princ, char *ccname, krb5_creds *creds)
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose return create_ccache_file(ctx, princ, ccname, creds);
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose return create_ccache_in_dir(uid, gid, ctx, princ, ccname, creds);
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose#endif /* HAVE_KRB5_DIRCACHE */
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown cache type\n"));
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bosestatic errno_t pack_response_packet(TALLOC_CTX *mem_ctx, errno_t error,
a50b229c8ea1e22c9efa677760b94d8c48c3ec89Sumit Bose /* A buffer with the following structure must be created:
a50b229c8ea1e22c9efa677760b94d8c48c3ec89Sumit Bose * int32_t status of the request (required)
a50b229c8ea1e22c9efa677760b94d8c48c3ec89Sumit Bose * message (zero or more)
44329653f423c632b027065a9c0ea0bf4199396aSumit Bose * A message consists of:
44329653f423c632b027065a9c0ea0bf4199396aSumit Bose * int32_t type of the message
44329653f423c632b027065a9c0ea0bf4199396aSumit Bose * int32_t length of the following data
44329653f423c632b027065a9c0ea0bf4199396aSumit Bose * uint8_t[len] data
44329653f423c632b027065a9c0ea0bf4199396aSumit Bose for (pdr = resp_list; pdr != NULL; pdr = pdr->next) {
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose DEBUG(1, ("Insufficient memory to create message.\n"));
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose for (pdr = resp_list; pdr != NULL; pdr = pdr->next) {
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose safealign_memcpy(&buf[p], pdr->data, pdr->len, &p);
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose DEBUG(SSSDBG_TRACE_INTERNAL, ("response packet size: [%d]\n", p));
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bosestatic errno_t k5c_attach_ccname_msg(struct krb5_req *kr)
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose msg = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, kr->ccname);
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bosestatic errno_t k5c_send_data(struct krb5_req *kr, int fd, errno_t error)
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bose ret = pack_response_packet(kr, error, kr->pd->resp_list, &buf, &len);
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bose ("write failed [%d][%s].\n", ret, strerror(ret)));
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bose ("Write error, wrote [%d] bytes, expected [%d]\n",
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bosestatic errno_t add_ticket_times_and_upn_to_response(struct krb5_req *kr)
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose unsigned int upn_len = 0;
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose ret = pam_add_response(kr->pd, SSS_KRB5_INFO_TGT_LIFETIME,
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bose kerr = krb5_unparse_name_ext(kr->ctx, kr->creds->client, &upn, &upn_len);
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose DEBUG(SSSDBG_OP_FAILURE, ("krb5_unparse_name failed.\n"));
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose ret = pam_add_response(kr->pd, SSS_KRB5_INFO_UPN, upn_len,
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bosestatic krb5_error_code validate_tgt(struct krb5_req *kr)
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bose kerr = krb5_kt_resolve(kr->ctx, kr->keytab, &keytab);
2bf1cbffaac3b4bc0bd736493c985ca865092805Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("error resolving keytab [%s], " \
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose kerr = krb5_kt_start_seq_get(kr->ctx, keytab, &cursor);
5a5f1e1053415efaa99bb4d5bc7ce7ac0a95b757Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, ("error reading keytab [%s], " \
cd5033e86bb4065d75188e2b6ef287a4421344c8Sumit Bose /* We look for the first entry from our realm or take the last one */
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose while ((kt_err = krb5_kt_next_entry(kr->ctx, keytab, &entry, &cursor)) == 0) {
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose kerr = krb5_copy_principal(kr->ctx, entry.principal,
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_copy_principal failed.\n"));
ccc2af010bbbe6d8a7496fb717216135bc4c1993Simo Sorce kerr = sss_krb5_free_keytab_entry_contents(kr->ctx, &entry);
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to free keytab entry.\n"));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose if (krb5_realm_compare(kr->ctx, validation_princ, kr->creds->client)) {
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose ("Found keytab entry with the realm of the credential.\n"));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose ("Keytab entry with the realm of the credential not found "
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose "in keytab. Using the last entry.\n"));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose /* Close the keytab here. Even though we're using cursors, the file
ad9ca94d0c793c2e30e77f4cc385bf10e42e382fJakub Hrozek * handle is stored in the krb5_keytab structure, and it gets
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose * overwritten when the verify_init_creds() call below creates its own
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose * cursor, creating a leak. */
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose kerr = krb5_kt_end_seq_get(kr->ctx, keytab, &cursor);
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_kt_end_seq_get failed, " \
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose "not verifying TGT.\n"));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* check if we got any errors from krb5_kt_next_entry */
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("error reading keytab [%s], " \
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* Get the principal to which the key belongs, for logging purposes. */
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce kerr = krb5_unparse_name(kr->ctx, validation_princ, &principal);
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, ("internal error parsing principal name, "
27e89b6925334565c73c407a9ae2809358789c81Jakub Hrozek "not verifying TGT.\n"));
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose kerr = krb5_verify_init_creds(kr->ctx, kr->creds, validation_princ, keytab,
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose DEBUG(SSSDBG_TRACE_FUNC, ("TGT verified using key for [%s].\n",
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE ,("TGT failed verification using key " \
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose /* Try to find and send the PAC to the PAC responder.
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose * Failures are not critical. */
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose kerr = sss_extract_pac(kr->ctx, validation_ccache, validation_princ,
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose DEBUG(SSSDBG_OP_FAILURE, ("sss_extract_and_send_pac failed, group " \
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose "membership for user with principal [%s] " \
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose DEBUG(SSSDBG_OP_FAILURE, ("sss_send_pac failed, group " \
08ab0d4ede41a1749e0bc26f78a37a4d10c20db8Sumit Bose "membership for user with principal [%s] " \
20ccfd63a17dc15dd24e6543424d86913d511c4bSumit Bose DEBUG(SSSDBG_MINOR_FAILURE, ("krb5_kt_close failed"));
20ccfd63a17dc15dd24e6543424d86913d511c4bSumit Bosestatic void krb5_set_canonicalize(krb5_get_init_creds_opt *opts)
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) {
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n",
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose SSSD_KRB5_CANONICALIZE, tmp_str ? tmp_str : "not set"));
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose sss_krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize);
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bosestatic krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx,
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose krb5_get_init_creds_opt_set_address_list(&options, NULL);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov krb5_get_init_creds_opt_set_forwardable(&options, 0);
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose krb5_get_init_creds_opt_set_proxiable(&options, 0);
096a9678919fae460342469989b97fd47d812823Sumit Bose kerr = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL,
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose /* Use the updated principal in the creds in case canonicalized */
386a66b1aa18a176e6a06fa126556c9590c373b6Sumit Bose kerr = create_ccache_file(ctx, creds.client, ccname, &creds);
5a5f1e1053415efaa99bb4d5bc7ce7ac0a95b757Jakub Hrozekstatic krb5_error_code get_and_save_tgt(struct krb5_req *kr,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny kerr = sss_krb5_get_init_creds_opt_set_expire_callback(kr->ctx, kr->options,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny DEBUG(1, ("Failed to set expire callback, continue without.\n"));
21f19d573047e70ee8ec0119ec00c1ed1af9ec04Simo Sorce sss_krb5_princ_realm(kr->ctx, kr->princ, &realm_name, &realm_length);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ("Attempting kinit for realm [%s]\n",realm_name));
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny DEBUG(SSSDBG_CONF_SETTINGS, ("TGT validation is disabled.\n"));
9af86b9c936d07cff9d0c2054acde908749ea522Jakub Hrozek /* We drop root privileges which were needed to read the keytab file
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * for the validation of the credentials or for FAST here to run the
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce * ccache I/O operations with user privileges. */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny principal = kr->creds ? kr->creds->client : kr->princ;
9af86b9c936d07cff9d0c2054acde908749ea522Jakub Hrozek /* If kr->ccname is cache collection (DIR:/...), we want to work
9af86b9c936d07cff9d0c2054acde908749ea522Jakub Hrozek * directly with file ccache (DIR::/...), but cache collection
9af86b9c936d07cff9d0c2054acde908749ea522Jakub Hrozek * should be returned back to back end.
9af86b9c936d07cff9d0c2054acde908749ea522Jakub Hrozek cc_name = sss_get_ccache_name_for_principal(kr->pd, kr->ctx, principal,
5a5f1e1053415efaa99bb4d5bc7ce7ac0a95b757Jakub Hrozek /* Use the updated principal in the creds in case canonicalized */
5a5f1e1053415efaa99bb4d5bc7ce7ac0a95b757Jakub Hrozek kerr = create_ccache(kr->uid, kr->gid, kr->ctx,
5a5f1e1053415efaa99bb4d5bc7ce7ac0a95b757Jakub Hrozek kerr = add_ticket_times_and_upn_to_response(kr);
5a5f1e1053415efaa99bb4d5bc7ce7ac0a95b757Jakub Hrozek DEBUG(1, ("add_ticket_times_and_upn_to_response failed.\n"));
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenystatic errno_t map_krb5_error(krb5_error_code kerr)
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorcestatic errno_t changepw_child(struct krb5_req *kr, bool prelim)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov krb5_get_init_creds_opt *chagepw_options;
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose DEBUG(SSSDBG_TRACE_LIBS, ("Password change operation\n"));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ret = sss_authtok_get_password(kr->pd->authtok, &password, NULL);
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose DEBUG(1, ("Failed to fetch current password [%d] %s.\n",
d6d8287a9b8a240e068a26769dc6ce4582604850Simo Sorce /* We do not need a password expiration warning here. */
6a81cb8c3424dbe9f764af3738299cbbe5874a15Simo Sorce kerr = get_changepw_options(kr->ctx, &chagepw_options);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_OP_FAILURE, ("get_changepw_options failed.\n"));
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose sss_krb5_princ_realm(kr->ctx, kr->princ, &realm_name, &realm_length);
cd4cc8d8829f1ea5257bf874b91980368114275fPavel Březina ("Attempting kinit for realm [%s]\n",realm_name));
99151f2217ddaa179543b89b49f836f29f7dcd2aSimo Sorce kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
44af0057c1fd52f6252f82ca73a06acfcac6c5e3Michal Zidek sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options);
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorce ("Initial authentication for change password operation "
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorce "successful.\n"));
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorce ret = sss_authtok_get_password(kr->pd->newauthtok, &newpassword, NULL);
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorce DEBUG(1, ("Failed to fetch new password [%d] %s.\n",
6a81cb8c3424dbe9f764af3738299cbbe5874a15Simo Sorce memset(&result_code_string, 0, sizeof(krb5_data));
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code,
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose result_code_string.length, result_code_string.data));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov user_error_message = talloc_strndup(kr->pd, result_code_string.data,
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose if (result_string.length > 0 && result_string.data[0] != '\0') {
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov user_error_message = talloc_strndup(kr->pd, result_string.data,
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose } else if (result_code == KRB5_KPASSWD_SOFTERROR) {
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose user_error_message = talloc_strdup(kr->pd, "Please make sure the "
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose "password meets the complexity constraints.");
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strndup failed.\n"));
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose ret = pack_user_info_chpass_error(kr->pd, user_error_message,
6a81cb8c3424dbe9f764af3738299cbbe5874a15Simo Sorce DEBUG(1, ("pack_user_info_chpass_error failed.\n"));
8e5549e453558d4bebdec333a93e215d5d6ffaecSimo Sorce ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, user_resp_len,
87ed72b47859e673b636c85f35b85f1546c7ed3dSimo Sorce DEBUG(SSSDBG_TRACE_LIBS, ("Attempting to get a TGT\n"));
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose ret = sss_authtok_get_password(kr->pd->authtok, &password, NULL);
5063dcc5ab685dce325b13b9c1e93cee2a673e60Sumit Bose DEBUG(SSSDBG_OP_FAILURE, ("Invalid authtok type\n"));
87ed72b47859e673b636c85f35b85f1546c7ed3dSimo Sorce DEBUG(SSSDBG_OP_FAILURE, ("No credentials available\n"));
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose /* If the password is expired the KDC will always return
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose not. In general the password can still be used to get a changepw ticket.
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose So we validate the password by trying to get a changepw ticket. */
fab48878db202d620f43c9da23e375866d1db2c6Sumit Bose DEBUG(SSSDBG_TRACE_LIBS, ("Password was expired\n"));
87f8bee53ee1b4ca87b602ff8536bc5fd5b5b595Lukas Slebodnik kerr = sss_krb5_get_init_creds_opt_set_expire_callback(kr->ctx,
87f8bee53ee1b4ca87b602ff8536bc5fd5b5b595Lukas Slebodnik DEBUG(1, ("Failed to unset expire callback, continue ...\n"));
3b533d57a737e2de1b3e85b073b14d3bfb49dafcSimo Sorce kerr = get_changepw_options(kr->ctx, &chagepw_options);
87f8bee53ee1b4ca87b602ff8536bc5fd5b5b595Lukas Slebodnik DEBUG(SSSDBG_OP_FAILURE, ("get_changepw_options failed.\n"));
2b4b6b829f197493b4901bec96fefaadbc7a2464Jakub Hrozek kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
b17b51c2779906bf3a5e4aecbb9ef8bfbfc2ebabJakub Hrozek sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options);
done:
return ret;
if (kerr != 0) {
if (access_allowed) {
return EOK;
return ERR_AUTH_DENIED;
const char *ccname;
int ret;
return ERR_INVALID_CRED_TYPE;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
done:
if (kerr != 0) {
return EINVAL;
switch (auth_token_type) {
case SSS_AUTHTOK_TYPE_EMPTY:
case SSS_AUTHTOK_TYPE_CCFILE:
return EINVAL;
*p += auth_token_length;
return ret;
size_t p = 0;
return ENOMEM;
p += len;
p += len;
p += len;
if (ret) {
return ret;
if (ret) {
return ret;
p += len;
return EOK;
return EOK;
if (krberr != 0) {
goto done;
if (krberr != 0) {
krberr = 0;
goto done;
krberr = 0;
done:
return krberr;
const char *primary,
const char *realm,
const char *keytab_name,
char **fast_ccname)
char *ccname;
char *server_name;
goto done;
goto done;
if (kerr) {
goto done;
if (kerr != 0) {
goto done;
goto done;
if (kerr != 0) {
goto done;
if (kerr == 0) {
goto done;
if (kerr != 0) {
goto done;
kerr = 0;
done:
if (kerr == 0) {
return kerr;
errno = 0;
return ret;
return ret;
char *fast_principal_realm;
char *fast_principal;
char *tmp_str;
if (tmp_str) {
if (kerr) {
return kerr;
&tmp_str);
if (kerr) {
return kerr;
if (!fast_principal) {
return KRB5KRB_ERR_GENERIC;
if (!fast_principal_realm) {
return ENOMEM;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (demand) {
if (kerr != 0) {
return kerr;
return EOK;
char *lifetime_str;
char *use_fast_str;
int parse_flags;
if (kerr != 0) {
return kerr;
if (kerr) {
return EIO;
* missing in krb5.conf or to allow SSSD to work with multiple unconnected
if (kerr != 0) {
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
return ENOMEM;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
lifetime_str));
return kerr;
if (kerr != 0) {
lifetime_str));
return kerr;
if (!offline) {
use_fast_str));
return EINVAL;
return kerr;
int opt;
switch(opt) {
if (!debug_prg_name) {
goto done;
goto done;
goto done;
case SSS_PAM_AUTHENTICATE:
if (offline) {
case SSS_PAM_CHAUTHTOK:
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_ACCT_MGMT:
case SSS_CMD_RENEW:
if (offline) {
goto done;
goto done;
done:
exit(0);