]> jfr.im git - solanum.git/blob - extensions/sasl_usercloak.c
Add sasl_usercloak module, to allow injecting SASL account name into a user's host...
[solanum.git] / extensions / sasl_usercloak.c
1 #include "stdinc.h"
2 #include "modules.h"
3 #include "hook.h"
4 #include "client.h"
5 #include "ircd.h"
6 #include "send.h"
7 #include "hash.h"
8 #include "s_conf.h"
9 #include "s_user.h"
10 #include "s_serv.h"
11 #include "numeric.h"
12
13 #include <stdint.h>
14
15 static void check_new_user(void *data);
16 mapi_hfn_list_av1 sasl_usercloak_hfnlist[] = {
17 { "new_local_user", (hookfn) check_new_user },
18 { NULL, NULL }
19 };
20
21 DECLARE_MODULE_AV1(sasl_usercloak, NULL, NULL, NULL, NULL,
22 sasl_usercloak_hfnlist, "$Revision: 3526 $");
23
24 unsigned int fnv_hash_string(char *str)
25 {
26 unsigned int hash = 0x811c9dc5; // Magic value for 32-bit fnv1 hash initialisation.
27 unsigned char *p = (unsigned char *)str;
28 while (*p)
29 {
30 hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
31 hash ^= *p++;
32 }
33 return hash;
34 }
35
36 static void
37 check_new_user(void *vdata)
38 {
39 struct Client *source_p = (void *)vdata;
40
41 if (!IsIPSpoof(source_p))
42 return;
43
44 if (EmptyString(source_p->user->suser))
45 return;
46
47 char *accountpart = strstr(source_p->host, "account");
48 if (!accountpart)
49 return;
50
51 char buf[HOSTLEN];
52 char *dst = buf;
53
54 strncpy(buf, source_p->host, accountpart - source_p->host);
55 dst += accountpart - source_p->host;
56
57 int needhash = 0;
58
59 for (char *src = source_p->user->suser; *src ; src++ )
60 {
61 if (dst > buf + sizeof(buf))
62 {
63 /* Doesn't fit. Warn opers and bail. */
64 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
65 "Couldn't fit account name part %s in hostname for %s!%s@%s",
66 source_p->user->suser, source_p->name, source_p->username, source_p->host);
67 return;
68 }
69
70 char c = ToLower(*src);
71
72 if (IsHostChar(c))
73 *dst++ = c;
74 else
75 needhash = 1;
76 }
77
78 if (needhash)
79 {
80 if (dst > buf + sizeof(buf) - 12) /* '/x-' plus eight digit hash plus null terminator */
81 {
82 /* Doesn't fit. Warn opers and bail. */
83 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
84 "Couldn't fit account name part %s in hostname for %s!%s@%s",
85 source_p->user->suser, source_p->name, source_p->user, source_p->host);
86 return;
87 }
88
89 *dst++ = '/';
90 *dst++ = 'x';
91 *dst++ = '-';
92
93 unsigned int hashval = fnv_hash_string(source_p->user->suser);
94 hashval %= 100000000; // eight digits only please.
95 snprintf(dst, 9, "%08ud", hashval);
96 }
97
98 /* just in case */
99 buf[HOSTLEN-1] = '\0';
100
101 change_nick_user_host(source_p, source_p->name, source_p->username, buf, 0, "Changing host");
102 }