mech-gssapi.c revision 6edf77bf423fe09849a79fd4077a697b8dc14a41
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen * GSSAPI Module
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen * Copyright (c) 2005 Jelmer Vernooij <jelmer@samba.org>
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen * Related standards:
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen * - draft-ietf-sasl-gssapi-03
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen * Some parts inspired by an older patch from Colin Walters
e074ffeaee1ce283bd42f167c6810e3d013f8218Timo Sirainen * This software is released under the MIT license.
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen/* Non-zero flags defined in RFC 2222 */
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenstatic void auth_request_log_gss_error(struct auth_request *request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_display_status(&minor_status, status_value,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen str_sanitize(status_string.value, (size_t)-1));
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_release_buffer(&minor_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen } while (message_context != 0);
448723dc1c12b126dd2d348d4ce385203abbaa7dTimo Sirainen#elif defined (HAVE_KRB5_GSS_REGISTER_ACCEPTOR_IDENTITY)
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenstatic struct auth_request *mech_gssapi_auth_new(void)
e03ec0b7b9d92551331bc509bcd86920544171d1Timo Sirainen pool = pool_alloconly_create("gssapi_auth_request", 1024);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen request = p_new(pool, struct gssapi_auth_request, 1);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenstatic OM_uint32 obtain_service_credentials(struct auth_request *request,
bde5b40c4fcc20e812a7caff9c0ed55e7090ced9Timo Sirainen if (strcmp(request->auth->gssapi_hostname, "$ALL") == 0) {
bde5b40c4fcc20e812a7caff9c0ed55e7090ced9Timo Sirainen "Using all keytab entries");
893f7d52acc42058045f188b625449981bd7f9bcTimo Sirainen if (strcasecmp(request->service, "POP3") == 0) {
893f7d52acc42058045f188b625449981bd7f9bcTimo Sirainen /* The standard POP3 service name with GSSAPI is called
893f7d52acc42058045f188b625449981bd7f9bcTimo Sirainen just "pop". */
ee5be4287d37f251f683fd2755eafc02504d527cTimo Sirainen str_append(principal_name, request->auth->gssapi_hostname);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "Obtaining credentials for %s", str_c(principal_name));
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen inbuf.value = str_c_modifiable(principal_name);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_import_name(&minor_status, &inbuf,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(request, major_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "importing principal name");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_acquire_cred(&minor_status, gss_principal, 0,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(request, major_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "acquiring service credentials");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(request, minor_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "acquiring service credentials");
da3f943e93b0ea5a8256a2e850f4738ad161f71dTimo Sirainen gss_release_name(&minor_status, &gss_principal);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenimport_name(struct auth_request *request, void *str, size_t len)
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(request, major_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenstatic void gssapi_sec_context(struct gssapi_auth_request *request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(&request->auth_request, major_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "processing incoming data");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(&request->auth_request, minor_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "processing incoming data");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_info(&request->auth_request, "gssapi",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "security context state completed.");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_info(&request->auth_request, "gssapi",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "Processed incoming packet correctly, "
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "waiting for another.");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen request->auth_request.callback(&request->auth_request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_release_buffer(&minor_status, &outbuf);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenstatic void gssapi_wrap(struct gssapi_auth_request *request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen /* The clients return data should be empty here */
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen /* Only authentication, no integrity or confidentiality
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen protection (yet?) */
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_wrap(&minor_status, request->gss_ctx, 0,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(&request->auth_request, major_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen GSS_C_GSS_CODE, "sending security layer negotiation");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(&request->auth_request, minor_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen GSS_C_MECH_CODE, "sending security layer negotiation");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_info(&request->auth_request, "gssapi",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "Negotiated security layer");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen request->auth_request.callback(&request->auth_request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_release_buffer(&minor_status, &outbuf);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen request->sasl_gssapi_state = GSS_STATE_UNWRAP;
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainengssapi_krb5_userok(struct gssapi_auth_request *request, gss_name_t name,
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen /* Parse out the principal's username */
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen major_status = gss_display_name(&minor_status, name,
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen auth_request_log_gss_error(&request->auth_request, major_status,
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen "gssapi_krb5_userok");
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen if (name_type != GSS_KRB5_NT_PRINCIPAL_NAME && check_name_type) {
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen "OID not kerberos principal name");
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen princ_display_name = t_strndup(princ_name.value, princ_name.length);
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen gss_release_buffer(&minor_status, &princ_name);
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen /* Init a krb5 context and parse the principal username */
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen "krb5_init_context() failed: %d", (int)krb5_err);
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen krb5_err = krb5_parse_name(ctx, princ_display_name, &princ);
c869c075b0b558e82a613a8320b3b3a7e120741bTimo Sirainen /* writing the error string would be better, but we probably
c869c075b0b558e82a613a8320b3b3a7e120741bTimo Sirainen rarely get here and there doesn't seem to be a standard
c869c075b0b558e82a613a8320b3b3a7e120741bTimo Sirainen way of getting it */
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
c869c075b0b558e82a613a8320b3b3a7e120741bTimo Sirainen "krb5_parse_name() failed: %d",
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen /* See if the principal is authorized to act as the
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen specified user */
c5b99a8a85370e7d1f7edb1fcb18a9d44616f726Timo Sirainen ret = krb5_kuserok(ctx, princ, request->auth_request.user);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenstatic void gssapi_unwrap(struct gssapi_auth_request *request,
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen#if defined(HAVE___GSS_USEROK) || !defined(USE_KRB5_USEROK)
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_unwrap(&minor_status, request->gss_ctx,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_gss_error(&request->auth_request, major_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "final negotiation: gss_unwrap");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "Invalid response length");
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen /* Solaris __gss_userok() correctly handles cross-realm
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen authentication. */
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen major_status = __gss_userok(&minor_status, request->authn_name,
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen auth_request_log_gss_error(&request->auth_request, major_status,
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen "__gss_userok failed");
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
44a9b5fc1b57e5cc0a113f8cada9d9011747cadcTimo Sirainen "credentials not valid");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen request->authz_name = import_name(&request->auth_request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen /* XXX (pod): is this check necessary? */
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "one of authn_name or authz_name not determined");
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen if (!gssapi_krb5_userok(request, request->authn_name, TRUE)) {
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen "authn_name not authorized");
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen if (!gssapi_krb5_userok(request, request->authz_name, FALSE)) {
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
6edf77bf423fe09849a79fd4077a697b8dc14a41Timo Sirainen "authz_name not authorized");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_compare_name(&minor_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_log_error(&request->auth_request, "gssapi",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen "authn_name and authz_name differ: not supported");
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen auth_request_success(&request->auth_request, NULL, 0);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenmech_gssapi_auth_continue(struct auth_request *request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenmech_gssapi_auth_initial(struct auth_request *request,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen gssapi_request->sasl_gssapi_state = GSS_STATE_SEC_CONTEXT;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen /* The client should go first */
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen request->callback(request, AUTH_CLIENT_RESULT_CONTINUE,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen mech_gssapi_auth_continue(request, data, data_size);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainenmech_gssapi_auth_free(struct auth_request *request)
9e3f0cc69cbc4af74d08d1e52aa5ed8a7675b8f1Timo Sirainen if (gssapi_request->gss_ctx != GSS_C_NO_CONTEXT) {
9e3f0cc69cbc4af74d08d1e52aa5ed8a7675b8f1Timo Sirainen major_status = gss_delete_sec_context(&minor_status,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen major_status = gss_release_cred(&minor_status,
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen if (gssapi_request->authn_name != GSS_C_NO_NAME) {
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen major_status = gss_release_name(&minor_status,
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen if (gssapi_request->authz_name != GSS_C_NO_NAME) {
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen major_status = gss_release_name(&minor_status,
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen/* MTI Kerberos v1.5+ and Heimdal v0.7+ supports SPNEGO for Kerberos tickets
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen internally. Nothing else needs to be done here. Note however that this does
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen not support SPNEGO when the only available credential is NTLM.. */
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainenconst struct mech_module mech_gssapi_spnego = {
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen "GSS-SPNEGO",