diff options
Diffstat (limited to 'server/providers/krb5/krb5_child.c')
-rw-r--r-- | server/providers/krb5/krb5_child.c | 1030 |
1 files changed, 0 insertions, 1030 deletions
diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c deleted file mode 100644 index 5e185940..00000000 --- a/server/providers/krb5/krb5_child.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module -- tgt_req and changepw child - - Authors: - Sumit Bose <sbose@redhat.com> - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sys/types.h> -#include <unistd.h> -#include <sys/stat.h> -#include <popt.h> - -#include <security/pam_modules.h> - -#include "util/util.h" -#include "util/user_info_msg.h" -#include "providers/child_common.h" -#include "providers/dp_backend.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/krb5/krb5_utils.h" - -struct krb5_child_ctx { - /* opts taken from kinit */ - /* in seconds */ - krb5_deltat starttime; - krb5_deltat lifetime; - krb5_deltat rlife; - - int forwardable; - int proxiable; - int addresses; - - int not_forwardable; - int not_proxiable; - int no_addresses; - - int verbose; - - char* principal_name; - char* service_name; - char* keytab_name; - char* k5_cache_name; - char* k4_cache_name; - - action_type action; - - char *kdcip; - char *realm; - char *changepw_principle; - char *ccache_dir; - char *ccname_template; - int auth_timeout; - - int child_debug_fd; -}; - -struct krb5_req { - krb5_context ctx; - krb5_principal princ; - char* name; - krb5_creds *creds; - krb5_get_init_creds_opt *options; - pid_t child_pid; - int read_from_child_fd; - int write_to_child_fd; - - struct be_req *req; - struct pam_data *pd; - struct krb5_child_ctx *krb5_ctx; - errno_t (*child_req)(int fd, struct krb5_req *kr); - - char *ccname; - char *keytab; - bool validate; -}; - -static krb5_context krb5_error_ctx; -static const char *__krb5_error_msg; -#define KRB5_DEBUG(level, krb5_error) do { \ - __krb5_error_msg = sss_krb5_get_error_message(krb5_error_ctx, krb5_error); \ - DEBUG(level, ("%d: [%d][%s]\n", __LINE__, krb5_error, __krb5_error_msg)); \ - sss_krb5_free_error_message(krb5_error_ctx, __krb5_error_msg); \ -} while(0); - -static krb5_error_code create_empty_cred(struct krb5_req *kr, krb5_creds **_cred) -{ - krb5_error_code kerr; - krb5_creds *cred = NULL; - krb5_data *krb5_realm; - - cred = calloc(sizeof(krb5_creds), 1); - if (cred == NULL) { - DEBUG(1, ("calloc failed.\n")); - return ENOMEM; - } - - kerr = krb5_copy_principal(kr->ctx, kr->princ, &cred->client); - if (kerr != 0) { - DEBUG(1, ("krb5_copy_principal failed.\n")); - goto done; - } - - krb5_realm = krb5_princ_realm(kr->ctx, kr->princ); - - kerr = krb5_build_principal_ext(kr->ctx, &cred->server, - krb5_realm->length, krb5_realm->data, - KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, - krb5_realm->length, krb5_realm->data, 0); - if (kerr != 0) { - DEBUG(1, ("krb5_build_principal_ext failed.\n")); - goto done; - } - -done: - if (kerr != 0) { - if (cred != NULL && cred->client != NULL) { - krb5_free_principal(kr->ctx, cred->client); - } - - free(cred); - } else { - *_cred = cred; - } - - return kerr; -} - -static krb5_error_code create_ccache_file(struct krb5_req *kr, krb5_creds *creds) -{ - krb5_error_code kerr; - krb5_ccache tmp_cc = NULL; - char *cc_file_name; - int fd = -1; - size_t ccname_len; - char *dummy; - char *tmp_ccname; - krb5_creds *l_cred; - - if (strncmp(kr->ccname, "FILE:", 5) == 0) { - cc_file_name = kr->ccname + 5; - } else { - cc_file_name = kr->ccname; - } - - if (cc_file_name[0] != '/') { - DEBUG(1, ("Ccache filename is not an absolute path.\n")); - return EINVAL; - } - - dummy = strrchr(cc_file_name, '/'); - tmp_ccname = talloc_strndup(kr, cc_file_name, (size_t) (dummy-cc_file_name)); - if (tmp_ccname == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return ENOMEM; - } - tmp_ccname = talloc_asprintf_append(tmp_ccname, "/.krb5cc_dummy_XXXXXX"); - - fd = mkstemp(tmp_ccname); - if (fd == -1) { - DEBUG(1, ("mkstemp failed [%d][%s].\n", errno, strerror(errno))); - return errno; - } - - kerr = krb5_cc_resolve(kr->ctx, tmp_ccname, &tmp_cc); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - - kerr = krb5_cc_initialize(kr->ctx, tmp_cc, kr->princ); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - if (fd != -1) { - close(fd); - fd = -1; - } - - if (creds == NULL) { - kerr = create_empty_cred(kr, &l_cred); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - } else { - l_cred = creds; - } - - kerr = krb5_cc_store_cred(kr->ctx, tmp_cc, l_cred); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - - kerr = krb5_cc_close(kr->ctx, tmp_cc); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - tmp_cc = NULL; - - ccname_len = strlen(cc_file_name); - if (ccname_len >= 6 && strcmp(cc_file_name + (ccname_len-6), "XXXXXX")==0 ) { - fd = mkstemp(cc_file_name); - if (fd == -1) { - DEBUG(1, ("mkstemp failed [%d][%s].\n", errno, strerror(errno))); - kerr = errno; - goto done; - } - } - - kerr = rename(tmp_ccname, cc_file_name); - if (kerr == -1) { - DEBUG(1, ("rename failed [%d][%s].\n", errno, strerror(errno))); - } - -done: - if (fd != -1) { - close(fd); - fd = -1; - } - if (kerr != 0 && tmp_cc != NULL) { - krb5_cc_destroy(kr->ctx, tmp_cc); - } - return kerr; -} - -static struct response *init_response(TALLOC_CTX *mem_ctx) { - struct response *r; - r = talloc(mem_ctx, struct response); - r->buf = talloc_size(mem_ctx, MAX_CHILD_MSG_SIZE); - if (r->buf == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - return NULL; - } - r->max_size = MAX_CHILD_MSG_SIZE; - r->size = 0; - - return r; -} - -static errno_t pack_response_packet(struct response *resp, int status, int type, - size_t len, const uint8_t *data) -{ - int p=0; - - if ((3*sizeof(int32_t) + len +1) > resp->max_size) { - DEBUG(1, ("response message too big.\n")); - return ENOMEM; - } - - COPY_INT32_VALUE(&resp->buf[p], status, p); - COPY_INT32_VALUE(&resp->buf[p], type, p); - COPY_INT32_VALUE(&resp->buf[p], len, p); - COPY_MEM(&resp->buf[p], data, p, len); - - resp->size = p; - - return EOK; -} - -static struct response *prepare_response_message(struct krb5_req *kr, - krb5_error_code kerr, - char *user_error_message, - int pam_status) -{ - char *msg = NULL; - const char *krb5_msg = NULL; - int ret; - struct response *resp; - size_t user_resp_len; - uint8_t *user_resp; - - resp = init_response(kr); - if (resp == NULL) { - DEBUG(1, ("init_response failed.\n")); - return NULL; - } - - if (kerr == 0) { - if(kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { - ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_SYSTEM_INFO, - strlen("success") + 1, - (const uint8_t *) "success"); - } else { - if (kr->ccname == NULL) { - DEBUG(1, ("Error obtaining ccname.\n")); - return NULL; - } - - msg = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, kr->ccname); - if (msg == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - return NULL; - } - - ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_ENV_ITEM, - strlen(msg) + 1, (uint8_t *) msg); - talloc_zfree(msg); - } - } else { - - if (user_error_message != NULL) { - ret = pack_user_info_chpass_error(kr, user_error_message, - &user_resp_len, &user_resp); - if (ret != EOK) { - DEBUG(1, ("pack_user_info_chpass_error failed.\n")); - talloc_zfree(user_error_message); - } else { - ret = pack_response_packet(resp, pam_status, SSS_PAM_USER_INFO, - user_resp_len, user_resp); - if (ret != EOK) { - DEBUG(1, ("pack_response_packet failed.\n")); - talloc_zfree(user_error_message); - } - } - } - - if (user_error_message == NULL) { - krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr); - if (krb5_msg == NULL) { - DEBUG(1, ("sss_krb5_get_error_message failed.\n")); - return NULL; - } - - ret = pack_response_packet(resp, pam_status, SSS_PAM_SYSTEM_INFO, - strlen(krb5_msg) + 1, - (const uint8_t *) krb5_msg); - sss_krb5_free_error_message(krb5_error_ctx, krb5_msg); - } else { - - } - - } - - if (ret != EOK) { - DEBUG(1, ("pack_response_packet failed.\n")); - return NULL; - } - - return resp; -} - -static errno_t sendresponse(int fd, krb5_error_code kerr, - char *user_error_message, int pam_status, - struct krb5_req *kr) -{ - struct response *resp; - size_t written; - int ret; - - resp = prepare_response_message(kr, kerr, user_error_message, pam_status); - if (resp == NULL) { - DEBUG(1, ("prepare_response_message failed.\n")); - return ENOMEM; - } - - written = 0; - while (written < resp->size) { - ret = write(fd, resp->buf + written, resp->size - written); - if (ret == -1) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } - ret = errno; - DEBUG(1, ("write failed [%d][%s].\n", ret, strerror(ret))); - return ret; - } - written += ret; - } - - return EOK; -} - -static krb5_error_code validate_tgt(struct krb5_req *kr) -{ - krb5_error_code kerr; - krb5_error_code kt_err; - char *principal; - krb5_keytab keytab; - krb5_kt_cursor cursor; - krb5_keytab_entry entry; - krb5_verify_init_creds_opt opt; - - memset(&keytab, 0, sizeof(keytab)); - kerr = krb5_kt_resolve(kr->ctx, kr->keytab, &keytab); - if (kerr != 0) { - DEBUG(1, ("error resolving keytab [%s], not verifying TGT.\n", - kr->keytab)); - return kerr; - } - - memset(&cursor, 0, sizeof(cursor)); - kerr = krb5_kt_start_seq_get(kr->ctx, keytab, &cursor); - if (kerr != 0) { - DEBUG(1, ("error reading keytab [%s], not verifying TGT.\n", - kr->keytab)); - return kerr; - } - - /* We look for the first entry from our realm or take the last one */ - memset(&entry, 0, sizeof(entry)); - while ((kt_err = krb5_kt_next_entry(kr->ctx, keytab, &entry, &cursor)) == 0) { - if (krb5_realm_compare(kr->ctx, entry.principal, kr->princ)) { - DEBUG(9, ("Found keytab entry with the realm of the credential.\n")); - break; - } - - kerr = krb5_free_keytab_entry_contents(kr->ctx, &entry); - if (kerr != 0) { - DEBUG(1, ("Failed to free keytab entry.\n")); - } - memset(&entry, 0, sizeof(entry)); - } - - /* Close the keytab here. Even though we're using cursors, the file - * handle is stored in the krb5_keytab structure, and it gets - * overwritten when the verify_init_creds() call below creates its own - * cursor, creating a leak. */ - kerr = krb5_kt_end_seq_get(kr->ctx, keytab, &cursor); - if (kerr != 0) { - DEBUG(1, ("krb5_kt_end_seq_get failed, not verifying TGT.\n")); - goto done; - } - - /* check if we got any errors from krb5_kt_next_entry */ - if (kt_err != 0 && kt_err != KRB5_KT_END) { - DEBUG(1, ("error reading keytab [%s], not verifying TGT.\n", - kr->keytab)); - goto done; - } - - /* Get the principal to which the key belongs, for logging purposes. */ - principal = NULL; - kerr = krb5_unparse_name(kr->ctx, entry.principal, &principal); - if (kerr != 0) { - DEBUG(1, ("internal error parsing principal name, " - "not verifying TGT.\n")); - goto done; - } - - - krb5_verify_init_creds_opt_init(&opt); - kerr = krb5_verify_init_creds(kr->ctx, kr->creds, entry.principal, keytab, - NULL, &opt); - - if (kerr == 0) { - DEBUG(5, ("TGT verified using key for [%s].\n", principal)); - } else { - DEBUG(1 ,("TGT failed verification using key for [%s].\n", principal)); - } - -done: - if (krb5_kt_close(kr->ctx, keytab) != 0) { - DEBUG(1, ("krb5_kt_close failed")); - } - if (krb5_free_keytab_entry_contents(kr->ctx, &entry) != 0) { - DEBUG(1, ("Failed to free keytab entry.\n")); - } - if (principal != NULL) { - sss_krb5_free_unparsed_name(kr->ctx, principal); - } - - return kerr; - -} - -static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) -{ - krb5_error_code kerr = 0; - int ret; - - kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, NULL, NULL, 0, NULL, - kr->options); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - return kerr; - } - - if (kr->validate) { - kerr = validate_tgt(kr); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - return kerr; - } - - /* We drop root privileges which were needed to read the keytab file - * for the validation validation of the credentials here to run the - * ccache I/O operations with user privileges. */ - ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid); - if (ret != EOK) { - DEBUG(1, ("become_user failed.\n")); - return ret; - } - } else { - DEBUG(9, ("TGT validation is disabled.\n")); - } - - kerr = create_ccache_file(kr, kr->creds); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - - kerr = 0; - -done: - krb5_free_cred_contents(kr->ctx, kr->creds); - - return kerr; - -} - -static errno_t changepw_child(int fd, struct krb5_req *kr) -{ - int ret; - krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; - int pam_status = PAM_SYSTEM_ERR; - int result_code = -1; - krb5_data result_code_string; - krb5_data result_string; - char *user_error_message = NULL; - - pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, NULL, NULL, 0, - kr->krb5_ctx->changepw_principle, - kr->options); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - if (kerr == KRB5_KDC_UNREACH) { - pam_status = PAM_AUTHINFO_UNAVAIL; - } - goto sendresponse; - } - - memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); - - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { - DEBUG(9, ("Initial authentication for change password operation " - "successfull.\n")); - krb5_free_cred_contents(kr->ctx, kr->creds); - pam_status = PAM_SUCCESS; - goto sendresponse; - } - - newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, - kr->pd->newauthtok_size); - if (newpass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, - &result_code_string, &result_string); - - if (kerr != 0 || result_code != 0) { - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - } else { - kerr = KRB5KRB_ERR_GENERIC; - } - - if (result_code_string.length > 0) { - DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, - result_code_string.length, result_code_string.data)); - user_error_message = talloc_strndup(kr->pd, result_code_string.data, - result_code_string.length); - if (user_error_message == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - } - } - - if (result_string.length > 0) { - DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, - result_string.length, result_string.data)); - talloc_free(user_error_message); - user_error_message = talloc_strndup(kr->pd, result_string.data, - result_string.length); - if (user_error_message == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - } - } - - pam_status = PAM_AUTHTOK_ERR; - goto sendresponse; - } - - krb5_free_cred_contents(kr->ctx, kr->creds); - - kerr = get_and_save_tgt(kr, newpass_str); - memset(newpass_str, 0, kr->pd->newauthtok_size); - talloc_zfree(newpass_str); - memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); - - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - if (kerr == KRB5_KDC_UNREACH) { - pam_status = PAM_AUTHINFO_UNAVAIL; - } - } - -sendresponse: - ret = sendresponse(fd, kerr, user_error_message, pam_status, kr); - if (ret != EOK) { - DEBUG(1, ("sendresponse failed.\n")); - } - - return ret; -} - -static errno_t tgt_req_child(int fd, struct krb5_req *kr) -{ - int ret; - krb5_error_code kerr = 0; - char *pass_str = NULL; - int pam_status = PAM_SYSTEM_ERR; - - pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - kerr = KRB5KRB_ERR_GENERIC; - goto sendresponse; - } - - kerr = get_and_save_tgt(kr, pass_str); - - /* If the password is expired the KDC will always return - KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or - not. In general the password can still be used to get a changepw ticket. - So we validate the password by trying to get a changepw ticket. */ - if (kerr == KRB5KDC_ERR_KEY_EXP) { - kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, NULL, NULL, 0, - kr->krb5_ctx->changepw_principle, - kr->options); - krb5_free_cred_contents(kr->ctx, kr->creds); - if (kerr == 0) { - kerr = KRB5KDC_ERR_KEY_EXP; - } - } - - memset(pass_str, 0, kr->pd->authtok_size); - talloc_zfree(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); - - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - switch (kerr) { - case KRB5_KDC_UNREACH: - pam_status = PAM_AUTHINFO_UNAVAIL; - break; - case KRB5KDC_ERR_KEY_EXP: - pam_status = PAM_AUTHTOK_EXPIRED; - break; - case KRB5KDC_ERR_PREAUTH_FAILED: - pam_status = PAM_CRED_ERR; - break; - default: - pam_status = PAM_SYSTEM_ERR; - } - } - -sendresponse: - ret = sendresponse(fd, kerr, NULL, pam_status, kr); - if (ret != EOK) { - DEBUG(1, ("sendresponse failed.\n")); - } - - return ret; -} - -static errno_t create_empty_ccache(int fd, struct krb5_req *kr) -{ - int ret; - int pam_status = PAM_SUCCESS; - - ret = create_ccache_file(kr, NULL); - if (ret != 0) { - KRB5_DEBUG(1, ret); - pam_status = PAM_SYSTEM_ERR; - } - - ret = sendresponse(fd, ret, NULL, pam_status, kr); - if (ret != EOK) { - DEBUG(1, ("sendresponse failed.\n")); - } - - return ret; -} - -static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, - char **ccname, char **keytab, uint32_t *validate, - uint32_t *offline) -{ - size_t p = 0; - uint32_t len; - - COPY_UINT32_CHECK(&pd->cmd, buf + p, p, size); - COPY_UINT32_CHECK(&pd->pw_uid, buf + p, p, size); - COPY_UINT32_CHECK(&pd->gr_gid, buf + p, p, size); - COPY_UINT32_CHECK(validate, buf + p, p, size); - COPY_UINT32_CHECK(offline, buf + p, p, size); - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len ) > size) return EINVAL; - pd->upn = talloc_strndup(pd, (char *)(buf + p), len); - if (pd->upn == NULL) return ENOMEM; - p += len; - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len ) > size) return EINVAL; - *ccname = talloc_strndup(pd, (char *)(buf + p), len); - if (*ccname == NULL) return ENOMEM; - p += len; - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len ) > size) return EINVAL; - *keytab = talloc_strndup(pd, (char *)(buf + p), len); - if (*keytab == NULL) return ENOMEM; - p += len; - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; - - if (pd->cmd == SSS_PAM_CHAUTHTOK) { - COPY_UINT32_CHECK(&len, buf + p, p, size); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; - } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; - } - - return EOK; -} - -static int krb5_cleanup(void *ptr) -{ - struct krb5_req *kr = talloc_get_type(ptr, struct krb5_req); - if (kr == NULL) return EOK; - - if (kr->options != NULL) { - sss_krb5_get_init_creds_opt_free(kr->ctx, kr->options); - } - - if (kr->creds != NULL) { - krb5_free_cred_contents(kr->ctx, kr->creds); - krb5_free_creds(kr->ctx, kr->creds); - } - if (kr->name != NULL) - sss_krb5_free_unparsed_name(kr->ctx, kr->name); - if (kr->princ != NULL) - krb5_free_principal(kr->ctx, kr->princ); - if (kr->ctx != NULL) - krb5_free_context(kr->ctx); - - if (kr->krb5_ctx != NULL) { - memset(kr->krb5_ctx, 0, sizeof(struct krb5_child_ctx)); - } - memset(kr, 0, sizeof(struct krb5_req)); - - return EOK; -} - -static int krb5_setup(struct pam_data *pd, const char *user_princ_str, - uint32_t offline, struct krb5_req **krb5_req) -{ - struct krb5_req *kr = NULL; - krb5_error_code kerr = 0; - - kr = talloc_zero(pd, struct krb5_req); - if (kr == NULL) { - DEBUG(1, ("talloc failed.\n")); - kerr = ENOMEM; - goto failed; - } - talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); - - kr->krb5_ctx = talloc_zero(kr, struct krb5_child_ctx); - if (kr->krb5_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - kerr = ENOMEM; - goto failed; - } - - kr->krb5_ctx->changepw_principle = getenv(SSSD_KRB5_CHANGEPW_PRINCIPLE); - if (kr->krb5_ctx->changepw_principle == NULL) { - DEBUG(1, ("Cannot read [%s] from environment.\n", - SSSD_KRB5_CHANGEPW_PRINCIPLE)); - if (pd->cmd == SSS_PAM_CHAUTHTOK) { - goto failed; - } - } - - kr->krb5_ctx->realm = getenv(SSSD_KRB5_REALM); - if (kr->krb5_ctx->realm == NULL) { - DEBUG(2, ("Cannot read [%s] from environment.\n", SSSD_KRB5_REALM)); - } - - kr->pd = pd; - - switch(pd->cmd) { - case SSS_PAM_AUTHENTICATE: - /* If we are offline, we need to create an empty ccache file */ - if (offline) { - kr->child_req = create_empty_ccache; - } else { - kr->child_req = tgt_req_child; - } - break; - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - kr->child_req = changepw_child; - break; - default: - DEBUG(1, ("PAM command [%d] not supported.\n", pd->cmd)); - kerr = EINVAL; - goto failed; - } - - kerr = krb5_init_context(&kr->ctx); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto failed; - } - - kerr = krb5_parse_name(kr->ctx, user_princ_str, &kr->princ); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto failed; - } - - kerr = krb5_unparse_name(kr->ctx, kr->princ, &kr->name); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto failed; - } - - kr->creds = calloc(1, sizeof(krb5_creds)); - if (kr->creds == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - kerr = ENOMEM; - goto failed; - } - - kerr = sss_krb5_get_init_creds_opt_alloc(kr->ctx, &kr->options); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto failed; - } - -/* TODO: set options, e.g. - * krb5_get_init_creds_opt_set_tkt_life - * krb5_get_init_creds_opt_set_renew_life - * krb5_get_init_creds_opt_set_forwardable - * krb5_get_init_creds_opt_set_proxiable - * krb5_get_init_creds_opt_set_etype_list - * krb5_get_init_creds_opt_set_address_list - * krb5_get_init_creds_opt_set_preauth_list - * krb5_get_init_creds_opt_set_salt - * krb5_get_init_creds_opt_set_change_password_prompt - * krb5_get_init_creds_opt_set_pa - */ - - *krb5_req = kr; - return EOK; - -failed: - talloc_free(kr); - - return kerr; -} - -int main(int argc, const char *argv[]) -{ - uint8_t *buf = NULL; - int ret; - ssize_t len = 0; - struct pam_data *pd = NULL; - struct krb5_req *kr = NULL; - char *ccname; - char *keytab; - uint32_t validate; - uint32_t offline; - int opt; - poptContext pc; - int debug_fd = -1; - - struct poptOption long_options[] = { - POPT_AUTOHELP - {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, - _("Debug level"), NULL}, - {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0, - _("Add debug timestamps"), NULL}, - {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0, - _("An open file descriptor for the debug logs"), NULL}, - POPT_TABLEEND - }; - - - pc = poptGetContext(argv[0], argc, argv, long_options, 0); - while((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - default: - fprintf(stderr, "\nInvalid option %s: %s\n\n", - poptBadOption(pc, 0), poptStrerror(opt)); - poptPrintUsage(pc, stderr, 0); - _exit(-1); - } - } - - poptFreeContext(pc); - - DEBUG(7, ("krb5_child started.\n")); - - pd = talloc(NULL, struct pam_data); - if (pd == NULL) { - DEBUG(1, ("malloc failed.\n")); - _exit(-1); - } - - debug_prg_name = talloc_asprintf(pd, "[sssd[krb5_child[%d]]]", getpid()); - - if (debug_fd != -1) { - ret = set_debug_file_from_fd(debug_fd); - if (ret != EOK) { - DEBUG(1, ("set_debug_file_from_fd failed.\n")); - } - } - - buf = talloc_size(pd, sizeof(uint8_t)*IN_BUF_SIZE); - if (buf == NULL) { - DEBUG(1, ("malloc failed.\n")); - _exit(-1); - } - - while ((ret = read(STDIN_FILENO, buf + len, IN_BUF_SIZE - len)) != 0) { - if (ret == -1) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - DEBUG(1, ("read failed [%d][%s].\n", errno, strerror(errno))); - goto fail; - } else if (ret > 0) { - len += ret; - if (len > IN_BUF_SIZE) { - DEBUG(1, ("read too much, this should never happen.\n")); - goto fail; - } - continue; - } else { - DEBUG(1, ("unexpected return code of read [%d].\n", ret)); - goto fail; - } - } - close(STDIN_FILENO); - - ret = unpack_buffer(buf, len, pd, &ccname, &keytab, &validate, &offline); - if (ret != EOK) { - DEBUG(1, ("unpack_buffer failed.\n")); - goto fail; - } - - ret = krb5_setup(pd, pd->upn, offline, &kr); - if (ret != EOK) { - DEBUG(1, ("krb5_setup failed.\n")); - goto fail; - } - kr->ccname = ccname; - kr->keytab = keytab; - kr->validate = (validate == 0) ? false : true; - - ret = kr->child_req(STDOUT_FILENO, kr); - if (ret != EOK) { - DEBUG(1, ("Child request failed.\n")); - goto fail; - } - - close(STDOUT_FILENO); - talloc_free(pd); - - return 0; - -fail: - close(STDOUT_FILENO); - talloc_free(pd); - exit(-1); -} |