#include <my_config.h>
#include <gssapi/gssapi.h>
#include <stdio.h>
#include <mysql/plugin_auth.h>
#include <mysqld_error.h>
#include <string.h>
#include "server_plugin.h"
#include "gssapi_errmsg.h"
static gss_name_t service_name = GSS_C_NO_NAME;
/* This sends the error to the client */
static void log_error( OM_uint32 major, OM_uint32 minor, const char *msg)
{
if (GSS_ERROR(major))
{
char sysmsg[1024 ];
gssapi_errmsg(major, minor, sysmsg, sizeof (sysmsg));
my_printf_error(ER_UNKNOWN_ERROR,"Server GSSAPI error (major %u, minor %u) : %s -%s" ,
0 , major, minor, msg, sysmsg);
}
else
{
my_printf_error(ER_UNKNOWN_ERROR, "Server GSSAPI error : %s" , 0 , msg);
}
}
/*
Generate default principal service name formatted as principal name " mariadb / server . fqdn @ REALM "
*/
#include <krb5.h>
#ifdef HAVE_KRB5_XFREE
#define krb5_free_unparsed_name(a,b) krb5_xfree(b)
#endif
static char * get_default_principal_name()
{
static char default_name[1024 ];
char *unparsed_name= NULL;
krb5_context context= NULL;
krb5_principal principal= NULL;
krb5_keyblock *key= NULL;
if (krb5_init_context(&context))
{
my_printf_error(1 , "GSSAPI plugin : krb5_init_context failed" ,
ME_ERROR_LOG | ME_WARNING);
goto cleanup;
}
if (krb5_sname_to_principal(context, NULL, "mariadb" , KRB5_NT_SRV_HST, &principal))
{
my_printf_error(1 , "GSSAPI plugin : krb5_sname_to_principal failed" ,
ME_ERROR_LOG | ME_WARNING);
goto cleanup;
}
if (krb5_unparse_name(context, principal, &unparsed_name))
{
my_printf_error(1 , "GSSAPI plugin : krb5_unparse_name failed" ,
ME_ERROR_LOG | ME_WARNING);
goto cleanup;
}
/* Check for entry in keytab */
if (krb5_kt_read_service_key(context, NULL, principal, 0 , (krb5_enctype)0 , &key))
{
my_printf_error(1 , "GSSAPI plugin : default principal '%s' not found in keytab" ,
ME_ERROR_LOG | ME_WARNING, unparsed_name);
goto cleanup;
}
strncpy(default_name, unparsed_name, sizeof (default_name)-1 );
cleanup:
if (key)
krb5_free_keyblock(context, key);
if (unparsed_name)
krb5_free_unparsed_name(context, unparsed_name);
if (principal)
krb5_free_principal(context, principal);
if (context)
krb5_free_context(context);
return default_name;
}
static void release_service_name()
{
if (service_name != GSS_C_NO_NAME)
{
OM_uint32 minor;
gss_release_name(&minor, &service_name);
service_name= GSS_C_NO_NAME;
}
}
int plugin_init()
{
gss_buffer_desc principal_name_buf;
OM_uint32 major= 0 , minor= 0 ;
gss_cred_id_t cred= GSS_C_NO_CREDENTIAL;
if (srv_keytab_path && srv_keytab_path[0 ])
{
setenv("KRB5_KTNAME" , srv_keytab_path, 1 );
}
if (!srv_principal_name || !srv_principal_name[0 ])
srv_principal_name= get_default_principal_name();
/* import service principal from plain text */
if (srv_principal_name && srv_principal_name[0 ])
{
my_printf_error(1 , "GSSAPI plugin : using principal name '%s'" ,
ME_ERROR_LOG | ME_NOTE, srv_principal_name);
principal_name_buf.length= strlen(srv_principal_name);
principal_name_buf.value= srv_principal_name;
major= gss_import_name(&minor, &principal_name_buf, GSS_C_NT_USER_NAME, &service_name);
if (GSS_ERROR(major))
{
log_error(major, minor, "gss_import_name" );
return -1 ;
}
}
else
{
service_name= GSS_C_NO_NAME;
}
/* Check if SPN configuration is OK */
major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL,
NULL);
if (GSS_ERROR(major))
{
log_error(major, minor, "gss_acquire_cred failed" );
release_service_name();
return -1 ;
}
gss_release_cred(&minor, &cred);
return 0 ;
}
int plugin_deinit()
{
release_service_name();
return 0 ;
}
int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
{
int rc= CR_ERROR; /* return code */
/* GSSAPI related fields */
OM_uint32 major= 0 , minor= 0 , flags= 0 ;
gss_cred_id_t cred= GSS_C_NO_CREDENTIAL; /* credential identifier */
gss_ctx_id_t ctxt= GSS_C_NO_CONTEXT; /* context identifier */
gss_name_t client_name;
gss_buffer_desc client_name_buf, input, output;
char *client_name_str;
const char *user= 0 ;
size_t userlen= 0 ;
int use_full_name= 0 ;
/* server acquires credential */
major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL,
NULL);
if (GSS_ERROR(major))
{
log_error(major, minor, "gss_acquire_cred failed" );
goto cleanup;
}
input.length= 0 ;
input.value= NULL;
do
{
/* receive token from peer */
int len= vio->read_packet(vio, (unsigned char **) &input.value);
if (len < 0 )
{
log_error(0 , 0 , "fail to read token from client" );
goto cleanup;
}
if (!user)
{
if (auth_info->auth_string_length > 0 )
{
use_full_name= 1 ;
user= auth_info->auth_string;
userlen= auth_info->auth_string_length;
}
else
{
use_full_name= 0 ;
user= auth_info->user_name;
userlen= auth_info->user_name_length;
}
}
input.length= len;
major= gss_accept_sec_context(&minor, &ctxt, cred, &input,
GSS_C_NO_CHANNEL_BINDINGS, &client_name,
NULL, &output, &flags, NULL, NULL);
if (GSS_ERROR(major))
{
log_error(major, minor, "gss_accept_sec_context" );
rc= CR_ERROR;
goto cleanup;
}
/* send token to peer */
if (output.length)
{
if (vio->write_packet(vio, (const unsigned char *) output.value, output.length))
{
gss_release_buffer(&minor, &output);
log_error(major, minor, "communication error(write)" );
goto cleanup;
}
gss_release_buffer(&minor, &output);
}
} while (major & GSS_S_CONTINUE_NEEDED);
/* extract plain text client name */
major= gss_display_name(&minor, client_name, &client_name_buf, NULL);
if (GSS_ERROR(major))
{
log_error(major, minor, "gss_display_name" );
goto cleanup;
}
client_name_str= (char *)client_name_buf.value;
/*
* Compare input user name with the actual one . Return success if
* the names match exactly , or if use_full_name parameter is not set
* up to the ' @ ' separator .
*/
if ((userlen == client_name_buf.length) ||
(!use_full_name
&& userlen < client_name_buf.length
&& client_name_str[userlen] == '@' ))
{
if (user && strncmp(client_name_str, user, userlen) == 0 )
{
rc= CR_OK;
}
}
if (rc != CR_OK)
{
my_printf_error(ER_ACCESS_DENIED_ERROR,
"GSSAPI name mismatch, requested '%s', actual name '%.*s'" ,
0 , user, (int )client_name_buf.length, client_name_str);
}
gss_release_buffer(&minor, &client_name_buf);
cleanup:
if (ctxt != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&minor, &ctxt, GSS_C_NO_BUFFER);
if (cred != GSS_C_NO_CREDENTIAL)
gss_release_cred(&minor, &cred);
return (rc);
}
Messung V0.5 in Prozent C=95 H=73 G=84
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland