static gss_client_response *create_krb5_ccache(gss_server_state *state, krb5_context kcontext, krb5_principal princ, krb5_ccache *ccache) { char *ccname = NULL; int fd; krb5_error_code problem; krb5_ccache tmp_ccache = NULL; gss_client_response *error = NULL; // TODO: mod_auth_kerb used a temp file under /run/httpd/krbcache. what can we do? ccname = strdup("FILE:/tmp/krb5cc_nodekerberos_XXXXXX"); if (!ccname) die1("Memory allocation failed"); fd = mkstemp(ccname + strlen("FILE:")); if (fd < 0) { error = other_error("mkstemp() failed: %s", strerror(errno)); goto end; } close(fd); problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache); if (problem) { error = krb5_ctx_error(kcontext, problem); goto end; } problem = krb5_cc_initialize(kcontext, tmp_ccache, princ); if (problem) { error = krb5_ctx_error(kcontext, problem); goto end; } state->delegated_credentials_cache = strdup(ccname); // TODO: how/when to cleanup the creds cache file? // TODO: how to expose the credentials expiration time? *ccache = tmp_ccache; tmp_ccache = NULL; end: if (tmp_ccache) krb5_cc_destroy(kcontext, tmp_ccache); if (ccname && error) unlink(ccname); if (ccname) free(ccname); return error; }
static gss_client_response *store_gss_creds(gss_server_state *state) { OM_uint32 maj_stat, min_stat; krb5_principal princ = NULL; krb5_ccache ccache = NULL; krb5_error_code problem; krb5_context context; gss_client_response *response = NULL; problem = krb5_init_context(&context); if (problem) { response = other_error("No auth_data value in request from client"); return response; } problem = krb5_parse_name(context, state->username, &princ); if (problem) { response = krb5_ctx_error(context, problem); goto end; } if ((response = create_krb5_ccache(state, context, princ, &ccache))) { goto end; } maj_stat = gss_krb5_copy_ccache(&min_stat, state->client_creds, ccache); if (GSS_ERROR(maj_stat)) { response = gss_error(__func__, "gss_krb5_copy_ccache", maj_stat, min_stat); response->return_code = AUTH_GSS_ERROR; goto end; } krb5_cc_close(context, ccache); ccache = NULL; response = calloc(1, sizeof(gss_client_response)); if(response == NULL) die1("Memory allocation failed"); // TODO: something other than AUTH_GSS_COMPLETE? response->return_code = AUTH_GSS_COMPLETE; end: if (princ) krb5_free_principal(context, princ); if (ccache) krb5_cc_destroy(context, ccache); krb5_free_context(context); return response; }
void simple_socket_stoppable::wait_for_read () { if (fd_to_monitor == INVALID_SOCKET) return; fd_set select_fds; FD_ZERO(&select_fds); FD_SET(sock, &select_fds); FD_SET(fd_to_monitor, &select_fds); timeval timeout_copy = *timeout; // For Linux timeval* select_tm = (timeout_action == timeout_act::NO_TIMEOUT) ? NULL : &timeout_copy; int selcode = select(((fd_to_monitor > sock) ? fd_to_monitor : sock), &select_fds, NULL, NULL, select_tm); if (selcode == SOCKET_ERROR) throw other_error("select() error in stoppable socket"); if (selcode) { if (FD_ISSET(sock, &select_fds)) return; else throw stop_exception(context, fd_to_monitor); } else { if (timeout_action == timeout_act::RAISE_STOP) throw stop_exception(context, fd_to_monitor); else throw io_error(io_error::READ); } }
static gss_client_response *init_gss_creds(const char *credential_cache, gss_cred_id_t *cred) { OM_uint32 maj_stat; OM_uint32 min_stat; krb5_context context; krb5_error_code problem; gss_client_response *response = NULL; krb5_ccache ccache = NULL; *cred = GSS_C_NO_CREDENTIAL; if (credential_cache == NULL || strlen(credential_cache) == 0) { return NULL; } problem = krb5_init_context(&context); if (problem) { return other_error("unable to initialize krb5 context (%d)", (int)problem); } problem = krb5_cc_resolve(context, credential_cache, &ccache); if (problem) { response = krb5_ctx_error(context, problem); goto done; } maj_stat = gss_krb5_import_cred(&min_stat, ccache, NULL, NULL, cred); if (GSS_ERROR(maj_stat)) { response = gss_error(__func__, "gss_krb5_import_cred", maj_stat, min_stat); response->return_code = AUTH_GSS_ERROR; } done: if (response && ccache) { krb5_cc_close(context, ccache); } krb5_free_context(context); return response; }
static other_error create(int id_, const std::string& what_arg) { std::string w = exception::name("other_error", id_) + what_arg; return other_error(id_, w.c_str()); }
/* * username, password: Credentials to validate. Null not allowed * service: Service principal (e.g. HTTP/somehost.example.org) of key * stored in default keytab which will be used to verify KDC. * Empty string (*not* NULL) will bypass KDC verification * return: response->return_code will be * -1 (AUTH_GSS_ERROR) for error, see response->message * 0 for auth fail * 1 for auth ok */ gss_client_response *authenticate_user_krb5_password(const char *username, const char *password, const char *service) { krb5_context context = NULL; krb5_error_code problem; krb5_principal user_principal = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_creds creds; bool auth_ok = false; gss_client_response *response = NULL; if (username == NULL || password == NULL || service == NULL) { return other_error("username, password and service must all be non-null"); } memset(&creds, 0, sizeof(creds)); problem = krb5_init_context(&context); if (problem) { // can't call krb5_ctx_error without a context... response = other_error("unable to initialize krb5 context (%d)", (int)problem); goto out; } problem = krb5_parse_name(context, username, &user_principal); if (problem) { response = krb5_ctx_error(context, problem); goto out; } problem = krb5_get_init_creds_opt_alloc(context, &opt); if (problem) { response = krb5_ctx_error(context, problem); goto out; } problem = krb5_get_init_creds_password(context, &creds, user_principal, (char *)password, NULL, NULL, 0, NULL, opt); switch (problem) { case 0: auth_ok = true; break; case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: /* "expected" error */ auth_ok = false; break; default: /* unexpected error */ response = krb5_ctx_error(context, problem); break; } if (auth_ok && strlen(service) > 0) { response = verify_krb5_kdc(context, &creds, service); } out: krb5_free_cred_contents(context, &creds); if (opt != NULL) { krb5_get_init_creds_opt_free(context, opt); } if (user_principal != NULL) { krb5_free_principal(context, user_principal); } if (context != NULL) { krb5_free_context(context); } if (response == NULL) { response = calloc(1, sizeof(gss_client_response)); if(response == NULL) die1("Memory allocation failed"); response->return_code = auth_ok ? 1 : 0; } return response; }