Tip of the day: Channel mode +H provides Channel history to modern clients. Optionally, it can be stored on-disk to be preserved between server restarts.
|
Dev:Authentication module
Jump to navigation
Jump to search
Usually, you use Services which provide SASL. Sometimes, a (third party) module may want to provide SASL locally instead.
Note that at the time of writing this is still a dumb interface and not a real proper authentication framework.
To do so, in your module:
- First, point set::sasl-server to your own servername (as shown in the module below in MOD_LOAD).
- Hook into HOOKTYPE_SASL_MECHS and tell what SASL mechanisms you support
- Hook into HOOKTYPE_SASL_AUTHENTICATE:
- Check the authentication mechanism if first==1 and set client->local->sasl_agent if you are OK with it.
- Do the authentication when first==0, you can use the decode_authenticate_plain() helper function
- If succeeded: set client->user->account, call user_account_login() and sasl_succeeded()
- If rejected: call sasl_failed()
/* SASL Authentication Example Backend Module
* (C) Copyright 2024 Bram Matthys ("Syzop")
* License: GPLv2 or later
*
* This is a simple local SASL backend example module for
* illustrative purposes only.
* If you log in with SASL, method AUTHENTICATE PLAIN,
* with the account "Example" and password "test"
* (both are case sensitive) then SASL authentication will
* succeed and you will be logged into the account "Example".
*
* This module does not do anything else. In particular
* it does not provide any nick-related functions such as
* nick ownership nor does it set user mode +r.
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER
= {
"third/auth_example",
"1.0.0",
"SASL authentication example backend module",
"UnrealIRCd Team",
"unrealircd-6",
};
/* Forward declarations */
int auth_example_sasl_authenticate(Client *client, int first, const char *param);
const char *auth_example_sasl_mechs(Client *client);
MOD_INIT()
{
ModDataInfo mreq;
HookAdd(modinfo->handle, HOOKTYPE_SASL_AUTHENTICATE, 0, auth_example_sasl_authenticate);
HookAddConstString(modinfo->handle, HOOKTYPE_SASL_MECHS, 0, auth_example_sasl_mechs);
return MOD_SUCCESS;
}
MOD_LOAD()
{
/* Set the set::sasl-server to our server name */
safe_strdup(iConf.sasl_server, me.name);
return MOD_SUCCESS;
}
MOD_UNLOAD()
{
return MOD_SUCCESS;
}
int auth_example_check_auth(const char *username, const char *passwd)
{
if (!strcmp(username, "Example") && !strcmp(passwd, "test"))
return 1;
return 0;
}
const char *auth_example_sasl_mechs(Client *client)
{
return "PLAIN";
}
int auth_example_sasl_authenticate(Client *client, int first, const char *param)
{
char *authorization_id = NULL;
char *authentication_id = NULL;
char *passwd = NULL;
if (first)
{
if (!strcmp(param, "PLAIN"))
{
/* Yup, we'll take that request */
strlcpy(client->local->sasl_agent, me.name, sizeof(client->local->sasl_agent));
sendto_one(client, NULL, "AUTHENTICATE +");
} else {
sasl_failed(client);
}
return 0;
}
/* Else it is a continuation and we can do the authentication now */
if (!decode_authenticate_plain(param, &authorization_id, &authentication_id, &passwd))
{
sasl_failed(client);
return 0;
}
if (auth_example_check_auth(authentication_id, passwd))
{
strlcpy(client->user->account, authentication_id, sizeof(client->user->account));
user_account_login(NULL, client); // mtags is NULL here because we don't have it
if (IsDead(client))
return 0; /* was killed due to *LINE on ~account probably */
sasl_succeeded(client);
} else {
sasl_failed(client);
}
return 0;
}