2 * ircd-ratbox: A slightly useful ircd.
3 * m_dline.c: Bans/unbans a user.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include "irc_string.h"
32 #include "sprintf_irc.h"
38 #include "s_newconf.h"
47 static int mo_dline(struct Client
*, struct Client
*, int, const char **);
48 static int me_dline(struct Client
*, struct Client
*, int, const char **);
49 static int mo_undline(struct Client
*, struct Client
*, int, const char **);
50 static int me_undline(struct Client
*, struct Client
*, int, const char **);
52 struct Message dline_msgtab
= {
53 "DLINE", 0, 0, 0, MFLG_SLOW
,
54 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_dline
, 3}, {mo_dline
, 2}}
56 struct Message undline_msgtab
= {
57 "UNDLINE", 0, 0, 0, MFLG_SLOW
,
58 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, {me_undline
, 1}, {mo_undline
, 2}}
61 mapi_clist_av1 dline_clist
[] = { &dline_msgtab
, &undline_msgtab
, NULL
};
62 DECLARE_MODULE_AV1(dline
, NULL
, NULL
, dline_clist
, NULL
, NULL
, "$Revision: 107 $");
64 static int valid_comment(char *comment
);
65 static int flush_write(struct Client
*, FILE *, char *, char *);
66 static int remove_temp_dline(const char *);
67 static int apply_dline(struct Client
*, const char *, int, char *);
68 static int apply_undline(struct Client
*, const char *);
72 * parv[1] - dline to add
76 mo_dline(struct Client
*client_p
, struct Client
*source_p
,
77 int parc
, const char *parv
[])
79 char def
[] = "No Reason";
82 char cidr_form_host
[HOSTLEN
+ 1];
84 const char *target_server
= NULL
;
87 if(!IsOperK(source_p
))
89 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
90 me
.name
, source_p
->name
, "kline");
94 if((tdline_time
= valid_temp_time(parv
[loc
])) >= 0)
98 strlcpy(cidr_form_host
, dlhost
, sizeof(cidr_form_host
));
102 if(parc
>= loc
+2 && !irccmp(parv
[loc
], "ON"))
104 target_server
= parv
[loc
+1];
108 if(parc
>= loc
+ 1 && !EmptyString(parv
[loc
]))
109 reason
= LOCAL_COPY(parv
[loc
]);
111 if(target_server
!= NULL
)
113 sendto_match_servs(source_p
, target_server
,
115 "ENCAP %s DLINE %d %s :%s",
116 target_server
, tdline_time
, dlhost
, reason
);
118 if(!match(target_server
, me
.name
))
122 apply_dline(source_p
, dlhost
, tdline_time
, reason
);
130 * parv[1] = dline to remove
133 mo_undline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
136 const char *target_server
= NULL
;
138 if(!IsOperUnkline(source_p
))
140 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
141 me
.name
, source_p
->name
, "unkline");
147 if(parc
>= 4 && !irccmp(parv
[2], "ON"))
149 target_server
= parv
[3];
150 sendto_match_servs(source_p
, target_server
,
152 "ENCAP %s UNDLINE %s",
153 target_server
, cidr
);
155 if(!match(target_server
, me
.name
))
159 apply_undline(source_p
, cidr
);
165 me_dline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
167 int tdline_time
= atoi(parv
[1]);
169 /* Since this is coming over a server link, assume that the originating
170 * server did the relevant permission/sanity checks...
173 if(!IsPerson(source_p
))
175 if (!find_client_shared_conf(source_p
, tdline_time
> 0 ? SHARED_TDLINE
: SHARED_PDLINE
))
178 apply_dline(source_p
, parv
[2], tdline_time
, LOCAL_COPY(parv
[3]));
185 me_undline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char **parv
)
187 if(!IsPerson(source_p
))
189 if (!find_client_shared_conf(source_p
, SHARED_UNDLINE
))
192 apply_undline(source_p
, parv
[1]);
198 apply_dline(struct Client
*source_p
, const char *dlhost
, int tdline_time
, char *reason
)
200 struct ConfItem
*aconf
;
202 char dlbuffer
[IRCD_BUFSIZE
];
203 const char *current_date
;
204 struct irc_sockaddr_storage daddr
;
205 int t
= AF_INET
, ty
, b
;
208 ty
= parse_netmask(dlhost
, (struct sockaddr
*)&daddr
, &b
);
211 sendto_one(source_p
, ":%s NOTICE %s :Invalid D-Line",
212 me
.name
, source_p
->name
);
222 /* This means dlines wider than /16 cannot be set remotely */
223 if(IsOperAdmin(source_p
))
227 sendto_one_notice(source_p
,
228 ":For safety, bitmasks less than 8 require conf access.");
236 sendto_one_notice(source_p
,
237 ":Dline bitmasks less than 16 are for admins only.");
242 if(!valid_comment(reason
))
245 ":%s NOTICE %s :Invalid character '\"' in comment",
246 me
.name
, source_p
->name
);
250 /* Look for an oper reason */
251 if((oper_reason
= strchr(reason
, '|')) != NULL
)
256 if(!EmptyString(oper_reason
))
257 DupString(aconf
->spasswd
, oper_reason
);
260 if(ConfigFileEntry
.non_redundant_klines
)
262 if((aconf
= find_dline((struct sockaddr
*)&daddr
, t
)) != NULL
)
265 parse_netmask(aconf
->host
, NULL
, &bx
);
268 creason
= aconf
->passwd
? aconf
->passwd
: "<No Reason>";
269 if(IsConfExemptKline(aconf
))
271 ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
272 me
.name
, source_p
->name
, dlhost
, aconf
->host
, creason
);
275 ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
276 me
.name
, source_p
->name
, dlhost
, aconf
->host
, creason
);
283 current_date
= smalldate();
286 aconf
->status
= CONF_DLINE
;
287 DupString(aconf
->host
, dlhost
);
291 ircsnprintf(dlbuffer
, sizeof(dlbuffer
),
292 "Temporary D-line %d min. - %s (%s)",
293 (int) (tdline_time
/ 60), reason
, current_date
);
294 DupString(aconf
->passwd
, dlbuffer
);
295 aconf
->hold
= CurrentTime
+ tdline_time
;
296 add_temp_dline(aconf
);
298 if(EmptyString(oper_reason
))
300 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
301 "%s added temporary %d min. D-Line for [%s] [%s]",
302 get_oper_name(source_p
), tdline_time
/ 60,
303 aconf
->host
, reason
);
304 ilog(L_KLINE
, "D %s %d %s %s",
305 get_oper_name(source_p
), tdline_time
/ 60,
306 aconf
->host
, reason
);
310 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
311 "%s added temporary %d min. D-Line for [%s] [%s|%s]",
312 get_oper_name(source_p
), tdline_time
/ 60,
313 aconf
->host
, reason
, oper_reason
);
314 ilog(L_KLINE
, "D %s %d %s %s|%s",
315 get_oper_name(source_p
), tdline_time
/ 60,
316 aconf
->host
, reason
, oper_reason
);
319 sendto_one(source_p
, ":%s NOTICE %s :Added temporary %d min. D-Line for [%s]",
320 me
.name
, source_p
->name
, tdline_time
/ 60, aconf
->host
);
324 ircsnprintf(dlbuffer
, sizeof(dlbuffer
), "%s (%s)", reason
, current_date
);
325 DupString(aconf
->passwd
, dlbuffer
);
326 add_conf_by_address(aconf
->host
, CONF_DLINE
, NULL
, aconf
);
327 write_confitem(DLINE_TYPE
, source_p
, NULL
, aconf
->host
, reason
,
328 oper_reason
, current_date
, 0);
335 apply_undline(struct Client
*source_p
, const char *cidr
)
339 char buf
[BUFSIZE
], buff
[BUFSIZE
], temppath
[BUFSIZE
], *p
;
340 const char *filename
, *found_cidr
;
341 int pairme
= NO
, error_on_write
= NO
;
344 if(parse_netmask(cidr
, NULL
, NULL
) == HM_HOST
)
346 sendto_one(source_p
, ":%s NOTICE %s :Invalid D-Line",
347 me
.name
, source_p
->name
);
351 ircsnprintf(temppath
, sizeof(temppath
), "%s.tmp", ConfigFileEntry
.dlinefile
);
353 if(remove_temp_dline(cidr
))
356 ":%s NOTICE %s :Un-dlined [%s] from temporary D-lines",
357 me
.name
, source_p
->name
, cidr
);
358 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
359 "%s has removed the temporary D-Line for: [%s]",
360 get_oper_name(source_p
), cidr
);
361 ilog(L_KLINE
, "UD %s %s", get_oper_name(source_p
), cidr
);
365 filename
= get_conf_name(DLINE_TYPE
);
367 if((in
= fopen(filename
, "r")) == 0)
369 sendto_one(source_p
, ":%s NOTICE %s :Cannot open %s", me
.name
, source_p
->name
, filename
);
374 if((out
= fopen(temppath
, "w")) == 0)
376 sendto_one(source_p
, ":%s NOTICE %s :Cannot open %s", me
.name
, source_p
->name
, temppath
);
384 while (fgets(buf
, sizeof(buf
), in
))
386 strlcpy(buff
, buf
, sizeof(buff
));
388 if((p
= strchr(buff
, '\n')) != NULL
)
391 if((*buff
== '\0') || (*buff
== '#'))
394 flush_write(source_p
, out
, buf
, temppath
);
398 if((found_cidr
= getfield(buff
)) == NULL
)
401 flush_write(source_p
, out
, buf
, temppath
);
405 if(irccmp(found_cidr
, cidr
) == 0)
412 flush_write(source_p
, out
, buf
, temppath
);
423 ":%s NOTICE %s :Couldn't write D-line file, aborted",
424 me
.name
, source_p
->name
);
429 sendto_one(source_p
, ":%s NOTICE %s :No D-Line for %s",
430 me
.name
, source_p
->name
, cidr
);
433 (void) unlink(temppath
);
438 (void) rename(temppath
, filename
);
441 sendto_one(source_p
, ":%s NOTICE %s :D-Line for [%s] is removed", me
.name
, source_p
->name
, cidr
);
442 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
443 "%s has removed the D-Line for: [%s]", get_oper_name(source_p
), cidr
);
444 ilog(L_KLINE
, "UD %s %s", get_oper_name(source_p
), cidr
);
453 * inputs - pointer to client
454 * - pointer to comment
455 * output - 0 if no valid comment, 1 if valid
456 * side effects - NONE
459 valid_comment(char *comment
)
461 if(strchr(comment
, '"'))
464 if(strlen(comment
) > REASONLEN
)
465 comment
[REASONLEN
] = '\0';
473 * inputs - pointer to client structure of oper requesting unkline
474 * - out is the file descriptor
475 * - buf is the buffer to write
476 * - ntowrite is the expected number of character to be written
477 * - temppath is the temporary file name to be written
478 * output - YES for error on write
480 * side effects - if successful, the buf is written to output file
481 * if a write failure happesn, and the file pointed to
482 * by temppath, if its non NULL, is removed.
484 * The idea here is, to be as robust as possible when writing to the
490 flush_write(struct Client
*source_p
, FILE * out
, char *buf
, char *temppath
)
492 int error_on_write
= (fputs(buf
, out
) < 0) ? YES
: NO
;
496 sendto_one(source_p
, ":%s NOTICE %s :Unable to write to %s",
497 me
.name
, source_p
->name
, temppath
);
500 (void) unlink(temppath
);
502 return (error_on_write
);
505 /* remove_temp_dline()
507 * inputs - hostname to undline
509 * side effects - tries to undline anything that matches
512 remove_temp_dline(const char *host
)
514 struct ConfItem
*aconf
;
516 struct irc_sockaddr_storage addr
, caddr
;
520 parse_netmask(host
, (struct sockaddr
*)&addr
, &bits
);
522 for (i
= 0; i
< LAST_TEMP_TYPE
; i
++)
524 DLINK_FOREACH(ptr
, temp_dlines
[i
].head
)
528 parse_netmask(aconf
->host
, (struct sockaddr
*)&caddr
, &cbits
);
530 if(comp_with_mask_sock((struct sockaddr
*)&addr
, (struct sockaddr
*)&caddr
, bits
) && bits
== cbits
)
532 dlinkDestroy(ptr
, &temp_dlines
[i
]);
533 delete_one_address_conf(aconf
->host
, aconf
);