Tip of the day: The Security article gives hands-on tips on how to deal with drone attacks, flooding, spammers, (D)DoS and more. |
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; }