1 |
adx |
30 |
/* |
2 |
michael |
2820 |
* ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd) |
3 |
adx |
30 |
* |
4 |
michael |
7925 |
* Copyright (c) 1997-2017 ircd-hybrid development team |
5 |
adx |
30 |
* |
6 |
|
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
|
* it under the terms of the GNU General Public License as published by |
8 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
9 |
|
|
* (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
michael |
4564 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 |
19 |
adx |
30 |
* USA |
20 |
|
|
*/ |
21 |
|
|
|
22 |
michael |
2820 |
/*! \file m_server.c |
23 |
|
|
* \brief Includes required functions for processing the SERVER/SID command. |
24 |
|
|
* \version $Id$ |
25 |
|
|
*/ |
26 |
|
|
|
27 |
adx |
30 |
#include "stdinc.h" |
28 |
michael |
1011 |
#include "list.h" |
29 |
michael |
2820 |
#include "client.h" |
30 |
adx |
30 |
#include "event.h" |
31 |
michael |
2820 |
#include "hash.h" |
32 |
michael |
6160 |
#include "id.h" |
33 |
michael |
2820 |
#include "irc_string.h" |
34 |
|
|
#include "ircd.h" |
35 |
|
|
#include "numeric.h" |
36 |
|
|
#include "conf.h" |
37 |
michael |
7247 |
#include "conf_service.h" |
38 |
michael |
2820 |
#include "log.h" |
39 |
michael |
3347 |
#include "misc.h" |
40 |
|
|
#include "server.h" |
41 |
|
|
#include "user.h" |
42 |
michael |
2820 |
#include "send.h" |
43 |
adx |
30 |
#include "parse.h" |
44 |
michael |
3303 |
#include "memory.h" |
45 |
adx |
30 |
#include "modules.h" |
46 |
|
|
|
47 |
|
|
|
48 |
michael |
7106 |
/*! Parses server flags to be potentially set |
49 |
|
|
* \param client_p Pointer to server's Client structure |
50 |
|
|
* \param flags Pointer to the flag string to be parsed |
51 |
|
|
*/ |
52 |
|
|
static void |
53 |
|
|
server_set_flags(struct Client *client_p, const char *flags) |
54 |
|
|
{ |
55 |
|
|
const unsigned char *p = (const unsigned char *)flags; |
56 |
|
|
|
57 |
|
|
if (*p != '+') |
58 |
|
|
return; |
59 |
|
|
|
60 |
|
|
while (*++p) |
61 |
|
|
{ |
62 |
|
|
switch (*p) |
63 |
|
|
{ |
64 |
|
|
case 'h': |
65 |
|
|
AddFlag(client_p, FLAGS_HIDDEN); |
66 |
|
|
break; |
67 |
|
|
default: |
68 |
|
|
break; |
69 |
|
|
} |
70 |
|
|
} |
71 |
|
|
} |
72 |
|
|
|
73 |
michael |
3303 |
/* |
74 |
|
|
* send_tb |
75 |
|
|
* |
76 |
|
|
* inputs - pointer to Client |
77 |
|
|
* - pointer to channel |
78 |
|
|
* output - NONE |
79 |
|
|
* side effects - Called on a server burst when |
80 |
michael |
6353 |
* server is CAPAB_TBURST capable |
81 |
michael |
3303 |
*/ |
82 |
|
|
static void |
83 |
michael |
7554 |
server_send_tburst(struct Client *client_p, const struct Channel *chptr) |
84 |
michael |
3303 |
{ |
85 |
|
|
/* |
86 |
|
|
* We may also send an empty topic here, but only if topic_time isn't 0, |
87 |
|
|
* i.e. if we had a topic that got unset. This is required for syncing |
88 |
|
|
* topics properly. |
89 |
|
|
* |
90 |
|
|
* Imagine the following scenario: Our downlink introduces a channel |
91 |
|
|
* to us with a TS that is equal to ours, but the channel topic on |
92 |
|
|
* their side got unset while the servers were in splitmode, which means |
93 |
|
|
* their 'topic' is newer. They simply wanted to unset it, so we have to |
94 |
|
|
* deal with it in a more sophisticated fashion instead of just resetting |
95 |
|
|
* it to their old topic they had before. Read m_tburst.c:ms_tburst |
96 |
|
|
* for further information -Michael |
97 |
|
|
*/ |
98 |
|
|
if (chptr->topic_time) |
99 |
michael |
6781 |
sendto_one(client_p, ":%s TBURST %ju %s %ju %s :%s", me.id, |
100 |
|
|
chptr->creationtime, chptr->name, |
101 |
|
|
chptr->topic_time, |
102 |
michael |
3303 |
chptr->topic_info, |
103 |
|
|
chptr->topic); |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
/* sendnick_TS() |
107 |
|
|
* |
108 |
|
|
* inputs - client (server) to send nick towards |
109 |
|
|
* - client to send nick for |
110 |
|
|
* output - NONE |
111 |
|
|
* side effects - NICK message is sent towards given client_p |
112 |
|
|
*/ |
113 |
michael |
3306 |
static void |
114 |
michael |
7554 |
server_send_client(struct Client *client_p, struct Client *target_p) |
115 |
michael |
3303 |
{ |
116 |
michael |
5559 |
dlink_node *node = NULL; |
117 |
michael |
3303 |
char ubuf[IRCD_BUFSIZE] = ""; |
118 |
|
|
|
119 |
michael |
7962 |
assert(IsClient(target_p)); |
120 |
michael |
3303 |
|
121 |
michael |
7598 |
send_umode(target_p, 0, 0, ubuf); |
122 |
michael |
3303 |
|
123 |
|
|
if (ubuf[0] == '\0') |
124 |
|
|
{ |
125 |
|
|
ubuf[0] = '+'; |
126 |
|
|
ubuf[1] = '\0'; |
127 |
|
|
} |
128 |
|
|
|
129 |
michael |
6921 |
sendto_one(client_p, ":%s UID %s %u %ju %s %s %s %s %s %s :%s", |
130 |
|
|
target_p->servptr->id, |
131 |
|
|
target_p->name, target_p->hopcount + 1, |
132 |
|
|
target_p->tsinfo, |
133 |
|
|
ubuf, target_p->username, target_p->host, |
134 |
|
|
target_p->sockhost, target_p->id, |
135 |
|
|
target_p->account, target_p->info); |
136 |
michael |
3303 |
|
137 |
|
|
if (!EmptyString(target_p->certfp)) |
138 |
|
|
sendto_one(client_p, ":%s CERTFP %s", target_p->id, target_p->certfp); |
139 |
|
|
|
140 |
|
|
if (target_p->away[0]) |
141 |
|
|
sendto_one(client_p, ":%s AWAY :%s", target_p->id, target_p->away); |
142 |
|
|
|
143 |
michael |
5559 |
|
144 |
|
|
DLINK_FOREACH(node, target_p->svstags.head) |
145 |
|
|
{ |
146 |
|
|
const struct ServicesTag *svstag = node->data; |
147 |
|
|
char *m = ubuf; |
148 |
|
|
|
149 |
|
|
for (const struct user_modes *tab = umode_tab; tab->c; ++tab) |
150 |
|
|
if (svstag->umodes & tab->flag) |
151 |
|
|
*m++ = tab->c; |
152 |
|
|
*m = '\0'; |
153 |
|
|
|
154 |
michael |
6781 |
sendto_one(client_p, ":%s SVSTAG %s %ju %u +%s :%s", me.id, target_p->id, |
155 |
michael |
5559 |
target_p->tsinfo, svstag->numeric, ubuf, svstag->tag); |
156 |
|
|
} |
157 |
michael |
3303 |
} |
158 |
|
|
|
159 |
michael |
7554 |
/* burst_all() |
160 |
michael |
3303 |
* |
161 |
michael |
7554 |
* inputs - pointer to server to send burst to |
162 |
michael |
3303 |
* output - NONE |
163 |
michael |
7554 |
* side effects - complete burst of channels/nicks is sent to client_p |
164 |
michael |
3303 |
*/ |
165 |
|
|
static void |
166 |
michael |
7554 |
server_burst(struct Client *client_p) |
167 |
michael |
3303 |
{ |
168 |
michael |
4816 |
dlink_node *node = NULL; |
169 |
michael |
3303 |
|
170 |
michael |
7554 |
DLINK_FOREACH(node, global_client_list.head) |
171 |
michael |
3303 |
{ |
172 |
michael |
7554 |
struct Client *target_p = node->data; |
173 |
michael |
3303 |
|
174 |
michael |
7554 |
if (target_p->from != client_p) |
175 |
|
|
server_send_client(client_p, target_p); |
176 |
michael |
3303 |
} |
177 |
|
|
|
178 |
michael |
4816 |
DLINK_FOREACH(node, channel_list.head) |
179 |
michael |
3303 |
{ |
180 |
michael |
4816 |
struct Channel *chptr = node->data; |
181 |
michael |
3303 |
|
182 |
|
|
if (dlink_list_length(&chptr->members)) |
183 |
|
|
{ |
184 |
michael |
6374 |
channel_send_modes(client_p, chptr); |
185 |
michael |
3303 |
|
186 |
michael |
6353 |
if (IsCapable(client_p, CAPAB_TBURST)) |
187 |
michael |
7554 |
server_send_tburst(client_p, chptr); |
188 |
michael |
3303 |
} |
189 |
|
|
} |
190 |
|
|
|
191 |
|
|
/* Always send a PING after connect burst is done */ |
192 |
|
|
sendto_one(client_p, "PING :%s", me.id); |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
/* server_estab() |
196 |
|
|
* |
197 |
|
|
* inputs - pointer to a struct Client |
198 |
|
|
* output - |
199 |
|
|
* side effects - |
200 |
|
|
*/ |
201 |
michael |
3306 |
static void |
202 |
michael |
3303 |
server_estab(struct Client *client_p) |
203 |
|
|
{ |
204 |
|
|
struct MaskItem *conf = NULL; |
205 |
michael |
4816 |
dlink_node *node = NULL; |
206 |
michael |
3303 |
|
207 |
michael |
6434 |
if ((conf = find_conf_name(&client_p->connection->confs, client_p->name, CONF_SERVER)) == NULL) |
208 |
michael |
3303 |
{ |
209 |
|
|
/* This shouldn't happen, better tell the ops... -A1kmm */ |
210 |
michael |
6434 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
211 |
|
|
"Warning: lost connect{} block for %s", |
212 |
|
|
get_client_name(client_p, SHOW_IP)); |
213 |
|
|
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
214 |
|
|
"Warning: lost connect{} block for %s", |
215 |
|
|
get_client_name(client_p, MASK_IP)); |
216 |
michael |
3303 |
exit_client(client_p, "Lost connect{} block!"); |
217 |
|
|
return; |
218 |
|
|
} |
219 |
|
|
|
220 |
michael |
7033 |
xfree(client_p->connection->password); |
221 |
michael |
4589 |
client_p->connection->password = NULL; |
222 |
michael |
3303 |
|
223 |
michael |
4613 |
if (!ConfigServerInfo.hub && dlink_list_length(&local_server_list)) |
224 |
michael |
3303 |
{ |
225 |
michael |
4613 |
++ServerStats.is_ref; |
226 |
|
|
exit_client(client_p, "I'm a leaf not a hub"); |
227 |
|
|
return; |
228 |
michael |
3303 |
} |
229 |
|
|
|
230 |
|
|
if (IsUnknown(client_p)) |
231 |
|
|
{ |
232 |
michael |
7356 |
sendto_one(client_p, "PASS %s TS %u %s", conf->spasswd, TS_CURRENT, me.id); |
233 |
michael |
3303 |
|
234 |
michael |
7589 |
sendto_one(client_p, "CAPAB :%s", get_capabilities(NULL)); |
235 |
michael |
3303 |
|
236 |
|
|
sendto_one(client_p, "SERVER %s 1 :%s%s", |
237 |
|
|
me.name, ConfigServerHide.hidden ? "(H) " : "", me.info); |
238 |
|
|
} |
239 |
|
|
|
240 |
michael |
7356 |
sendto_one(client_p, ":%s SVINFO %u %u 0 :%ju", me.id, TS_CURRENT, TS_MIN, |
241 |
michael |
6781 |
CurrentTime); |
242 |
michael |
3303 |
|
243 |
|
|
/* *WARNING* |
244 |
|
|
** In the following code in place of plain server's |
245 |
|
|
** name we send what is returned by get_client_name |
246 |
|
|
** which may add the "sockhost" after the name. It's |
247 |
|
|
** *very* *important* that there is a SPACE between |
248 |
|
|
** the name and sockhost (if present). The receiving |
249 |
|
|
** server will start the information field from this |
250 |
|
|
** first blank and thus puts the sockhost into info. |
251 |
|
|
** ...a bit tricky, but you have been warned, besides |
252 |
|
|
** code is more neat this way... --msa |
253 |
|
|
*/ |
254 |
|
|
client_p->servptr = &me; |
255 |
|
|
|
256 |
michael |
6471 |
if (HasFlag(client_p, FLAGS_CLOSING)) |
257 |
michael |
3303 |
return; |
258 |
|
|
|
259 |
|
|
SetServer(client_p); |
260 |
|
|
|
261 |
|
|
/* Some day, all these lists will be consolidated *sigh* */ |
262 |
|
|
dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list); |
263 |
|
|
|
264 |
|
|
assert(dlinkFind(&unknown_list, client_p)); |
265 |
|
|
|
266 |
michael |
4589 |
dlink_move_node(&client_p->connection->lclient_node, |
267 |
michael |
4212 |
&unknown_list, &local_server_list); |
268 |
michael |
3303 |
|
269 |
|
|
Count.myserver++; |
270 |
|
|
|
271 |
michael |
7962 |
dlinkAdd(client_p, &client_p->node, &global_server_list); |
272 |
michael |
3303 |
hash_add_client(client_p); |
273 |
|
|
hash_add_id(client_p); |
274 |
|
|
|
275 |
michael |
4580 |
/* Doesn't duplicate client_p->serv if allocated this struct already */ |
276 |
michael |
3303 |
make_server(client_p); |
277 |
|
|
|
278 |
michael |
4580 |
/* Fixing eob timings.. -gnp */ |
279 |
michael |
4589 |
client_p->connection->firsttime = CurrentTime; |
280 |
michael |
3303 |
|
281 |
michael |
7247 |
if (service_find(client_p->name)) |
282 |
michael |
3303 |
AddFlag(client_p, FLAGS_SERVICE); |
283 |
|
|
|
284 |
|
|
/* Show the real host/IP to admins */ |
285 |
michael |
7106 |
if (tls_isusing(&client_p->connection->fd.ssl)) |
286 |
michael |
3303 |
{ |
287 |
michael |
7106 |
/* Show the real host/IP to admins */ |
288 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
289 |
michael |
7106 |
"Link with %s established: [TLS: %s] (Capabilities: %s)", |
290 |
|
|
get_client_name(client_p, SHOW_IP), tls_get_cipher(&client_p->connection->fd.ssl), |
291 |
michael |
7589 |
get_capabilities(client_p)); |
292 |
michael |
7106 |
|
293 |
michael |
3303 |
/* Now show the masked hostname/IP to opers */ |
294 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
295 |
michael |
7106 |
"Link with %s established: [TLS: %s] (Capabilities: %s)", |
296 |
|
|
get_client_name(client_p, MASK_IP), tls_get_cipher(&client_p->connection->fd.ssl), |
297 |
michael |
7589 |
get_capabilities(client_p)); |
298 |
michael |
7106 |
ilog(LOG_TYPE_IRCD, "Link with %s established: [TLS: %s] (Capabilities: %s)", |
299 |
|
|
get_client_name(client_p, SHOW_IP), tls_get_cipher(&client_p->connection->fd.ssl), |
300 |
michael |
7589 |
get_capabilities(client_p)); |
301 |
michael |
3303 |
} |
302 |
|
|
else |
303 |
|
|
{ |
304 |
michael |
7106 |
/* Show the real host/IP to admins */ |
305 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
306 |
michael |
3303 |
"Link with %s established: (Capabilities: %s)", |
307 |
michael |
7589 |
get_client_name(client_p, SHOW_IP), get_capabilities(client_p)); |
308 |
michael |
3303 |
/* Now show the masked hostname/IP to opers */ |
309 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
310 |
michael |
3303 |
"Link with %s established: (Capabilities: %s)", |
311 |
michael |
7589 |
get_client_name(client_p, MASK_IP), get_capabilities(client_p)); |
312 |
michael |
3303 |
ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)", |
313 |
michael |
7589 |
get_client_name(client_p, SHOW_IP), get_capabilities(client_p)); |
314 |
michael |
3303 |
} |
315 |
|
|
|
316 |
michael |
4589 |
fd_note(&client_p->connection->fd, "Server: %s", client_p->name); |
317 |
michael |
3303 |
|
318 |
michael |
4963 |
sendto_server(client_p, 0, 0, ":%s SID %s 2 %s :%s%s", |
319 |
michael |
3303 |
me.id, client_p->name, client_p->id, |
320 |
|
|
IsHidden(client_p) ? "(H) " : "", client_p->info); |
321 |
|
|
|
322 |
|
|
/* |
323 |
|
|
* Pass on my client information to the new server |
324 |
|
|
* |
325 |
|
|
* First, pass only servers (idea is that if the link gets |
326 |
|
|
* cancelled beacause the server was already there, |
327 |
|
|
* there are no NICK's to be cancelled...). Of course, |
328 |
|
|
* if cancellation occurs, all this info is sent anyway, |
329 |
|
|
* and I guess the link dies when a read is attempted...? --msa |
330 |
|
|
* |
331 |
|
|
* Note: Link cancellation to occur at this point means |
332 |
|
|
* that at least two servers from my fragment are building |
333 |
|
|
* up connection this other fragment at the same time, it's |
334 |
|
|
* a race condition, not the normal way of operation... |
335 |
|
|
*/ |
336 |
michael |
4816 |
DLINK_FOREACH_PREV(node, global_server_list.tail) |
337 |
michael |
3303 |
{ |
338 |
michael |
4816 |
struct Client *target_p = node->data; |
339 |
michael |
3303 |
|
340 |
|
|
/* target_p->from == target_p for target_p == client_p */ |
341 |
|
|
if (IsMe(target_p) || target_p->from == client_p) |
342 |
|
|
continue; |
343 |
|
|
|
344 |
michael |
5785 |
sendto_one(client_p, ":%s SID %s %u %s :%s%s", |
345 |
michael |
3303 |
target_p->servptr->id, target_p->name, target_p->hopcount+1, |
346 |
|
|
target_p->id, IsHidden(target_p) ? "(H) " : "", |
347 |
|
|
target_p->info); |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
server_burst(client_p); |
351 |
michael |
4710 |
|
352 |
michael |
6353 |
if (IsCapable(client_p, CAPAB_EOB)) |
353 |
michael |
4710 |
{ |
354 |
michael |
4816 |
DLINK_FOREACH_PREV(node, global_server_list.tail) |
355 |
michael |
4710 |
{ |
356 |
michael |
4816 |
struct Client *target_p = node->data; |
357 |
michael |
4710 |
|
358 |
|
|
if (target_p->from == client_p) |
359 |
|
|
continue; |
360 |
|
|
|
361 |
|
|
if (IsMe(target_p) || HasFlag(target_p, FLAGS_EOB)) |
362 |
|
|
sendto_one(client_p, ":%s EOB", target_p->id); |
363 |
|
|
} |
364 |
|
|
} |
365 |
michael |
3303 |
} |
366 |
|
|
|
367 |
michael |
1997 |
/* set_server_gecos() |
368 |
|
|
* |
369 |
|
|
* input - pointer to client |
370 |
|
|
* output - NONE |
371 |
|
|
* side effects - servers gecos field is set |
372 |
|
|
*/ |
373 |
|
|
static void |
374 |
michael |
7106 |
server_set_gecos(struct Client *client_p, const char *info) |
375 |
michael |
1997 |
{ |
376 |
|
|
const char *s = info; |
377 |
adx |
30 |
|
378 |
michael |
1997 |
/* check for (H) which is a hidden server */ |
379 |
|
|
if (!strncmp(s, "(H) ", 4)) |
380 |
|
|
{ |
381 |
michael |
6314 |
AddFlag(client_p, FLAGS_HIDDEN); |
382 |
michael |
1997 |
s = s + 4; |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
if (!EmptyString(s)) |
386 |
|
|
strlcpy(client_p->info, s, sizeof(client_p->info)); |
387 |
|
|
else |
388 |
|
|
strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info)); |
389 |
|
|
} |
390 |
|
|
|
391 |
michael |
7950 |
static int |
392 |
|
|
server_check(const char *name, struct Client *client_p) |
393 |
|
|
{ |
394 |
|
|
dlink_node *node = NULL; |
395 |
|
|
struct MaskItem *server_conf = NULL; |
396 |
|
|
int error = -1; |
397 |
|
|
|
398 |
|
|
assert(client_p); |
399 |
|
|
|
400 |
|
|
/* Loop through looking for all possible connect items that might work */ |
401 |
|
|
DLINK_FOREACH(node, connect_items.head) |
402 |
|
|
{ |
403 |
|
|
struct MaskItem *conf = node->data; |
404 |
|
|
|
405 |
|
|
if (irccmp(name, conf->name)) |
406 |
|
|
continue; |
407 |
|
|
|
408 |
|
|
error = -3; |
409 |
|
|
|
410 |
|
|
if (!irccmp(conf->host, client_p->host) || |
411 |
|
|
!irccmp(conf->host, client_p->sockhost)) |
412 |
|
|
{ |
413 |
|
|
error = -2; |
414 |
|
|
|
415 |
|
|
if (!match_conf_password(client_p->connection->password, conf)) |
416 |
|
|
return -2; |
417 |
|
|
|
418 |
|
|
if (!EmptyString(conf->certfp)) |
419 |
|
|
if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp)) |
420 |
|
|
return -4; |
421 |
|
|
|
422 |
|
|
server_conf = conf; |
423 |
|
|
} |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
if (server_conf == NULL) |
427 |
|
|
return error; |
428 |
|
|
|
429 |
|
|
attach_conf(client_p, server_conf); |
430 |
|
|
|
431 |
|
|
switch (server_conf->aftype) |
432 |
|
|
{ |
433 |
|
|
case AF_INET6: |
434 |
|
|
{ |
435 |
|
|
const struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&server_conf->addr; |
436 |
|
|
|
437 |
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr)) |
438 |
|
|
memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr)); |
439 |
|
|
break; |
440 |
|
|
} |
441 |
|
|
case AF_INET: |
442 |
|
|
{ |
443 |
|
|
const struct sockaddr_in *v4 = (struct sockaddr_in *)&server_conf->addr; |
444 |
|
|
|
445 |
|
|
if (v4->sin_addr.s_addr == INADDR_NONE) |
446 |
|
|
memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr)); |
447 |
|
|
break; |
448 |
|
|
} |
449 |
|
|
} |
450 |
|
|
|
451 |
|
|
return 0; |
452 |
|
|
} |
453 |
|
|
|
454 |
adx |
30 |
/* mr_server() |
455 |
michael |
3096 |
* parv[0] = command |
456 |
adx |
30 |
* parv[1] = servername |
457 |
michael |
3139 |
* parv[2] = hopcount |
458 |
adx |
30 |
* parv[3] = serverinfo |
459 |
michael |
7106 |
* |
460 |
|
|
* 8.3.x+: |
461 |
|
|
* parv[0] = command |
462 |
|
|
* parv[1] = servername |
463 |
|
|
* parv[2] = hopcount |
464 |
|
|
* parv[3] = sid |
465 |
|
|
* parv[4] = string of flags starting with '+' |
466 |
|
|
* parv[5] = serverinfo |
467 |
adx |
30 |
*/ |
468 |
michael |
2820 |
static int |
469 |
michael |
3156 |
mr_server(struct Client *source_p, int parc, char *parv[]) |
470 |
adx |
30 |
{ |
471 |
michael |
4754 |
const char *name = parv[1]; |
472 |
michael |
7106 |
const char *sid = parc == 6 ? parv[3] : source_p->id; /* TBR: compatibility 'mode' */ |
473 |
michael |
3246 |
struct Client *target_p = NULL; |
474 |
adx |
30 |
|
475 |
michael |
4658 |
if (EmptyString(parv[parc - 1])) |
476 |
adx |
30 |
{ |
477 |
michael |
4610 |
exit_client(source_p, "No server description supplied"); |
478 |
michael |
2820 |
return 0; |
479 |
adx |
30 |
} |
480 |
|
|
|
481 |
michael |
1118 |
if (!valid_servname(name)) |
482 |
adx |
30 |
{ |
483 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
484 |
michael |
1118 |
"Unauthorized server connection attempt from %s: Bogus server name " |
485 |
michael |
6426 |
"for server %s", get_client_name(source_p, SHOW_IP), name); |
486 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
487 |
michael |
1118 |
"Unauthorized server connection attempt from %s: Bogus server name " |
488 |
michael |
3156 |
"for server %s", get_client_name(source_p, MASK_IP), name); |
489 |
michael |
3171 |
exit_client(source_p, "Bogus server name"); |
490 |
michael |
2820 |
return 0; |
491 |
adx |
30 |
} |
492 |
|
|
|
493 |
michael |
7106 |
if (!valid_sid(sid)) |
494 |
michael |
3148 |
{ |
495 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
496 |
michael |
3148 |
"Link %s introduced server with bogus server ID %s", |
497 |
michael |
7106 |
get_client_name(source_p, SHOW_IP), sid); |
498 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
499 |
michael |
3148 |
"Link %s introduced server with bogus server ID %s", |
500 |
michael |
7106 |
get_client_name(source_p, MASK_IP), sid); |
501 |
michael |
4571 |
exit_client(source_p, "Bogus server ID introduced"); |
502 |
michael |
3148 |
return 0; |
503 |
|
|
} |
504 |
|
|
|
505 |
michael |
7950 |
/* Now we just have to call server_check() and everything should |
506 |
adx |
30 |
* be check for us... -A1kmm. |
507 |
|
|
*/ |
508 |
michael |
7950 |
switch (server_check(name, source_p)) |
509 |
adx |
30 |
{ |
510 |
|
|
case -1: |
511 |
michael |
4341 |
if (ConfigGeneral.warn_no_connect_block) |
512 |
adx |
30 |
{ |
513 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
514 |
adx |
30 |
"Unauthorized server connection attempt from %s: No entry for " |
515 |
michael |
6426 |
"servername %s", get_client_name(source_p, SHOW_IP), name); |
516 |
adx |
30 |
|
517 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
518 |
adx |
30 |
"Unauthorized server connection attempt from %s: No entry for " |
519 |
michael |
3156 |
"servername %s", get_client_name(source_p, MASK_IP), name); |
520 |
adx |
30 |
} |
521 |
|
|
|
522 |
michael |
4610 |
exit_client(source_p, "No connect {} block."); |
523 |
michael |
2820 |
return 0; |
524 |
adx |
30 |
/* NOT REACHED */ |
525 |
|
|
break; |
526 |
|
|
|
527 |
|
|
case -2: |
528 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
529 |
adx |
30 |
"Unauthorized server connection attempt from %s: Bad password " |
530 |
michael |
6426 |
"for server %s", get_client_name(source_p, SHOW_IP), name); |
531 |
adx |
30 |
|
532 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
533 |
adx |
30 |
"Unauthorized server connection attempt from %s: Bad password " |
534 |
michael |
3156 |
"for server %s", get_client_name(source_p, MASK_IP), name); |
535 |
adx |
30 |
|
536 |
michael |
3171 |
exit_client(source_p, "Invalid password."); |
537 |
michael |
2820 |
return 0; |
538 |
adx |
30 |
/* NOT REACHED */ |
539 |
|
|
break; |
540 |
|
|
|
541 |
|
|
case -3: |
542 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
543 |
adx |
30 |
"Unauthorized server connection attempt from %s: Invalid host " |
544 |
michael |
6426 |
"for server %s", get_client_name(source_p, SHOW_IP), name); |
545 |
adx |
30 |
|
546 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
547 |
adx |
30 |
"Unauthorized server connection attempt from %s: Invalid host " |
548 |
michael |
3156 |
"for server %s", get_client_name(source_p, MASK_IP), name); |
549 |
adx |
30 |
|
550 |
michael |
3171 |
exit_client(source_p, "Invalid host."); |
551 |
michael |
2820 |
return 0; |
552 |
michael |
2228 |
case -4: |
553 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
554 |
michael |
2228 |
"Unauthorized server connection attempt from %s: Invalid certificate fingerprint " |
555 |
michael |
6426 |
"for server %s", get_client_name(source_p, SHOW_IP), name); |
556 |
michael |
2228 |
|
557 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
558 |
michael |
2228 |
"Unauthorized server connection attempt from %s: Invalid certificate fingerprint " |
559 |
michael |
3156 |
"for server %s", get_client_name(source_p, MASK_IP), name); |
560 |
michael |
2228 |
|
561 |
michael |
3171 |
exit_client(source_p, "Invalid certificate fingerprint."); |
562 |
michael |
2820 |
return 0; |
563 |
adx |
30 |
/* NOT REACHED */ |
564 |
|
|
break; |
565 |
|
|
} |
566 |
|
|
|
567 |
michael |
2976 |
if ((target_p = hash_find_server(name))) |
568 |
adx |
30 |
{ |
569 |
|
|
/* This link is trying feed me a server that I already have |
570 |
|
|
* access through another path -- multiple paths not accepted |
571 |
|
|
* currently, kill this link immediately!! |
572 |
|
|
* |
573 |
|
|
* Rather than KILL the link which introduced it, KILL the |
574 |
|
|
* youngest of the two links. -avalon |
575 |
|
|
* |
576 |
|
|
* Definitely don't do that here. This is from an unregistered |
577 |
|
|
* connect - A1kmm. |
578 |
|
|
*/ |
579 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
580 |
michael |
2976 |
"Attempt to re-introduce server %s from %s", |
581 |
michael |
6426 |
name, get_client_name(source_p, SHOW_IP)); |
582 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
583 |
michael |
2976 |
"Attempt to re-introduce server %s from %s", |
584 |
michael |
3156 |
name, get_client_name(source_p, MASK_IP)); |
585 |
michael |
3171 |
exit_client(source_p, "Server already exists"); |
586 |
michael |
2976 |
return 0; |
587 |
|
|
} |
588 |
|
|
|
589 |
michael |
3156 |
if ((target_p = hash_find_id(source_p->id))) |
590 |
michael |
2976 |
{ |
591 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
592 |
michael |
2820 |
"Attempt to re-introduce server %s SID %s from %s", |
593 |
michael |
3156 |
name, source_p->id, |
594 |
michael |
6426 |
get_client_name(source_p, SHOW_IP)); |
595 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
596 |
michael |
2820 |
"Attempt to re-introduce server %s SID %s from %s", |
597 |
michael |
3156 |
name, source_p->id, |
598 |
|
|
get_client_name(source_p, MASK_IP)); |
599 |
michael |
3171 |
exit_client(source_p, "Server ID already exists"); |
600 |
michael |
2820 |
return 0; |
601 |
adx |
30 |
} |
602 |
|
|
|
603 |
|
|
/* XXX If somehow there is a connect in progress and |
604 |
|
|
* a connect comes in with same name toss the pending one, |
605 |
|
|
* but only if it's not the same client! - Dianora |
606 |
|
|
*/ |
607 |
|
|
if ((target_p = find_servconn_in_progress(name))) |
608 |
michael |
3156 |
if (target_p != source_p) |
609 |
michael |
3171 |
exit_client(target_p, "Overridden"); |
610 |
adx |
30 |
|
611 |
|
|
/* if we are connecting (Handshake), we already have the name from the |
612 |
michael |
3156 |
* connect{} block in source_p->name |
613 |
adx |
30 |
*/ |
614 |
michael |
3156 |
strlcpy(source_p->name, name, sizeof(source_p->name)); |
615 |
michael |
7106 |
|
616 |
|
|
if (parc == 6) /* TBR: compatibility 'mode' */ |
617 |
|
|
{ |
618 |
|
|
strlcpy(source_p->id, sid, sizeof(source_p->id)); |
619 |
|
|
strlcpy(source_p->info, parv[parc - 1], sizeof(source_p->info)); |
620 |
|
|
server_set_flags(source_p, parv[4]); |
621 |
|
|
} |
622 |
|
|
else |
623 |
|
|
server_set_gecos(source_p, parv[parc - 1]); |
624 |
|
|
|
625 |
michael |
3190 |
source_p->hopcount = atoi(parv[2]); |
626 |
michael |
3156 |
server_estab(source_p); |
627 |
michael |
2820 |
return 0; |
628 |
adx |
30 |
} |
629 |
|
|
|
630 |
|
|
/* ms_sid() |
631 |
michael |
3096 |
* parv[0] = command |
632 |
adx |
30 |
* parv[1] = servername |
633 |
michael |
3139 |
* parv[2] = hopcount |
634 |
adx |
30 |
* parv[3] = sid of new server |
635 |
|
|
* parv[4] = serverinfo |
636 |
michael |
7106 |
* |
637 |
|
|
* 8.3.x+: |
638 |
|
|
* parv[0] = command |
639 |
|
|
* parv[1] = servername |
640 |
|
|
* parv[2] = hopcount |
641 |
|
|
* parv[3] = sid of new server |
642 |
|
|
* parv[4] = string of flags starting with '+' |
643 |
|
|
* parv[5] = serverinfo |
644 |
adx |
30 |
*/ |
645 |
michael |
2820 |
static int |
646 |
michael |
3156 |
ms_sid(struct Client *source_p, int parc, char *parv[]) |
647 |
adx |
30 |
{ |
648 |
michael |
4816 |
dlink_node *node = NULL; |
649 |
michael |
3139 |
struct Client *target_p = NULL; |
650 |
michael |
3156 |
struct Client *client_p = source_p->from; /* XXX */ |
651 |
michael |
3139 |
const struct MaskItem *conf = NULL; |
652 |
adx |
30 |
int hlined = 0; |
653 |
|
|
int llined = 0; |
654 |
|
|
|
655 |
|
|
/* Just to be sure -A1kmm. */ |
656 |
|
|
if (!IsServer(source_p)) |
657 |
michael |
2820 |
return 0; |
658 |
adx |
30 |
|
659 |
michael |
4658 |
if (EmptyString(parv[parc - 1])) |
660 |
michael |
1118 |
{ |
661 |
michael |
4610 |
exit_client(client_p, "No server description supplied"); |
662 |
michael |
2820 |
return 0; |
663 |
michael |
1118 |
} |
664 |
adx |
30 |
|
665 |
michael |
1118 |
if (!valid_servname(parv[1])) |
666 |
|
|
{ |
667 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
668 |
michael |
1118 |
"Link %s introduced server with bogus server name %s", |
669 |
|
|
get_client_name(client_p, SHOW_IP), parv[1]); |
670 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
671 |
michael |
1118 |
"Link %s introduced server with bogus server name %s", |
672 |
|
|
get_client_name(client_p, MASK_IP), parv[1]); |
673 |
michael |
4571 |
exit_client(client_p, "Bogus server name introduced"); |
674 |
michael |
2820 |
return 0; |
675 |
michael |
1118 |
} |
676 |
|
|
|
677 |
|
|
if (!valid_sid(parv[3])) |
678 |
|
|
{ |
679 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
680 |
michael |
1118 |
"Link %s introduced server with bogus server ID %s", |
681 |
|
|
get_client_name(client_p, SHOW_IP), parv[3]); |
682 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
683 |
michael |
1118 |
"Link %s introduced server with bogus server ID %s", |
684 |
|
|
get_client_name(client_p, MASK_IP), parv[3]); |
685 |
michael |
4571 |
exit_client(client_p, "Bogus server ID introduced"); |
686 |
michael |
2820 |
return 0; |
687 |
michael |
1118 |
} |
688 |
|
|
|
689 |
adx |
30 |
/* collision on SID? */ |
690 |
michael |
1118 |
if ((target_p = hash_find_id(parv[3]))) |
691 |
adx |
30 |
{ |
692 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
693 |
michael |
4610 |
"Link %s cancelled, server ID %s already exists", |
694 |
michael |
1118 |
get_client_name(client_p, SHOW_IP), parv[3]); |
695 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
696 |
michael |
4610 |
"Link %s cancelled, server ID %s already exists", |
697 |
michael |
6439 |
get_client_name(client_p, MASK_IP), parv[3]); |
698 |
michael |
4610 |
exit_client(client_p, "Link cancelled, server ID already exists"); |
699 |
michael |
2820 |
return 0; |
700 |
adx |
30 |
} |
701 |
|
|
|
702 |
|
|
/* collision on name? */ |
703 |
michael |
1169 |
if ((target_p = hash_find_server(parv[1]))) |
704 |
adx |
30 |
{ |
705 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
706 |
michael |
2820 |
"Link %s cancelled, server %s already exists", |
707 |
michael |
1118 |
get_client_name(client_p, SHOW_IP), parv[1]); |
708 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
709 |
michael |
2820 |
"Link %s cancelled, server %s already exists", |
710 |
michael |
6439 |
get_client_name(client_p, MASK_IP), parv[1]); |
711 |
michael |
4610 |
exit_client(client_p, "Server exists"); |
712 |
michael |
2820 |
return 0; |
713 |
adx |
30 |
} |
714 |
|
|
|
715 |
|
|
/* XXX If somehow there is a connect in progress and |
716 |
|
|
* a connect comes in with same name toss the pending one, |
717 |
|
|
* but only if it's not the same client! - Dianora |
718 |
|
|
*/ |
719 |
michael |
1118 |
if ((target_p = find_servconn_in_progress(parv[1]))) |
720 |
adx |
30 |
if (target_p != client_p) |
721 |
michael |
3171 |
exit_client(target_p, "Overridden"); |
722 |
adx |
30 |
|
723 |
michael |
4589 |
conf = client_p->connection->confs.head->data; |
724 |
michael |
1384 |
|
725 |
adx |
30 |
/* See if the newly found server is behind a guaranteed |
726 |
|
|
* leaf. If so, close the link. |
727 |
|
|
*/ |
728 |
michael |
4816 |
DLINK_FOREACH(node, conf->leaf_list.head) |
729 |
michael |
3139 |
{ |
730 |
michael |
4816 |
if (!match(node->data, parv[1])) |
731 |
michael |
1529 |
{ |
732 |
|
|
llined = 1; |
733 |
|
|
break; |
734 |
|
|
} |
735 |
michael |
3139 |
} |
736 |
adx |
30 |
|
737 |
michael |
4816 |
DLINK_FOREACH(node, conf->hub_list.head) |
738 |
michael |
3139 |
{ |
739 |
michael |
4816 |
if (!match(node->data, parv[1])) |
740 |
michael |
1529 |
{ |
741 |
|
|
hlined = 1; |
742 |
|
|
break; |
743 |
|
|
} |
744 |
michael |
3139 |
} |
745 |
michael |
1118 |
|
746 |
adx |
30 |
/* Ok, this way this works is |
747 |
|
|
* |
748 |
|
|
* A server can have a CONF_HUB allowing it to introduce servers |
749 |
|
|
* behind it. |
750 |
|
|
* |
751 |
|
|
* connect { |
752 |
|
|
* name = "irc.bighub.net"; |
753 |
|
|
* hub_mask="*"; |
754 |
|
|
* ... |
755 |
michael |
2820 |
* |
756 |
adx |
30 |
* That would allow "irc.bighub.net" to introduce anything it wanted.. |
757 |
|
|
* |
758 |
|
|
* However |
759 |
|
|
* |
760 |
|
|
* connect { |
761 |
|
|
* name = "irc.somehub.fi"; |
762 |
|
|
* hub_mask="*"; |
763 |
|
|
* leaf_mask="*.edu"; |
764 |
|
|
*... |
765 |
|
|
* Would allow this server in finland to hub anything but |
766 |
|
|
* .edu's |
767 |
|
|
*/ |
768 |
|
|
|
769 |
|
|
/* Ok, check client_p can hub the new server, and make sure it's not a LL */ |
770 |
michael |
885 |
if (!hlined) |
771 |
adx |
30 |
{ |
772 |
|
|
/* OOOPs nope can't HUB */ |
773 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
774 |
michael |
1618 |
"Non-Hub link %s introduced %s.", |
775 |
michael |
1118 |
get_client_name(client_p, SHOW_IP), parv[1]); |
776 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
777 |
michael |
1618 |
"Non-Hub link %s introduced %s.", |
778 |
michael |
1118 |
get_client_name(client_p, MASK_IP), parv[1]); |
779 |
michael |
3171 |
exit_client(source_p, "No matching hub_mask."); |
780 |
michael |
2820 |
return 0; |
781 |
adx |
30 |
} |
782 |
|
|
|
783 |
|
|
/* Check for the new server being leafed behind this HUB */ |
784 |
|
|
if (llined) |
785 |
|
|
{ |
786 |
|
|
/* OOOPs nope can't HUB this leaf */ |
787 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE, |
788 |
michael |
2820 |
"Link %s introduced leafed server %s.", |
789 |
michael |
1118 |
get_client_name(client_p, SHOW_IP), parv[1]); |
790 |
michael |
6317 |
sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE, |
791 |
michael |
2820 |
"Link %s introduced leafed server %s.", |
792 |
michael |
1118 |
get_client_name(client_p, MASK_IP), parv[1]); |
793 |
michael |
4610 |
exit_client(client_p, "Leafed server."); |
794 |
michael |
2820 |
return 0; |
795 |
adx |
30 |
} |
796 |
|
|
|
797 |
michael |
7956 |
target_p = client_make(client_p); |
798 |
adx |
30 |
make_server(target_p); |
799 |
michael |
3190 |
target_p->hopcount = atoi(parv[2]); |
800 |
michael |
1118 |
target_p->servptr = source_p; |
801 |
adx |
30 |
|
802 |
michael |
1118 |
strlcpy(target_p->name, parv[1], sizeof(target_p->name)); |
803 |
|
|
strlcpy(target_p->id, parv[3], sizeof(target_p->id)); |
804 |
adx |
30 |
|
805 |
michael |
7106 |
if (parc == 6) /* TBR: compatibility 'mode' */ |
806 |
|
|
{ |
807 |
|
|
strlcpy(target_p->info, parv[parc - 1], sizeof(target_p->info)); |
808 |
|
|
server_set_flags(target_p, parv[4]); |
809 |
|
|
} |
810 |
|
|
else |
811 |
|
|
server_set_gecos(target_p, parv[parc - 1]); |
812 |
|
|
|
813 |
adx |
30 |
SetServer(target_p); |
814 |
|
|
|
815 |
michael |
7247 |
if (service_find(target_p->name)) |
816 |
michael |
1219 |
AddFlag(target_p, FLAGS_SERVICE); |
817 |
michael |
1157 |
|
818 |
michael |
7962 |
dlinkAdd(target_p, &target_p->node, &global_server_list); |
819 |
michael |
1118 |
dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list); |
820 |
adx |
30 |
|
821 |
|
|
hash_add_client(target_p); |
822 |
|
|
hash_add_id(target_p); |
823 |
|
|
|
824 |
michael |
5785 |
sendto_server(client_p, 0, 0, ":%s SID %s %u %s :%s%s", |
825 |
michael |
3192 |
source_p->id, target_p->name, target_p->hopcount + 1, |
826 |
michael |
1527 |
target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info); |
827 |
michael |
1618 |
sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE, |
828 |
michael |
1118 |
"Server %s being introduced by %s", |
829 |
adx |
30 |
target_p->name, source_p->name); |
830 |
michael |
2820 |
return 0; |
831 |
adx |
30 |
} |
832 |
|
|
|
833 |
michael |
2820 |
static struct Message server_msgtab = |
834 |
|
|
{ |
835 |
michael |
5880 |
.cmd = "SERVER", |
836 |
|
|
.args_min = 4, |
837 |
|
|
.args_max = MAXPARA, |
838 |
|
|
.handlers[UNREGISTERED_HANDLER] = mr_server, |
839 |
|
|
.handlers[CLIENT_HANDLER] = m_registered, |
840 |
|
|
.handlers[SERVER_HANDLER] = m_ignore, |
841 |
|
|
.handlers[ENCAP_HANDLER] = m_ignore, |
842 |
|
|
.handlers[OPER_HANDLER] = m_registered |
843 |
michael |
1230 |
}; |
844 |
|
|
|
845 |
michael |
2820 |
static struct Message sid_msgtab = |
846 |
|
|
{ |
847 |
michael |
5880 |
.cmd = "SID", |
848 |
|
|
.args_min = 5, |
849 |
|
|
.args_max = MAXPARA, |
850 |
|
|
.handlers[UNREGISTERED_HANDLER] = m_ignore, |
851 |
|
|
.handlers[CLIENT_HANDLER] = m_ignore, |
852 |
|
|
.handlers[SERVER_HANDLER] = ms_sid, |
853 |
|
|
.handlers[ENCAP_HANDLER] = m_ignore, |
854 |
|
|
.handlers[OPER_HANDLER] = m_ignore |
855 |
michael |
1230 |
}; |
856 |
|
|
|
857 |
|
|
static void |
858 |
|
|
module_init(void) |
859 |
|
|
{ |
860 |
|
|
mod_add_cmd(&sid_msgtab); |
861 |
|
|
mod_add_cmd(&server_msgtab); |
862 |
|
|
} |
863 |
|
|
|
864 |
|
|
static void |
865 |
|
|
module_exit(void) |
866 |
|
|
{ |
867 |
|
|
mod_del_cmd(&sid_msgtab); |
868 |
|
|
mod_del_cmd(&server_msgtab); |
869 |
|
|
} |
870 |
|
|
|
871 |
michael |
2820 |
struct module module_entry = |
872 |
|
|
{ |
873 |
michael |
1230 |
.version = "$Revision$", |
874 |
|
|
.modinit = module_init, |
875 |
|
|
.modexit = module_exit, |
876 |
|
|
.flags = MODULE_FLAG_CORE |
877 |
|
|
}; |