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
24 * $Id: m_dline.c 3225 2007-03-04 23:42:55Z jilles $
32 #include "irc_string.h"
37 #include "s_newconf.h"
46 static int mo_dline(struct Client
*, struct Client
*, int, const char **);
47 static int mo_undline(struct Client
*, struct Client
*, int, const char **);
49 struct Message dline_msgtab
= {
50 "DLINE", 0, 0, 0, MFLG_SLOW
,
51 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, mg_ignore
, {mo_dline
, 2}}
53 struct Message undline_msgtab
= {
54 "UNDLINE", 0, 0, 0, MFLG_SLOW
,
55 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, mg_ignore
, {mo_undline
, 2}}
58 mapi_clist_av1 dline_clist
[] = { &dline_msgtab
, &undline_msgtab
, NULL
};
59 DECLARE_MODULE_AV1(dline
, NULL
, NULL
, dline_clist
, NULL
, NULL
, "$Revision: 3225 $");
61 static int valid_comment(char *comment
);
62 static int flush_write(struct Client
*, FILE *, char *, char *);
63 static int remove_temp_dline(struct ConfItem
*);
67 * parv[1] - dline to add
71 mo_dline(struct Client
*client_p
, struct Client
*source_p
,
72 int parc
, const char *parv
[])
74 char def
[] = "No Reason";
78 struct rb_sockaddr_storage daddr
;
79 char cidr_form_host
[HOSTLEN
+ 1];
80 struct ConfItem
*aconf
;
82 char dlbuffer
[IRCD_BUFSIZE
];
83 const char *current_date
;
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)
99 sendto_one(source_p
, form_str(ERR_NEEDMOREPARAMS
),
100 me
.name
, source_p
->name
, "DLINE");
105 rb_strlcpy(cidr_form_host
, dlhost
, sizeof(cidr_form_host
));
107 if(!parse_netmask(dlhost
, NULL
, &bits
))
109 sendto_one(source_p
, ":%s NOTICE %s :Invalid D-Line",
110 me
.name
, source_p
->name
);
116 if(parc
>= loc
+ 1) /* host :reason */
118 if(!EmptyString(parv
[loc
]))
119 reason
= LOCAL_COPY(parv
[loc
]);
121 if(!valid_comment(reason
))
124 ":%s NOTICE %s :Invalid character '\"' in comment",
125 me
.name
, source_p
->name
);
130 if(IsOperAdmin(source_p
))
135 ":%s NOTICE %s :For safety, bitmasks less than 8 require conf access.",
145 ":%s NOTICE %s :Dline bitmasks less than 16 are for admins only.",
151 if(ConfigFileEntry
.non_redundant_klines
)
154 int t
= AF_INET
, ty
, b
;
155 ty
= parse_netmask(dlhost
, (struct sockaddr
*)&daddr
, &b
);
163 if((aconf
= find_dline((struct sockaddr
*)&daddr
, t
)) != NULL
)
166 parse_netmask(aconf
->host
, NULL
, &bx
);
169 creason
= aconf
->passwd
? aconf
->passwd
: "<No Reason>";
170 if(IsConfExemptKline(aconf
))
172 ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
173 me
.name
, parv
[0], dlhost
, aconf
->host
, creason
);
176 ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
177 me
.name
, parv
[0], dlhost
, aconf
->host
, creason
);
184 current_date
= smalldate();
187 aconf
->status
= CONF_DLINE
;
188 aconf
->host
= rb_strdup(dlhost
);
190 /* Look for an oper reason */
191 if((oper_reason
= strchr(reason
, '|')) != NULL
)
196 if(!EmptyString(oper_reason
))
197 aconf
->spasswd
= rb_strdup(oper_reason
);
202 rb_snprintf(dlbuffer
, sizeof(dlbuffer
),
203 "Temporary D-line %d min. - %s (%s)",
204 (int) (tdline_time
/ 60), reason
, current_date
);
205 aconf
->passwd
= rb_strdup(dlbuffer
);
206 aconf
->hold
= rb_current_time() + tdline_time
;
207 add_temp_dline(aconf
);
209 if(EmptyString(oper_reason
))
211 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
212 "%s added temporary %d min. D-Line for [%s] [%s]",
213 get_oper_name(source_p
), tdline_time
/ 60,
214 aconf
->host
, reason
);
215 ilog(L_KLINE
, "D %s %d %s %s",
216 get_oper_name(source_p
), tdline_time
/ 60,
217 aconf
->host
, reason
);
221 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
222 "%s added temporary %d min. D-Line for [%s] [%s|%s]",
223 get_oper_name(source_p
), tdline_time
/ 60,
224 aconf
->host
, reason
, oper_reason
);
225 ilog(L_KLINE
, "D %s %d %s %s|%s",
226 get_oper_name(source_p
), tdline_time
/ 60,
227 aconf
->host
, reason
, oper_reason
);
230 sendto_one(source_p
, ":%s NOTICE %s :Added temporary %d min. D-Line for [%s]",
231 me
.name
, source_p
->name
, tdline_time
/ 60, aconf
->host
);
235 rb_snprintf(dlbuffer
, sizeof(dlbuffer
), "%s (%s)", reason
, current_date
);
236 aconf
->passwd
= rb_strdup(dlbuffer
);
237 add_conf_by_address(aconf
->host
, CONF_DLINE
, NULL
, aconf
);
238 write_confitem(DLINE_TYPE
, source_p
, NULL
, aconf
->host
, reason
,
239 oper_reason
, current_date
, 0);
248 * parv[1] = dline to remove
251 mo_undline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
255 char buf
[BUFSIZE
], buff
[BUFSIZE
], temppath
[BUFSIZE
], *p
;
256 const char *filename
, *found_cidr
;
258 struct ConfItem
*aconf
;
259 int pairme
= NO
, error_on_write
= NO
;
262 rb_snprintf(temppath
, sizeof(temppath
), "%s.tmp", ConfigFileEntry
.dlinefile
);
264 if(!IsOperUnkline(source_p
))
266 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
267 me
.name
, source_p
->name
, "unkline");
273 if(parse_netmask(cidr
, NULL
, NULL
) == HM_HOST
)
275 sendto_one_notice(source_p
, ":Invalid D-Line");
279 aconf
= find_exact_conf_by_address(cidr
, CONF_DLINE
, NULL
);
282 sendto_one_notice(source_p
, ":No D-Line for %s", cidr
);
286 rb_strlcpy(buf
, aconf
->host
, sizeof buf
);
287 if(remove_temp_dline(aconf
))
290 ":%s NOTICE %s :Un-dlined [%s] from temporary D-lines",
291 me
.name
, parv
[0], buf
);
292 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
293 "%s has removed the temporary D-Line for: [%s]",
294 get_oper_name(source_p
), buf
);
295 ilog(L_KLINE
, "UD %s %s", get_oper_name(source_p
), buf
);
299 filename
= get_conf_name(DLINE_TYPE
);
301 if((in
= fopen(filename
, "r")) == 0)
303 sendto_one(source_p
, ":%s NOTICE %s :Cannot open %s", me
.name
, parv
[0], filename
);
308 if((out
= fopen(temppath
, "w")) == 0)
310 sendto_one(source_p
, ":%s NOTICE %s :Cannot open %s", me
.name
, parv
[0], temppath
);
318 while (fgets(buf
, sizeof(buf
), in
))
320 rb_strlcpy(buff
, buf
, sizeof(buff
));
322 if((p
= strchr(buff
, '\n')) != NULL
)
325 if((*buff
== '\0') || (*buff
== '#'))
328 flush_write(source_p
, out
, buf
, temppath
);
332 if((found_cidr
= getfield(buff
)) == NULL
)
335 flush_write(source_p
, out
, buf
, temppath
);
339 if(irccmp(found_cidr
, aconf
->host
) == 0)
346 flush_write(source_p
, out
, buf
, temppath
);
353 error_on_write
= YES
;
358 ":%s NOTICE %s :Couldn't write D-line file, aborted",
364 sendto_one_notice(source_p
, ":Cannot find D-Line for %s in file",
368 (void) unlink(temppath
);
373 if (rename(temppath
, filename
))
375 sendto_one_notice(source_p
, ":Couldn't rename temp file, aborted");
379 sendto_one(source_p
, ":%s NOTICE %s :D-Line for [%s] is removed", me
.name
, parv
[0], aconf
->host
);
380 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
381 "%s has removed the D-Line for: [%s]", get_oper_name(source_p
), aconf
->host
);
382 ilog(L_KLINE
, "UD %s %s", get_oper_name(source_p
), aconf
->host
);
384 delete_one_address_conf(aconf
->host
, aconf
);
391 * inputs - pointer to client
392 * - pointer to comment
393 * output - 0 if no valid comment, 1 if valid
394 * side effects - NONE
397 valid_comment(char *comment
)
399 if(strchr(comment
, '"'))
402 if(strlen(comment
) > BANREASONLEN
)
403 comment
[BANREASONLEN
] = '\0';
411 * inputs - pointer to client structure of oper requesting unkline
412 * - out is the file descriptor
413 * - buf is the buffer to write
414 * - ntowrite is the expected number of character to be written
415 * - temppath is the temporary file name to be written
416 * output - YES for error on write
418 * side effects - if successful, the buf is written to output file
419 * if a write failure happesn, and the file pointed to
420 * by temppath, if its non NULL, is removed.
422 * The idea here is, to be as robust as possible when writing to the
428 flush_write(struct Client
*source_p
, FILE * out
, char *buf
, char *temppath
)
430 int error_on_write
= (fputs(buf
, out
) < 0) ? YES
: NO
;
434 sendto_one_notice(source_p
, ":Unable to write to %s", temppath
);
437 (void) unlink(temppath
);
439 return (error_on_write
);
442 /* remove_temp_dline()
444 * inputs - confitem to undline
446 * side effects - tries to undline anything that matches
449 remove_temp_dline(struct ConfItem
*aconf
)
454 for (i
= 0; i
< LAST_TEMP_TYPE
; i
++)
456 RB_DLINK_FOREACH(ptr
, temp_dlines
[i
].head
)
458 if (aconf
== ptr
->data
)
460 rb_dlinkDestroy(ptr
, &temp_dlines
[i
]);
461 delete_one_address_conf(aconf
->host
, aconf
);