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