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