]> jfr.im git - solanum.git/blame - extensions/sasl_usercloak.c
sasl_usercloak: check K-lines after host change
[solanum.git] / extensions / sasl_usercloak.c
CommitLineData
721410d5
SB
1#include "stdinc.h"
2#include "modules.h"
3#include "hook.h"
4#include "client.h"
5958d6b9 5#include "hostmask.h"
721410d5
SB
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
16static void check_new_user(void *data);
17mapi_hfn_list_av1 sasl_usercloak_hfnlist[] = {
18 { "new_local_user", (hookfn) check_new_user },
19 { NULL, NULL }
20};
21
22DECLARE_MODULE_AV1(sasl_usercloak, NULL, NULL, NULL, NULL,
23 sasl_usercloak_hfnlist, "$Revision: 3526 $");
24
5958d6b9
EK
25enum
26{
27 D_LINED,
28 K_LINED
29};
30
31static void
32notify_banned_client(struct Client *client_p, struct ConfItem *aconf, int ban)
33{
34 static const char conn_closed[] = "Connection closed";
35 static const char d_lined[] = "D-lined";
36 static const char k_lined[] = "K-lined";
37 const char *reason = NULL;
38 const char *exit_reason = conn_closed;
39
40 if(ConfigFileEntry.kline_with_reason)
41 {
42 reason = get_user_ban_reason(aconf);
43 exit_reason = reason;
44 }
45 else
46 {
47 reason = aconf->status == D_LINED ? d_lined : k_lined;
48 }
49
50 if(ban == D_LINED && !IsPerson(client_p))
51 sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined");
52 else
53 sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
54 me.name, client_p->name, reason);
55
56 exit_client(client_p, client_p, &me,
57 EmptyString(ConfigFileEntry.kline_reason) ? exit_reason :
58 ConfigFileEntry.kline_reason);
59}
60
721410d5
SB
61unsigned int fnv_hash_string(char *str)
62{
63 unsigned int hash = 0x811c9dc5; // Magic value for 32-bit fnv1 hash initialisation.
64 unsigned char *p = (unsigned char *)str;
65 while (*p)
66 {
67 hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
68 hash ^= *p++;
69 }
70 return hash;
71}
72
73static void
74check_new_user(void *vdata)
75{
76 struct Client *source_p = (void *)vdata;
77
78 if (!IsIPSpoof(source_p))
79 return;
80
81 if (EmptyString(source_p->user->suser))
82 return;
83
dae6f5db 84 char *accountpart = strstr(source_p->orighost, "account");
721410d5
SB
85 if (!accountpart)
86 return;
87
88 char buf[HOSTLEN];
271ddd99 89 memset(buf, 0, sizeof(buf));
721410d5
SB
90 char *dst = buf;
91
dae6f5db
SB
92 strncpy(buf, source_p->orighost, accountpart - source_p->orighost);
93 dst += accountpart - source_p->orighost;
721410d5
SB
94
95 int needhash = 0;
96
97 for (char *src = source_p->user->suser; *src ; src++ )
98 {
5958d6b9 99 if (dst >= buf + sizeof(buf))
721410d5
SB
100 {
101 /* Doesn't fit. Warn opers and bail. */
102 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
103 "Couldn't fit account name part %s in hostname for %s!%s@%s",
dae6f5db 104 source_p->user->suser, source_p->name, source_p->username, source_p->orighost);
721410d5
SB
105 return;
106 }
107
108 char c = ToLower(*src);
109
110 if (IsHostChar(c))
111 *dst++ = c;
112 else
113 needhash = 1;
114 }
115
116 if (needhash)
117 {
118 if (dst > buf + sizeof(buf) - 12) /* '/x-' plus eight digit hash plus null terminator */
119 {
120 /* Doesn't fit. Warn opers and bail. */
121 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
122 "Couldn't fit account name part %s in hostname for %s!%s@%s",
dae6f5db 123 source_p->user->suser, source_p->name, source_p->username, source_p->orighost);
721410d5
SB
124 return;
125 }
126
127 *dst++ = '/';
128 *dst++ = 'x';
129 *dst++ = '-';
130
131 unsigned int hashval = fnv_hash_string(source_p->user->suser);
132 hashval %= 100000000; // eight digits only please.
133 snprintf(dst, 9, "%08ud", hashval);
134 }
135
136 /* just in case */
137 buf[HOSTLEN-1] = '\0';
138
dae6f5db
SB
139 /* If hostname has been changed already (probably by services cloak on SASL login), then
140 * leave it intact. If not, change it. In either case, update the original hostname.
141 */
142 if (0 == irccmp(source_p->host, source_p->orighost))
143 change_nick_user_host(source_p, source_p->name, source_p->username, buf, 0, "Changing host");
144 strncpy(source_p->orighost, buf, HOSTLEN);
5958d6b9
EK
145
146 {
147 struct ConfItem *aconf = find_kline(source_p);
148
149 if(aconf == NULL)
150 return;
151
152 if(IsExemptKline(source_p))
153 {
154 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
155 "KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
156 get_client_name(source_p, HIDE_IP),
157 aconf->user, aconf->host);
158 return;
159 }
160
161 sendto_realops_snomask(SNO_GENERAL, L_ALL,
162 "KLINE active for %s",
163 get_client_name(source_p, HIDE_IP));
164
165 notify_banned_client(source_p, aconf, K_LINED);
166 }
721410d5 167}