Exemple #1
0
static void
list_bans(void)
{
	static char buf[512];
	struct rsdb_table table;
	int i, j;

	/* schedule a clear of anything already pending */
	rb_helper_write_queue(bandb_helper, "C");

	for(i = 0; i < LAST_BANDB_TYPE; i++)
	{
		rsdb_exec_fetch(&table, "SELECT mask1,mask2,oper,reason FROM %s WHERE 1",
				bandb_table[i]);

		for(j = 0; j < table.row_count; j++)
		{
			if(i == BANDB_KLINE)
				rb_snprintf(buf, sizeof(buf), "%c %s %s %s :%s",
					    bandb_letter[i], table.row[j][0],
					    table.row[j][1], table.row[j][2], table.row[j][3]);
			else
				rb_snprintf(buf, sizeof(buf), "%c %s %s :%s",
					    bandb_letter[i], table.row[j][0],
					    table.row[j][2], table.row[j][3]);

			rb_helper_write_queue(bandb_helper, "%s", buf);
		}

		rsdb_exec_fetch_end(&table);
	}

	rb_helper_write(bandb_helper, "F");
}
static int eb_extended(const char *data, struct Client *client_p,
                       struct Channel *chptr, long mode_type)
{
    char buf[BUFSIZE];
    int ret;

    (void)chptr;

    if (data == NULL)
        return EXTBAN_INVALID;

    rb_snprintf(buf, BUFSIZE, "%s!%s@%s#%s",
                client_p->name, client_p->username, client_p->host, client_p->info);

    ret = match(data, buf) ? EXTBAN_MATCH : EXTBAN_NOMATCH;

    if (ret == EXTBAN_NOMATCH && IsDynSpoof(client_p)) {
        rb_snprintf(buf, BUFSIZE, "%s!%s@%s#%s",
                    client_p->name, client_p->username, client_p->orighost, client_p->info);

        ret = match(data, buf) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
    }

    return ret;
}
Exemple #3
0
/*
 * ms_svinfo - SVINFO message handler
 *      parv[1] = TS_CURRENT for the server
 *      parv[2] = TS_MIN for the server
 *      parv[3] = unused, send 0
 *      parv[4] = server's idea of UTC time
 */
static int
ms_svinfo(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
    signed long deltat;
    time_t theirtime;
    char squitreason[120];

    /* SVINFO isnt remote. */
    if(source_p != client_p)
        return 0;

    if(TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN)
    {
        /* TS version is too low on one of the sides, drop the link */
        sendto_realops_snomask(SNO_GENERAL, L_ALL,
                               "Link %s dropped, wrong TS protocol version (%s,%s)",
                               source_p->name, parv[1], parv[2]);
        rb_snprintf(squitreason, sizeof squitreason, "Incompatible TS version (%s,%s)",
                    parv[1], parv[2]);
        exit_client(source_p, source_p, source_p, squitreason);
        return 0;
    }

    /*
     * since we're here, might as well set rb_current_time() while we're at it
     */
    rb_set_time();
    theirtime = atol(parv[4]);
    deltat = labs(theirtime - rb_current_time());

    if(deltat > ConfigFileEntry.ts_max_delta)
    {
        sendto_realops_snomask(SNO_GENERAL, L_ALL,
                               "Link %s dropped, excessive TS delta"
                               " (my TS=%ld, their TS=%ld, delta=%ld)",
                               source_p->name,
                               (long) rb_current_time(), (long) theirtime, deltat);
        ilog(L_SERVER,
             "Link %s dropped, excessive TS delta"
             " (my TS=%ld, their TS=%ld, delta=%ld)",
             log_client_name(source_p, SHOW_IP), (long) rb_current_time(), (long) theirtime, deltat);
        rb_snprintf(squitreason, sizeof squitreason, "Excessive TS delta (my TS=%ld, their TS=%ld, delta=%ld)",
                    (long) rb_current_time(), (long) theirtime, deltat);
        disable_server_conf_autoconn(source_p->name);
        exit_client(source_p, source_p, source_p, squitreason);
        return 0;
    }

    if(deltat > ConfigFileEntry.ts_warn_delta)
    {
        sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
                               "Link %s notable TS delta"
                               " (my TS=%ld, their TS=%ld, delta=%ld)",
                               source_p->name, (long) rb_current_time(), (long) theirtime, deltat);
    }

    return 0;
}
Exemple #4
0
/* mr_user()
 *      parv[1] = username (login name, account)
 *      parv[2] = client host name (ignored)
 *      parv[3] = server host name (ignored)
 *      parv[4] = users gecos
 */
static int
mr_user(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
    static char buf[BUFSIZE];
    char *p;

    if (strlen(client_p->id) == 3)
    {
        exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
        return 0;
    }

    if(source_p->flags & FLAGS_SENTUSER)
        return 0;

    if((p = strchr(parv[1], '@')))
        *p = '\0';

    rb_snprintf(buf, sizeof(buf), "%s %s", parv[2], parv[3]);
    rb_free(source_p->localClient->fullcaps);
    source_p->localClient->fullcaps = rb_strdup(buf);

    do_local_user(client_p, source_p, parv[1], parv[4]);
    return 0;
}
Exemple #5
0
void
server_reboot(void)
{
	int i;
	char path[PATH_MAX+1];

	sendto_realops_snomask(SNO_GENERAL, L_ALL, "Restarting server...");

	ilog(L_MAIN, "Restarting server...");

	/*
	 * XXX we used to call flush_connections() here. But since this routine
	 * doesn't exist anymore, we won't be flushing. This is ok, since
	 * when close handlers come into existance, rb_close() will be called
	 * below, and the data flushing will be implicit.
	 *    -- adrian
	 *
	 * bah, for now, the program ain't coming back to here, so forcibly
	 * close everything the "wrong" way for now, and just LEAVE...
	 */
	for (i = 0; i < maxconnections; ++i)
		close(i);

	unlink(pidFileName);
	execv(SPATH, (void *)myargv);

	/* use this if execv of SPATH fails */
	rb_snprintf(path, sizeof(path), "%s/bin/ircd", ConfigFileEntry.dpath);

	execv(path, (void *)myargv);
	exit(-1);
}
static int eb_unidentified(const char *data, struct Client *client_p,
		struct Channel *chptr, long mode_type)
{

	(void)chptr;
	
	/* $u doesn't make sense for ban exceptions and invex. */
	if(mode_type == CHFL_EXCEPTION || mode_type == CHFL_INVEX)
		return EXTBAN_INVALID;

	/* $u makes little sense without an argument, use $~a. */
	if (data == NULL)
	{
		return EXTBAN_INVALID;
	}
	/* $u has an argument, check it.  It should be n!u@h . */
	else
	{
		char buf[BUFSIZE];

		rb_snprintf(buf, BUFSIZE, "%s!%s@%s",
			client_p->name, client_p->username, client_p->host);

		if ((match(data, buf) != 0) && EmptyString(client_p->user->suser))
		{
			return EXTBAN_MATCH;
		}
		else
		{
			return EXTBAN_NOMATCH;
		}
	}
}
Exemple #7
0
/*
** m_quit
**      parv[1] = comment
*/
static int
m_quit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
    char *comment = LOCAL_COPY((parc > 1 && parv[1]) ? parv[1] : client_p->name);
    char reason[REASONLEN + 1];

    source_p->flags |= FLAGS_NORMALEX;

    if(strlen(comment) > (size_t) REASONLEN)
        comment[REASONLEN] = '\0';

    strip_colour(comment);

    if(ConfigFileEntry.client_exit && comment[0]) {
        rb_snprintf(reason, sizeof(reason), "Quit: %s", comment);
        comment = reason;
    }

    if(!IsOper(source_p) && !EmptyString(ConfigFileEntry.static_quit)) {
        exit_client(client_p, source_p, source_p, ConfigFileEntry.static_quit);
        return 0;
    }

    if(!IsOper(source_p) &&
       (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) >
       rb_current_time()) {
        exit_client(client_p, source_p, source_p, "Client Quit");
        return 0;
    }

    exit_client(client_p, source_p, source_p, comment);

    return 0;
}
Exemple #8
0
/*
** m_quit
**      parv[1] = comment
*/
static int
m_quit(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	char comment[REASONLEN + 1]; /* Better safe than sorry */
	char reason[REASONLEN + 1];

	source_p->flags |= FLAGS_NORMALEX;

	strip_colour((parc > 1 && parv[1]) ? parv[1] : client_p->name, comment, REASONLEN);

	if(ConfigFileEntry.client_exit && comment[0])
	{
		rb_snprintf(reason, sizeof(reason), "Quit: %s", comment);
		rb_strlcpy(comment, reason, REASONLEN + 1);
	}

	if(!IsOper(source_p) && !EmptyString(ConfigFileEntry.static_quit))
	{
		exit_client(client_p, source_p, source_p, ConfigFileEntry.static_quit);
		return 0;
	}

	if(!IsOper(source_p) &&
	   (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) >
	   rb_current_time())
	{
		exit_client(client_p, source_p, source_p, "Client Quit");
		return 0;
	}

	exit_client(client_p, source_p, source_p, comment);

	return 0;
}
Exemple #9
0
/* ms_operspy()
 *
 * parv[1] - operspy command
 * parv[2] - optional params
 */
static int
ms_operspy(struct Client *client_p, struct Client *source_p,
           int parc, const char *parv[])
{
	static char buffer[BUFSIZE];
	char *ptr;
	int cur_len = 0;
	int len, i;
	if (parc < 4) {
		report_operspy(source_p, parv[1],
		               parc < 3 ? NULL : parv[2]);
	}
	/* buffer all remaining into one param */
	else {
		ptr = buffer;
		cur_len = 0;
		for (i = 2; i < parc; i++) {
			len = strlen(parv[i]) + 1;
			if ((size_t)(cur_len + len) >= sizeof(buffer))
				return 0;
			rb_snprintf(ptr, sizeof(buffer) - cur_len, "%s ",
			            parv[i]);
			ptr += len;
			cur_len += len;
		}
		report_operspy(source_p, parv[1], buffer);
	}
	return 0;
}
Exemple #10
0
void
ilog(ilogfile dest, const char *format, ...)
{
	FILE *logfile = *log_table[dest].logfile;
	char buf[BUFSIZE];
	char buf2[BUFSIZE];
	va_list args;

	if(logfile == NULL)
		return;

	va_start(args, format);
	rb_vsnprintf(buf, sizeof(buf), format, args);
	va_end(args);

	rb_snprintf(buf2, sizeof(buf2), "%s %s\n",
			smalldate(rb_current_time()), buf);

	if(fputs(buf2, logfile) < 0)
	{
		fclose(logfile);
		*log_table[dest].logfile = NULL;
		return;
	}

	fflush(logfile);
}
Exemple #11
0
static int
rb_epoll_sched_event_timerfd(struct ev_entry *event, int when)
{
	struct itimerspec ts;
	static char buf[FD_DESC_SZ + 8];
	int fd;
	rb_fde_t *F;

	if((fd = timerfd_create(CLOCK_REALTIME, 0)) < 0)
	{
		rb_lib_log("timerfd_create: %s\n", strerror(errno));
		return 0;
	}

	memset(&ts, 0, sizeof(ts));
	ts.it_value.tv_sec = when;
	ts.it_value.tv_nsec = 0;
	if(event->frequency != 0)
		ts.it_interval = ts.it_value;

	if(timerfd_settime(fd, 0, &ts, NULL) < 0)
	{
		rb_lib_log("timerfd_settime: %s\n", strerror(errno));
		close(fd);
		return 0;
	}
	rb_snprintf(buf, sizeof(buf), "timerfd: %s", event->name);
	F = rb_open(fd, RB_FD_UNKNOWN, buf);
	rb_set_nb(F);
	event->comm_ptr = F;
	rb_setselect(F, RB_SELECT_READ, rb_read_timerfd, event);
	return 1;
}
Exemple #12
0
void
rb_get_ssl_info(char *buf, size_t len)
{
	rb_snprintf(buf, len, "Using SSL: %s compiled: 0x%lx, library 0x%lx",
		    SSLeay_version(SSLEAY_VERSION),
		    (long)OPENSSL_VERSION_NUMBER, SSLeay());
}
Exemple #13
0
/* ms_encap()
 *
 * parv[1] - destination server
 * parv[2] - subcommand
 * parv[3] - parameters
 */
static int
ms_encap(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	char buffer[BUFSIZE];
	char *ptr;
	int cur_len = 0;
	int len;
	int i;

	ptr = buffer;
	
	for(i = 1; i < parc - 1; i++)
	{
		len = strlen(parv[i]) + 1;

		/* ugh, not even at the last parameter, just bail --fl */
		if((size_t)(cur_len + len) >= sizeof(buffer))
			return 0;

		rb_snprintf(ptr, sizeof(buffer) - cur_len, "%s ", parv[i]);
		cur_len += len;
		ptr += len;
	}

	len = strlen(parv[i]);

	/* if its a command without parameters, dont prepend a ':' */
	if(parc == 3)
		rb_snprintf(ptr, sizeof(buffer) - cur_len, "%s", parv[2]);
	else
		rb_snprintf(ptr, sizeof(buffer) - cur_len, ":%s", parv[parc-1]);

	/* add a trailing \0 if it was too long */
	if((cur_len + len) >= BUFSIZE)
		buffer[BUFSIZE-1] = '\0';

	sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
			   "ENCAP %s", buffer);

	/* if it matches us, find a matching handler and call it */
	if(match(parv[1], me.name))
		handle_encap(client_p, source_p, parv[2], parc - 2, parv + 2);

	return 0;
}
Exemple #14
0
static void
db_error_cb(const char *errstr)
{
	char buf[256];
	rb_snprintf(buf, sizeof(buf), "! :%s", errstr);
	rb_helper_write(bandb_helper, "%s", buf);
	rb_sleep(2 << 30, 0);
	exit(1);
}
Exemple #15
0
static void
verify_logfile_access(const char *filename)
{
	char *dirname, *d;
	char buf[512];
	d = rb_dirname(filename);
	dirname = LOCAL_COPY(d);
	rb_free(d);
	
	if(access(dirname, F_OK) == -1)
	{
		rb_snprintf(buf, sizeof(buf), "WARNING: Unable to access logfile %s - parent directory %s does not exist", filename, dirname);
		if(testing_conf || server_state_foreground)
			fprintf(stderr, "%s\n", buf);
		sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s", buf);
		return;
	}

	if(access(filename, F_OK) == -1)
	{
		if(access(dirname, W_OK) == -1)
		{
			rb_snprintf(buf, sizeof(buf), "WARNING: Unable to access logfile %s - access to parent directory %s failed: %s", 
				    filename, dirname, strerror(errno));
			if(testing_conf || server_state_foreground)
				fprintf(stderr, "%s\n", buf);
			sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s", buf);
		}
		return;
	}
	
	if(access(filename, W_OK) == -1)
	{
		rb_snprintf(buf, sizeof(buf), "WARNING: Access denied for logfile %s: %s", filename, strerror(errno));
		if(testing_conf || server_state_foreground)
			fprintf(stderr, "%s\n", buf);	
		sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s", buf);
		return;
	}
	return;
}
Exemple #16
0
/*
 * get_listener_name - return displayable listener name and port
 * returns "host.foo.org:6667" for a given listener
 */
const char *
get_listener_name(const struct Listener *listener)
{
	static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];

	s_assert(NULL != listener);
	if(listener == NULL)
		return NULL;

	rb_snprintf(buf, sizeof(buf), "%s[%s/%u]",
			me.name, listener->name, get_listener_port(listener));
	return buf;
}
Exemple #17
0
const char *
smalldate(time_t ltime)
{
	static char buf[MAX_DATE_STRING];
	struct tm *lt;

	lt = localtime(&ltime);

	rb_snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
		    lt->tm_year + 1900, lt->tm_mon + 1,
		    lt->tm_mday, lt->tm_hour, lt->tm_min);

	return buf;
}
Exemple #18
0
void
server_reboot(void)
{
	char path[PATH_MAX + 1];

	sendto_realops_flags(UMODE_ALL, L_ALL, "Restarting server...");

	ilog(L_MAIN, "Restarting server...");

	/* set all the signal handlers to a dummy */
	setup_reboot_signals();
	/*
	 * XXX we used to call flush_connections() here. But since this routine
	 * doesn't exist anymore, we won't be flushing. This is ok, since 
	 * when close handlers come into existance, rb_close() will be called
	 * below, and the data flushing will be implicit.
	 *    -- adrian
	 *
	 * bah, for now, the program ain't coming back to here, so forcibly
	 * close everything the "wrong" way for now, and just LEAVE...
	 */
#ifndef _WIN32
	int i;
	for(i = 0; i < maxconnections; ++i)
		close(i);
#endif

	unlink(pidFileName);
#ifndef _WIN32
	int fd = open("/dev/null", O_RDWR);
	dup2(fd, 0);
	dup2(fd, 1);
	dup2(fd, 2);
#endif

	execv(SPATH, (void *)myargv);

	/* use this if execv of SPATH fails */
	rb_snprintf(path, sizeof(path), "%s/bin/ircd", ConfigFileEntry.dpath);

	execv(path, (void *)myargv);
	exit(-1);
}
Exemple #19
0
/*
 * get_listener_name - return displayable listener name and port
 * returns "host.foo.org:6667" for a given listener
 */
const char *
get_listener_name(const struct Listener *listener)
{
	static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];
	int port = 0;

	s_assert(NULL != listener);
	if(listener == NULL)
		return NULL;

#ifdef RB_IPV6
	if(listener->addr.ss_family == AF_INET6)
		port = ntohs(((const struct sockaddr_in6 *)&listener->addr)->sin6_port);
	else
#endif
		port = ntohs(((const struct sockaddr_in *)&listener->addr)->sin_port);	

	rb_snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name, listener->name, port);
	return buf;
}
Exemple #20
0
static int
change_nick(struct Client *client_p, const char *newnick)
{
	char note[NICKLEN + 10];

	client_p->tsinfo = rb_current_time();

	monitor_signoff(client_p);

	invalidate_bancache_user(client_p);

	sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
			"Forced nick change: From %s to %s [%s@%s]",
			client_p->name, newnick, client_p->username,
			client_p->host);

	sendto_common_channels_local(client_p, NOCAPS, ":%s!%s@%s NICK :%s",
				client_p->name, client_p->username,
				client_p->host, newnick);

	add_history(client_p, 1);
	sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
			use_id(client_p), newnick, (long) client_p->tsinfo);

	del_from_client_hash(client_p->name, client_p);
	strcpy(client_p->name, newnick);
	add_to_client_hash(client_p->name, client_p);

	monitor_signon(client_p);

	del_all_accepts(client_p);

	rb_snprintf(note, NICKLEN + 10, "Nick: %s", client_p->name);
	rb_note(client_p->localClient->F, note);
	return 0;
}
Exemple #21
0
static void
cap_req(struct Client *source_p, const char *arg)
{
	char buf[BUFSIZE];
	char pbuf[2][BUFSIZE];
	struct clicap *cap;
	int buflen, plen;
	int i = 0;
	int capadd = 0, capdel = 0;
	int finished = 0, negate;

	if(!IsRegistered(source_p))
		source_p->flags |= FLAGS_CLICAP;

	if(EmptyString(arg))
		return;

	buflen = rb_snprintf(buf, sizeof(buf), ":%s CAP %s ACK",
			me.name, EmptyString(source_p->name) ? "*" : source_p->name);

	pbuf[0][0] = '\0';
	plen = 0;

	for(cap = clicap_find(arg, &negate, &finished); cap;
	    cap = clicap_find(NULL, &negate, &finished))
	{
		/* filled the first array, but cant send it in case the
		 * request fails.  one REQ should never fill more than two
		 * buffers --fl
		 */
		if(buflen + plen + cap->namelen + 6 >= BUFSIZE)
		{
			pbuf[1][0] = '\0';
			plen = 0;
			i = 1;
		}

		if(negate)
		{
			if(cap->flags & CLICAP_FLAGS_STICKY)
			{
				finished = 0;
				break;
			}

			strcat(pbuf[i], "-");
			plen++;

			capdel |= cap->cap_serv;
		}
		else
		{
			if(cap->flags & CLICAP_FLAGS_STICKY)
			{
				strcat(pbuf[i], "=");
				plen++;
			}

			capadd |= cap->cap_serv;
		}

		if(cap->cap_cli)
		{
			strcat(pbuf[i], "~");
			plen++;
		}

		strcat(pbuf[i], cap->name);
		strcat(pbuf[i], " ");
		plen += (cap->namelen + 1);
	}

	if(!finished)
	{
		sendto_one(source_p, ":%s CAP %s NAK :%s",
			me.name, EmptyString(source_p->name) ? "*" : source_p->name, arg);
		return;
	}

	if(i)
	{
		sendto_one(source_p, "%s * :%s", buf, pbuf[0]);
		sendto_one(source_p, "%s :%s", buf, pbuf[1]);
	}
	else
		sendto_one(source_p, "%s :%s", buf, pbuf[0]);

	source_p->localClient->caps |= capadd;
	source_p->localClient->caps &= ~capdel;
}
Exemple #22
0
static int
accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
{
	struct Listener *listener = (struct Listener *)data;
	char buf[BUFSIZE];
	struct ConfItem *aconf;
	static time_t last_oper_notice = 0;
	int len;

	if(listener->ssl && (!ssl_ok || !get_ssld_count()))
	{
		rb_close(F);
		return 0;
	}

	if((maxconnections - 10) < rb_get_fd(F)) /* XXX this is kinda bogus */
	{
		++ServerStats.is_ref;
		/*
		 * slow down the whining to opers bit
		 */
		if((last_oper_notice + 20) <= rb_current_time())
		{
			sendto_realops_snomask(SNO_GENERAL, L_ALL,
					     "All connections in use. (%s)",
					     get_listener_name(listener));
			last_oper_notice = rb_current_time();
		}
			
		rb_write(F, "ERROR :All connections in use\r\n", 32);
		rb_close(F);
		/* Re-register a new IO request for the next accept .. */
		return 0;
	}

	aconf = find_dline(addr, addr->sa_family);
	if(aconf != NULL && (aconf->status & CONF_EXEMPTDLINE))
		return 1;
	
	/* Do an initial check we aren't connecting too fast or with too many
	 * from this IP... */
	if(aconf != NULL)
	{
		ServerStats.is_ref++;
			
		if(ConfigFileEntry.dline_with_reason)
		{
			len = rb_snprintf(buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", get_user_ban_reason(aconf));
			if (len >= (int)(sizeof(buf)-1))
			{
				buf[sizeof(buf) - 3] = '\r';
				buf[sizeof(buf) - 2] = '\n';
				buf[sizeof(buf) - 1] = '\0';
			}
		}
		else
			strcpy(buf, "ERROR :You have been D-lined.\r\n");
	
		rb_write(F, buf, strlen(buf));
		rb_close(F);
		return 0;
	}

	if(check_reject(F, addr))
		return 0;
		
	if(throttle_add(addr))
	{
		rb_write(F, toofast, strlen(toofast));
		rb_close(F);
		return 0;
	}

	return 1;
}
Exemple #23
0
static int
mo_testline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct ConfItem *aconf;
	struct ConfItem *resv_p;
	struct rb_sockaddr_storage ip;
	const char *name = NULL;
	const char *username = NULL;
	const char *host = NULL;
	char *mask;
	char *p;
	int host_mask;
	int type;

	mask = LOCAL_COPY(parv[1]);

	if(IsChannelName(mask))
	{
		resv_p = hash_find_resv(mask);
		if(resv_p != NULL)
		{
			sendto_one(source_p, form_str(RPL_TESTLINE),
				   me.name, source_p->name,
				   (resv_p->flags & CONF_FLAGS_TEMPORARY) ? 'q' : 'Q',
				   (resv_p->flags & CONF_FLAGS_TEMPORARY) ? (long)((resv_p->hold -
										    rb_current_time
										    ()) / 60) : 0L,
				   resv_p->host, resv_p->passwd);
			/* this is a false positive, so make sure it isn't counted in stats q
			 * --nenolod
			 */
			resv_p->port--;
		}
		else
			sendto_one(source_p, form_str(RPL_NOTESTLINE),
				   me.name, source_p->name, parv[1]);
		return 0;
	}

	if((p = strchr(mask, '!')))
	{
		*p++ = '\0';
		name = mask;
		mask = p;

		if(EmptyString(mask))
			return 0;
	}

	if((p = strchr(mask, '@')))
	{
		*p++ = '\0';
		username = mask;
		host = p;

		if(EmptyString(host))
			return 0;
	}
	else
		host = mask;

	/* parses as an IP, check for a dline */
	if((type = parse_netmask(host, (struct sockaddr *)&ip, &host_mask)) != HM_HOST)
	{
		aconf = find_dline((struct sockaddr *)&ip);

		if(aconf && aconf->status & CONF_DLINE)
		{
			sendto_one(source_p, form_str(RPL_TESTLINE),
				   me.name, source_p->name,
				   (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D',
				   (aconf->flags & CONF_FLAGS_TEMPORARY) ?
				   (long)((aconf->hold - rb_current_time()) / 60) : 0L,
				   aconf->host, aconf->passwd);

			return 0;
		}
	}

	/* now look for a matching I/K/G */
	if((aconf = find_address_conf(host, NULL, username ? username : "******",
				      (type != HM_HOST) ? (struct sockaddr *)&ip : NULL,
				      (type != HM_HOST) ? (
#ifdef RB_IPV6
										(type ==
										 HM_IPV6) ? AF_INET6
										:
#endif
										AF_INET) : 0)))
	{
		static char buf[HOSTLEN + USERLEN + 2];

		if(aconf->status & CONF_KILL)
		{
			rb_snprintf(buf, sizeof(buf), "%s@%s", aconf->user, aconf->host);
			sendto_one(source_p, form_str(RPL_TESTLINE),
				   me.name, source_p->name,
				   (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K',
				   (aconf->flags & CONF_FLAGS_TEMPORARY) ?
				   (long)((aconf->hold - rb_current_time()) / 60) : 0L,
				   buf, aconf->passwd);
			return 0;
		}
		else if(aconf->status & CONF_GLINE)
		{
			rb_snprintf(buf, sizeof(buf), "%s@%s", aconf->user, aconf->host);
			sendto_one(source_p, form_str(RPL_TESTLINE),
				   me.name, source_p->name,
				   'G', (long)((aconf->hold - rb_current_time()) / 60),
				   buf, aconf->passwd);
			return 0;
		}
	}

	/* they asked us to check a nick, so hunt for resvs.. */
	if(name && (resv_p = find_nick_resv(name)))
	{
		sendto_one(source_p, form_str(RPL_TESTLINE),
			   me.name, source_p->name,
			   (resv_p->flags & CONF_FLAGS_TEMPORARY) ? 'q' : 'Q',
			   (resv_p->flags & CONF_FLAGS_TEMPORARY) ? (long)((resv_p->hold -
									    rb_current_time()) /
									   60) : 0L, resv_p->host,
			   resv_p->passwd);

		/* this is a false positive, so make sure it isn't counted in stats q
		 * --nenolod
		 */
		resv_p->port--;
		return 0;
	}

	/* no matching resv, we can print the I: if it exists */
	if(aconf && aconf->status & CONF_CLIENT)
	{
		sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
				   aconf->info.name, show_iline_prefix(source_p, aconf,
								       aconf->user), aconf->host,
				   aconf->port, get_class_name(aconf));
		return 0;
	}

	/* nothing matches.. */
	sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]);
	return 0;
}
Exemple #24
0
void
rb_get_ssl_info(char *buf, size_t len)
{
        rb_snprintf(buf, len, "Not compiled with SSL support"); 
}
Exemple #25
0
static int
mo_testline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct ConfItem *aconf;
	struct ConfItem *resv_p;
	struct rb_sockaddr_storage ip;
	char user_trunc[USERLEN + 1], notildeuser_trunc[USERLEN + 1];
	const char *name = NULL;
	const char *username = NULL;
	const char *host = NULL;
	char *mask;
	char *p;
	int host_mask;
	int type;
	int duration;
	char *puser, *phost, *reason, *operreason;
	char reasonbuf[BUFSIZE];

	mask = LOCAL_COPY(parv[1]);

	if (IsChannelName(mask))
	{
		resv_p = hash_find_resv(mask);
		if (resv_p != NULL)
		{
			sendto_one(source_p, form_str(RPL_TESTLINE),
					me.name, source_p->name,
					resv_p->hold ? 'q' : 'Q',
					resv_p->hold ? (long) ((resv_p->hold - rb_current_time()) / 60) : 0L,
					resv_p->host, resv_p->passwd);
			/* this is a false positive, so make sure it isn't counted in stats q
			 * --nenolod
			 */
			resv_p->port--;
		}
		else
			sendto_one(source_p, form_str(RPL_NOTESTLINE),
					me.name, source_p->name, parv[1]);
		return 0;
	}

	if((p = strchr(mask, '!')))
	{
		*p++ = '\0';
		name = mask;
		mask = p;

		if(EmptyString(mask))
			return 0;
	}

	if((p = strchr(mask, '@')))
	{
		*p++ = '\0';
		username = mask;
		host = p;

		if(EmptyString(host))
			return 0;
	}
	else
		host = mask;

	/* parses as an IP, check for a dline */
	if((type = parse_netmask(host, (struct sockaddr *)&ip, &host_mask)) != HM_HOST)
	{
#ifdef RB_IPV6
		if(type == HM_IPV6)
			aconf = find_dline((struct sockaddr *)&ip, AF_INET6);
		else
#endif
			aconf = find_dline((struct sockaddr *)&ip, AF_INET);

		if(aconf && aconf->status & CONF_DLINE)
		{
			get_printable_kline(source_p, aconf, &phost, &reason, &puser, &operreason);
			rb_snprintf(reasonbuf, sizeof(reasonbuf), "%s%s%s", reason,
				operreason ? "|" : "", operreason ? operreason : "");
			sendto_one(source_p, form_str(RPL_TESTLINE),
				me.name, source_p->name,
				(aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D',
				(aconf->flags & CONF_FLAGS_TEMPORARY) ? 
				 (long) ((aconf->hold - rb_current_time()) / 60) : 0L, 
				phost, reasonbuf);

			return 0;
		}
		/* Otherwise, aconf is an exempt{} */
		if(aconf == NULL &&
				(duration = is_reject_ip((struct sockaddr *)&ip)))
			sendto_one(source_p, form_str(RPL_TESTLINE),
					me.name, source_p->name,
					'!',
					duration / 60L,
					host, "Reject cache");
		if(aconf == NULL &&
				(duration = is_throttle_ip((struct sockaddr *)&ip)))
			sendto_one(source_p, form_str(RPL_TESTLINE),
					me.name, source_p->name,
					'!',
					duration / 60L,
					host, "Throttled");
	}

	if (username != NULL)
	{
		rb_strlcpy(user_trunc, username, sizeof user_trunc);
		rb_strlcpy(notildeuser_trunc, *username == '~' ? username + 1 : username, sizeof notildeuser_trunc);
	}
	else
	{
		rb_strlcpy(user_trunc, "dummy", sizeof user_trunc);
		rb_strlcpy(notildeuser_trunc, "dummy", sizeof notildeuser_trunc);
	}
	/* now look for a matching I/K/G */
	if((aconf = find_address_conf(host, NULL, user_trunc, notildeuser_trunc,
				(type != HM_HOST) ? (struct sockaddr *)&ip : NULL,
				(type != HM_HOST) ? (
#ifdef RB_IPV6
				 (type == HM_IPV6) ? AF_INET6 : 
#endif
				  AF_INET) : 0, NULL)))
	{
		static char buf[HOSTLEN+USERLEN+2];

		if(aconf->status & CONF_KILL)
		{
			get_printable_kline(source_p, aconf, &phost, &reason, &puser, &operreason);
			rb_snprintf(buf, sizeof(buf), "%s@%s", 
					puser, phost);
			rb_snprintf(reasonbuf, sizeof(reasonbuf), "%s%s%s", reason,
				operreason ? "|" : "", operreason ? operreason : "");
			sendto_one(source_p, form_str(RPL_TESTLINE),
				me.name, source_p->name,
				(aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K',
				(aconf->flags & CONF_FLAGS_TEMPORARY) ? 
				 (long) ((aconf->hold - rb_current_time()) / 60) : 0L,
				buf, reasonbuf);
			return 0;
		}
	}

	/* they asked us to check a nick, so hunt for resvs.. */
	if(name && (resv_p = find_nick_resv(name)))
	{
		sendto_one(source_p, form_str(RPL_TESTLINE),
				me.name, source_p->name,
				resv_p->hold ? 'q' : 'Q',
				resv_p->hold ? (long) ((resv_p->hold - rb_current_time()) / 60) : 0L,
				resv_p->host, resv_p->passwd);

		/* this is a false positive, so make sure it isn't counted in stats q
		 * --nenolod
		 */
		resv_p->port--;
		return 0;
	}

	/* no matching resv, we can print the I: if it exists */
	if(aconf && aconf->status & CONF_CLIENT)
	{
		sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
				aconf->info.name, EmptyString(aconf->spasswd) ? "<NULL>" : aconf->spasswd,
				show_iline_prefix(source_p, aconf, aconf->user),
				aconf->host, aconf->port, aconf->className);
		return 0;
	}

	/* nothing matches.. */
	sendto_one(source_p, form_str(RPL_NOTESTLINE),
			me.name, source_p->name, parv[1]);
	return 0;
}
Exemple #26
0
void
rb_get_ssl_info(char *buf, size_t len)
{
    rb_snprintf(buf, len, "GNUTLS: compiled (%s), library(%s)",
                LIBGNUTLS_VERSION, gnutls_check_version(NULL));
}
Exemple #27
0
static int
m_displaymsg(struct Client *source_p, const char *channel, int underline, int action, const char *nick, const char *text)
{
	struct Channel *chptr;
	struct membership *msptr;
	char nick2[NICKLEN+1];
	char *nick3 = rb_strdup(nick);
	char text2[BUFSIZE];

	if((chptr = find_channel(channel)) == NULL)
	{
		sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), channel);
		return 0;
	}

	if(!(msptr = find_channel_membership(chptr, source_p)))
	{
		sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
				   form_str(ERR_NOTONCHANNEL), chptr->chname);
		return 0;
	}

	if(!(chptr->mode.mode & chmode_flags['N']))
	{
		sendto_one_numeric(source_p, 573, "%s :Roleplay commands are not enabled on this channel.", chptr->chname);
		return 0;
	}

	if(!can_send(chptr, source_p, msptr))
	{
		sendto_one_numeric(source_p, 573, "%s :Cannot send to channel.", chptr->chname);
		return 0;
	}

	/* enforce flood stuff on roleplay commands */
	if(flood_attack_channel(0, source_p, chptr, chptr->chname))
		return 0;

	/* enforce target change on roleplay commands */
	if(!is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr))
	{
		sendto_one(source_p, form_str(ERR_TARGCHANGE),
			   me.name, source_p->name, chptr->chname);
		return 0;
	}

	if(underline)
		rb_snprintf(nick2, sizeof(nick2), "\x1F%s\x1F", strip_unprintable(nick3));
	else
		rb_snprintf(nick2, sizeof(nick2), "%s", strip_unprintable(nick3));

	/* don't allow nicks to be empty after stripping
	 * this prevents nastiness like fake factions, etc. */
	if(EmptyString(nick3))
	{
		sendto_one_numeric(source_p, 573, "%s :No visible non-stripped characters in nick.", chptr->chname);
		return 0;
	}

	if(action)
		rb_snprintf(text2, sizeof(text2), "\1ACTION %s\1", text);
	else
		rb_snprintf(text2, sizeof(text2), "%s", text);

	sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%[email protected] PRIVMSG %s :%s (%s)", nick2, source_p->name, channel, text2, source_p->name); 
	sendto_match_servs(source_p, "*", CAP_ENCAP, NOCAPS, "ENCAP * ROLEPLAY %s %s :%s",
			channel, nick2, text2);
	return 0;
}
Exemple #28
0
/*
** m_kick
**      parv[1] = channel
**      parv[2] = client to kick
**      parv[3] = kick comment
*/
static int
m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct membership *msptr;
	struct Client *who;
	struct Channel *chptr;
	int chasing = 0;
	char *comment;
	const char *name;
	char *p = NULL;
	char text[10];
	const char *user;
	static char buf[BUFSIZE];
	int is_override = 0;

	if(MyClient(source_p) && !IsFloodDone(source_p))
		flood_endgrace(source_p);

	*buf = '\0';
	if((p = strchr(parv[1], ',')))
		*p = '\0';

	name = parv[1];

	chptr = find_channel(name);
	if(chptr == NULL)
	{
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
		return 0;
	}

	user = parv[2];		/* strtoken(&p2, parv[2], ","); */

	if(!(who = find_chasing(source_p, user, &chasing)))
	{
		return 0;
	}

	if(!IsServer(source_p))
	{
		msptr = find_channel_membership(chptr, source_p);

		if((msptr == NULL) && MyConnect(source_p))
		{
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					   form_str(ERR_NOTONCHANNEL), name);
			return 0;
		}

		if(!can_kick_deop(msptr, find_channel_membership(chptr, who)))
		{
			if(MyConnect(source_p))
			{
				if(IsOverride(source_p))
					is_override = 1;
				else
				{
					sendto_one(source_p, ":%s 482 %s %s :You do not have the proper privileges to kick this user",
							me.name, source_p->name, name);
					return 0;
				}
			}

			/* If its a TS 0 channel, do it the old way */
			else if(chptr->channelts == 0)
			{
				sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
					   get_id(&me, source_p), get_id(source_p, source_p), name);
				return 0;
			}
		}

		/* Its a user doing a kick, but is not showing as chanop locally
		 * its also not a user ON -my- server, and the channel has a TS.
		 * There are two cases we can get to this point then...
		 *
		 *     1) connect burst is happening, and for some reason a legit
		 *        op has sent a KICK, but the SJOIN hasn't happened yet or 
		 *        been seen. (who knows.. due to lag...)
		 *
		 *     2) The channel is desynced. That can STILL happen with TS
		 *        
		 *     Now, the old code roger wrote, would allow the KICK to 
		 *     go through. Thats quite legit, but lets weird things like
		 *     KICKS by users who appear not to be chanopped happen,
		 *     or even neater, they appear not to be on the channel.
		 *     This fits every definition of a desync, doesn't it? ;-)
		 *     So I will allow the KICK, otherwise, things are MUCH worse.
		 *     But I will warn it as a possible desync.
		 *
		 *     -Dianora
		 */
	}

	if((p = strchr(parv[2], ',')))
		*p = '\0';

	msptr = find_channel_membership(chptr, who);

	if(msptr != NULL)
	{
		if(MyClient(source_p) && IsService(who))
		{
			sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
				   me.name, source_p->name, who->name, chptr->chname);
			return 0;
		}

		if(MyClient(source_p) && chptr->mode.mode & MODE_NOKICK)
		{
			sendto_one_numeric(source_p, ERR_NOKICK,
					form_str(ERR_NOKICK),
					chptr->chname);
			return 0;
		}

		if (MyClient(source_p) && chptr->mode.mode & MODE_NOOPERKICK && IsOper(who))
		{
			sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
					"Overriding KICK from %s on %s in %s (channel is +M)",
					source_p->name, who->name, chptr->chname);
			sendto_one_numeric(source_p, ERR_ISCHANSERVICE,
					"%s %s :Cannot kick IRC operators from that channel.",
					who->name, chptr->chname);
			return 0;
		}

		if(MyClient(source_p))
		{
			hook_data_channel_approval hookdata;

			hookdata.client = source_p;
			hookdata.chptr = chptr;
			hookdata.target = who;
			hookdata.approved = 1;

			call_hook(h_can_kick, &hookdata);

			if (!hookdata.approved)
				return 0;
		}

		comment = LOCAL_COPY((EmptyString(parv[3])) ? who->name : parv[3]);
		if(strlen(comment) > (size_t) REASONLEN)
			comment[REASONLEN] = '\0';

		if(is_override)
		{
			sendto_wallops_flags(UMODE_WALLOP, &me,
					"%s is overriding KICK [%s] on [%s] [%s]",
					get_oper_name(source_p), who->name, chptr->chname, comment);
			sendto_server(NULL, chptr, NOCAPS, NOCAPS,
					":%s WALLOPS :%s is overriding KICK [%s] on [%s] [%s]",
					me.name, get_oper_name(source_p), who->name, chptr->chname, comment);
		}

		/* jdc
		 * - In the case of a server kicking a user (i.e. CLEARCHAN),
		 *   the kick should show up as coming from the server which did
		 *   the kick.
		 * - Personally, flame and I believe that server kicks shouldn't
		 *   be sent anyways.  Just waiting for some oper to abuse it...
		 */
		if(IsServer(source_p))
			sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
					     source_p->name, name, who->name, comment);
		else
			sendto_channel_local(ALL_MEMBERS, chptr,
					     ":%s!%s@%s KICK %s %s :%s",
					     source_p->name, source_p->username,
					     source_p->host, name, who->name, comment);

		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s KICK %s %s :%s",
			      use_id(source_p), chptr->chname, use_id(who), comment);
		remove_user_from_channel(msptr);

		rb_snprintf(text, sizeof(text), "K%s", who->id);

		/* we don't need to track NOREJOIN stuff unless it's our client being kicked */
		if(MyClient(who) && chptr->mode.mode & MODE_NOREJOIN)
			channel_metadata_time_add(chptr, text, rb_current_time(), "KICKNOREJOIN");
	}
	else if (MyClient(source_p))
		sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
				   form_str(ERR_USERNOTINCHANNEL), user, name);

	return 0;
}
Exemple #29
0
static int
me_svslogin(struct Client *client_p, struct Client *source_p,
            int parc, const char *parv[])
{
    struct Client *target_p, *exist_p;
    char nick[NICKLEN+1], login[NICKLEN+1];
    char user[USERLEN+1], host[HOSTLEN+1];
    int valid = 0;

    if(!(source_p->flags & FLAGS_SERVICE))
        return 0;

    if((target_p = find_client(parv[1])) == NULL)
        return 0;

    if(!MyClient(target_p) && !IsUnknown(target_p))
        return 0;

    if(clean_nick(parv[2])) {
        rb_strlcpy(nick, parv[2], NICKLEN + 1);
        valid |= NICK_VALID;
    } else if(*target_p->name)
        rb_strlcpy(nick, target_p->name, NICKLEN + 1);
    else
        strcpy(nick, "*");

    if(clean_username(parv[3])) {
        rb_strlcpy(user, parv[3], USERLEN + 1);
        valid |= USER_VALID;
    } else
        rb_strlcpy(user, target_p->username, USERLEN + 1);

    if(clean_host(parv[4])) {
        rb_strlcpy(host, parv[4], HOSTLEN + 1);
        valid |= HOST_VALID;
    } else
        rb_strlcpy(host, target_p->host, HOSTLEN + 1);

    if(*parv[5] == '*') {
        if(target_p->user)
            rb_strlcpy(login, target_p->user->suser, NICKLEN + 1);
        else
            login[0] = '\0';
    } else if(!strcmp(parv[5], "0"))
        login[0] = '\0';
    else
        rb_strlcpy(login, parv[5], NICKLEN + 1);

    /* Login (mostly) follows nick rules. */
    if(*login && !clean_nick(login))
        return 0;

    if((exist_p = find_person(nick)) && target_p != exist_p) {
        char buf[BUFSIZE];

        if(MyClient(exist_p))
            sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)",
                       me.name, exist_p->name);

        exist_p->flags |= FLAGS_KILLED;
        kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)",
                                me.name);

        rb_snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
                    me.name);
        exit_client(NULL, exist_p, &me, buf);
    } else if((exist_p = find_client(nick)) && IsUnknown(exist_p) && exist_p != target_p) {
        exit_client(NULL, exist_p, &me, "Overridden");
    }

    if(*login) {
        /* Strip leading digits, unless it's purely numeric. */
        const char *p = login;
        while(IsDigit(*p))
            p++;
        if(!*p)
            p = login;

        sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
                   nick, user, host, p, p);
    } else
        sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
                   nick, user, host);

    if(IsUnknown(target_p)) {
        struct User *user_p = make_user(target_p);

        if(valid & NICK_VALID)
            strcpy(target_p->preClient->spoofnick, nick);

        if(valid & USER_VALID)
            strcpy(target_p->preClient->spoofuser, user);

        if(valid & HOST_VALID)
            strcpy(target_p->preClient->spoofhost, host);

        rb_strlcpy(user_p->suser, login, NICKLEN + 1);
    } else {
        char note[NICKLEN + 10];

        send_signon(NULL, target_p, nick, user, host, rb_current_time(), login);

        rb_snprintf(note, NICKLEN + 10, "Nick: %s", target_p->name);
        rb_note(target_p->localClient->F, note);
    }

    return 0;
}
Exemple #30
0
/*
** m_okick
**      parv[1] = channel
**      parv[2] = client to kick
**      parv[3] = kick comment
*/
static int
mo_okick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Client *who;
	struct Client *target_p;
	struct Channel *chptr;
	struct membership *msptr;
	int chasing = 0;
	char *comment;
	char *name;
	char *p = NULL;
	char *user;
	char text[10];
	static char buf[BUFSIZE];

	if(*parv[2] == '\0')
	{
		sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "KICK");
		return 0;
	}

	if(MyClient(source_p) && !IsFloodDone(source_p))
		flood_endgrace(source_p);

	comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]);
	if(strlen(comment) > (size_t) TOPICLEN)
		comment[TOPICLEN] = '\0';

	*buf = '\0';
	if((p = strchr(parv[1], ',')))
		*p = '\0';

	name = LOCAL_COPY(parv[1]);

	chptr = find_channel(name);
	if(!chptr)
	{
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
		return 0;
	}


	if((p = strchr(parv[2], ',')))
		*p = '\0';
	user = LOCAL_COPY(parv[2]);	// strtoken(&p2, parv[2], ","); 
	if(!(who = find_chasing(source_p, user, &chasing)))
	{
		return 0;
	}

	if((target_p = find_client(user)) == NULL)
	{
		sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, user);
		return 0;
	}

	if((msptr = find_channel_membership(chptr, target_p)) == NULL)
	{
		sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
			   me.name, source_p->name, parv[1], parv[2]);
		return 0;
	}

	sendto_realops_snomask(SNO_GENERAL, L_ALL,
			       "OKICK called for %s %s by %s!%s@%s",
			       chptr->chname, target_p->name,
			       source_p->name, source_p->username, source_p->host);
	ilog(L_MAIN, "OKICK called for %s %s by %s",
	     chptr->chname, target_p->name,
	     get_oper_name(source_p));

	sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
			     me.name, chptr->chname, who->name, comment);
	sendto_server(&me, chptr, CAP_TS6, NOCAPS,
		      ":%s KICK %s %s :%s", me.id, chptr->chname, who->id, comment);
	remove_user_from_channel(msptr);

	rb_snprintf(text, sizeof(text), "K%s", who->id);

	/* we don't need to track NOREJOIN stuff unless it's our client being kicked */
	if(MyClient(who) && chptr->mode.mode & MODE_NOREJOIN)
		channel_metadata_time_add(chptr, text, rb_current_time(), "KICKNOREJOIN");
	return 0;
}