char fakehost[HOSTLEN+1];
char *ident;
- /* nick/ident section: return 0 (no match) if they don't match */
+ /* If it's not valid, don't bother */
if (bp->flags & CHANBAN_INVALID)
return 0;
+ /* nick/ident section: return 0 (no match) if they don't match */
+
/* Pick up the visible username. If a sethost username is set, the real
* username is not checked. */
ident=np->ident;
if (bp->flags & CHANBAN_HOSTANY)
return 1;
+
+ /* "visibleonly" means don't check IP/realhost if they are sethosted/+x.
+ * We change this to mean "Don't check IP/realhost unconditionally" - by
+ * clearing it to 0 if the user isn't sethosted or +x. Simplifies logic
+ * later. */
+
+ if (!(IsSetHost(np) || (IsAccount(np) && IsHideHost(np))))
+ visibleonly=0;
- if ((bp->flags & CHANBAN_IP) && !(visibleonly && (IsSetHost(np) || (IsAccount(np) && IsHideHost(np))))) {
+ if ((bp->flags & CHANBAN_IP) && !visibleonly) {
if (ipmask_check(&(np->ipnode->prefix->sin), &(bp->ipaddr), bp->prefixlen))
return 1;
}
/* Hostname bans need to be checked against +x host, +h host (if set)
* and actual host. Note that the +x host is only generated (and checked) if it's
- * possible for the ban to match a hidden host.. */
+ * possible for the ban to match a hidden host. And it's checked regardless
+ * of whether the user is actually +x. */
if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) {
sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST);
/* If we are only checking visible host and the host is somehow masked, don't check
* against the real one. */
- if (visibleonly && (IsSetHost(np) || (IsAccount(np) && IsHideHost(np))))
+ if (visibleonly)
return 0;
if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content))
if (!(trup=findreguser(sender, cargv[arg])))
return CMD_ERROR;
- /* don't allow non-opers to view oper auth history, but allow helpers to view non-oper history */
- if ((trup != rup) && ((UHasOperPriv(trup) && !UHasOperPriv(rup)) || !UHasHelperPriv(rup))) {
- chanservstdmessage(sender, QM_NOACCESSONUSER, "authhistory", cargv[arg]);
- return CMD_ERROR;
+ /* if target != command issuer */
+ if (trup != rup) {
+ /* only opers and helpers can view authhistory of other users */
+ if (!UHasHelperPriv(rup)) {
+ chanservstdmessage(sender, QM_NOACCESSONUSER, "authhistory", cargv[arg]);
+ return CMD_ERROR;
+ }
+
+ /* and only opers can view opers history */
+ if (UHasOperPriv(trup) && !UHasOperPriv(rup)) {
+ chanservwallmessage("%s (%s) just FAILED using AUTHHISTORY on %s", sender->nick, rup->username, trup->username);
+ chanservstdmessage(sender, QM_NOACCESSONUSER, "authhistory", cargv[arg]);
+ return CMD_ERROR;
+ }
+
+ /* checks passed */
+ chanservwallmessage("%s (%s) used AUTHHISTORY on %s", sender->nick, rup->username, trup->username);
}
} else {
trup=rup;
}
-
+
csdb_retreiveauthhistory(sender, trup, limit);
return CMD_OK;
void _init() {
authtrackerdb = dbgetid();
+ chanservaddcommand("dumpauthtracker",QCMD_DEV,1,at_dumpdb,"Shows servers with dangling authtracker entries.\n","");
at_finddanglingsessions();
}
void _fini() {
at_hookfini();
nsfreeall(POOL_AUTHTRACKER);
+
+ chanservremovecommand("dumpauthtracker",at_dumpdb);
dbfreeid(authtrackerdb);
}
int at_foundnick(unsigned int numeric, unsigned long userid, time_t accountts);
void at_serverback(unsigned int server);
void at_flushghosts();
+int at_dumpdb(void *source, int argc, char **argv);
/* authtracker_hooks.c */
unsigned long at_getuserid(nick *np);
*/
#include "authtracker.h"
+#include "../chanserv.h"
#include "../../core/nsmalloc.h"
#include "../../server/server.h"
#include "../../irc/irc_config.h"
at_serverback(i);
}
}
+
+int at_dumpdb(void *source, int argc, char **argv) {
+ nick *np=source;
+ struct dangling_entry *dep;
+ unsigned int i,j,k;
+
+ for(i=0;i<MAXSERVERS;i++) {
+ if (ds[i]) {
+ k=0;
+ for(j=0;j<DANGLING_HASHSIZE;j++) {
+ for (dep=ds[i]->de[j];dep;dep=dep->next) {
+ k++;
+ }
+ }
+ chanservsendmessage(np, "Server %d (%s) has %d entries.",i,longtonumeric(i,2),k);
+ }
+ }
+
+ chanservstdmessage(np,QM_ENDOFLIST);
+
+ return CMD_OK;
+}
\ No newline at end of file
continue;
}
- localinvite(chanservnick, rcup->chan->index->channel, sender);
+ localinvite(chanservnick, rcup->chan->index, sender);
}
chanservstdmessage(sender, QM_DONE);
return CMD_ERROR;
if (cip->channel) {
- localinvite(chanservnick, cip->channel, sender);
+ localinvite(chanservnick, cip, sender);
}
chanservstdmessage(sender, QM_DONE);
}
}
-
localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick);
if (*lp & CUMODE_OP) {
if (!IsService(np) && (CUIsDeny(rcup) || (CIsBitch(rcup->chan) && !CUHasOpPriv(rcup))))
} else {
/* Channel exists but user is not joined: invite if they are +j-b */
if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
- localinvite(chanservnick, rcup->chan->index->channel, np);
+ localinvite(chanservnick, rcup->chan->index, np);
}
}
- }
- }
+ } /* if (rcup->chan->index->channel) */ else {
+ /* Channel doesn't currently exist - send invite anyway for +j */
+ if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
+ localinvite(chanservnick, rcup->chan->index, np);
+ }
+ }
+ } /* for */
}
void cs_checknickbans(nick *np) {
}
}
+ if (target->away) {
+ controlreply((nick *)sender, "Away : %s",target->away->content);
+ }
+
hooknick=(nick *)sender;
registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
triggerhook(HOOK_CONTROL_WHOISREQUEST,target);
if (hchan->flags & H_PASSIVE)
return;
- localinvite(helpmodnick, hchan->real_channel, husr->real_user);
+ localinvite(helpmodnick, hchan->real_channel->index, husr->real_user);
}
static void hmode_set_channel(hchannel *hchan)
#define TOPICLEN 250
#define CHANNELLEN 200
#define KEYLEN 23
+#define AWAYLEN 160
#define MAXSERVERS 4096
newuser->timestamp=getnettime();
newuser->shident=NULL;
newuser->sethost=NULL;
+ newuser->away=NULL;
newuser->marker=0;
memset(newuser->exts, 0, MAXNICKEXTS * sizeof(void *));
}
}
-void localinvite(nick *source, channel *cp, nick *target) {
+void localinvite(nick *source, chanindex *cip, nick *target) {
/* Servers can't send invites */
if (!source)
* argument */
if (connected) {
irc_send("%s I %s :%s",longtonumeric(source->numeric,5),
- target->nick, cp->index->name->content);
+ target->nick, cip->name->content);
}
}
void localusermodechange(nick *np, channel *cp, char *modes);
void sendmessagetochannel(nick *source, channel *cp, char *format, ... ) __attribute__ ((format (printf, 3, 4)));
void sendopnoticetochannel(nick *source, channel *cp, char *format, ... ) __attribute__ ((format (printf, 3, 4)));
-void localinvite(nick *source, channel *cp, nick *target);
+void localinvite(nick *source, chanindex *cip, nick *target);
void localsetmodeinit (modechanges *changes, channel *cp, nick *np);
void localdosetmode_nick (modechanges *changes, nick *target, short modes);
if(!cp)
LUA_RETURN(ps, LUA_FAIL);
- localinvite(lua_nick, cp, np);
+ localinvite(lua_nick, cp->index, np);
LUA_RETURN(ps, LUA_OK);
}
.PHONY: all clean distclean
all: newsearch.so
-NSCOMMANDS=ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-cumodecount.o ns-cumodepct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o ns-authid.o ns-notice.o newsearch_ast.o ns-any.o ns-channeliter.o ns-var.o ns-all.o ns-cumodes.o ns-cidr.o ns-nickiter.o ns-ipv6.o
+NSCOMMANDS=ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-away.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-cumodecount.o ns-cumodepct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o ns-authid.o ns-notice.o newsearch_ast.o ns-any.o ns-channeliter.o ns-var.o ns-all.o ns-cumodes.o ns-cidr.o ns-nickiter.o ns-ipv6.o
@ifeq@${NEWSEARCH_NEWPARSER}@ifeqsep@1@ifeqend@
CFLAGS+=-DNEWSEARCH_NEWPARSER=1
/* Nickname operations */
registersearchterm(reg_nicksearch, "hostmask",hostmask_parse, 0, "The user's nick!user@host; \"hostmask real\" returns nick!user@host\rreal"); /* nick only */
registersearchterm(reg_nicksearch, "realname",realname_parse, 0, "User's current realname"); /* nick only */
+ registersearchterm(reg_nicksearch, "away",away_parse, 0, "User's current away message"); /* nick only */
registersearchterm(reg_nicksearch, "authname",authname_parse, 0, "User's current authname or false"); /* nick only */
registersearchterm(reg_nicksearch, "authts",authts_parse, 0, "User's Auth timestamp"); /* nick only */
registersearchterm(reg_nicksearch, "ident",ident_parse, 0, "User's current ident"); /* nick only */
/* Nick functions (various types) */
struct searchNode *hostmask_parse(searchCtx *ctx, int argc, char **argv);
struct searchNode *realname_parse(searchCtx *ctx, int argc, char **argv);
+struct searchNode *away_parse(searchCtx *ctx, int argc, char **argv);
struct searchNode *authname_parse(searchCtx *ctx, int argc, char **argv);
struct searchNode *authts_parse(searchCtx *ctx, int argc, char **argv);
struct searchNode *ident_parse(searchCtx *ctx, int argc, char **argv);
--- /dev/null
+/*
+ * AWAY functionality
+ */
+
+#include "newsearch.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *away_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput);
+void away_free(searchCtx *ctx, struct searchNode *thenode);
+
+struct searchNode *away_parse(searchCtx *ctx, int argc, char **argv) {
+ struct searchNode *thenode;
+
+ if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
+ parseError = "malloc: could not allocate memory for this search.";
+ return NULL;
+ }
+
+ thenode->returntype = RETURNTYPE_STRING;
+ thenode->localdata = NULL;
+ thenode->exe = away_exe;
+ thenode->free = away_free;
+
+ return thenode;
+}
+
+void *away_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) {
+ nick *np = (nick *)theinput;
+
+ return (np->away) ? np->away->content : "";
+}
+
+void away_free(searchCtx *ctx, struct searchNode *thenode) {
+ free(thenode);
+}
+
registerserverhandler("AC",&handleaccountmsg,4);
registerserverhandler("R",&handlestatsmsg,2);
registerserverhandler("P",&handleprivmsg,2);
+ registerserverhandler("A",&handleawaymsg,1);
/* Fake the addition of our own server */
handleserverchange(HOOK_SERVER_NEWSERVER,(void *)numerictolong(mynumeric->content,2));
deregisterserverhandler("AC",&handleaccountmsg);
deregisterserverhandler("R",&handlestatsmsg);
deregisterserverhandler("P",&handleprivmsg);
+ deregisterserverhandler("A",&handleawaymsg);
}
/*
authname *auth; /* This requires User ID numbers to work */
time_t timestamp;
time_t accountts;
+ sstring *away;
patricia_node_t *ipnode;
unsigned int marker;
struct nick *next;
int handleaccountmsg(void *source, int cargc, char **cargv);
int handlestatsmsg(void *source, int cargc, char **cargv);
int handleprivmsg(void *source, int cargc, char **cargv);
+int handleawaymsg(void *source, int cargc, char **cargv);
/* These functions have been replaced by macros
nick **gethandlebynumeric(long numeric);
np->ipnode = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
node_increment_usercount(np->ipnode);
+ np->away=NULL;
np->shident=NULL;
np->sethost=NULL;
np->opername=NULL;
return CMD_OK;
}
+int handleawaymsg(void *source, int cargc, char **cargv) {
+ nick *sender;
+
+ /* Check source is a valid user */
+ if (!(sender=getnickbynumericstr(source))) {
+ return CMD_OK;
+ }
+
+ /* Done with the old away message either way */
+ freesstring(sender->away);
+ sender->away=NULL;
+
+ /* If we have an arg and it isn't an empty string, this sets a new message */
+ if (cargc > 0 && *(cargv[0])) {
+ sender->away=getsstring(cargv[0], AWAYLEN);
+ }
+
+ return CMD_OK;
+}
LDFLAGS+=$(LIBDBAPI)
.PHONY: all
-all: proxyscan.so
+all: proxyscan.so proxyscan_newsearch.so
proxyscan.so: proxyscan.o proxyscanext.o proxyscanalloc.o proxyscanconnect.o proxyscancache.o proxyscanqueue.o proxyscanhandlers.o proxyscandb.o
+
+proxyscan_newsearch.so: proxyscan_newsearch.o pns-scan.o
--- /dev/null
+/*
+ * pscan functionality
+ */
+
+#include "../newsearch/newsearch.h"
+#include "proxyscan.h"
+
+#include <stdlib.h>
+
+void *pscan_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput);
+void pscan_free(searchCtx *ctx, struct searchNode *thenode);
+
+struct searchNode *pscan_parse(searchCtx *ctx, int argc, char **argv) {
+ struct searchNode *thenode;
+
+ if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
+ parseError = "malloc: could not allocate memory for this search.";
+ return NULL;
+ }
+
+ thenode->returntype = RETURNTYPE_BOOL;
+ thenode->exe = pscan_exe;
+ thenode->free = pscan_free;
+ thenode->localdata = (void *)0;
+
+ return thenode;
+}
+
+void *pscan_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) {
+ startnickscan((nick *)theinput);
+ thenode->localdata = (void *)((int)thenode->localdata + 1);
+ return (void *)1;
+}
+
+void pscan_free(searchCtx *ctx, struct searchNode *thenode) {
+ ctx->reply(senderNSExtern, "proxyscan now scanning: %d nick(s).", (int)thenode->localdata);
+ free(thenode);
+}
+
/* Default scan types */
proxyscan_addscantype(STYPE_HTTP, 8080);
+ proxyscan_addscantype(STYPE_HTTP, 8118);
proxyscan_addscantype(STYPE_HTTP, 80);
proxyscan_addscantype(STYPE_HTTP, 6588);
proxyscan_addscantype(STYPE_HTTP, 8000);
int i;
cachehost *chp;
foundproxy *fpp;
+ time_t now;
scansdone++;
scansbyclass[sp->class]++;
fpp->next=chp->proxies;
chp->proxies=fpp;
}
-
- if (!chp->glineid) {
+
+ now=time(NULL);
+ /* the purpose of this lastgline stuff is to stop gline spam from one scan */
+ if (!chp->glineid || (now>=chp->lastgline+SCANTIMEOUT)) {
+ chp->lastgline=now;
glinedhosts++;
- loggline(chp, sp->node);
+ loggline(chp, sp->node);
irc_send("%s GL * +*@%s 1800 %jd :Open Proxy, see http://www.quakenet.org/openproxies.html - ID: %d",
mynumeric->content,IPtostr(((patricia_node_t *)sp->node)->prefix->sin),(intmax_t)getnettime(), chp->glineid);
Error("proxyscan",ERR_DEBUG,"Found open proxy on host %s",IPtostr(((patricia_node_t *)sp->node)->prefix->sin));
return CMD_OK;
}
+void startnickscan(nick *np) {
+ time_t t = time(NULL);
+ int i;
+ for(i=0;i<numscans;i++) {
+ /* @@@TODO: we allow a forced scan to scan the same IP multiple times atm */
+ queuescan(np->ipnode,thescans[i].type,thescans[i].port,SCLASS_NORMAL,t);
+ }
+}
+
int proxyscandoscan(void *sender, int cargc, char **cargv) {
nick *np = (nick *)sender;
patricia_node_t *node;
if (0 == ipmask_parse(cargv[0],&sin, &bits)) {
sendnoticetouser(proxyscannick,np,"Usage: scan <ip>");
} else {
+ time_t t;
sendnoticetouser(proxyscannick,np,"Forcing scan of %s",IPtostr(sin));
// * Just queue the scans directly here.. plonk them on the priority queue * /
node = refnode(iptree, &sin, bits); /* node leaks node here - should only allow to scan a nick? */
+ t = time(NULL);
for(i=0;i<numscans;i++) {
/* @@@TODO: we allow a forced scan to scan the same IP multiple times atm */
- queuescan(node,thescans[i].type,thescans[i].port,SCLASS_NORMAL,time(NULL));
+ queuescan(node,thescans[i].type,thescans[i].port,SCLASS_NORMAL,t);
}
}
return CMD_OK;
time_t lastscan;
foundproxy *proxies;
int glineid;
+ time_t lastgline;
unsigned char marker;
#if defined(PROXYSCAN_MAIL)
sstring *lasthostmask; /* Not saved to disk */
/* proxyscan.c */
void startscan(patricia_node_t *node, int type, int port, int class);
+void startnickscan(nick *nick);
/* proxyscanext.c */
unsigned int extrascancount();
--- /dev/null
+#include "../newsearch/newsearch.h"
+
+struct searchNode *pscan_parse(searchCtx *ctx, int argc, char **argv);
+
+void _init() {
+ registersearchterm(reg_nicksearch, "pscan", pscan_parse, 0, "");
+}
+
+void _fini() {
+ deregistersearchterm(reg_nicksearch, "pscan", pscan_parse);
+}
chp->lastscan=timestamp;
chp->proxies=NULL;
chp->glineid=0;
+ chp->lastgline=0;
return chp;
}
} else
for (fpp=chp->proxies;fpp;fpp=fpp->next)
- fprintf(fp, "%s %lu %u %i %u\n",IPtostr(node->prefix->sin),chp->lastscan,chp->glineid,fpp->type,fpp->port);
+ fprintf(fp, "%s %lu %u %i %u %lu\n",IPtostr(node->prefix->sin),chp->lastscan,chp->glineid,fpp->type,fpp->port,chp->lastgline);
} else {
if (chp->lastscan < (now-cleanscaninterval)) {
/* Needs rescan anyway, so delete it */
void loadcachehosts() {
FILE *fp;
- unsigned long timestamp,glineid,ptype,pport;
+ unsigned long timestamp,glineid,ptype,pport,lastgline;
char buf[512];
cachehost *chp=NULL;
foundproxy *fpp;
break;
}
- res=sscanf(buf,"%s %lu %lu %lu %lu",ip,×tamp,&glineid,&ptype,&pport);
+ res=sscanf(buf,"%s %lu %lu %lu %lu %lu",ip,×tamp,&glineid,&ptype,&pport,&lastgline);
if (res<2)
continue;
chp=addcleanhost(timestamp);
node->exts[ps_cache_ext] = chp;
- if (res==5) {
+ if (res==6) {
chp->glineid=glineid;
+ chp->lastgline=lastgline;
fpp=getfoundproxy();
fpp->type=ptype;
fpp->port=pport;
if (irc_in_addr_is_loopback(&np->p_ipaddr) || !irc_in_addr_is_ipv4(&np->p_ipaddr))
return;
- /* before we look at a normal host, see if we think we have an open proxy */
- if ((esp=findextrascan(np->ipnode))) {
- Error("proxyextra", ERR_ERROR, "connection from possible proxy %s", IPtostr(np->p_ipaddr));
- for (espp=esp;espp;espp=espp->nextbynode) {
- /* we force a scan on any hosts that may be an open proxy, even if they are:
- * a) already in the queue, b) we've been running < 120 seconds */
- queuescan(np->ipnode, espp->type, espp->port, SCLASS_NORMAL, time(NULL));
- }
- }
+ /* slug: why is this here? why isn't it with the other queuing stuff? */
+ /* we're given a list of ip/subnets and port pairs which someone else has
+ seen a proxy on in the past, so we scan these very aggressively
+ (even ignoring the cache)
+ */
+ /* disabled as the list is hopelessly out of date */
+// if ((esp=findextrascan(np->ipnode))) {
+// Error("proxyextra", ERR_ERROR, "connection from possible proxy %s", IPtostr(np->p_ipaddr));
+// for (espp=esp;espp;espp=espp->nextbynode) {
+// /* we force a scan on any hosts that may be an open proxy, even if they are:
+// * a) already in the queue, b) we've been running < 120 seconds */
+// queuescan(np->ipnode, espp->type, espp->port, SCLASS_NORMAL, time(NULL));
+// }
+// }
- /* ignore newnick until initial burst complete */
- if (!ps_ready)
+/* slug: this BREAKS all of P's design assumptions, do NOT REENABLE THIS UNDER ANY CIRCUMSTANCES */
+/* ignore newnick until initial burst complete */
+/* if (!ps_ready)
return;
+*/
/*
* Logic for connecting hosts: