]>
Commit | Line | Data |
---|---|---|
0a17908b | 1 | sethost patch: minor overhaul of sethost system |
2 | ||
3 | this patch replaces a number of other patches: | |
4 | autosethost.patch invalidatebanssethost.patch issethost.patch | |
5 | sethostnewhostmask.patch sethostoldcode.patch sethostprotocolviolation.patch | |
6 | showumodehtoclients.patch ulined.patch | |
7 | ||
8 | makes usermode +h visible to clients | |
9 | ||
10 | removes HasSetHost() macro (was same as IsSetHost()) | |
11 | ||
12 | removed 'Using S-line privilege' message on connect | |
13 | client is informed of spoofhost by 396 RPL_HOSTHIDDEN (host :is now your hidden host) | |
14 | ||
15 | change syntax to "SETHOST [<user>@]<host> [<password>]" | |
16 | ||
17 | disallow client to use MODE +h [<user>@]<host> [<pass>] (bug: mode +h took 2 parameters, even from remote users!) | |
18 | ||
19 | sethost can only be unset with "MODE <nick> -h" | |
e455e308 | 20 | and only if the sethost was not remotely set by a service (unless the user is an oper) |
21 | and only if the user has an account set, and is +x (or is allowed to set +x) | |
22 | so the +x host becomes visible, and never the realhost | |
0a17908b | 23 | |
24 | sethost #N no longer supported (N being the Nth configured spoof block) | |
25 | ||
26 | remote sethost can now be undone by using 0 as username and host, | |
27 | but only when the user has an account set and is allowed by server settings to set mode +x, | |
28 | to avoid revealing the real host out of the blue | |
29 | ||
30 | SETHOST now same as OPER | |
31 | modes h and o can only be set with SETHOST and OPER | |
32 | modes h and o are visible to clients | |
33 | modes h and o can only be unset with MODE <nick> -ho | |
34 | ||
35 | user sethosts are now also checked against their user@host/ip (and not just the password) | |
36 | ||
37 | applying the sethost and syncing of clients (quit user, rejoin user, restore modes on user) is now done in one place | |
38 | ||
39 | remote sethost can come from any server, does not need to have a Uworld block or be a service (ACCOUNT doesnt require that either) | |
40 | ||
a5c2deba | 41 | allow chars -. 0-9 A-Z [\]^_ a-Z {|} ~: in user and host part of sethost (only change is that : is allowed because of IPv6) |
42 | ||
0a17908b | 43 | STATS s |
44 | show if spoofhost is valid or not (S = valid, s = invalid) | |
45 | removed numbering (not required anymore?) | |
46 | merged showing of user@host | |
47 | ||
6fe1b135 P |
48 | diff -r a771a07b5020 include/client.h |
49 | --- a/include/client.h Sat Jul 20 14:54:11 2013 +0100 | |
50 | +++ b/include/client.h Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 51 | @@ -90,7 +90,7 @@ |
52 | #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag)) | |
53 | ||
54 | /** String containing valid user modes, in no particular order. */ | |
6fe1b135 P |
55 | -#define infousermodes "diOoswkgxRXInP" |
56 | +#define infousermodes "diOoswkghxRXInP" | |
0a17908b | 57 | |
58 | /** Character to indicate no oper name available */ | |
59 | #define NOOPERNAMECHARACTER '-' | |
77cdb5de | 60 | @@ -171,6 +171,7 @@ |
61 | FLAG_BURST, /**< Server is receiving a net.burst */ | |
62 | FLAG_BURST_ACK, /**< Server is waiting for eob ack */ | |
63 | FLAG_IPCHECK, /**< Added or updated IPregistry data */ | |
64 | + FLAG_REMOTESETHOST, /**< user has a remote sethost */ | |
65 | FLAG_LOCOP, /**< Local operator -- SRB */ | |
66 | FLAG_SERVNOTICE, /**< server notices such as kill */ | |
67 | FLAG_OPER, /**< Operator */ | |
6fe1b135 | 68 | @@ -629,7 +630,8 @@ |
0a17908b | 69 | #define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x)) |
70 | /** Return non-zero if the client is using a spoofhost */ | |
71 | #define IsSetHost(x) HasFlag(x, FLAG_SETHOST) | |
72 | -#define HasSetHost(x) (IsSetHost(x)) | |
77cdb5de | 73 | +/** Return non-zero if the client is using a spoofhost that was set by a service */ |
74 | +#define IsRemoteSetHost(x) HasFlag(x, FLAG_REMOTESETHOST) | |
0a17908b | 75 | |
76 | /** Mark a client as having an in-progress net.burst. */ | |
77 | #define SetBurst(x) SetFlag(x, FLAG_BURST) | |
6fe1b135 | 78 | @@ -673,6 +675,8 @@ |
77cdb5de | 79 | #define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST) |
80 | /** Mark a client as having mode +h (spoofhost). */ | |
81 | #define SetSetHost(x) SetFlag(x, FLAG_SETHOST) | |
82 | +/** Mark a client as having a remote sethost. */ | |
83 | +#define SetRemoteSetHost(x) SetFlag(x, FLAG_REMOTESETHOST) | |
84 | /** Mark a client as having mode +X (xtraop). */ | |
85 | #define SetXtraOp(x) SetFlag(x, FLAG_XTRAOP) | |
86 | /** Mark a client as having mode +n (hide channels). */ | |
6fe1b135 | 87 | @@ -718,6 +722,8 @@ |
77cdb5de | 88 | #define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST) |
89 | /** Remove mode +h (spoofhost) from a client. */ | |
90 | #define ClearSetHost(x) ClrFlag(x, FLAG_SETHOST) | |
91 | +/** Clear the client's remote SETHOST flag. */ | |
92 | +#define ClearRemoteSetHost(x) ClrFlag(x, FLAG_REMOTESETHOST) | |
93 | /** Remove mode +X (xtraop) from a client. */ | |
94 | #define ClearXtraOp(x) ClrFlag(x, FLAG_XTRAOP) | |
95 | /** Remove mode +n (hide channels) from a client. */ | |
6fe1b135 P |
96 | diff -r a771a07b5020 include/ircd_chattr.h |
97 | --- a/include/ircd_chattr.h Sat Jul 20 14:54:11 2013 +0100 | |
98 | +++ b/include/ircd_chattr.h Sat Jul 20 14:54:45 2013 +0100 | |
34145209 | 99 | @@ -117,6 +117,8 @@ |
100 | #define IsUserChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCUI) | |
101 | /** Test whether a character is valid in a hostname. */ | |
102 | #define IsHostChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCHN) | |
a5c2deba | 103 | +/** Test whether a character is valid in a sethost - snircd */ |
34145209 | 104 | +#define IsSetHostChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & (NTL_IRCHN|NTL_IRCIP6)) |
105 | /** Test whether a character is valid in an IPv4 address. */ | |
106 | #define IsIPChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCIP) | |
107 | /** Test whether a character is valid in an IPv6 address. */ | |
108 | @@ -127,4 +129,5 @@ | |
109 | #define IsKTimeChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_KTIME) | |
110 | ||
111 | ||
112 | + | |
113 | #endif /* INCLUDED_ircd_chattr_h */ | |
6fe1b135 P |
114 | diff -r a771a07b5020 include/numeric.h |
115 | --- a/include/numeric.h Sat Jul 20 14:54:11 2013 +0100 | |
116 | +++ b/include/numeric.h Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 117 | @@ -314,7 +314,7 @@ |
118 | /* RPL_NOUSERS 395 Dalnet/EFnet/IRCnet */ | |
119 | #define RPL_HOSTHIDDEN 396 /* UMODE +x completed succesfuly */ | |
120 | #define RPL_STATSSLINE 398 /* QuakeNet extension -froo */ | |
121 | -#define RPL_USINGSLINE 399 /* QuakeNet extension -froo */ | |
122 | +/* RPL_USINGSLINE 399 QuakeNet extension -froo */ | |
123 | ||
124 | /* | |
125 | * Errors are in the range from 400-599 currently and are grouped by what | |
6fe1b135 P |
126 | diff -r a771a07b5020 include/s_conf.h |
127 | --- a/include/s_conf.h Sat Jul 20 14:54:11 2013 +0100 | |
128 | +++ b/include/s_conf.h Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 129 | @@ -205,7 +205,8 @@ |
130 | ||
131 | extern void conf_add_sline(const char* const* fields, int count); | |
132 | extern void clear_slines(void); | |
133 | -extern int conf_check_slines(struct Client *cptr); | |
8aa31c50 | 134 | +extern struct sline *find_spoofblock(struct Client *cptr, char *host, char *password); |
0a17908b | 135 | +extern int apply_spoofblock(struct Client *cptr); |
136 | extern void free_spoofhost(struct sline *spoof); | |
137 | ||
138 | extern void yyerror(const char *msg); | |
6fe1b135 P |
139 | diff -r a771a07b5020 include/s_user.h |
140 | --- a/include/s_user.h Sat Jul 20 14:54:11 2013 +0100 | |
141 | +++ b/include/s_user.h Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 142 | @@ -79,15 +79,15 @@ |
143 | extern int set_nick_name(struct Client* cptr, struct Client* sptr, | |
144 | const char* nick, int parc, char* parv[]); | |
145 | extern void send_umode_out(struct Client* cptr, struct Client* sptr, | |
146 | - struct Flags* old, int prop); | |
147 | + struct Flags* old, int prop, int alreadyh); | |
148 | extern int whisper(struct Client* source, const char* nick, | |
149 | const char* channel, const char* text, int is_notice); | |
150 | extern void send_user_info(struct Client* to, char* names, int rpl, | |
151 | InfoFormatter fmt); | |
152 | ||
153 | extern int hide_hostmask(struct Client *cptr, unsigned int flags); | |
154 | -extern int set_hostmask(struct Client *cptr, char *hostmask, char *password); | |
155 | -extern int is_hostmask(char *word); | |
156 | +extern int set_hostmask(struct Client *sptr, char *user, char *host); | |
04d03d60 | 157 | +extern int is_validsethost(char *user, char *host); |
0a17908b | 158 | extern int set_user_mode(struct Client *cptr, struct Client *sptr, |
159 | int parc, char *parv[], int allow_modes); | |
160 | extern int is_silenced(struct Client *sptr, struct Client *acptr); | |
161 | @@ -102,7 +102,7 @@ | |
162 | extern struct Client* next_client(struct Client* next, const char* ch); | |
163 | extern char *umode_str(struct Client *cptr, int type); | |
164 | extern void send_umode(struct Client *cptr, struct Client *sptr, | |
165 | - struct Flags *old, int sendset, int opernames); | |
166 | + struct Flags *old, int sendset, int opernames, int alreadyh); | |
167 | extern void set_snomask(struct Client *, unsigned int, int); | |
168 | extern int is_snomask(char *); | |
169 | extern int check_target_limit(struct Client *sptr, void *target, const char *name, | |
6fe1b135 P |
170 | diff -r a771a07b5020 ircd/channel.c |
171 | --- a/ircd/channel.c Sat Jul 20 14:54:11 2013 +0100 | |
172 | +++ b/ircd/channel.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 173 | @@ -384,12 +384,12 @@ |
174 | ircd_ntoa_r(iphost, &cli_ip(cptr)); | |
175 | ||
176 | /* sr is real host if +h */ | |
177 | - if (HasSetHost(cptr)) | |
178 | + if (IsSetHost(cptr)) | |
179 | sr = cli_user(cptr)->realhost; | |
180 | ||
181 | /* if +x and not +h sa is real host, if -x or +h sa is the account host */ | |
182 | if (IsAccount(cptr)) { | |
183 | - if (HasHiddenHost(cptr) && !HasSetHost(cptr)) { | |
184 | + if (HasHiddenHost(cptr) && !IsSetHost(cptr)) { | |
185 | sa = cli_user(cptr)->realhost; | |
186 | } else { | |
187 | ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s", | |
6fe1b135 P |
188 | diff -r a771a07b5020 ircd/m_oper.c |
189 | --- a/ircd/m_oper.c Sat Jul 20 14:54:11 2013 +0100 | |
190 | +++ b/ircd/m_oper.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 191 | @@ -189,7 +189,7 @@ |
192 | ||
193 | set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); | |
194 | cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ | |
195 | - send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); | |
196 | + send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE), 0); | |
197 | send_reply(sptr, RPL_YOUREOPER); | |
198 | ||
199 | sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c) as %s", | |
6fe1b135 P |
200 | diff -r a771a07b5020 ircd/m_remotemode.c |
201 | --- a/ircd/m_remotemode.c Sat Jul 20 14:54:11 2013 +0100 | |
202 | +++ b/ircd/m_remotemode.c Sat Jul 20 14:54:45 2013 +0100 | |
23015afc P |
203 | @@ -126,6 +126,7 @@ |
204 | int what = MODE_ADD; | |
205 | int do_host_hiding = 0; | |
206 | int do_set_host = 0; | |
207 | + int alreadyh = 0; | |
208 | ||
209 | /* not from a server */ | |
210 | if (!IsServer(sptr)) | |
211 | @@ -216,17 +217,15 @@ | |
212 | break; | |
213 | case 'h': | |
214 | if (what == MODE_ADD) { | |
215 | - if (*(p + 1) && is_hostmask(*(p + 1))) { | |
216 | - do_set_host = 1; | |
217 | - hostmask = *++p; | |
218 | - } else { | |
219 | - if (!*(p+1)) | |
220 | - protocol_violation(sptr, "Received REMOTEMODE +h without host parameter for user %C", acptr); | |
221 | - else { | |
222 | - protocol_violation(sptr, "Received REMOTEMODE +h with invalid host parameter %s for user %C", *(p+1), acptr); | |
223 | - p++; /* Swallow the arg anyway */ | |
224 | - } | |
225 | - } | |
226 | + /* TODO: */ | |
227 | + if (IsServer(cptr)) { | |
228 | + if (!*(p + 1)) | |
229 | + protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr); | |
230 | + else { | |
231 | + hostmask = *++p; | |
232 | + do_set_host = 1; | |
233 | + } | |
234 | + } | |
235 | } else { /* MODE_DEL */ | |
236 | do_set_host = 1; | |
237 | hostmask = NULL; | |
238 | @@ -275,10 +274,12 @@ | |
239 | host = hostmask; | |
240 | ||
241 | /* check if new sethost is different from before */ | |
242 | - if (IsSetHost(acptr) && | |
243 | - (!user || strcmp(cli_user(acptr)->username, user) == 0) && | |
244 | - strcmp(cli_user(acptr)->host, host) == 0) | |
245 | - do_set_host = 0; | |
246 | + if (IsSetHost(acptr)) { | |
247 | + alreadyh = 1; | |
248 | + if ((!user || strcmp(cli_user(acptr)->username, user) == 0) && | |
249 | + strcmp(cli_user(acptr)->host, host) == 0) | |
250 | + do_set_host = 0; | |
251 | + } | |
252 | } | |
253 | ||
254 | /* do host hiding for +h/-h */ | |
255 | @@ -353,7 +354,7 @@ | |
256 | assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns); | |
257 | ||
258 | /* send out the mode */ | |
259 | - send_umode_out(acptr, acptr, &setflags, 0); | |
260 | + send_umode_out(acptr, acptr, &setflags, 0, alreadyh); | |
261 | ||
262 | return 0; | |
263 | } | |
6fe1b135 P |
264 | diff -r a771a07b5020 ircd/m_sethost.c |
265 | --- a/ircd/m_sethost.c Sat Jul 20 14:54:11 2013 +0100 | |
266 | +++ b/ircd/m_sethost.c Sat Jul 20 14:54:45 2013 +0100 | |
23015afc | 267 | @@ -82,175 +82,233 @@ |
0a17908b | 268 | #include "config.h" |
269 | ||
270 | #include "client.h" | |
271 | +#include "ircd_features.h" | |
272 | +#include "ircd_log.h" | |
273 | #include "ircd_reply.h" | |
274 | #include "ircd_string.h" | |
275 | #include "ircd_snprintf.h" | |
276 | -#include "ircd_features.h" | |
277 | +#include "msg.h" | |
278 | #include "msgq.h" | |
279 | #include "numeric.h" | |
280 | #include "s_conf.h" | |
281 | +#include "s_debug.h" | |
282 | #include "s_user.h" | |
283 | -#include "s_debug.h" | |
284 | #include "send.h" | |
285 | #include "struct.h" | |
286 | #include "numnicks.h" | |
287 | ||
288 | -#include "channel.h" | |
289 | -#include "msg.h" | |
290 | - | |
291 | -#include <assert.h> | |
292 | #include <stdlib.h> | |
293 | ||
294 | -/* | |
295 | +/** | |
296 | * m_sethost - generic message handler | |
297 | * | |
298 | - * mimic old lain syntax: | |
299 | + * SETHOST [<user>@]<host> [<password>] | |
300 | * | |
301 | - * (Oper) /SETHOST ident host.cc [quit-message] | |
302 | - * (User) /SETHOST host.cc password | |
303 | - * (Both) /SETHOST undo | |
304 | + * parv[0] = sender prefix | |
305 | + * parv[1] = [user@]host | |
306 | + * parv[2] = password | |
307 | * | |
308 | - * check for undo, prepend parv w. <nick> -h or +h | |
309 | + * "MODE <nick> -h" to remove sethost | |
310 | + * | |
311 | */ | |
312 | int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
313 | { | |
314 | - char hostmask[USERLEN + HOSTLEN + 2]; | |
315 | - char curhostmask[USERLEN + HOSTLEN + 2]; | |
316 | + int alreadyh = 0; | |
317 | + int freeform = 0; | |
318 | + char *hostmask; | |
319 | + char *user = NULL; | |
320 | + char *host; | |
321 | + char *password = NULL; | |
322 | + struct Flags setflags; | |
323 | + struct sline *sconf; | |
324 | ||
325 | - struct Flags setflags; | |
326 | + /* disabled */ | |
327 | + if (!feature_bool(FEAT_SETHOST)) | |
328 | + return send_reply(sptr, ERR_DISABLED, "SETHOST"); | |
329 | ||
330 | - /* Back up the flags first */ | |
331 | + /* disabled for ordinary users */ | |
332 | + if (!IsAnOper(sptr) && !feature_bool(FEAT_SETHOST_USER)) | |
333 | + return send_reply(sptr, ERR_NOPRIVILEGES); | |
334 | + | |
335 | + /* need hostmask parameter | |
336 | + * and need password parameter from an ordinary user | |
337 | + */ | |
c23d9d77 | 338 | + if (parc < 2 || *parv[1] == 0 || (parc < 3 && !IsAnOper(sptr))) |
0a17908b | 339 | + return need_more_params(sptr, "SETHOST"); |
340 | + | |
341 | + hostmask = parv[1]; | |
342 | + | |
343 | + /* get user and host */ | |
344 | + if ((host = strrchr(hostmask, '@'))) { | |
345 | + *host++ = '\0'; | |
346 | + user = hostmask; | |
347 | + } | |
348 | + else | |
349 | + host = hostmask; | |
350 | + | |
c23d9d77 | 351 | + /* got a pasword and not empty */ |
352 | + if (parc > 2 && *parv[2]) | |
0a17908b | 353 | + password = parv[2]; |
354 | + | |
355 | + /* freeform - do not bother with password */ | |
356 | + if (IsAnOper(sptr) && HasPriv(sptr, PRIV_FREEFORM)) { | |
357 | + freeform = 1; | |
358 | + password = NULL; | |
359 | + } | |
360 | + | |
361 | + /* check if user and host are valid */ | |
04d03d60 | 362 | + if (!is_validsethost(user, host)) |
0a17908b | 363 | + return send_reply(sptr, ERR_BADHOSTMASK, user ? user : "", user ? "@" : "", host); |
364 | + | |
365 | + /* not freeform */ | |
366 | + if (!freeform) { | |
367 | + | |
368 | + /* find the spoof block */ | |
369 | + if (!(sconf = find_spoofblock(sptr, host, password))) | |
370 | + return send_reply(sptr, ERR_HOSTUNAVAIL, user ? user : "", user ? "@" : "", host); | |
371 | + else | |
372 | + host = (char *)sconf->spoofhost; | |
373 | + | |
374 | + /* only freeform allowed to specify user */ | |
375 | + user = NULL; | |
376 | + } | |
377 | + | |
378 | + /* backup flags */ | |
379 | setflags = cli_flags(sptr); | |
380 | ||
381 | - if (parc < 2) | |
382 | - return need_more_params(sptr, "SETHOST"); | |
77cdb5de | 383 | + /* already +h, clear flag to force mode +h to be sent out again, and clear remote sethost flag */ |
0a17908b | 384 | + if (IsSetHost(sptr)) { |
385 | + FlagClr(&setflags, FLAG_SETHOST); | |
386 | + alreadyh = 1; | |
77cdb5de | 387 | + ClearRemoteSetHost(sptr); |
0a17908b | 388 | + } |
389 | ||
390 | - if (0 == ircd_strcmp("undo", parv[1])) { | |
391 | - set_hostmask(sptr, NULL, NULL); | |
392 | - } else { | |
393 | - if (parc<3) | |
394 | - return need_more_params(sptr, "SETHOST"); | |
395 | - if (IsAnOper(sptr)) { | |
396 | - ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[1], parv[2]); | |
397 | - if (!is_hostmask(hostmask)) { | |
398 | - send_reply(sptr, ERR_BADHOSTMASK, hostmask); | |
399 | - return 0; | |
400 | - } | |
401 | - if (IsSetHost(sptr) || IsAccount(sptr)) { | |
402 | - ircd_snprintf(0, curhostmask, USERLEN + HOSTLEN + 2, "%s@%s", sptr->cli_user->username, sptr->cli_user->host); | |
403 | - if (0 == strcmp(hostmask, curhostmask)) { | |
404 | - send_reply(sptr, RPL_HOSTHIDDEN, curhostmask); | |
405 | - return 0; | |
406 | - } | |
407 | - } | |
408 | - if (set_hostmask(sptr, hostmask, NULL)) | |
409 | - FlagClr(&setflags, FLAG_SETHOST); | |
410 | - } else { | |
411 | - if (!is_hostmask(parv[1])) { | |
412 | - send_reply(sptr, ERR_BADHOSTMASK, parv[1]); | |
413 | - return 0; | |
414 | - } | |
415 | - if (IsSetHost(sptr) || IsAccount(sptr)) { | |
416 | - if (0 == strcmp(parv[1], sptr->cli_user->host)) { | |
417 | - send_reply(sptr, RPL_HOSTHIDDEN, parv[1]); | |
418 | - return 0; | |
419 | - } | |
420 | - } | |
421 | - if (set_hostmask(sptr, parv[1], parv[2])) | |
422 | - FlagClr(&setflags, FLAG_SETHOST); | |
423 | - } | |
424 | - } | |
425 | + /* check if new sethost is different from before */ | |
426 | + if (IsSetHost(sptr) && | |
427 | + (!user || strcmp(cli_user(sptr)->username, user) == 0) && | |
428 | + strcmp(cli_user(sptr)->host, host) == 0) | |
429 | + return send_reply(sptr, RPL_HOSTHIDDEN, user ? user : "", user ? "@" : "", host); | |
430 | ||
431 | - send_umode_out(cptr, sptr, &setflags, 0); | |
432 | + /* do it */ | |
433 | + set_hostmask(sptr, user, host); | |
434 | + | |
435 | + /* log freeform */ | |
9ba0fa7c | 436 | + if (freeform) { |
437 | + | |
438 | + sendto_opmask_butone(0, SNO_OLDSNO, | |
4b356e8c | 439 | + "%C SETHOST %s%s%s (freeform)", sptr, |
440 | + user ? user : "", user ? "@" : "", host); | |
9ba0fa7c | 441 | + |
442 | + log_write(LS_SETHOST, L_NOTICE, LOG_NOSNOTICE, | |
4b356e8c | 443 | + "%s SETHOST %s%s%s (freeform)", get_client_name(sptr, SHOW_IP), |
444 | + user ? user : "", user ? "@" : "", host); | |
9ba0fa7c | 445 | + } |
0a17908b | 446 | + |
447 | + /* send the mode out */ | |
448 | + send_umode_out(cptr, sptr, &setflags, 0, alreadyh); | |
449 | + | |
450 | return 0; | |
451 | } | |
452 | ||
453 | ||
454 | -/* | |
455 | + | |
456 | +/** | |
457 | * ms_sethost - sethost server message handler | |
458 | * | |
459 | * parv[0] = sender prefix | |
460 | * parv[1] = target user numeric | |
461 | - * parv[2] = target user's new ident | |
462 | - * parv[3] = target user's new host | |
463 | + * parv[2] = spoof username | |
464 | + * parv[3] = spoof host | |
465 | + * | |
466 | + * undo sethost when spoof username and host are 0 | |
467 | + * | |
468 | */ | |
469 | + /* TODO: IsRemoteSetHost() */ | |
470 | int ms_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
471 | { | |
472 | - struct Client *target; | |
473 | - char hostmask[USERLEN + HOSTLEN + 2]; | |
474 | - struct Membership *chan; | |
475 | + int alreadyh = 0; | |
476 | + char *target; | |
477 | + char *user; | |
478 | + char *host; | |
479 | + struct Client *acptr; | |
480 | struct Flags setflags; | |
481 | ||
71300e6b | 482 | + /* not from a server */ |
483 | + if (!IsServer(sptr)) | |
484 | + return protocol_violation(cptr, "Received SETHOST from user %C", sptr); | |
485 | + | |
0a17908b | 486 | + /* check paramaters */ |
487 | if (parc < 4) | |
71300e6b | 488 | - return need_more_params(sptr, "SETHOST"); |
489 | + return protocol_violation(cptr, "Received too few parameters for SETHOST from %C (got %d - need 4)", sptr, parc); | |
0a17908b | 490 | |
71300e6b | 491 | - if (!IsServer(sptr)) |
492 | - return protocol_violation(cptr, "SETHOST from non-server %s", | |
493 | - cli_name(sptr)); | |
0a17908b | 494 | + target = parv[1]; |
495 | + user = parv[2]; | |
496 | + host = parv[3]; | |
0a17908b | 497 | |
498 | - /* Locate our target user; ignore the message if we can't */ | |
499 | - if(!(target = findNUser(parv[1]))) | |
500 | + /* find user */ | |
501 | + if(!(acptr = findNUser(target))) | |
502 | return 0; | |
503 | ||
504 | - /* Fake host assignments must be from services */ | |
505 | - if (!find_conf_byhost(cli_confs(sptr), cli_name(sptr), CONF_UWORLD)) | |
506 | - return protocol_violation(cptr, "Non-U:lined server %s set fake host on user %s", cli_name(sptr), cli_name(target)); | |
507 | - | |
508 | - if (!MyConnect(target)) { | |
509 | - sendcmdto_one(sptr, CMD_SETHOST, cli_user(target)->server, "%C %s %s", target, | |
510 | - parv[2], parv[3]); | |
511 | + /* not for my user, pass it along */ | |
512 | + if (!MyConnect(acptr)) { | |
513 | + sendcmdto_one(sptr, CMD_SETHOST, acptr, "%C %s %s", acptr, user, host); | |
514 | return 0; | |
515 | } | |
516 | ||
517 | - /* Back up the flags first */ | |
518 | - setflags = cli_flags(target); | |
519 | - FlagClr(&setflags, FLAG_SETHOST); | |
520 | + /* backup flags */ | |
521 | + setflags = cli_flags(acptr); | |
522 | ||
523 | - if (IsSetHost(target) || IsAccount(target)) { | |
524 | - if ((0 == strcmp(parv[2], target->cli_user->username)) && (0 == strcmp(parv[3], target->cli_user->host))) | |
525 | + /* check user and host are valid */ | |
04d03d60 | 526 | + if (!is_validsethost(user, host)) |
0a17908b | 527 | + return protocol_violation(cptr, |
71300e6b | 528 | + "Received SETHOST for %C with invalid user host '%s %s' from %C", |
529 | + acptr, user, host, sptr); | |
0a17908b | 530 | + |
531 | + /* 'user host' is '0 0' - undo sethost */ | |
532 | + if (user[0] == '0' && user[1] == '\0' && | |
533 | + host[0] == '0' && host[1] == '\0') { | |
534 | + | |
535 | + /* user has no sethost or has no account | |
536 | + * | |
1bc74ef7 | 537 | + * user has +h - their host is hidden, do not remove it |
0a17908b | 538 | + * unless the user has an account set |
539 | + * we should not out of the blue expose the real host | |
540 | + */ | |
541 | + if (!IsSetHost(acptr) || !IsAccount(acptr)) | |
542 | return 0; | |
543 | + | |
544 | + /* user not +x and not allowed to set it */ | |
545 | + if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING)) | |
546 | + return 0; | |
547 | + | |
548 | + /* set +x */ | |
549 | + SetHiddenHost(acptr); | |
550 | + user = NULL; | |
551 | + host = NULL; | |
552 | } | |
553 | ||
554 | - ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[2], parv[3]); | |
555 | - if (!is_hostmask(hostmask)) | |
556 | - return protocol_violation(cptr, "Bad Host mask %s for user %s", hostmask, cli_name(target)); | |
557 | + /* check if new sethost is different from before */ | |
558 | + else if (IsSetHost(acptr) && | |
559 | + strcmp(cli_user(acptr)->username, user) == 0 && | |
560 | + strcmp(cli_user(acptr)->host, host) == 0) | |
561 | + return 0; | |
562 | ||
563 | - sendcmdto_common_channels_butone(target, CMD_QUIT, target, ":Host change"); | |
564 | - | |
565 | - /* Assign and propagate the fakehost */ | |
566 | - SetSetHost(target); | |
567 | - ircd_strncpy(cli_user(target)->username, parv[2], USERLEN); | |
568 | - ircd_strncpy(cli_user(target)->host, parv[3], HOSTLEN); | |
569 | - | |
570 | - send_reply(target, RPL_HOSTHIDDEN, hostmask); | |
571 | - | |
572 | - /* | |
573 | - * Go through all channels the client was on, rejoin him | |
574 | - * and set the modes, if any | |
575 | - */ | |
576 | - for (chan = cli_user(target)->channel; chan; chan = chan->next_channel) { | |
577 | - if (IsZombie(chan)) | |
578 | - continue; | |
579 | - /* If this channel has delayed joins and the user has no modes, just set | |
580 | - * the delayed join flag rather than showing the join, even if the user | |
581 | - * was visible before */ | |
582 | - if (!IsChanOp(chan) && !HasVoice(chan) | |
583 | - && (chan->channel->mode.mode & MODE_DELJOINS)) { | |
584 | - SetDelayedJoin(chan); | |
585 | - } else { | |
586 | - sendcmdto_channel_butserv_butone(target, CMD_JOIN, chan->channel, target, 0, | |
587 | - "%H", chan->channel); | |
588 | - } | |
589 | - if (IsChanOp(chan) && HasVoice(chan)) { | |
590 | - sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0, | |
591 | - "%H +ov %C %C", chan->channel, target, target); | |
592 | - } else if (IsChanOp(chan) || HasVoice(chan)) { | |
593 | - sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0, | |
594 | - "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', target); | |
595 | - } | |
596 | + /* already +h, clear flag to force mode +h to be sent out again */ | |
597 | + else if (IsSetHost(acptr)) { | |
598 | + FlagClr(&setflags, FLAG_SETHOST); | |
599 | + alreadyh = 1; | |
600 | } | |
601 | ||
602 | - send_umode_out(target, target, &setflags, 0); | |
77cdb5de | 603 | + /* setting remote sethost, set flag */ |
604 | + if (host) | |
605 | + SetRemoteSetHost(acptr); | |
606 | + | |
0a17908b | 607 | + /* do it */ |
608 | + set_hostmask(acptr, user, host); | |
609 | + | |
610 | + /* send out the mode */ | |
611 | + send_umode_out(acptr, acptr, &setflags, 0, alreadyh); | |
612 | + | |
613 | return 0; | |
614 | } | |
23015afc | 615 | |
6fe1b135 P |
616 | diff -r a771a07b5020 ircd/m_userhost.c |
617 | --- a/ircd/m_userhost.c Sat Jul 20 14:54:11 2013 +0100 | |
618 | +++ b/ircd/m_userhost.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 619 | @@ -104,7 +104,7 @@ |
620 | * of +x. If an oper wants the real host, he should go to | |
621 | * /whois to get it. | |
622 | */ | |
623 | - (HasHiddenHost(cptr) || HasSetHost(cptr)) && (sptr != cptr) ? | |
624 | + (HasHiddenHost(cptr) || IsSetHost(cptr)) && (sptr != cptr) ? | |
625 | cli_user(cptr)->host : cli_user(cptr)->realhost); | |
626 | } | |
627 | ||
6fe1b135 P |
628 | diff -r a771a07b5020 ircd/m_userip.c |
629 | --- a/ircd/m_userip.c Sat Jul 20 14:54:11 2013 +0100 | |
630 | +++ b/ircd/m_userip.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 631 | @@ -106,7 +106,7 @@ |
632 | * of +x. If an oper wants the real IP, he should go to | |
633 | * /whois to get it. | |
634 | */ | |
635 | - ((HasHiddenHost(cptr) || HasSetHost(cptr) || feature_bool(FEAT_HIS_USERIP)) && (sptr != cptr)) ? | |
636 | + ((HasHiddenHost(cptr) || IsSetHost(cptr) || feature_bool(FEAT_HIS_USERIP)) && (sptr != cptr)) ? | |
637 | feature_str(FEAT_HIDDEN_IP) : | |
638 | ircd_ntoa(&cli_ip(cptr))); | |
639 | } | |
6fe1b135 P |
640 | diff -r a771a07b5020 ircd/m_who.c |
641 | --- a/ircd/m_who.c Sat Jul 20 14:54:11 2013 +0100 | |
642 | +++ b/ircd/m_who.c Sat Jul 20 14:54:45 2013 +0100 | |
643 | @@ -395,14 +395,14 @@ | |
0a17908b | 644 | && ((!(matchsel & WHO_FIELD_HOS)) |
645 | || matchexec(cli_user(acptr)->host, mymask, minlen)) | |
646 | && ((!(matchsel & WHO_FIELD_HOS)) | |
647 | - || !HasSetHost(acptr) | |
648 | + || !IsSetHost(acptr) | |
649 | || !HasHiddenHost(acptr) | |
650 | || !IsAnOper(sptr) | |
651 | || matchexec(cli_user(acptr)->realhost, mymask, minlen)) | |
652 | && ((!(matchsel & WHO_FIELD_REN)) | |
653 | || matchexec(cli_info(acptr), mymask, minlen)) | |
654 | && ((!(matchsel & WHO_FIELD_NIP)) | |
655 | - || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr)) | |
656 | + || ((HasHiddenHost(acptr) || IsSetHost(acptr)) && !IsAnOper(sptr)) | |
657 | || !ipmask_check(&cli_ip(acptr), &imask, ibits)) | |
658 | && ((!(matchsel & WHO_FIELD_ACC)) | |
659 | || matchexec(cli_user(acptr)->account, mymask, minlen))) | |
6fe1b135 | 660 | @@ -434,14 +434,14 @@ |
0a17908b | 661 | && ((!(matchsel & WHO_FIELD_HOS)) |
662 | || matchexec(cli_user(acptr)->host, mymask, minlen)) | |
663 | && ((!(matchsel & WHO_FIELD_HOS)) | |
664 | - || !HasSetHost(acptr) | |
665 | + || !IsSetHost(acptr) | |
666 | || !HasHiddenHost(acptr) | |
667 | || !IsAnOper(sptr) | |
668 | || matchexec(cli_user(acptr)->realhost, mymask, minlen)) | |
669 | && ((!(matchsel & WHO_FIELD_REN)) | |
670 | || matchexec(cli_info(acptr), mymask, minlen)) | |
671 | && ((!(matchsel & WHO_FIELD_NIP)) | |
672 | - || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr)) | |
673 | + || ((HasHiddenHost(acptr) || IsSetHost(acptr)) && !IsAnOper(sptr)) | |
674 | || !ipmask_check(&cli_ip(acptr), &imask, ibits)) | |
675 | && ((!(matchsel & WHO_FIELD_ACC)) | |
676 | || matchexec(cli_user(acptr)->account, mymask, minlen))) | |
6fe1b135 P |
677 | diff -r a771a07b5020 ircd/m_whois.c |
678 | --- a/ircd/m_whois.c Sat Jul 20 14:54:11 2013 +0100 | |
679 | +++ b/ircd/m_whois.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 680 | @@ -214,7 +214,7 @@ |
681 | if (IsAccount(acptr)) | |
682 | send_reply(sptr, RPL_WHOISACCOUNT, name, user->account); | |
683 | ||
684 | - if ((HasHiddenHost(acptr) || HasSetHost(acptr)) && ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || acptr == sptr)) | |
685 | + if ((HasHiddenHost(acptr) || IsSetHost(acptr)) && ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || acptr == sptr)) | |
686 | send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername, | |
687 | user->realhost, ircd_ntoa(&cli_ip(acptr))); | |
688 | ||
6fe1b135 P |
689 | diff -r a771a07b5020 ircd/s_conf.c |
690 | --- a/ircd/s_conf.c Sat Jul 20 14:54:11 2013 +0100 | |
691 | +++ b/ircd/s_conf.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 692 | @@ -52,6 +52,7 @@ |
693 | #include "s_bsd.h" | |
694 | #include "s_debug.h" | |
695 | #include "s_misc.h" | |
696 | +#include "s_user.h" | |
697 | #include "send.h" | |
698 | #include "struct.h" | |
699 | #include "sys.h" | |
6fe1b135 | 700 | @@ -1204,6 +1205,10 @@ |
cabe24c1 | 701 | return 0; |
702 | } | |
703 | ||
704 | +/** | |
705 | + * clear spoof blocks | |
706 | + * | |
707 | + */ | |
708 | void clear_slines(void) | |
709 | { | |
710 | struct sline *sline; | |
6fe1b135 | 711 | @@ -1220,61 +1225,164 @@ |
cabe24c1 | 712 | } |
713 | } | |
714 | ||
715 | -/* | |
716 | - * conf_check_slines() | |
0a17908b | 717 | +/** |
718 | + * find_spoofblock | |
cabe24c1 | 719 | * |
720 | - * Check S lines for the specified client, passed in cptr struct. | |
721 | - * If the client's IP is S-lined, process the substitution here. | |
0a17908b | 722 | + * Find matching spoof block for a user for the given spoofhost and password |
cabe24c1 | 723 | * |
724 | - * Precondition | |
725 | - * cptr != NULL | |
0a17908b | 726 | + * @param cptr User wanting to get a spoof host. |
8aa31c50 | 727 | + * @param host Spoof host to look for. |
0a17908b | 728 | + * @param password Password given by user (can be NULL). |
cabe24c1 | 729 | * |
730 | - * Returns | |
731 | - * 0 = No S-line found | |
732 | - * 1 = S-line found and substitution done. | |
733 | - * | |
734 | - * -mbuna 9/2001 | |
735 | - * -froo 1/2003 | |
0a17908b | 736 | + * @return pointer to the matching spoofblock is found, else NULL |
cabe24c1 | 737 | * |
738 | */ | |
8aa31c50 | 739 | +struct sline *find_spoofblock(struct Client *cptr, char *host, char *password) { |
9ba0fa7c | 740 | |
2d34e05c | 741 | -int |
742 | -conf_check_slines(struct Client *cptr) | |
743 | -{ | |
744 | struct sline *sconf; | |
745 | - char *hostonly; | |
0a17908b | 746 | + int result = 0; |
747 | + int r = 0; | |
2a3660fd | 748 | + char *error; |
9ba0fa7c | 749 | + |
8aa31c50 | 750 | + Debug((DEBUG_INFO, "find_spoofblock() cptr=%C host=%s password=%s", |
751 | + cptr, host, password)); | |
2d34e05c | 752 | |
753 | for (sconf = GlobalSList; sconf; sconf = sconf->next) { | |
0a17908b | 754 | + |
755 | + /* check result of previous loop */ | |
756 | + if (r > result) | |
757 | + result = r; | |
758 | + | |
759 | + /* check spoofhost */ | |
8aa31c50 | 760 | + if (strcasecmp(sconf->spoofhost, host) != 0) |
0a17908b | 761 | + continue; |
762 | + r = 1; | |
763 | + | |
764 | + /* check cptr's host */ | |
765 | + /* cidr mask */ | |
2d34e05c | 766 | if (sconf->flags == SLINE_FLAGS_IP) { |
767 | if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits)) | |
768 | continue; | |
769 | - } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) { | |
770 | - if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) && | |
771 | - (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */ | |
772 | - continue; | |
773 | - } else { | |
0a17908b | 774 | + } |
775 | + | |
776 | + /* hostname */ | |
777 | + else if (sconf->flags == SLINE_FLAGS_HOSTNAME) { | |
778 | + if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) && | |
779 | + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */ | |
2d34e05c | 780 | continue; |
781 | } | |
782 | ||
783 | - if (match(sconf->username, cli_user(cptr)->username) == 0) { | |
784 | - /* Ignore user part if u@h. */ | |
785 | - if ((hostonly = strchr(sconf->spoofhost, '@'))) | |
786 | - hostonly++; | |
787 | - else | |
788 | - hostonly = sconf->spoofhost; | |
0a17908b | 789 | + /* not cidr or hostname.. */ |
790 | + else | |
791 | + continue; | |
792 | + r = 2; | |
2d34e05c | 793 | |
794 | - if(!*hostonly) | |
0a17908b | 795 | + /* check cptr's username */ |
796 | + if (!EmptyString(sconf->username) && match(sconf->username, cli_user(cptr)->realusername) != 0) | |
797 | + continue; | |
798 | + r = 3; | |
799 | + | |
800 | + /* check password */ | |
c23d9d77 | 801 | + if (!EmptyString(password)) { |
0a17908b | 802 | + if (EmptyString(sconf->passwd) || strcmp(sconf->passwd, password) != 0) |
803 | + continue; | |
804 | + } | |
805 | + | |
806 | + /* no password, but need one for this spoofblock */ | |
807 | + else if (!EmptyString(sconf->passwd)) | |
808 | + continue; | |
809 | + | |
810 | + /* got one */ | |
4b356e8c | 811 | + log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (ok) [password: %s]", |
812 | + get_client_name(cptr, SHOW_IP), sconf->spoofhost, | |
813 | + password ? "yes" : "no"); | |
0a17908b | 814 | + return sconf; |
815 | + } | |
816 | + | |
4b356e8c | 817 | + /* set error messages */ |
2a3660fd | 818 | + switch (result) { |
819 | + case 0: | |
820 | + error = "no such Spoof block"; | |
821 | + break; | |
822 | + case 1: | |
823 | + error = "IP / host mismatch"; | |
824 | + break; | |
825 | + case 2: | |
826 | + error = "username mismatch"; | |
827 | + break; | |
828 | + case 3: | |
829 | + error = password ? "password mismatch" : "password required"; | |
830 | + break; | |
831 | + default: | |
832 | + error = "unknown failure"; | |
833 | + } | |
4b356e8c | 834 | + |
0a17908b | 835 | + /* TODO: lookup LOG stuff */ |
836 | + /* TODO: L_INFO LOG_NOSNOTICE */ | |
9ba0fa7c | 837 | + /* log best result we got */ |
2a3660fd | 838 | + log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (failed: %s) [password: %s]", |
8aa31c50 | 839 | + get_client_name(cptr, SHOW_IP), host, |
4b356e8c | 840 | + error, password ? "yes" : "no"); |
0a17908b | 841 | + return NULL; |
842 | +} | |
843 | + | |
0a17908b | 844 | +/** |
845 | + * apply_spoofblock | |
846 | + * | |
847 | + * @param cptr User to apply Spoof block to on connect | |
848 | + * | |
849 | + * @return 1 for success, else 0 | |
850 | + * | |
851 | + */ | |
2d34e05c | 852 | +int |
0a17908b | 853 | +apply_spoofblock(struct Client *cptr) |
2d34e05c | 854 | +{ |
855 | + struct sline *sconf; | |
856 | + | |
0a17908b | 857 | + /* disabled */ |
858 | + if(!feature_bool(FEAT_SETHOST_AUTO)) | |
859 | + return 0; | |
860 | + | |
861 | + /* go over spoof blocks */ | |
2d34e05c | 862 | + for (sconf = GlobalSList; sconf; sconf = sconf->next) { |
0a17908b | 863 | + |
864 | + /* check IP */ | |
2d34e05c | 865 | + if (sconf->flags == SLINE_FLAGS_IP) { |
866 | + if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits)) | |
0a17908b | 867 | continue; |
2d34e05c | 868 | |
869 | - ircd_strncpy(cli_user(cptr)->host, hostonly, HOSTLEN); | |
870 | - log_write(LS_USER, L_INFO, LOG_NOSNOTICE, "S-Line (%s@%s) by (%#R)", | |
871 | - cli_user(cptr)->username, hostonly, cptr); | |
872 | - return 1; | |
873 | - } | |
0a17908b | 874 | + /* check host */ |
2d34e05c | 875 | + } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) { |
876 | + if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) && | |
0a17908b | 877 | + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */ |
2d34e05c | 878 | + continue; |
0a17908b | 879 | + } else |
880 | + continue; | |
2d34e05c | 881 | + |
0a17908b | 882 | + /* check username */ |
1bdfce7f | 883 | + if (match(sconf->username, cli_user(cptr)->realusername) != 0) |
0a17908b | 884 | + continue; |
2d34e05c | 885 | + |
0a17908b | 886 | + /* invalid */ |
2d34e05c | 887 | + if (!is_validsethost(NULL, sconf->spoofhost)) |
0a17908b | 888 | + continue; |
889 | + | |
c7da5b33 | 890 | + /* do it */ |
2d34e05c | 891 | + set_hostmask(cptr, NULL, sconf->spoofhost); |
c7da5b33 | 892 | + |
893 | + /* TODO: LOG_NOSNOTICE */ | |
894 | + /* log it */ | |
895 | + log_write(LS_USER, L_INFO, 0, "%s SETHOST %s (auto)", | |
896 | + get_client_name(cptr, SHOW_IP), sconf->spoofhost); | |
0a17908b | 897 | + return 1; |
898 | } | |
899 | return 0; | |
900 | } | |
901 | ||
0a17908b | 902 | +/** |
cabe24c1 | 903 | + * free a spoofblock |
0a17908b | 904 | + * |
905 | + */ | |
906 | void free_spoofhost(struct sline *spoof) { | |
907 | MyFree(spoof->spoofhost); | |
908 | MyFree(spoof->passwd); | |
6fe1b135 P |
909 | diff -r a771a07b5020 ircd/s_err.c |
910 | --- a/ircd/s_err.c Sat Jul 20 14:54:11 2013 +0100 | |
911 | +++ b/ircd/s_err.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 912 | @@ -824,13 +824,13 @@ |
913 | /* 395 */ | |
914 | { 0 }, | |
915 | /* 396 */ | |
916 | - { RPL_HOSTHIDDEN, "%s :is now your hidden host", "396" }, | |
917 | + { RPL_HOSTHIDDEN, "%s%s%s :is now your hidden host", "396" }, | |
918 | /* 397 */ | |
919 | { 0 }, | |
920 | /* 398 */ | |
921 | - { RPL_STATSSLINE, "%d %s %s %s %s", "398" }, | |
922 | + { RPL_STATSSLINE, "%c %s %s %s%s%s", "398" }, | |
923 | /* 399 */ | |
924 | - { RPL_USINGSLINE, ":Using S-line privilege", "399" }, | |
925 | + { 0 }, | |
926 | /* 400 */ | |
927 | { 0 }, | |
928 | /* 401 */ | |
929 | @@ -1092,9 +1092,9 @@ | |
930 | /* 529 */ | |
931 | { 0 }, | |
932 | /* 530 */ | |
933 | - { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" }, | |
934 | + { ERR_BADHOSTMASK, "%s%s%s :Invalid username/hostmask", "530" }, | |
935 | /* 531 */ | |
936 | - { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" }, | |
937 | + { ERR_HOSTUNAVAIL, "%s%s%s :Sethost not found", "531" }, | |
938 | /* 532 */ | |
939 | { 0 }, | |
940 | /* 533 */ | |
6fe1b135 P |
941 | diff -r a771a07b5020 ircd/s_stats.c |
942 | --- a/ircd/s_stats.c Sat Jul 20 14:54:11 2013 +0100 | |
943 | +++ b/ircd/s_stats.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 944 | @@ -400,41 +400,37 @@ |
945 | } | |
946 | } | |
947 | ||
948 | +/* TODO: */ | |
949 | +/** List spoof blocks. | |
950 | + * @param[in] to Client requesting statistics. | |
951 | + * @param[in] sd Stats descriptor for request (ignored). | |
952 | + * @param[in] param Filter for spoofhost names. | |
953 | + */ | |
954 | static void | |
955 | stats_sline(struct Client* to, const struct StatDesc* sd, char* param) | |
956 | { | |
957 | - int y = 1, i = 1; | |
958 | struct sline *sline; | |
959 | ||
960 | if (IsAnOper(to)) | |
961 | - send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident"); | |
962 | + send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost Hostmask"); | |
963 | else | |
964 | - send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost"); | |
965 | + send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost"); | |
966 | ||
967 | for (sline = GlobalSList; sline; sline = sline->next) { | |
968 | - if (param && match(param, sline->spoofhost)) { /* narrow search */ | |
969 | - if (IsAnOper(to)) | |
970 | - y++; | |
971 | - else | |
972 | - if (!EmptyString(sline->passwd)) | |
973 | - y++; | |
974 | + | |
975 | + if (param && match(param, sline->spoofhost)) | |
976 | continue; | |
977 | - } | |
978 | ||
979 | - if (IsAnOper(to)) { | |
980 | - send_reply(to, RPL_STATSSLINE, (param) ? y : i, | |
981 | - (EmptyString(sline->passwd)) ? "oper" : "user", | |
982 | - sline->spoofhost, | |
983 | - (EmptyString(sline->realhost)) ? "" : sline->realhost, | |
984 | - (EmptyString(sline->username)) ? "" : sline->username); | |
985 | - i++; | |
986 | - } else { | |
987 | - if (!EmptyString(sline->passwd)) { | |
988 | - send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost, | |
989 | - "", "", ""); | |
990 | - i++; | |
991 | - } | |
992 | - } | |
993 | + if (IsAnOper(to)) | |
994 | + send_reply(to, RPL_STATSSLINE, | |
04d03d60 | 995 | + is_validsethost(NULL, sline->spoofhost) ? 'S' : 's', /* valid show S else s */ |
0a17908b | 996 | + (EmptyString(sline->passwd)) ? "Oper" : "User", |
997 | + sline->spoofhost, | |
998 | + (EmptyString(sline->username)) ? "" : sline->username, | |
999 | + (!EmptyString(sline->username)) ? "@" : "", /* always place a @ after the username */ | |
1000 | + (EmptyString(sline->realhost)) ? "" : sline->realhost); | |
04d03d60 | 1001 | + else if (!EmptyString(sline->passwd) && is_validsethost(NULL, sline->spoofhost)) |
0a17908b | 1002 | + send_reply(to, RPL_STATSSLINE, 'S', "User", sline->spoofhost, "", "", ""); |
1003 | } | |
1004 | } | |
1005 | ||
6fe1b135 P |
1006 | diff -r a771a07b5020 ircd/s_user.c |
1007 | --- a/ircd/s_user.c Sat Jul 20 14:54:11 2013 +0100 | |
1008 | +++ b/ircd/s_user.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 1009 | @@ -73,9 +73,6 @@ |
1010 | #include <string.h> | |
1011 | #include <sys/stat.h> | |
1012 | ||
1013 | -static char *IsVhost(char *hostmask, int oper); | |
1014 | -static char *IsVhostPass(char *hostmask); | |
1015 | - | |
1016 | /** Count of allocated User structures. */ | |
1017 | static int userCount = 0; | |
1018 | ||
1019 | @@ -373,13 +370,6 @@ | |
1020 | ||
1021 | if (feature_bool(FEAT_AUTOINVISIBLE)) | |
1022 | SetInvisible(sptr); | |
1023 | - | |
1024 | - if(feature_bool(FEAT_SETHOST_AUTO)) { | |
1025 | - if (conf_check_slines(sptr)) { | |
1026 | - send_reply(sptr, RPL_USINGSLINE); | |
1027 | - SetSetHost(sptr); | |
1028 | - } | |
1029 | - } | |
1030 | ||
1031 | SetUser(sptr); | |
1032 | cli_handler(sptr) = CLIENT_HANDLER; | |
1033 | @@ -411,6 +401,10 @@ | |
1034 | cli_info(sptr), NumNick(cptr) /* two %s's */); | |
1035 | ||
1036 | IPcheck_connect_succeeded(sptr); | |
1037 | + | |
1038 | + /* TODO: */ | |
1039 | + /* apply auto sethost if needed */ | |
1040 | + apply_spoofblock(sptr); | |
1041 | } | |
1042 | else { | |
1043 | struct Client *acptr = user->server; | |
1044 | @@ -519,7 +513,7 @@ | |
1045 | else | |
1046 | FlagClr(&flags, FLAG_ACCOUNT); | |
1047 | client_set_privs(sptr, NULL); | |
1048 | - send_umode(cptr, sptr, &flags, ALL_UMODES, 0); | |
1049 | + send_umode(cptr, sptr, &flags, ALL_UMODES, 0, 0); | |
1050 | if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE)) | |
1051 | send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr)); | |
1052 | } | |
1053 | @@ -874,14 +868,15 @@ | |
1054 | * @param[in] sptr Client who sent us the mode change message. | |
1055 | * @param[in] old Prior set of user flags. | |
1056 | * @param[in] prop If non-zero, also include FLAG_OPER. | |
1057 | + * @param[in] alreadyh Client is already +h, do not show +h change | |
1058 | */ | |
1059 | void send_umode_out(struct Client *cptr, struct Client *sptr, | |
1060 | - struct Flags *old, int prop) | |
1061 | + struct Flags *old, int prop, int alreadyh) | |
1062 | { | |
1063 | int i; | |
1064 | struct Client *acptr; | |
1065 | ||
1066 | - send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0); | |
1067 | + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0, 0); | |
1068 | ||
1069 | for (i = HighestFd; i >= 0; i--) | |
1070 | { | |
1071 | @@ -890,7 +885,7 @@ | |
1072 | sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf); | |
1073 | } | |
1074 | ||
1075 | - send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1); | |
1076 | + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1, 0); | |
1077 | ||
1078 | for (i = HighestFd; i >= 0; i--) | |
1079 | { | |
1080 | @@ -900,7 +895,7 @@ | |
1081 | } | |
1082 | ||
1083 | if (cptr && MyUser(cptr)) | |
1084 | - send_umode(cptr, sptr, old, ALL_UMODES, 0); | |
1085 | + send_umode(cptr, sptr, old, ALL_UMODES, 0, alreadyh); | |
1086 | } | |
1087 | ||
1088 | ||
1089 | @@ -965,7 +960,7 @@ | |
1090 | } | |
1091 | ||
1092 | SetFlag(cptr, flag); | |
1093 | - if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || HasSetHost(cptr)) | |
1094 | + if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || IsSetHost(cptr)) | |
1095 | return 0; | |
1096 | ||
1097 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered"); | |
1098 | @@ -974,7 +969,7 @@ | |
1099 | ||
1100 | /* ok, the client is now fully hidden, so let them know -- hikari */ | |
1101 | if (MyConnect(cptr)) | |
1102 | - send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->host); | |
1103 | + send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host); | |
1104 | ||
1105 | /* | |
1106 | * Go through all channels the client was on, rejoin him | |
1107 | @@ -999,201 +994,104 @@ | |
1108 | return 0; | |
1109 | } | |
1110 | ||
1111 | +/* TODO: */ | |
1112 | /* | |
1113 | * set_hostmask() - derived from hide_hostmask() | |
1114 | * | |
1115 | */ | |
1116 | -int set_hostmask(struct Client *cptr, char *hostmask, char *password) | |
1117 | +int set_hostmask(struct Client *cptr, char *user, char *host) | |
1118 | { | |
1119 | - int restore = 0; | |
1120 | - int freeform = 0; | |
1121 | - char *host, *new_vhost, *vhost_pass; | |
1122 | - char hiddenhost[USERLEN + HOSTLEN + 2]; | |
1123 | + | |
1124 | + int userchange = 0; | |
0a17908b | 1125 | + char *msg = "Host change"; |
1126 | struct Membership *chan; | |
1127 | ||
1128 | - Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password)); | |
1129 | + assert(0 != cptr); | |
1130 | ||
1131 | - /* sethost enabled? */ | |
1132 | - if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) { | |
1133 | - send_reply(cptr, ERR_DISABLED, "SETHOST"); | |
1134 | + Debug((DEBUG_INFO, "set_hostmask() cptr=%C user=%s host=%s", | |
1135 | + cptr, user ? user : "<null>", host ? host : "<null>")); | |
1136 | + | |
1137 | + /* remove sethost, but user has none */ | |
1138 | + if (!host && !IsSetHost(cptr)) | |
1139 | return 0; | |
1140 | + | |
1141 | + /* remove sethost, user has +x host, realusername and username are the same | |
1142 | + * pretend the user just set +x | |
1143 | + */ | |
1144 | + if (!host && HasHiddenHost(cptr) && | |
1145 | + strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) == 0) | |
1146 | + msg = "Registered"; | |
1147 | + | |
1148 | + /* quit user */ | |
1149 | + sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":%s", msg); | |
1150 | + | |
1151 | + /* remove sethost */ | |
1152 | + if (!host) { | |
1153 | + | |
77cdb5de | 1154 | + /* clear flags */ |
0a17908b | 1155 | + ClearSetHost(cptr); |
77cdb5de | 1156 | + ClearRemoteSetHost(cptr); |
0a17908b | 1157 | + |
1158 | + /* restore user and host */ | |
1159 | + if (HasHiddenHost(cptr)) | |
1160 | + ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s", | |
1161 | + cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST)); | |
1162 | + else | |
1163 | + strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN); | |
1164 | + if (MyConnect(cptr) && strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) != 0) | |
1165 | + userchange = 1; | |
1166 | + strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN); | |
1167 | } | |
1168 | ||
1169 | - /* sethost enabled for users? */ | |
1170 | - if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) { | |
1171 | - send_reply(cptr, ERR_NOPRIVILEGES); | |
1172 | - return 0; | |
1173 | - } | |
1174 | - | |
1175 | - /* MODE_DEL: restore original hostmask */ | |
1176 | - if (EmptyString(hostmask)) { | |
1177 | - /* is already sethost'ed? and only opers can remove a sethost */ | |
1178 | - if (IsSetHost(cptr) && IsAnOper(cptr)) { | |
1179 | - restore = 1; | |
1180 | - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change"); | |
1181 | - /* If they are +rx, we need to return to their +x host, not their "real" host */ | |
1182 | - if (HasHiddenHost(cptr)) | |
1183 | - ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s", | |
1184 | - cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST)); | |
1185 | - else | |
1186 | - strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN); | |
1187 | - strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN); | |
1188 | - /* log it */ | |
1189 | - if (MyConnect(cptr)) | |
1190 | - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, | |
1191 | - "SETHOST (%s@%s) by (%#R): restoring real hostmask", | |
1192 | - cli_user(cptr)->username, cli_user(cptr)->host, cptr); | |
1193 | - } else | |
1194 | - return 0; | |
1195 | - /* MODE_ADD: set a new hostmask */ | |
1196 | - } else { | |
1197 | - /* chop up ident and host.cc */ | |
1198 | - if ((host = strrchr(hostmask, '@'))) { /* oper can specifiy ident@host.cc */ | |
1199 | - *host++ = '\0'; | |
1200 | - if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host)) && (0 == strcmp(hostmask, cli_user(cptr)->username))) { | |
1201 | - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s", | |
1202 | - cli_user(cptr)->username, cli_user(cptr)->host); | |
1203 | - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost); | |
1204 | - return 0; | |
1205 | - } | |
1206 | - } else { /* user can only specifiy host.cc [password] */ | |
1207 | - host = hostmask; | |
1208 | - if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host))) { | |
1209 | - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s", | |
1210 | - cli_user(cptr)->username, cli_user(cptr)->host); | |
1211 | - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost); | |
1212 | - return 0; | |
1213 | - } | |
1214 | - } | |
1215 | - /* | |
1216 | - * Oper sethost | |
1217 | - */ | |
1218 | - if (MyConnect(cptr)) { | |
1219 | - if (IsAnOper(cptr)) { | |
1220 | - if ((new_vhost = IsVhost(host, 1)) == NULL) { | |
1221 | - if (!HasPriv(cptr, PRIV_FREEFORM)) { | |
1222 | - send_reply(cptr, ERR_HOSTUNAVAIL, hostmask); | |
1223 | - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, | |
1224 | - "SETHOST (%s@%s) by (%#R): no such s-line", | |
1225 | - (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr); | |
1226 | - return 0; | |
1227 | - } else /* freeform active, log and go */ | |
1228 | - freeform = 1; | |
1229 | - } | |
1230 | - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change"); | |
1231 | - /* set the new ident and host */ | |
1232 | - if (host != hostmask) /* oper only specified host.cc */ | |
1233 | - strncpy(cli_user(cptr)->username, hostmask, USERLEN); | |
1234 | - strncpy(cli_user(cptr)->host, host, HOSTLEN); | |
1235 | - /* log it */ | |
1236 | - log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO, | |
1237 | - (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s", | |
1238 | - cli_user(cptr)->username, cli_user(cptr)->host, cptr, | |
1239 | - (freeform) ? ": using freeform" : ""); | |
1240 | - /* | |
1241 | - * plain user sethost, handled here | |
1242 | - */ | |
1243 | - } else { | |
1244 | - /* empty password? */ | |
1245 | - if (EmptyString(password)) { | |
1246 | - send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE"); | |
1247 | - return 0; | |
1248 | - } | |
1249 | - /* no such s-line */ | |
1250 | - if ((new_vhost = IsVhost(host, 0)) == NULL) { | |
1251 | - send_reply(cptr, ERR_HOSTUNAVAIL, hostmask); | |
1252 | - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line", | |
1253 | - cli_user(cptr)->username, host, password, cptr); | |
1254 | - return 0; | |
1255 | - } | |
1256 | - /* no password */ | |
1257 | - if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) { | |
1258 | - send_reply(cptr, ERR_PASSWDMISMATCH); | |
1259 | - log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line", | |
1260 | - cli_user(cptr)->username, host, password, cptr); | |
1261 | - return 0; | |
1262 | - } | |
1263 | - /* incorrect password */ | |
1264 | - if (strCasediff(vhost_pass, password)) { | |
1265 | - send_reply(cptr, ERR_PASSWDMISMATCH); | |
1266 | - log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password", | |
1267 | - cli_user(cptr)->username, host, password, cptr); | |
1268 | - return 0; | |
1269 | - } | |
1270 | - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change"); | |
1271 | - /* set the new host */ | |
1272 | - strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN); | |
1273 | - /* log it */ | |
1274 | - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)", | |
1275 | - cli_user(cptr)->username, cli_user(cptr)->host, cptr); | |
1276 | - } | |
1277 | - } else { /* remote user */ | |
1278 | - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change"); | |
1279 | - if (host != hostmask) /* oper only specified host.cc */ | |
1280 | - strncpy(cli_user(cptr)->username, hostmask, USERLEN); | |
1281 | - strncpy(cli_user(cptr)->host, host, HOSTLEN); | |
1282 | - } | |
1283 | + /* apply sethost */ | |
1284 | + else { | |
1285 | + | |
1286 | + /* set flag */ | |
1287 | + SetSetHost(cptr); | |
1288 | + | |
1289 | + /* update user and host */ | |
1290 | + if (user) | |
1291 | + strncpy(cli_user(cptr)->username, user, USERLEN); | |
1292 | + strncpy(cli_user(cptr)->host, host, HOSTLEN); | |
1293 | } | |
1294 | ||
1295 | - if (restore) | |
1296 | - ClearSetHost(cptr); | |
1297 | - else | |
1298 | - SetSetHost(cptr); | |
1299 | + /* tell user */ | |
1300 | + if (MyConnect(cptr)) { | |
1301 | ||
1302 | - if (MyConnect(cptr)) { | |
1303 | - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s", | |
1304 | - cli_user(cptr)->username, cli_user(cptr)->host); | |
1305 | - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost); | |
1306 | + /* user and host changed */ | |
1307 | + if (userchange || strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) != 0) | |
1308 | + send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->username, "@", cli_user(cptr)->host); | |
1309 | + | |
1310 | + /* just host changed */ | |
1311 | + else | |
1312 | + send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host); | |
1313 | } | |
1314 | ||
1315 | -#if 0 | |
1316 | - /* Code copied from hide_hostmask(). This is the old (pre-delayedjoin) | |
1317 | - * version. Switch this in if you're not using the delayed join patch. */ | |
1318 | - /* | |
1319 | - * Go through all channels the client was on, rejoin him | |
1320 | - * and set the modes, if any | |
1321 | - */ | |
1322 | + /* go over the channels */ | |
1323 | for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) { | |
1324 | + | |
1325 | + /* invalidate bans so they are rechecked */ | |
1326 | + ClearBanValid(chan); | |
1327 | + | |
1328 | + /* zombie */ | |
1329 | if (IsZombie(chan)) | |
1330 | continue; | |
1331 | - sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, | |
1332 | - "%H", chan->channel); | |
1333 | - if (IsChanOp(chan) && HasVoice(chan)) { | |
1334 | - sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, | |
1335 | - "%H +ov %C %C", chan->channel, cptr, cptr); | |
1336 | - } else if (IsChanOp(chan) || HasVoice(chan)) { | |
1337 | - sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, | |
1338 | - "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr); | |
1339 | - } | |
1340 | - } | |
1341 | -#endif | |
1342 | ||
1343 | - /* | |
1344 | - * Go through all channels the client was on, rejoin him | |
1345 | - * and set the modes, if any | |
1346 | - */ | |
1347 | - for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) { | |
1348 | - if (IsZombie(chan)) | |
1349 | - continue; | |
1350 | - /* If this channel has delayed joins and the user has no modes, just set | |
1351 | - * the delayed join flag rather than showing the join, even if the user | |
1352 | - * was visible before */ | |
1353 | - if (!IsChanOp(chan) && !HasVoice(chan) | |
1354 | - && (chan->channel->mode.mode & MODE_DELJOINS)) { | |
1355 | - SetDelayedJoin(chan); | |
1356 | - } else { | |
1357 | + /* not delayed join, rejoin user to chan */ | |
1358 | + if (!IsDelayedJoin(chan)) | |
1359 | sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0, | |
1360 | "%H", chan->channel); | |
1361 | - } | |
1362 | - if (IsChanOp(chan) && HasVoice(chan)) { | |
1363 | + | |
1364 | + /* restore modes */ | |
1365 | + if (IsChanOp(chan) && HasVoice(chan)) | |
1366 | sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0, | |
1367 | "%H +ov %C %C", chan->channel, cptr, cptr); | |
1368 | - } else if (IsChanOp(chan) || HasVoice(chan)) { | |
1369 | + else if (IsChanOp(chan) || HasVoice(chan)) | |
1370 | sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0, | |
1371 | "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr); | |
1372 | - } | |
1373 | } | |
1374 | - return 1; | |
1375 | + | |
1376 | + return 0; | |
1377 | } | |
1378 | ||
1379 | /** Set a user's mode. This function checks that \a cptr is trying to | |
1380 | @@ -1220,15 +1118,17 @@ | |
1381 | unsigned int tmpmask = 0; | |
1382 | int snomask_given = 0; | |
1383 | char buf[BUFSIZE]; | |
1384 | - char *hostmask, *password; | |
1385 | + char *hostmask = NULL; | |
1386 | int prop = 0; | |
1387 | int do_host_hiding = 0; | |
1388 | int do_set_host = 0; | |
1389 | + int alreadyh = 0; | |
1390 | size_t opernamelen; | |
1391 | char *opername = 0; | |
1392 | char* account = NULL; | |
1393 | + char *user = NULL; | |
1394 | + char *host = NULL; | |
1395 | ||
1396 | - hostmask = password = NULL; | |
1397 | what = MODE_ADD; | |
1398 | ||
1399 | if (parc < 3) | |
1400 | @@ -1238,8 +1138,7 @@ | |
1401 | for (i = 0; i < USERMODELIST_SIZE; i++) | |
1402 | { | |
1403 | if (HasFlag(sptr, userModeList[i].flag) && | |
1404 | - ((userModeList[i].flag != FLAG_ACCOUNT) && | |
1405 | - (userModeList[i].flag != FLAG_SETHOST))) | |
1406 | + userModeList[i].flag != FLAG_ACCOUNT) | |
1407 | *m++ = userModeList[i].c; | |
1408 | } | |
1409 | *m = '\0'; | |
1410 | @@ -1251,6 +1150,9 @@ | |
1411 | return 0; | |
1412 | } | |
1413 | ||
1414 | + if (IsSetHost(sptr)) | |
1415 | + alreadyh = 1; | |
1416 | + | |
1417 | /* | |
1418 | * find flags already set for user | |
1419 | * why not just copy them? | |
1420 | @@ -1394,26 +1296,18 @@ | |
1421 | break; | |
1422 | case 'h': | |
1423 | if (what == MODE_ADD) { | |
1424 | - if (*(p + 1) && is_hostmask(*(p + 1))) { | |
1425 | - do_set_host = 1; | |
1426 | - hostmask = *++p; | |
1427 | - /* DON'T step p onto the trailing NULL in the parameter array! - splidge */ | |
1428 | - if (*(p+1)) | |
1429 | - password = *++p; | |
1430 | - else | |
1431 | - password = NULL; | |
1432 | - } else { | |
1433 | - if (!*(p+1)) | |
1434 | - send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST"); | |
1435 | + /* TODO: */ | |
1436 | + if (IsServer(cptr)) { | |
1437 | + if (!*(p + 1)) | |
71300e6b | 1438 | + protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr); |
0a17908b | 1439 | else { |
1440 | - send_reply(sptr, ERR_BADHOSTMASK, *(p+1)); | |
1441 | - p++; /* Swallow the arg anyway */ | |
1442 | + hostmask = *++p; | |
1443 | + do_set_host = 1; | |
1444 | } | |
1445 | } | |
1446 | } else { /* MODE_DEL */ | |
1447 | + hostmask = NULL; | |
1448 | do_set_host = 1; | |
1449 | - hostmask = NULL; | |
1450 | - password = NULL; | |
1451 | } | |
1452 | break; | |
1453 | case 'R': | |
77cdb5de | 1454 | @@ -1468,6 +1362,23 @@ |
0a17908b | 1455 | if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID))) |
1456 | ClearParanoid(sptr); | |
1457 | ||
1458 | + /* TODO: */ | |
77cdb5de | 1459 | + /* setting -h */ |
1460 | + if (do_set_host && !hostmask && IsSetHost(sptr)) { | |
1461 | + /* cannot do -h if user has a remote sethost, unless they are an oper */ | |
1462 | + if (!FlagHas(&setflags, FLAG_LOCOP) && !FlagHas(&setflags, FLAG_OPER) && IsRemoteSetHost(sptr)) | |
1463 | + do_set_host = 0; | |
1464 | + /* cannot do -h if user has no account set */ | |
1465 | + else if (!IsAccount(sptr)) | |
1466 | + do_set_host = 0; | |
1467 | + /* cannot do -h if user does not have +x set and is not allowed to set it */ | |
1468 | + else if (!IsHiddenHost(sptr) && !feature_bool(FEAT_HOST_HIDING)) | |
1469 | + do_set_host = 0; | |
1470 | + /* all ok, set user +x */ | |
1471 | + else | |
1472 | + SetHiddenHost(sptr); | |
1473 | + } | |
0a17908b | 1474 | + |
1475 | /* | |
1476 | * only send wallops to opers | |
1477 | */ | |
6fe1b135 | 1478 | @@ -1524,11 +1435,38 @@ |
0a17908b | 1479 | } |
1480 | if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT) | |
1481 | hide_hostmask(sptr, FLAG_HIDDENHOST); | |
1482 | + | |
1483 | + /* TODO: */ | |
1484 | if (do_set_host) { | |
1485 | - /* We clear the flag in the old mask, so that the +h will be sent */ | |
1486 | - /* Only do this if we're SETTING +h and it succeeded */ | |
1487 | - if (set_hostmask(sptr, hostmask, password) && hostmask) | |
1488 | - FlagClr(&setflags, FLAG_SETHOST); | |
1489 | + | |
1490 | + /* mode -h */ | |
1491 | + if (!hostmask) | |
1492 | + set_hostmask(sptr, NULL, NULL); | |
1493 | + | |
1494 | + /* mode +h */ | |
1495 | + else { | |
1496 | + if ((host = strrchr(hostmask, '@'))) { | |
1497 | + *host++ = '\0'; | |
1498 | + user = hostmask; | |
1499 | + } | |
1500 | + else | |
1501 | + host = hostmask; | |
1502 | + | |
77cf570e | 1503 | + /* dont check if sethost from remote users is valid with is_validsethost(), |
1504 | + * do check that user and host are not emtpy and | |
04d03d60 | 1505 | + * do check if they start with a : as things go horribly wrong then |
1506 | + */ | |
77cf570e | 1507 | + if (*user == 0 || user[0] == ':' || *host == 0 || host[0] == ':') |
71300e6b | 1508 | + protocol_violation(cptr, "Received MODE +h for %C with an invalid user@host '%s@%s'", |
8e8fc2f9 | 1509 | + sptr, user ? user : "", host ? host : ""); |
0a17908b | 1510 | + |
1511 | + /* apply it */ | |
1512 | + else { | |
1513 | + /* clear flag in old mask so that +h will be sent again */ | |
1514 | + FlagClr(&setflags, FLAG_SETHOST); | |
1515 | + set_hostmask(sptr, user, host); | |
1516 | + } | |
1517 | + } | |
1518 | } | |
1519 | ||
1520 | if (IsRegistered(sptr)) { | |
6fe1b135 | 1521 | @@ -1580,7 +1518,7 @@ |
0a17908b | 1522 | } |
1523 | assert(UserStats.opers <= UserStats.clients + UserStats.unknowns); | |
1524 | assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns); | |
1525 | - send_umode_out(cptr, sptr, &setflags, prop); | |
1526 | + send_umode_out(cptr, sptr, &setflags, prop, alreadyh); | |
1527 | } | |
1528 | ||
1529 | return 0; | |
6fe1b135 | 1530 | @@ -1655,9 +1593,11 @@ |
0a17908b | 1531 | * @param[in] old Pre-change set of modes for \a sptr. |
1532 | * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER, | |
1533 | * SEND_UMODES, to select which changed user modes to send. | |
1534 | + * @param[in] opernames Include opername parameter. | |
1535 | + * @param[in] alreadyh Client already has +h set, do not show +h change. | |
1536 | */ | |
1537 | void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old, | |
1538 | - int sendset, int opernames) | |
1539 | + int sendset, int opernames, int alreadyh) | |
1540 | { | |
1541 | int i; | |
1542 | int flag; | |
6fe1b135 | 1543 | @@ -1700,12 +1640,15 @@ |
0a17908b | 1544 | } |
1545 | /* Special case for SETHOST.. */ | |
1546 | if (flag == FLAG_SETHOST) { | |
1547 | - /* Don't send to users */ | |
1548 | - if (cptr && MyUser(cptr)) | |
1549 | - continue; | |
1550 | - | |
1551 | - /* If we're setting +h, add the parameter later */ | |
1552 | - if (!FlagHas(old, flag)) | |
1553 | + | |
1554 | + /* do not show +h if client already had it */ | |
1555 | + if (cptr && MyUser(cptr) && IsSetHost(cptr) && alreadyh) | |
1556 | + continue; | |
1557 | + | |
1558 | + /* If we're setting +h, add the parameter later, | |
1559 | + * but not when showing to the user | |
1560 | + */ | |
1561 | + if (!FlagHas(old, flag) && (!cptr || !MyUser(cptr))) | |
1562 | needhost++; | |
1563 | } | |
1564 | if (FlagHas(old, flag)) | |
6fe1b135 | 1565 | @@ -1744,7 +1687,7 @@ |
6fb35586 | 1566 | } |
1567 | if (needhost) { | |
1568 | *m++ = ' '; | |
1569 | - ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username, | |
1570 | + ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(sptr)->username, | |
1571 | cli_user(sptr)->host); | |
1572 | } else | |
1573 | *m = '\0'; | |
6fe1b135 | 1574 | @@ -1772,108 +1715,53 @@ |
0a17908b | 1575 | return 0; |
1576 | } | |
1577 | ||
1578 | - /* | |
1579 | - * Check to see if it resembles a valid hostmask. | |
1580 | - */ | |
1581 | -int is_hostmask(char *word) | |
04d03d60 | 1582 | +/* TODO: */ |
0a17908b | 1583 | +/** |
1584 | + * Check to see if it resembles a valid sethost. | |
1585 | + * | |
04d03d60 | 1586 | + * @param[in] user Username to check (can be NULL) |
1587 | + * @param[in] host Hostname to check | |
1588 | + * @return Non-zero if user and host look valid for a sethost | |
0a17908b | 1589 | + * |
1590 | + */ | |
04d03d60 | 1591 | +int is_validsethost(char *user, char *host) |
0a17908b | 1592 | { |
1593 | - int i = 0; | |
1594 | - char *host; | |
34145209 | 1595 | + int i; /* loop variable */ |
0a17908b | 1596 | |
1597 | - Debug((DEBUG_INFO, "is_hostmask() %s", word)); | |
04d03d60 | 1598 | + assert(host != NULL); |
1599 | ||
0a17908b | 1600 | - if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0) |
34145209 | 1601 | + /* must not be empty, not longer than HOSTLEN, not start with a : */ |
04d03d60 | 1602 | + if (*host == 0 || strlen(host) > HOSTLEN || host[0] == ':') |
0a17908b | 1603 | return 0; |
1604 | ||
1605 | - /* if a host is specified, make sure it's valid */ | |
1606 | - host = strrchr(word, '@'); | |
1607 | - if (host) { | |
1608 | - if (strlen(++host) < 1) | |
1609 | - return 0; | |
1610 | - if (strlen(host) > HOSTLEN) | |
1611 | - return 0; | |
04d03d60 | 1612 | + /* got a user part */ |
1613 | + if (user) { | |
1614 | + | |
34145209 | 1615 | + /* must not be empty, not longer than USERLEN, not start with a : */ |
1616 | + if (*user == 0 || strlen(user) > USERLEN || user[0] == ':') | |
0a17908b | 1617 | + return 0; |
04d03d60 | 1618 | + |
34145209 | 1619 | + /* check user chars |
1620 | + * use IsSetHostChar instead of IsUserChar | |
04d03d60 | 1621 | + * as the latter allows a lot more chars |
1622 | + * we dont want in a sethost | |
1623 | + */ | |
1624 | + for (i = 0; user[i]; i++) { | |
34145209 | 1625 | + if (!IsSetHostChar(user[i])) |
04d03d60 | 1626 | + return 0; |
1627 | + } | |
0a17908b | 1628 | } |
1629 | ||
1630 | - if (word) { | |
1631 | - if ('@' == *word) /* no leading @'s */ | |
1632 | - return 0; | |
1633 | - | |
1634 | - if ('#' == *word) { /* numeric index given? */ | |
1635 | - for (word++; *word; word++) { | |
1636 | - if (!IsDigit(*word)) | |
1637 | - return 0; | |
1638 | - } | |
1639 | - return 1; | |
1640 | - } | |
1641 | - | |
1642 | - /* normal hostmask, account for at most one '@' */ | |
1643 | - for (; *word; word++) { | |
1644 | - if ('@' == *word) { | |
1645 | - i++; | |
1646 | - continue; | |
1647 | - } | |
1648 | - if (!IsHostChar(*word)) | |
1649 | - return 0; | |
1650 | - } | |
1651 | - return (1 < i) ? 0 : 1; /* no more than on '@' */ | |
1652 | - } | |
1653 | - return 0; | |
1654 | -} | |
1655 | - | |
1656 | - /* | |
1657 | - * IsVhost() - Check if given host is a valid spoofhost | |
1658 | - * (ie: configured thru a S:line) | |
1659 | - */ | |
1660 | -static char *IsVhost(char *hostmask, int oper) | |
1661 | -{ | |
1662 | - unsigned int i = 0, y = 0; | |
1663 | - struct sline *sconf; | |
1664 | - | |
1665 | - Debug((DEBUG_INFO, "IsVhost() %s", hostmask)); | |
1666 | - | |
1667 | - if (EmptyString(hostmask)) | |
1668 | - return NULL; | |
1669 | - | |
1670 | - /* spoofhost specified as index, ie: #27 */ | |
1671 | - if ('#' == hostmask[0]) { | |
1672 | - y = atoi(hostmask + 1); | |
1673 | - for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) { | |
1674 | - if (!oper && EmptyString(sconf->passwd)) | |
1675 | - continue; | |
1676 | - if (y == ++i) | |
1677 | - return sconf->spoofhost; | |
1678 | - } | |
1679 | - return NULL; | |
34145209 | 1680 | + /* check host chars |
1681 | + * IsSetHostChar allows -. 0-9 A-Z [\]^_ a-Z {|} ~ and : | |
1682 | + */ | |
04d03d60 | 1683 | + for (i = 0; host[i]; i++) { |
34145209 | 1684 | + if (!IsSetHostChar(host[i])) |
04d03d60 | 1685 | + return 0; |
1686 | } | |
1687 | ||
0a17908b | 1688 | - /* spoofhost specified as host, ie: host.cc */ |
1689 | - for (sconf = GlobalSList; sconf; sconf = sconf->next) | |
1690 | - if (strCasediff(hostmask, sconf->spoofhost) == 0) | |
1691 | - return sconf->spoofhost; | |
34145209 | 1692 | - |
0a17908b | 1693 | - return NULL; |
1694 | -} | |
34145209 | 1695 | - |
0a17908b | 1696 | - /* |
1697 | - * IsVhostPass() - Check if given spoofhost has a password | |
1698 | - * associated with it, and if, return the password (cleartext) | |
1699 | - */ | |
1700 | -static char *IsVhostPass(char *hostmask) | |
1701 | -{ | |
1702 | - struct sline *sconf; | |
1703 | - | |
1704 | - Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask)); | |
1705 | - | |
1706 | - if (EmptyString(hostmask)) | |
1707 | - return NULL; | |
1708 | - | |
1709 | - for (sconf = GlobalSList; sconf; sconf = sconf->next) | |
1710 | - if (strCasediff(hostmask, sconf->spoofhost) == 0) { | |
1711 | - Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd)); | |
1712 | - return EmptyString(sconf->passwd) ? NULL : sconf->passwd; | |
1713 | - } | |
1714 | - | |
1715 | - return NULL; | |
34145209 | 1716 | + /* valid */ |
0a17908b | 1717 | + return 1; |
1718 | } | |
1719 | ||
1720 | /** Update snomask \a oldmask according to \a arg and \a what. | |
6fe1b135 P |
1721 | diff -r a771a07b5020 ircd/send.c |
1722 | --- a/ircd/send.c Sat Jul 20 14:54:11 2013 +0100 | |
1723 | +++ b/ircd/send.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 1724 | @@ -281,7 +281,7 @@ |
1725 | { | |
1726 | case MATCH_HOST: | |
1727 | return (match(mask, cli_user(one)->host) == 0 || | |
1728 | - ((HasHiddenHost(one) || HasSetHost(one)) && match(mask, cli_user(one)->realhost) == 0)); | |
1729 | + ((HasHiddenHost(one) || IsSetHost(one)) && match(mask, cli_user(one)->realhost) == 0)); | |
1730 | case MATCH_SERVER: | |
1731 | default: | |
1732 | return (match(mask, cli_name(cli_user(one)->server)) == 0); | |
6fe1b135 P |
1733 | diff -r a771a07b5020 ircd/whocmds.c |
1734 | --- a/ircd/whocmds.c Sat Jul 20 14:54:11 2013 +0100 | |
1735 | +++ b/ircd/whocmds.c Sat Jul 20 14:54:45 2013 +0100 | |
0a17908b | 1736 | @@ -134,7 +134,7 @@ |
1737 | ||
1738 | if (fields & WHO_FIELD_NIP) | |
1739 | { | |
1740 | - const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr) || feature_bool(FEAT_HIS_USERIP)) && (!IsAnOper(sptr) || (IsAnOper(sptr) && !HasPriv(sptr, PRIV_USER_PRIVACY))) ? | |
1741 | + const char* p2 = (HasHiddenHost(acptr) || IsSetHost(acptr) || feature_bool(FEAT_HIS_USERIP)) && (!IsAnOper(sptr) || (IsAnOper(sptr) && !HasPriv(sptr, PRIV_USER_PRIVACY))) ? | |
1742 | feature_str(FEAT_HIDDEN_IP) : | |
1743 | ircd_ntoa(&cli_ip(acptr)); | |
1744 | *(p1++) = ' '; | |
1745 | @@ -210,7 +210,7 @@ | |
1746 | *(p1++) = 'w'; | |
1747 | if (SendDebug(acptr)) | |
1748 | *(p1++) = 'g'; | |
1749 | - if (HasSetHost(acptr)) | |
1750 | + if (IsSetHost(acptr)) | |
1751 | *(p1++) = 'h'; | |
1752 | } | |
1753 | if (HasHiddenHost(acptr)) |