ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 1008
Committed: Sun Sep 13 13:56:11 2009 UTC (15 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/modules/m_gline.c
File size: 21186 byte(s)
Log Message:
- doxyfy

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 *
4 * Copyright (C) 2002 by the past and present ircd coders, and others.
5 *
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 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 /*! \file m_gline.c
23 * \brief Includes required functions for processing the GLINE command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "tools.h"
29 #include "handlers.h"
30 #include "s_gline.h"
31 #include "channel.h"
32 #include "client.h"
33 #include "common.h"
34 #include "irc_string.h"
35 #include "sprintf_irc.h"
36 #include "ircd.h"
37 #include "hostmask.h"
38 #include "numeric.h"
39 #include "fdlist.h"
40 #include "s_bsd.h"
41 #include "s_conf.h"
42 #include "s_misc.h"
43 #include "send.h"
44 #include "msg.h"
45 #include "fileio.h"
46 #include "s_serv.h"
47 #include "hash.h"
48 #include "parse.h"
49 #include "modules.h"
50 #include "list.h"
51 #include "s_log.h"
52
53 #define GLINE_NOT_PLACED 0
54 #define GLINE_ALREADY_VOTED -1
55 #define GLINE_PLACED 1
56
57
58 static void me_gline(struct Client *, struct Client *, int, char *[]);
59 static void ms_gline(struct Client *, struct Client *, int, char *[]);
60 static void mo_gline(struct Client *, struct Client *, int, char *[]);
61 static void me_gungline(struct Client *, struct Client *, int, char *[]);
62 static void mo_gungline(struct Client *, struct Client *, int, char *[]);
63
64 /*
65 * gline enforces 3 parameters to force operator to give a reason
66 * a gline is not valid with "No reason"
67 * -db
68 */
69 struct Message gline_msgtab = {
70 "GLINE", 0, 0, 3, 0, MFLG_SLOW, 0,
71 { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
72 };
73
74 struct Message ungline_msgtab = {
75 "GUNGLINE", 0, 0, 3, 0, MFLG_SLOW, 0,
76 { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
77 };
78
79
80 void
81 _modinit(void)
82 {
83 mod_add_cmd(&gline_msgtab);
84 mod_add_cmd(&ungline_msgtab);
85 add_capability("GLN", CAP_GLN, 1);
86 }
87
88 void
89 _moddeinit(void)
90 {
91 mod_del_cmd(&gline_msgtab);
92 mod_del_cmd(&ungline_msgtab);
93 delete_capability("GLN");
94 }
95
96 const char *_version = "$Revision$";
97
98
99
100 /*! \brief This function is called once a majority of opers have agreed on a
101 * GLINE/GUNGLINE, and it can be placed. The information about an
102 * operator being passed to us happens to be the operator who pushed us
103 * over the "majority" level needed. See check_majority() for more
104 * information.
105 *
106 * \param source_p Operator requesting gline
107 * \param user Username covered by the gline
108 * \param host Hostname covered by the gline
109 * \param reason Reason for the gline
110 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
111 * GLINE_PENDING_DEL_TYPE
112 */
113 static void
114 add_new_majority(const struct Client *source_p, const char *user,
115 const char *host, const char *reason, const unsigned int type)
116 {
117 struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
118
119 strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
120 strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
121 strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
122 strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
123
124 strlcpy(pending->user, user, sizeof(pending->user));
125 strlcpy(pending->host, host, sizeof(pending->host));
126 strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
127
128 pending->last_gline_time = CurrentTime;
129 pending->vote_1.time_request = CurrentTime;
130
131 dlinkAdd(pending, &pending->node, &pending_glines[type]);
132 }
133
134 /*! \brief See if there is a majority agreement on a GLINE on the given user.
135 * There must be at least 3 different opers agreeing on this
136 * GLINE/GUNGLINE
137 *
138 * \param source_p Operator requesting gline
139 * \param user Username covered by the gline
140 * \param host Hostname covered by the gline
141 * \param reason Reason for the gline
142 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
143 * GLINE_PENDING_DEL_TYPE
144 *
145 * \return
146 * - GLINE_ALREADY_VOTED returned if oper/server has already voted
147 * - GLINE_PLACED returned if this triggers a gline
148 * - GLINE_NOT_PLACED returned if not triggered
149 */
150 static int
151 check_majority(const struct Client *source_p, const char *user,
152 const char *host, const char *reason, const int type)
153 {
154 dlink_node *dn_ptr = NULL;
155
156 cleanup_glines(NULL);
157
158 /* if its already glined, why bother? :) -- fl_ */
159 if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
160 return GLINE_NOT_PLACED;
161
162 DLINK_FOREACH(dn_ptr, pending_glines[type].head)
163 {
164 struct gline_pending *gp_ptr = dn_ptr->data;
165
166 if (irccmp(gp_ptr->user, user) ||
167 irccmp(gp_ptr->host, host))
168 continue;
169
170 if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
171 !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
172 !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
173 return GLINE_ALREADY_VOTED;
174
175 if (gp_ptr->vote_2.oper_user[0] != '\0')
176 {
177 /* if two other opers on two different servers have voted yes */
178 if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
179 !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
180 !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
181 return GLINE_ALREADY_VOTED;
182
183 if (type == GLINE_PENDING_DEL_TYPE)
184 {
185 if (remove_gline_match(user, host))
186 {
187 sendto_realops_flags(UMODE_ALL, L_ALL,
188 "%s has removed the G-Line for: [%s@%s]",
189 get_oper_name(source_p), user, host);
190 ilog(L_NOTICE, "%s removed G-Line for [%s@%s]",
191 get_oper_name(source_p), user, host);
192 }
193 }
194 else
195 /* trigger the gline using the original reason --fl */
196 set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
197
198 cleanup_glines(gp_ptr);
199 return GLINE_PLACED;
200 }
201
202 strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
203 sizeof(gp_ptr->vote_2.oper_nick));
204 strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
205 sizeof(gp_ptr->vote_2.oper_user));
206 strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
207 sizeof(gp_ptr->vote_2.oper_host));
208 strlcpy(gp_ptr->vote_2.reason, reason,
209 sizeof(gp_ptr->vote_2.reason));
210 strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
211 sizeof(gp_ptr->vote_2.oper_server));
212 gp_ptr->last_gline_time = CurrentTime;
213 gp_ptr->vote_2.time_request = CurrentTime;
214 return GLINE_NOT_PLACED;
215 }
216
217 /*
218 * Didn't find this user@host gline in pending gline list
219 * so add it.
220 */
221 add_new_majority(source_p, user, host, reason, type);
222 return GLINE_NOT_PLACED;
223 }
224
225 /*! \brief Adds a GLINE to the configuration subsystem.
226 *
227 * \param source_p Operator requesting gline
228 * \param user Username covered by the gline
229 * \param host Hostname covered by the gline
230 * \param reason Reason for the gline
231 */
232 static void
233 set_local_gline(const struct Client *source_p, const char *user,
234 const char *host, const char *reason)
235 {
236 char buffer[IRCD_BUFSIZE];
237 struct ConfItem *conf;
238 struct AccessItem *aconf;
239
240
241 conf = make_conf_item(GLINE_TYPE);
242 aconf = map_to_conf(conf);
243
244 snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(CurrentTime));
245 DupString(aconf->reason, buffer);
246 DupString(aconf->user, user);
247 DupString(aconf->host, host);
248
249 aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
250 add_temp_line(conf);
251
252 sendto_realops_flags(UMODE_ALL, L_ALL,
253 "%s added G-Line for [%s@%s] [%s]",
254 get_oper_name(source_p),
255 aconf->user, aconf->host, aconf->reason);
256 ilog(L_TRACE, "%s added G-Line for [%s@%s] [%s]",
257 get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
258 log_oper_action(LOG_GLINE_TYPE, source_p, "[%s@%s] [%s]\n",
259 aconf->user, aconf->host, aconf->reason);
260 /* Now, activate gline against current online clients */
261 rehashed_klines = 1;
262 }
263
264 /*! \brief Removes a GLINE from the configuration subsystem.
265 *
266 * \param user Username covered by the gline
267 * \param host Hostname covered by the gline
268 */
269 static int
270 remove_gline_match(const char *user, const char *host)
271 {
272 struct AccessItem *aconf;
273 dlink_node *ptr = NULL;
274 struct irc_ssaddr addr, caddr;
275 int nm_t, cnm_t, bits, cbits;
276
277 nm_t = parse_netmask(host, &addr, &bits);
278
279 DLINK_FOREACH(ptr, temporary_glines.head)
280 {
281 aconf = map_to_conf(ptr->data);
282 cnm_t = parse_netmask(aconf->host, &caddr, &cbits);
283
284 if (cnm_t != nm_t || irccmp(user, aconf->user))
285 continue;
286
287 if ((nm_t == HM_HOST && !irccmp(aconf->host, host)) ||
288 (nm_t == HM_IPV4 && bits == cbits && match_ipv4(&addr, &caddr, bits))
289 #ifdef IPV6
290 || (nm_t == HM_IPV6 && bits == cbits && match_ipv6(&addr, &caddr, bits))
291 #endif
292 )
293 {
294 dlinkDelete(ptr, &temporary_glines);
295 delete_one_address_conf(aconf->host, aconf);
296 return 1;
297 }
298 }
299
300 return 0;
301 }
302
303 static void
304 do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
305 {
306 const char *reason = NULL; /* reason for "victims" demise */
307 char *user = NULL;
308 char *host = NULL; /* user and host of GLINE "victim" */
309 int var_offset = 0, logged = 0;
310 dlink_node *ptr;
311 struct Client *target_p = NULL;
312
313 switch (parc)
314 {
315 case 4: /* hyb-7 style */
316 if (!IsClient(source_p))
317 return;
318 break;
319 case 8: /* hyb-6 style */
320 if (!IsServer(source_p))
321 return;
322 target_p = find_person(source_p->from, parv[1]);
323 if (target_p == NULL || target_p->servptr != source_p)
324 return;
325 source_p = target_p, var_offset = 4;
326 break;
327 default:
328 return;
329 }
330
331 assert(source_p->servptr != NULL);
332
333 user = parv[++var_offset];
334 host = parv[++var_offset];
335 reason = parv[++var_offset];
336
337 DLINK_FOREACH(ptr, gdeny_items.head)
338 {
339 struct ConfItem *conf = ptr->data;
340 struct AccessItem *aconf = map_to_conf(conf);
341
342 if (match(conf->name, source_p->servptr->name) &&
343 match(aconf->user, source_p->username) &&
344 match(aconf->host, source_p->host))
345 {
346 var_offset = aconf->flags;
347 break;
348 }
349 }
350
351 if (prop && !(var_offset & GDENY_BLOCK))
352 {
353 sendto_server(source_p->from, NULL, CAP_GLN, NOCAPS,
354 ":%s GLINE %s %s :%s",
355 source_p->name, user, host, reason);
356 /* hyb-6 version to the rest */
357 sendto_server(source_p->from, NULL, NOCAPS, CAP_GLN,
358 ":%s GLINE %s %s %s %s %s %s :%s",
359 source_p->servptr->name,
360 source_p->name, source_p->username, source_p->host,
361 source_p->servptr->name,
362 user, host, reason);
363 }
364 else if (ConfigFileEntry.gline_logging & GDENY_BLOCK && ServerInfo.hub)
365 {
366 sendto_realops_flags(UMODE_ALL, L_ALL, "Blocked G-Line %s requested on [%s@%s] [%s]",
367 get_oper_name(source_p), user, host, reason);
368 ilog(L_TRACE, "Blocked G-Line %s requested on [%s@%s] [%s]",
369 get_oper_name(source_p), user, host, reason);
370 logged = 1;
371 }
372
373 if (var_offset & GDENY_REJECT)
374 {
375 if (ConfigFileEntry.gline_logging & GDENY_REJECT && !logged)
376 {
377 sendto_realops_flags(UMODE_ALL, L_ALL, "Rejected G-Line %s requested on [%s@%s] [%s]",
378 get_oper_name(source_p), user, host, reason);
379 ilog(L_TRACE, "Rejected G-Line %s requested on [%s@%s] [%s]",
380 get_oper_name(source_p), user, host, reason);
381 }
382
383 return;
384 }
385
386 if (ConfigFileEntry.glines)
387 {
388 if (!valid_wild_card(source_p, YES, 2, user, host))
389 return;
390
391 if (IsClient(source_p))
392 {
393 const char *p = NULL;
394
395 if ((p = strchr(host, '/')))
396 {
397 int bitlen = strtol(++p, NULL, 10);
398 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
399 ConfigFileEntry.gline_min_cidr;
400
401 if (bitlen < min_bitlen)
402 {
403 sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
404 "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
405 source_p->name, source_p->username, source_p->host,
406 source_p->servptr->name, min_bitlen, user, host, reason);
407 return;
408 }
409 }
410 }
411
412 /* If at least 3 opers agree this user should be G lined then do it */
413 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
414 GLINE_ALREADY_VOTED)
415 {
416 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
417 return;
418 }
419
420 sendto_realops_flags(UMODE_ALL, L_ALL,
421 "%s requesting G-Line for [%s@%s] [%s]",
422 get_oper_name(source_p),
423 user, host, reason);
424 ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s",
425 user, host, reason, get_oper_name(source_p));
426 }
427 }
428
429
430 /*! \brief GLINE command handler (called by operators)
431 *
432 * \param client_p Pointer to allocated Client struct with physical connection
433 * to this server, i.e. with an open socket connected.
434 * \param source_p Pointer to allocated Client struct from which the message
435 * originally comes from. This can be a local or remote client.
436 * \param parc Integer holding the number of supplied arguments.
437 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
438 * pointers.
439 * \note Valid arguments for this command are:
440 * - parv[0] = sender prefix
441 * - parv[1] = user\@host mask
442 * - parv[2] = reason
443 */
444 static void
445 mo_gline(struct Client *client_p, struct Client *source_p,
446 int parc, char *parv[])
447 {
448 char *user = NULL;
449 char *host = NULL;
450 char *reason = NULL;
451 char *p;
452
453 if (!ConfigFileEntry.glines)
454 {
455 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
456 me.name, source_p->name);
457 return;
458 }
459
460 if (!IsOperGline(source_p))
461 {
462 sendto_one(source_p, form_str(ERR_NOPRIVS),
463 me.name, source_p->name, "gline");
464 return;
465 }
466
467 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
468 &user, &host, NULL, NULL, &reason) < 0)
469 return;
470
471 if ((p = strchr(host, '/')) != NULL)
472 {
473 int bitlen = strtol(++p, NULL, 10);
474 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
475 ConfigFileEntry.gline_min_cidr;
476 if (bitlen < min_bitlen)
477 {
478 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
479 me.name, source_p->name, min_bitlen);
480 return;
481 }
482 }
483
484 /* If at least 3 opers agree this user should be G lined then do it */
485 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
486 GLINE_ALREADY_VOTED)
487 {
488 sendto_one(source_p,
489 ":%s NOTICE %s :This server or oper has already voted",
490 me.name, source_p->name);
491 return;
492 }
493
494 /*
495 * call these two functions first so the 'requesting' notice always comes
496 * before the 'has triggered' notice. -bill
497 */
498 sendto_realops_flags(UMODE_ALL, L_ALL,
499 "%s requesting G-Line for [%s@%s] [%s]",
500 get_oper_name(source_p),
501 user, host, reason);
502 ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s!%s@%s",
503 user, host, reason, source_p->name, source_p->username,
504 source_p->host);
505
506 /* 4 param version for hyb-7 servers */
507 sendto_server(NULL, NULL, CAP_GLN|CAP_TS6, NOCAPS,
508 ":%s GLINE %s %s :%s",
509 ID(source_p), user, host, reason);
510 sendto_server(NULL, NULL, CAP_GLN, CAP_TS6,
511 ":%s GLINE %s %s :%s",
512 source_p->name, user, host, reason);
513
514 /* 8 param for hyb-6 */
515 sendto_server(NULL, NULL, CAP_TS6, CAP_GLN,
516 ":%s GLINE %s %s %s %s %s %s :%s",
517 ID(&me),
518 ID(source_p), source_p->username,
519 source_p->host, source_p->servptr->name, user, host,
520 reason);
521 sendto_server(NULL, NULL, NOCAPS, CAP_GLN|CAP_TS6,
522 ":%s GLINE %s %s %s %s %s %s :%s",
523 me.name, source_p->name, source_p->username,
524 source_p->host, source_p->servptr->name, user, host,
525 reason);
526 }
527
528 /* ms_gline()
529 * me_gline()
530 * do_sgline()
531 *
532 * inputs - The usual for a m_ function
533 * output -
534 * side effects -
535 *
536 * Place a G line if 3 opers agree on the identical user@host
537 *
538 * Allow this server to pass along GLINE if received and
539 * GLINES is not defined.
540 *
541 * ENCAP'd GLINES are propagated by encap code.
542 */
543
544 static void
545 ms_gline(struct Client *client_p, struct Client *source_p,
546 int parc, char *parv[])
547 {
548 do_sgline(source_p, parc, parv, 1);
549 }
550
551 static void
552 me_gline(struct Client *client_p, struct Client *source_p,
553 int parc, char *parv[])
554 {
555 do_sgline(source_p, parc, parv, 0);
556 }
557
558 static void
559 do_sungline(struct Client *source_p, const char *user,
560 const char *host, const char *reason, int prop)
561 {
562 assert(source_p->servptr != NULL);
563
564 sendto_realops_flags(UMODE_ALL, L_ALL,
565 "%s requesting UNG-Line for [%s@%s] [%s]",
566 get_oper_name(source_p), user, host, reason);
567 ilog(L_TRACE, "#ungline for %s@%s [%s] requested by %s",
568 user, host, reason, get_oper_name(source_p));
569
570 /* If at least 3 opers agree this user should be un G lined then do it */
571 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
572 GLINE_ALREADY_VOTED)
573 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
574
575 if (prop)
576 {
577 sendto_server(source_p->from, NULL, CAP_ENCAP|CAP_TS6, NOCAPS,
578 ":%s ENCAP * GUNGLINE %s %s :%s",
579 ID(source_p), user, host, reason);
580 sendto_server(source_p->from, NULL, CAP_ENCAP, CAP_TS6,
581 ":%s ENCAP * GUNGLINE %s %s :%s",
582 source_p->name, user, host, reason);
583 }
584 }
585
586 /*! \brief GUNGLINE command handler (called in response to an encapsulated
587 * GUNGLINE command)
588 *
589 * \param client_p Pointer to allocated Client struct with physical connection
590 * to this server, i.e. with an open socket connected.
591 * \param source_p Pointer to allocated Client struct from which the message
592 * originally comes from. This can be a local or remote client.
593 * \param parc Integer holding the number of supplied arguments.
594 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
595 * pointers.
596 * \note Valid arguments for this command are:
597 * - parv[0] = sender prefix
598 * - parv[1] = username
599 * - parv[2] = hostname
600 * - parv[3] = reason
601 */
602 static void
603 me_gungline(struct Client *client_p, struct Client *source_p,
604 int parc, char *parv[])
605 {
606 if (ConfigFileEntry.glines)
607 do_sungline(source_p, parv[1], parv[2], parv[3], 0);
608 }
609
610 /*! \brief GUNGLINE command handler (called by operators)
611 *
612 * \param client_p Pointer to allocated Client struct with physical connection
613 * to this server, i.e. with an open socket connected.
614 * \param source_p Pointer to allocated Client struct from which the message
615 * originally comes from. This can be a local or remote client.
616 * \param parc Integer holding the number of supplied arguments.
617 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
618 * pointers.
619 * \note Valid arguments for this command are:
620 * - parv[0] = sender prefix
621 * - parv[1] = user\@host mask
622 * - parv[2] = reason
623 */
624 static void
625 mo_gungline(struct Client *client_p, struct Client *source_p,
626 int parc, char *parv[])
627 {
628 char *user = NULL;
629 char *host = NULL;
630 char *reason = NULL;
631
632 if (!ConfigFileEntry.glines)
633 {
634 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
635 me.name, source_p->name);
636 return;
637 }
638
639 if (!IsOperGline(source_p))
640 {
641 sendto_one(source_p, form_str(ERR_NOPRIVS),
642 me.name, source_p->name, "gungline");
643 return;
644 }
645
646 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
647 &host, NULL, NULL, &reason) < 0)
648 return;
649
650 do_sungline(source_p, user, host, reason, 1);
651 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision