]>
Commit | Line | Data |
---|---|---|
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 | ||
16 | static void check_new_user(void *data); | |
17 | mapi_hfn_list_av1 sasl_usercloak_hfnlist[] = { | |
18 | { "new_local_user", (hookfn) check_new_user }, | |
19 | { NULL, NULL } | |
20 | }; | |
21 | ||
22 | DECLARE_MODULE_AV1(sasl_usercloak, NULL, NULL, NULL, NULL, | |
23 | sasl_usercloak_hfnlist, "$Revision: 3526 $"); | |
24 | ||
5958d6b9 EK |
25 | enum |
26 | { | |
27 | D_LINED, | |
28 | K_LINED | |
29 | }; | |
30 | ||
31 | static void | |
32 | notify_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 |
61 | unsigned 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 | ||
73 | static void | |
74 | check_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 | } |