Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ tools/sidconvert/sid2num
tools/sidconvert/num2sid
!tools/sidconvert/Makefile
.*.sw?

# iauthd-ts build artifacts
tools/iauthd-ts/dist/
tools/iauthd-ts/node_modules/
26 changes: 22 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ FROM debian:12
ENV GID 1234
ENV UID 1234

RUN DEBIAN_FRONTEND=noninteractive RUNLEVEL=1 apt-get update
RUN DEBIAN_FRONTEND=noninteractive RUNLEVEL=1 apt-get update && apt-get -y install build-essential libssl-dev autoconf automake flex libpcre3-dev byacc gawk git vim libpoe-perl libpoe-component-client-dns-perl libterm-readkey-perl libfile-slurp-perl libtime-duration-perl procps net-tools iputils-ping bind9-host
#libgeoip-dev libmaxminddb-dev
RUN DEBIAN_FRONTEND=noninteractive RUNLEVEL=1 apt-get update
RUN DEBIAN_FRONTEND=noninteractive RUNLEVEL=1 apt-get -y install build-essential libssl-dev autoconf automake flex libpcre3-dev byacc gawk git vim procps net-tools iputils-ping bind9-host
#libgeoip-dev libmaxminddb-dev

# Perl dependencies for iauthd.pl (commented out - using TypeScript version)
#RUN DEBIAN_FRONTEND=noninteractive apt-get -y install libpoe-perl libpoe-component-client-dns-perl libterm-readkey-perl libfile-slurp-perl libtime-duration-perl

# Node.js for iauthd-ts
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install nodejs npm

RUN mkdir -p /home/nefarious/nefarious2
RUN mkdir -p /home/nefarious/ircd
Expand All @@ -29,6 +35,16 @@ RUN ./configure --libdir=/home/nefarious/ircd --enable-debug --with-maxcon=4096
RUN make
RUN touch /home/nefarious/ircd/ircd.pem && make install && rm /home/nefarious/ircd/ircd.pem

# Build iauthd-ts
WORKDIR /home/nefarious/nefarious2/tools/iauthd-ts
RUN npm install && npm run build

# Copy iauthd-ts to ircd directory
RUN cp -r /home/nefarious/nefarious2/tools/iauthd-ts/dist /home/nefarious/ircd/iauthd-ts
RUN cp /home/nefarious/nefarious2/tools/iauthd-ts/package.json /home/nefarious/ircd/iauthd-ts/
WORKDIR /home/nefarious/ircd/iauthd-ts
RUN npm install --omit=dev

WORKDIR /home/nefarious/ircd

USER root
Expand All @@ -41,7 +57,9 @@ USER nefarious

COPY ./tools/docker/dockerentrypoint.sh /home/nefarious/dockerentrypoint.sh
COPY ./tools/linesync/gitsync.sh /home/nefarious/ircd/gitsync.sh
COPY ./tools/iauthd.pl /home/nefarious/ircd/iauthd.pl

# Perl iauthd (commented out - using TypeScript version)
#COPY ./tools/iauthd.pl /home/nefarious/ircd/iauthd.pl

#This ircd.conf just includes the other 3
COPY tools/docker/ircd.conf /home/nefarious/ircd/ircd.conf
Expand Down
6 changes: 6 additions & 0 deletions include/s_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,11 @@ extern void auth_close_unused(void);
extern void report_iauth_conf(struct Client *cptr, const struct StatDesc *sd, char *param);
extern void report_iauth_stats(struct Client *cptr, const struct StatDesc *sd, char *param);

/* SASL via IAuth */
extern int auth_iauth_handles_sasl(void);
extern int auth_send_sasl_start(struct Client *cptr, const char *mechanism, const char *certfp);
extern int auth_send_sasl_host(struct Client *cptr, const char *username, const char *host, const char *ip);
extern int auth_send_sasl_data(struct Client *cptr, const char *data);

#endif /* INCLUDED_s_auth_h */

40 changes: 40 additions & 0 deletions ircd/m_authenticate.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
#include "numnicks.h"
#include "random.h"
#include "send.h"
#include "s_auth.h"
#include "s_misc.h"
#include "s_user.h"

Expand All @@ -120,6 +121,45 @@ int m_authenticate(struct Client* cptr, struct Client* sptr, int parc, char* par
if (IsSASLComplete(cptr))
return send_reply(cptr, ERR_SASLALREADY);

/* Check if IAuth handles SASL */
if (auth_iauth_handles_sasl()) {
/* Route SASL to IAuth */
if (!cli_saslcookie(cptr)) {
do {
cli_saslcookie(cptr) = ircrandom() & 0x7fffffff;
} while (!cli_saslcookie(cptr));
first = 1;
}

if (strchr(hoststr, ':') != NULL)
ircd_snprintf(0, realhost, sizeof(realhost), "[%s]", hoststr);
else
ircd_strncpy(realhost, hoststr, sizeof(realhost));

if (first) {
if (*parv[1] == ':' || strchr(parv[1], ' '))
return exit_client(cptr, sptr, sptr, "Malformed AUTHENTICATE");

/* Send SASL start to IAuth */
auth_send_sasl_start(cptr, parv[1], cli_sslclifp(cptr));

/* Send host info if configured */
if (feature_bool(FEAT_SASL_SENDHOST))
auth_send_sasl_host(cptr, cli_username(cptr), realhost, cli_sock_ip(cptr));
} else {
/* Send SASL continuation data to IAuth */
auth_send_sasl_data(cptr, parv[1]);
}

if (!t_active(&cli_sasltimeout(cptr)))
timer_add(timer_init(&cli_sasltimeout(cptr)), sasl_timeout_callback, (void*) cptr,
TT_RELATIVE, feature_int(FEAT_SASL_TIMEOUT));

return 0;
}

/* Original code: route SASL to services via P10 */

/* Look up the target server */
if (!(acptr = cli_saslagent(cptr))) {
if (strcmp(feature_str(FEAT_SASL_SERVER), "*"))
Expand Down
172 changes: 172 additions & 0 deletions ircd/s_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ enum IAuthFlag
IAUTH_SSLFP, /**< Enable Nefarious SSL client certificate fingerprint notifcation. */
IAUTH_ACCOUNT, /**< Enable Nefarious SASL account notification. */
IAUTH_EVENTS, /**< Enable Nefarious Event notifications. */
IAUTH_SASL, /**< Enable SASL authentication handling in IAuth. */
IAUTH_LAST_FLAG /**< total number of flags */
};
/** Declare a bitset structure indexed by IAuthFlag. */
Expand Down Expand Up @@ -1432,6 +1433,59 @@ int auth_cap_done(struct AuthRequest *auth)
return check_auth_finished(auth);
}

/** Check if IAuth is configured to handle SASL authentication.
* @return Non-zero if IAuth handles SASL, zero otherwise.
*/
int auth_iauth_handles_sasl(void)
{
return IAuthHas(iauth, IAUTH_SASL);
}

/** Send SASL authentication start to IAuth.
* @param[in] cptr Client starting SASL.
* @param[in] mechanism SASL mechanism name.
* @param[in] certfp SSL certificate fingerprint (may be NULL).
* @return Non-zero on success, zero on failure.
*/
int auth_send_sasl_start(struct Client *cptr, const char *mechanism, const char *certfp)
{
if (!IAuthHas(iauth, IAUTH_SASL))
return 0;

if (!EmptyString(certfp))
return sendto_iauth(cptr, "A S %s :%s", mechanism, certfp);
else
return sendto_iauth(cptr, "A S :%s", mechanism);
}

/** Send SASL host information to IAuth.
* @param[in] cptr Client authenticating.
* @param[in] username Client's username.
* @param[in] host Client's hostname.
* @param[in] ip Client's IP address.
* @return Non-zero on success, zero on failure.
*/
int auth_send_sasl_host(struct Client *cptr, const char *username, const char *host, const char *ip)
{
if (!IAuthHas(iauth, IAUTH_SASL))
return 0;

return sendto_iauth(cptr, "A H :%s@%s:%s", username, host, ip);
}

/** Send SASL authentication data to IAuth.
* @param[in] cptr Client authenticating.
* @param[in] data Base64-encoded SASL data.
* @return Non-zero on success, zero on failure.
*/
int auth_send_sasl_data(struct Client *cptr, const char *data)
{
if (!IAuthHas(iauth, IAUTH_SASL))
return 0;

return sendto_iauth(cptr, "a :%s", data);
}

/** Attempt to spawn the process for an IAuth instance.
* @param[in] iauth IAuth descriptor.
* @param[in] automatic If non-zero, apply sanity checks against
Expand Down Expand Up @@ -1828,6 +1882,7 @@ static int iauth_cmd_policy(struct IAuth *iauth, struct Client *cli,
case 'F': IAuthSet(iauth, IAUTH_SSLFP); break;
case 'r': IAuthSet(iauth, IAUTH_ACCOUNT); break;
case 'e': IAuthSet(iauth, IAUTH_EVENTS); break;
case 'S': IAuthSet(iauth, IAUTH_SASL); break;
}

/* Optionally notify operators. */
Expand Down Expand Up @@ -2429,6 +2484,117 @@ static int iauth_cmd_xquery(struct IAuth *iauth, struct Client *cli,
return 0;
}

/** Handle SASL challenge from IAuth.
* @param[in] iauth Active IAuth session.
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters (1).
* @param[in] params Challenge data (base64).
* @return Zero.
*/
static int iauth_cmd_sasl_challenge(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
{
if (EmptyString(params[0]))
return 0;

/* Forward challenge to client */
sendrawto_one(cli, "AUTHENTICATE %s", params[0]);
return 0;
}

/** Handle SASL login success from IAuth.
* @param[in] iauth Active IAuth session.
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters (1+).
* @param[in] params Account name.
* @return Non-zero to check auth completion.
*/
static int iauth_cmd_sasl_loggedin(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
{
size_t len;

if (EmptyString(params[0])) {
sendto_iauth(cli, "E Missing :Missing account parameter");
return 0;
}

/* Check length of account name. */
len = strcspn(params[0], ": ");
if (len > ACCOUNTLEN) {
sendto_iauth(cli, "E Invalid :Account parameter too long");
return 0;
}

/* Store account in SASL fields */
ircd_strncpy(cli_saslaccount(cli), params[0], ACCOUNTLEN);

/* If account has a creation timestamp, use it. */
if (params[0][len] == ':') {
cli_saslacccreate(cli) = strtoul(params[0] + len + 1, NULL, 10);
}

/* Send RPL_LOGGEDIN to client */
send_reply(cli, RPL_LOGGEDIN, cli_name(cli), cli_user(cli) ? cli_user(cli)->username : "*",
cli_user(cli) ? cli_user(cli)->host : "*", cli_saslaccount(cli), cli_saslaccount(cli));

return 0;
}

/** Handle SASL authentication failure from IAuth.
* @param[in] iauth Active IAuth session.
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters.
* @param[in] params Unused.
* @return Zero.
*/
static int iauth_cmd_sasl_fail(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
{
send_reply(cli, ERR_SASLFAIL, EmptyString(params[0]) ? "" : params[0]);
return 0;
}

/** Handle SASL mechanism list from IAuth.
* @param[in] iauth Active IAuth session.
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters (1).
* @param[in] params Mechanism list.
* @return Zero.
*/
static int iauth_cmd_sasl_mechs(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
{
if (EmptyString(params[0]))
return 0;

send_reply(cli, ERR_SASLMECHS, params[0]);
return 0;
}

/** Handle SASL authentication success (done) from IAuth.
* @param[in] iauth Active IAuth session.
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters.
* @param[in] params Unused.
* @return Zero.
*/
static int iauth_cmd_sasl_done(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
{
/* Mark SASL as complete */
SetFlag(cli, FLAG_SASLCOMPLETE);

/* Send success to client */
send_reply(cli, RPL_SASLSUCCESS);

/* Cancel SASL timeout */
if (t_active(&cli_sasltimeout(cli)))
timer_del(&cli_sasltimeout(cli));

return 0;
}

/** Parse a \a message from \a iauth.
* @param[in] iauth Active IAuth session.
* @param[in] message Message to be parsed.
Expand Down Expand Up @@ -2472,6 +2638,12 @@ static void iauth_parse(struct IAuth *iauth, char *message)
*/
case 'K': handler = iauth_cmd_kill; has_cli = 2; break;
case 'r': /* we handle termination directly */ return;
/* SASL-related commands from IAuth */
case 'c': handler = iauth_cmd_sasl_challenge; has_cli = 2; break;
case 'L': handler = iauth_cmd_sasl_loggedin; has_cli = 2; break;
case 'f': handler = iauth_cmd_sasl_fail; has_cli = 2; break;
case 'l': handler = iauth_cmd_sasl_mechs; has_cli = 2; break;
case 'Z': handler = iauth_cmd_sasl_done; has_cli = 2; break;
default: sendto_iauth(NULL, "E Garbage :[%s]", message); return;
}

Expand Down
Loading