]> jfr.im git - solanum.git/blob - extensions/sasl_usercloak.c
extensions/umode_hide_idle_time: mask times for hidden sources (#373)
[solanum.git] / extensions / sasl_usercloak.c
1 #include "stdinc.h"
2 #include "modules.h"
3 #include "hook.h"
4 #include "client.h"
5 #include "hostmask.h"
6 #include "ircd.h"
7 #include "send.h"
8 #include "hash.h"
9 #include "s_conf.h"
10 #include "s_user.h"
11 #include "s_serv.h"
12 #include "numeric.h"
13
14 #include <stdint.h>
15
16 static const char sasl_usercloak_desc[] =
17 "Insert the SASL account name into certain iline spoofed hosts";
18
19 static void check_new_user(void *data);
20 mapi_hfn_list_av1 sasl_usercloak_hfnlist[] = {
21 { "new_local_user", check_new_user },
22 { NULL, NULL }
23 };
24
25
26 unsigned int fnv_hash_string(char *str)
27 {
28 unsigned int hash = 0x811c9dc5; // Magic value for 32-bit fnv1 hash initialisation.
29 unsigned char *p = (unsigned char *)str;
30 while (*p)
31 {
32 hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
33 hash ^= *p++;
34 }
35 return hash;
36 }
37
38 static void
39 check_new_user(void *vdata)
40 {
41 struct Client *source_p = vdata;
42
43 if (IsAnyDead(source_p))
44 return;
45
46 if (!IsIPSpoof(source_p))
47 return;
48
49 if (EmptyString(source_p->user->suser))
50 return;
51
52 char *accountpart = strstr(source_p->orighost, "/account");
53 if (!accountpart || accountpart[8] != '\0')
54 return;
55
56 accountpart += 1;
57
58 char buf[HOSTLEN];
59 memset(buf, 0, sizeof(buf));
60 char *dst = buf;
61
62 strncpy(buf, source_p->orighost, accountpart - source_p->orighost);
63 dst += accountpart - source_p->orighost;
64
65 int needhash = 0;
66
67 for (char *src = source_p->user->suser; *src ; src++ )
68 {
69 if (dst >= buf + sizeof(buf))
70 {
71 /* Doesn't fit. Warn opers and bail. */
72 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
73 "Couldn't fit account name part %s in hostname for %s!%s@%s",
74 source_p->user->suser, source_p->name, source_p->username, source_p->orighost);
75 return;
76 }
77
78 char c = tolower(*src);
79
80 if (IsHostChar(c))
81 *dst++ = c;
82 else
83 needhash = 1;
84 }
85
86 if (needhash)
87 {
88 if (dst > buf + sizeof(buf) - 12) /* '/x-' plus eight digit hash plus null terminator */
89 {
90 /* Doesn't fit. Warn opers and bail. */
91 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
92 "Couldn't fit account name part %s in hostname for %s!%s@%s",
93 source_p->user->suser, source_p->name, source_p->username, source_p->orighost);
94 return;
95 }
96
97 *dst++ = '/';
98 *dst++ = 'x';
99 *dst++ = '-';
100
101 unsigned int hashval = fnv_hash_string(source_p->user->suser);
102 hashval %= 100000000; // eight digits only please.
103 snprintf(dst, 9, "%08u", hashval);
104 }
105
106 /* just in case */
107 buf[HOSTLEN-1] = '\0';
108
109 /* If hostname has been changed already (probably by services cloak on SASL login), then
110 * leave it intact. If not, change it. In either case, update the original hostname.
111 */
112 if (0 == irccmp(source_p->host, source_p->orighost))
113 change_nick_user_host(source_p, source_p->name, source_p->username, buf, 0, "Changing host");
114 strncpy(source_p->orighost, buf, HOSTLEN);
115
116 {
117 struct ConfItem *aconf = find_kline(source_p);
118
119 if(aconf == NULL)
120 return;
121
122 if(IsExemptKline(source_p))
123 {
124 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
125 "KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
126 get_client_name(source_p, HIDE_IP),
127 aconf->user, aconf->host);
128 return;
129 }
130
131 sendto_realops_snomask(SNO_BANNED, L_NETWIDE,
132 "Rejecting K-Lined user %s [%s] (%s@%s)", get_client_name(source_p, HIDE_IP),
133 show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255", aconf->user, aconf->host);
134
135 notify_banned_client(source_p, aconf, K_LINED);
136 }
137 }
138
139 DECLARE_MODULE_AV2(sasl_usercloak, NULL, NULL, NULL, NULL, sasl_usercloak_hfnlist, NULL, NULL, sasl_usercloak_desc);