mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 18:22:50 +01:00
d69601a5e2
The change also applies to xlines sent to other servers. Note that the backslash must be supplied in an unxline. Incoming xlines containing '",' are rejected to avoid inconsistency between servers.
738 lines
18 KiB
C
738 lines
18 KiB
C
/* modules/m_xline.c
|
|
*
|
|
* Copyright (C) 2002-2003 Lee Hardy <lee@leeh.co.uk>
|
|
* Copyright (C) 2002-2005 ircd-ratbox development team
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1.Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2.Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3.The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $Id: m_xline.c 3161 2007-01-25 07:23:01Z nenolod $
|
|
*/
|
|
|
|
#include "stdinc.h"
|
|
#include "send.h"
|
|
#include "channel.h"
|
|
#include "client.h"
|
|
#include "common.h"
|
|
#include "config.h"
|
|
#include "class.h"
|
|
#include "ircd.h"
|
|
#include "numeric.h"
|
|
#include "logger.h"
|
|
#include "s_serv.h"
|
|
#include "whowas.h"
|
|
#include "match.h"
|
|
#include "hash.h"
|
|
#include "msg.h"
|
|
#include "parse.h"
|
|
#include "modules.h"
|
|
#include "s_conf.h"
|
|
#include "s_newconf.h"
|
|
#include "reject.h"
|
|
|
|
static int mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
|
|
static int ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
|
|
static int me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
|
|
static int mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
|
|
static int ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
|
|
static int me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
|
|
|
|
struct Message xline_msgtab = {
|
|
"XLINE", 0, 0, 0, MFLG_SLOW,
|
|
{mg_unreg, mg_not_oper, {ms_xline, 5}, {ms_xline, 5}, {me_xline, 5}, {mo_xline, 3}}
|
|
};
|
|
struct Message unxline_msgtab = {
|
|
"UNXLINE", 0, 0, 0, MFLG_SLOW,
|
|
{mg_unreg, mg_not_oper, {ms_unxline, 3}, {ms_unxline, 3}, {me_unxline, 2}, {mo_unxline, 2}}
|
|
};
|
|
|
|
mapi_clist_av1 xline_clist[] = { &xline_msgtab, &unxline_msgtab, NULL };
|
|
DECLARE_MODULE_AV1(xline, NULL, NULL, xline_clist, NULL, NULL, "$Revision: 3161 $");
|
|
|
|
static char *escape_perm_xline(const char *);
|
|
static int valid_xline(struct Client *, const char *, const char *, int);
|
|
static void apply_xline(struct Client *client_p, const char *name,
|
|
const char *reason, int temp_time);
|
|
static void write_xline(struct Client *source_p, struct ConfItem *aconf);
|
|
static void propagate_xline(struct Client *source_p, const char *target,
|
|
int temp_time, const char *name,
|
|
const char *type, const char *reason);
|
|
static void cluster_xline(struct Client *source_p, int temp_time,
|
|
const char *name, const char *reason);
|
|
|
|
static void handle_remote_xline(struct Client *source_p, int temp_time,
|
|
const char *name, const char *reason);
|
|
static void handle_remote_unxline(struct Client *source_p, const char *name);
|
|
|
|
static void remove_xline(struct Client *source_p, const char *name);
|
|
static int remove_xline_from_file(struct Client *source_p, const char *gecos);
|
|
|
|
|
|
/* m_xline()
|
|
*
|
|
* parv[1] - thing to xline
|
|
* parv[2] - optional type/reason
|
|
* parv[3] - reason
|
|
*/
|
|
static int
|
|
mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
|
{
|
|
struct ConfItem *aconf;
|
|
const char *name;
|
|
char *escapedname;
|
|
const char *reason;
|
|
const char *target_server = NULL;
|
|
int temp_time;
|
|
int loc = 1;
|
|
|
|
if(!IsOperXline(source_p))
|
|
{
|
|
sendto_one(source_p, form_str(ERR_NOPRIVS),
|
|
me.name, source_p->name, "xline");
|
|
return 0;
|
|
}
|
|
|
|
if((temp_time = valid_temp_time(parv[loc])) >= 0)
|
|
loc++;
|
|
/* we just set temp_time to -1! */
|
|
else
|
|
temp_time = 0;
|
|
|
|
name = parv[loc];
|
|
loc++;
|
|
|
|
/* XLINE <gecos> ON <server> :<reason> */
|
|
if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
|
|
{
|
|
if(!IsOperRemoteBan(source_p))
|
|
{
|
|
sendto_one(source_p, form_str(ERR_NOPRIVS),
|
|
me.name, source_p->name, "remoteban");
|
|
return 0;
|
|
}
|
|
|
|
target_server = parv[loc+1];
|
|
loc += 2;
|
|
}
|
|
|
|
if(parc <= loc || EmptyString(parv[loc]))
|
|
{
|
|
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
|
me.name, source_p->name, "XLINE");
|
|
return 0;
|
|
}
|
|
|
|
reason = parv[loc];
|
|
|
|
if (temp_time == 0)
|
|
{
|
|
escapedname = escape_perm_xline(name);
|
|
if (strcmp(escapedname, name))
|
|
sendto_one_notice(source_p, ":Changed xline from [%s] to [%s]",
|
|
name, escapedname);
|
|
}
|
|
else
|
|
escapedname = rb_strdup(name);
|
|
|
|
if(target_server != NULL)
|
|
{
|
|
propagate_xline(source_p, target_server, temp_time,
|
|
escapedname, "2", reason);
|
|
|
|
if(!match(target_server, me.name))
|
|
{
|
|
rb_free(escapedname);
|
|
return 0;
|
|
}
|
|
}
|
|
else if(rb_dlink_list_length(&cluster_conf_list) > 0)
|
|
cluster_xline(source_p, temp_time, escapedname, reason);
|
|
|
|
if((aconf = find_xline_mask(escapedname)) != NULL)
|
|
{
|
|
sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
|
|
me.name, source_p->name, escapedname, aconf->name, aconf->passwd);
|
|
rb_free(escapedname);
|
|
return 0;
|
|
}
|
|
|
|
if(!valid_xline(source_p, escapedname, reason, temp_time))
|
|
{
|
|
rb_free(escapedname);
|
|
return 0;
|
|
}
|
|
|
|
apply_xline(source_p, escapedname, reason, temp_time);
|
|
rb_free(escapedname);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ms_xline()
|
|
*
|
|
* handles a remote xline
|
|
*/
|
|
static int
|
|
ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
|
{
|
|
/* source_p parv[1] parv[2] parv[3] parv[4]
|
|
* oper target serv xline type reason
|
|
*/
|
|
propagate_xline(source_p, parv[1], 0, parv[2], parv[3], parv[4]);
|
|
|
|
if(!IsPerson(source_p))
|
|
return 0;
|
|
|
|
/* destined for me? */
|
|
if(!match(parv[1], me.name))
|
|
return 0;
|
|
|
|
handle_remote_xline(source_p, 0, parv[2], parv[4]);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
|
{
|
|
/* time name type :reason */
|
|
if(!IsPerson(source_p))
|
|
return 0;
|
|
|
|
handle_remote_xline(source_p, atoi(parv[1]), parv[2], parv[4]);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
handle_remote_xline(struct Client *source_p, int temp_time,
|
|
const char *name, const char *reason)
|
|
{
|
|
struct ConfItem *aconf;
|
|
|
|
if(!find_shared_conf(source_p->username, source_p->host,
|
|
source_p->servptr->name,
|
|
(temp_time > 0) ? SHARED_TXLINE : SHARED_PXLINE))
|
|
return;
|
|
|
|
if(!valid_xline(source_p, name, reason, temp_time))
|
|
return;
|
|
|
|
/* already xlined */
|
|
if((aconf = find_xline_mask(name)) != NULL)
|
|
{
|
|
sendto_one_notice(source_p, ":[%s] already X-Lined by [%s] - %s", name, aconf->name, aconf->passwd);
|
|
return;
|
|
}
|
|
|
|
apply_xline(source_p, name, reason, temp_time);
|
|
}
|
|
|
|
/* escape_perm_xline()
|
|
*
|
|
* inputs - gecos
|
|
* outputs - escaped gecos (allocated with rb_malloc())
|
|
* side effects - none
|
|
*/
|
|
static char *
|
|
escape_perm_xline(const char *gecos)
|
|
{
|
|
char *result;
|
|
int i, j;
|
|
|
|
result = rb_malloc(2 * strlen(gecos) + 1);
|
|
for (i = 0, j = 0; gecos[i] != '\0'; i++)
|
|
{
|
|
result[j++] = gecos[i];
|
|
if (gecos[i] == '"' && gecos[i + 1] == ',')
|
|
result[j++] = '\\';
|
|
}
|
|
result[j] = '\0';
|
|
return result;
|
|
}
|
|
|
|
/* valid_xline()
|
|
*
|
|
* inputs - client xlining, gecos, reason and temp time
|
|
* outputs -
|
|
* side effects - checks the xline for validity, erroring if needed
|
|
*/
|
|
static int
|
|
valid_xline(struct Client *source_p, const char *gecos,
|
|
const char *reason, int temp_time)
|
|
{
|
|
if(EmptyString(reason))
|
|
{
|
|
sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
|
|
get_id(&me, source_p),
|
|
get_id(source_p, source_p), "XLINE");
|
|
return 0;
|
|
}
|
|
|
|
if(temp_time == 0 && strstr(gecos, "\",") != NULL)
|
|
{
|
|
sendto_one_notice(source_p,
|
|
":Invalid character sequence '\",' in xline, please replace with '\"\\,'");
|
|
return 0;
|
|
}
|
|
|
|
if(strchr(reason, ':') != NULL)
|
|
{
|
|
sendto_one_notice(source_p,
|
|
":Invalid character ':' in comment");
|
|
return 0;
|
|
}
|
|
|
|
if(strchr(reason, '"'))
|
|
{
|
|
sendto_one_notice(source_p,
|
|
":Invalid character '\"' in comment");
|
|
return 0;
|
|
}
|
|
|
|
if(!valid_wild_card_simple(gecos))
|
|
{
|
|
sendto_one_notice(source_p,
|
|
":Please include at least %d non-wildcard "
|
|
"characters with the xline",
|
|
ConfigFileEntry.min_nonwildcard_simple);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
apply_xline(struct Client *source_p, const char *name, const char *reason,
|
|
int temp_time)
|
|
{
|
|
struct ConfItem *aconf;
|
|
|
|
aconf = make_conf();
|
|
aconf->status = CONF_XLINE;
|
|
|
|
aconf->name = rb_strdup(name);
|
|
aconf->passwd = rb_strdup(reason);
|
|
collapse(aconf->name);
|
|
|
|
if(temp_time > 0)
|
|
{
|
|
aconf->hold = rb_current_time() + temp_time;
|
|
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL,
|
|
"%s added temporary %d min. X-Line for [%s] [%s]",
|
|
get_oper_name(source_p), temp_time / 60,
|
|
aconf->name, reason);
|
|
ilog(L_KLINE, "X %s %d %s %s",
|
|
get_oper_name(source_p), temp_time / 60,
|
|
name, reason);
|
|
sendto_one_notice(source_p, ":Added temporary %d min. X-Line [%s]",
|
|
temp_time / 60, aconf->name);
|
|
}
|
|
else
|
|
{
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s added X-Line for [%s] [%s]",
|
|
get_oper_name(source_p),
|
|
aconf->name, aconf->passwd);
|
|
sendto_one_notice(source_p, ":Added X-Line for [%s] [%s]",
|
|
aconf->name, aconf->passwd);
|
|
write_xline(source_p, aconf);
|
|
ilog(L_KLINE, "X %s 0 %s %s",
|
|
get_oper_name(source_p), name, reason);
|
|
}
|
|
|
|
rb_dlinkAddAlloc(aconf, &xline_conf_list);
|
|
check_xlines();
|
|
}
|
|
|
|
/* write_xline()
|
|
*
|
|
* inputs - gecos, reason, xline type
|
|
* outputs - writes an xline to the config
|
|
* side effects -
|
|
*/
|
|
static void
|
|
write_xline(struct Client *source_p, struct ConfItem *aconf)
|
|
{
|
|
char buffer[BUFSIZE * 2];
|
|
FILE *out;
|
|
const char *filename;
|
|
char *mangle_gecos;
|
|
|
|
if(strstr(aconf->name, "\\s"))
|
|
{
|
|
char *tmp = LOCAL_COPY(aconf->name);
|
|
char *orig = tmp;
|
|
char *new = tmp;
|
|
while(*orig)
|
|
{
|
|
if(*orig == '\\' && *(orig + 1) != '\0')
|
|
{
|
|
if(*(orig + 1) == 's')
|
|
{
|
|
*new++ = ' ';
|
|
orig += 2;
|
|
}
|
|
/* otherwise skip that and the escaped
|
|
* character after it, so we dont mistake
|
|
* \\s as \s --fl
|
|
*/
|
|
else
|
|
{
|
|
*new++ = *orig++;
|
|
*new++ = *orig++;
|
|
}
|
|
}
|
|
else
|
|
*new++ = *orig++;
|
|
}
|
|
|
|
*new = '\0';
|
|
mangle_gecos = tmp;
|
|
} else
|
|
mangle_gecos = aconf->name;
|
|
|
|
filename = ConfigFileEntry.xlinefile;
|
|
|
|
if((out = fopen(filename, "a")) == NULL)
|
|
{
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem opening %s ", filename);
|
|
sendto_one_notice(source_p, ":*** Problem opening file, xline added temporarily only");
|
|
return;
|
|
}
|
|
|
|
rb_sprintf(buffer, "\"%s\",\"0\",\"%s\",\"%s\",%ld\n",
|
|
mangle_gecos, aconf->passwd,
|
|
get_oper_name(source_p), (long) rb_current_time());
|
|
|
|
if(fputs(buffer, out) == -1)
|
|
{
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
|
|
sendto_one_notice(source_p, ":*** Problem writing to file, xline added temporarily only");
|
|
fclose(out);
|
|
return;
|
|
}
|
|
|
|
if(fclose(out))
|
|
{
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
|
|
sendto_one_notice(source_p, ":*** Problem writing to file, xline added temporarily only");
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
propagate_xline(struct Client *source_p, const char *target,
|
|
int temp_time, const char *name, const char *type,
|
|
const char *reason)
|
|
{
|
|
if(!temp_time)
|
|
{
|
|
sendto_match_servs(source_p, target, CAP_CLUSTER, NOCAPS,
|
|
"XLINE %s %s %s :%s",
|
|
target, name, type, reason);
|
|
sendto_match_servs(source_p, target, CAP_ENCAP, CAP_CLUSTER,
|
|
"ENCAP %s XLINE %d %s 2 :%s",
|
|
target, temp_time, name, reason);
|
|
}
|
|
else
|
|
sendto_match_servs(source_p, target, CAP_ENCAP, NOCAPS,
|
|
"ENCAP %s XLINE %d %s %s :%s",
|
|
target, temp_time, name, type, reason);
|
|
}
|
|
|
|
static void
|
|
cluster_xline(struct Client *source_p, int temp_time, const char *name,
|
|
const char *reason)
|
|
{
|
|
struct remote_conf *shared_p;
|
|
rb_dlink_node *ptr;
|
|
|
|
RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
|
|
{
|
|
shared_p = ptr->data;
|
|
|
|
/* old protocol cant handle temps, and we dont really want
|
|
* to convert them to perm.. --fl
|
|
*/
|
|
if(!temp_time)
|
|
{
|
|
if(!(shared_p->flags & SHARED_PXLINE))
|
|
continue;
|
|
|
|
sendto_match_servs(source_p, shared_p->server, CAP_CLUSTER, NOCAPS,
|
|
"XLINE %s %s 2 :%s",
|
|
shared_p->server, name, reason);
|
|
sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, CAP_CLUSTER,
|
|
"ENCAP %s XLINE 0 %s 2 :%s",
|
|
shared_p->server, name, reason);
|
|
}
|
|
else if(shared_p->flags & SHARED_TXLINE)
|
|
sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, NOCAPS,
|
|
"ENCAP %s XLINE %d %s 2 :%s",
|
|
shared_p->server, temp_time, name, reason);
|
|
}
|
|
}
|
|
|
|
/* mo_unxline()
|
|
*
|
|
* parv[1] - thing to unxline
|
|
*/
|
|
static int
|
|
mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
|
{
|
|
if(!IsOperXline(source_p))
|
|
{
|
|
sendto_one(source_p, form_str(ERR_NOPRIVS),
|
|
me.name, source_p->name, "xline");
|
|
return 0;
|
|
}
|
|
|
|
if(parc == 4 && !(irccmp(parv[2], "ON")))
|
|
{
|
|
if(!IsOperRemoteBan(source_p))
|
|
{
|
|
sendto_one(source_p, form_str(ERR_NOPRIVS),
|
|
me.name, source_p->name, "remoteban");
|
|
return 0;
|
|
}
|
|
|
|
propagate_generic(source_p, "UNXLINE", parv[3], CAP_CLUSTER,
|
|
"%s", parv[1]);
|
|
|
|
if(match(parv[3], me.name) == 0)
|
|
return 0;
|
|
}
|
|
else if(rb_dlink_list_length(&cluster_conf_list))
|
|
cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER,
|
|
"%s", parv[1]);
|
|
|
|
remove_xline(source_p, parv[1]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ms_unxline()
|
|
*
|
|
* handles a remote unxline
|
|
*/
|
|
static int
|
|
ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
|
{
|
|
/* source_p parv[1] parv[2]
|
|
* oper target server gecos
|
|
*/
|
|
propagate_generic(source_p, "UNXLINE", parv[1], CAP_CLUSTER,
|
|
"%s", parv[2]);
|
|
|
|
if(!match(parv[1], me.name))
|
|
return 0;
|
|
|
|
if(!IsPerson(source_p))
|
|
return 0;
|
|
|
|
handle_remote_unxline(source_p, parv[2]);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
|
{
|
|
/* name */
|
|
if(!IsPerson(source_p))
|
|
return 0;
|
|
|
|
handle_remote_unxline(source_p, parv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
handle_remote_unxline(struct Client *source_p, const char *name)
|
|
{
|
|
if(!find_shared_conf(source_p->username, source_p->host,
|
|
source_p->servptr->name, SHARED_UNXLINE))
|
|
return;
|
|
|
|
remove_xline(source_p, name);
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
remove_xline(struct Client *source_p, const char *name)
|
|
{
|
|
struct ConfItem *aconf;
|
|
rb_dlink_node *ptr;
|
|
char *encoded;
|
|
|
|
encoded = xline_encode_spaces(name);
|
|
|
|
RB_DLINK_FOREACH(ptr, xline_conf_list.head)
|
|
{
|
|
aconf = ptr->data;
|
|
|
|
if(!irccmp(aconf->name, encoded))
|
|
{
|
|
if (!aconf->hold)
|
|
{
|
|
if (!remove_xline_from_file(source_p, encoded))
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
sendto_one_notice(source_p,
|
|
":X-Line for [%s] is removed",
|
|
encoded);
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL,
|
|
"%s has removed the temporary X-Line for: [%s]",
|
|
get_oper_name(source_p), encoded);
|
|
ilog(L_KLINE, "UX %s %s",
|
|
get_oper_name(source_p), encoded);
|
|
}
|
|
|
|
remove_reject_mask(aconf->name, NULL);
|
|
free_conf(aconf);
|
|
rb_dlinkDestroy(ptr, &xline_conf_list);
|
|
rb_free(encoded);
|
|
return;
|
|
}
|
|
}
|
|
|
|
sendto_one_notice(source_p, ":No X-Line for %s", encoded);
|
|
rb_free(encoded);
|
|
|
|
return;
|
|
}
|
|
|
|
/* remove_xline_from_file()
|
|
*
|
|
* inputs - gecos to remove
|
|
* outputs -
|
|
* side effects - removes xline from conf, if exists
|
|
* - does not touch xline_conf_list
|
|
*/
|
|
static int
|
|
remove_xline_from_file(struct Client *source_p, const char *huntgecos)
|
|
{
|
|
FILE *in, *out;
|
|
char buf[BUFSIZE];
|
|
char buff[BUFSIZE];
|
|
char temppath[BUFSIZE];
|
|
const char *filename;
|
|
const char *gecos;
|
|
mode_t oldumask;
|
|
char *p;
|
|
char *encoded;
|
|
int error_on_write = 0;
|
|
int found_xline = 0;
|
|
|
|
filename = ConfigFileEntry.xlinefile;
|
|
rb_snprintf(temppath, sizeof(temppath),
|
|
"%s.tmp", ConfigFileEntry.xlinefile);
|
|
|
|
if((in = fopen(filename, "r")) == NULL)
|
|
{
|
|
sendto_one_notice(source_p, ":Cannot open %s", filename);
|
|
return 0;
|
|
}
|
|
|
|
oldumask = umask(0);
|
|
|
|
if((out = fopen(temppath, "w")) == NULL)
|
|
{
|
|
sendto_one_notice(source_p, ":Cannot open %s", temppath);
|
|
fclose(in);
|
|
umask(oldumask);
|
|
return 0;
|
|
}
|
|
|
|
umask(oldumask);
|
|
|
|
while (fgets(buf, sizeof(buf), in))
|
|
{
|
|
if(error_on_write)
|
|
{
|
|
if(temppath != NULL)
|
|
(void) unlink(temppath);
|
|
|
|
break;
|
|
}
|
|
|
|
rb_strlcpy(buff, buf, sizeof(buff));
|
|
|
|
if((p = strchr(buff, '\n')) != NULL)
|
|
*p = '\0';
|
|
|
|
if((*buff == '\0') || (*buff == '#'))
|
|
{
|
|
error_on_write = (fputs(buf, out) < 0) ? YES : NO;
|
|
continue;
|
|
}
|
|
|
|
if((gecos = getfield(buff)) == NULL)
|
|
{
|
|
error_on_write = (fputs(buf, out) < 0) ? YES : NO;
|
|
continue;
|
|
}
|
|
|
|
/* matching.. */
|
|
encoded = xline_encode_spaces(gecos);
|
|
if(irccmp(encoded, huntgecos) == 0)
|
|
found_xline++;
|
|
else
|
|
error_on_write = (fputs(buf, out) < 0) ? YES : NO;
|
|
rb_free(encoded);
|
|
}
|
|
|
|
fclose(in);
|
|
if (fclose(out))
|
|
error_on_write = YES;
|
|
|
|
if(error_on_write)
|
|
{
|
|
sendto_one_notice(source_p,
|
|
":Couldn't write temp xline file, aborted");
|
|
return 0;
|
|
}
|
|
else if(found_xline == 0)
|
|
{
|
|
sendto_one_notice(source_p, ":Cannot find X-Line for %s in file", huntgecos);
|
|
|
|
if(temppath != NULL)
|
|
(void) unlink(temppath);
|
|
return 0;
|
|
}
|
|
|
|
if (rename(temppath, filename))
|
|
{
|
|
sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
|
|
return 0;
|
|
}
|
|
|
|
sendto_one_notice(source_p, ":X-Line for [%s] is removed", huntgecos);
|
|
sendto_realops_snomask(SNO_GENERAL, L_ALL,
|
|
"%s has removed the X-Line for: [%s]",
|
|
get_oper_name(source_p), huntgecos);
|
|
ilog(L_KLINE, "UX %s %s", get_oper_name(source_p), huntgecos);
|
|
|
|
return 1;
|
|
}
|