]>
jfr.im git - irc/quakenet/newserv.git/blob - nterfacer/nterfacer_relay.c
3 Copyright (C) 2004-2005 Chris Porter.
6 - made it return an error instead of a timeout when sending to local users
8 - found a load of stuff on froo's box
12 - made sure stats buffer was checked (no security problem, just helps pauline)
16 - found \r bug, and another format string problem...
18 - oops, fixed quit bug
19 - oops, forgot about rehash hook
21 - added S support, though it's gross
23 - fixed audit found format string vunerability
25 - split O username and password from .h file into config file
26 - added rehash support
28 - item->schedule was not unset and checked upon timeout
35 #include "../lib/irc_string.h"
36 #include "../lib/strlfunc.h"
37 #include "../core/schedule.h"
38 #include "../irc/irc.h"
39 #include "../core/config.h"
40 #include "../lib/version.h"
42 #include "nterfacer_relay.h"
46 struct service_node
*node
;
47 sstring
*ousername
, *opassword
;
51 char nickprefix
[NICKLEN
- 5 + 1];
52 static unsigned long userid
;
54 int stats_handler(struct rline
*ri
, int argc
, char **argv
);
60 node
= register_service("R");
63 register_handler(node
, "relay", 4, relay_handler
);
64 register_handler(node
, "stats", 2, stats_handler
);
66 registerhook(HOOK_NICK_LOSTNICK
, &relay_quits
);
67 registerhook(HOOK_IRC_DISCON
, &relay_disconnect
);
68 registerhook(HOOK_CORE_REHASH
, &relay_rehash
);
73 int load_config(void) {
74 /* eww, I don't know how to make this any nicer! */
75 sstring
*ou
, *op
, *on
, *opr
;
78 memset(&newregex
, 0, sizeof(newregex
));
80 userid
= getcopyconfigitemintpositive("nterfacer", "serviceuserid", 0);
82 Error("nterfacer_relay", ERR_WARNING
, "No user id specified (serviceuserid)!");
86 opr
= getcopyconfigitem("nterfacer", "nickprefix", DEFAULT_NICK_PREFIX
, sizeof(nickprefix
) - 1); /* the terminator is included in nickprefix */
87 strlcpy(nickprefix
, (opr
&&opr
->content
)?opr
->content
:DEFAULT_NICK_PREFIX
, sizeof(nickprefix
));
88 freesstring(opr
); /* works fine with NULL */
90 ou
= getcopyconfigitem("nterfacer", "serviceusername", "nterfacer", 100);
91 op
= getcopyconfigitem("nterfacer", "servicepassword", "setme", 100);
92 on
= getcopyconfigitem("nterfacer", "servicenickname", "^O$", 100);
97 newregex
.phrase
= pcre_compile(on
->content
, PCRE_CASELESS
, &rerror
, &erroroffset
, NULL
);
99 newregex
.hint
= pcre_study(newregex
.phrase
, 0, &rerror
);
101 pcre_free(newregex
.phrase
);
102 newregex
.phrase
= NULL
;
107 if(!ou
|| !op
|| !on
|| !newregex
.phrase
) {
111 if(newregex
.phrase
) {
112 pcre_free(newregex
.phrase
);
114 pcre_free(newregex
.hint
);
122 freesstring(ousername
);
124 freesstring(opassword
);
125 if(onickname
.phrase
) {
126 pcre_free(onickname
.phrase
);
128 pcre_free(onickname
.hint
);
136 memcpy(&onickname
, &newregex
, sizeof(onickname
));
140 void relay_rehash(int hook
, void *args
) {
151 freesstring(ousername
);
153 freesstring(opassword
);
154 if(onickname
.phrase
) {
155 pcre_free(onickname
.phrase
);
157 pcre_free(onickname
.hint
);
160 deregisterhook(HOOK_NICK_LOSTNICK
, &relay_quits
);
161 deregisterhook(HOOK_IRC_DISCON
, &relay_disconnect
);
162 deregisterhook(HOOK_CORE_REHASH
, &relay_rehash
);
165 struct rline
*ri
= np
->rline
;
169 ri_error(ri
, RELAY_UNLOADED
, "Module was unloaded");
175 deregister_service(node
);
178 nick
*relay_getnick(void) {
179 static char ournick
[NICKLEN
+ 1];
183 snprintf(ournick
, sizeof(ournick
), "%s%d", nickprefix
, number
++);
187 if(!getnickbynick(ournick
))
188 return registerlocaluserflags(ournick
, "nterf", "cer", "nterfacer relay", "nterfacer", userid
, 0, UMODE_SERVICE
| UMODE_DEAF
| UMODE_OPER
| UMODE_INV
| UMODE_ACCOUNT
, &relay_messages
);
191 } while(attempts
> 0);
196 int relay_handler(struct rline
*ri
, int argc
, char **argv
) {
204 return ri_error(ri
, RELAY_NOT_ON_IRC
, "Not currently on IRC");
206 if(argv
[0][0] == '1') {
207 lines
= positive_atoi(argv
[1]);
209 return ri_error(ri
, RELAY_PARSE_ERROR
, "Parse error");
210 } else if(argv
[0][0] != '2') {
211 return ri_error(ri
, RELAY_PARSE_ERROR
, "Parse error");
214 dest
= getnickbynick(argv
[2]);
216 return ri_error(ri
, RELAY_NICK_NOT_FOUND
, "Nickname not found!");
218 if(homeserver(dest
->numeric
) == mylongnum
)
219 return ri_error(ri
, RELAY_LOCAL_USER
, "Cannot relay to local users");
222 if(strchr(argv
[i
], '\r'))
223 return ri_error(ri
, RELAY_INVALID_CHARS
, "Invalid character in input");
225 np
= ntmalloc(sizeof(struct rld
));
226 MemCheckR(np
, ri_error(ri
, RELAY_MEMORY_ERROR
, "Memory error"));
230 np
->termination
.pcre
.phrase
= pcre_compile(argv
[1], PCRE_FLAGS
, &rerror
, &erroroffset
, NULL
);
231 if(!np
->termination
.pcre
.phrase
) {
234 return ri_error(ri
, RELAY_REGEX_ERROR
, "Regex compliation error");
236 np
->termination
.pcre
.hint
= pcre_study(np
->termination
.pcre
.phrase
, 0, &rerror
);
238 pcre_free(np
->termination
.pcre
.phrase
);
240 return ri_error(ri
, RELAY_REGEX_HINT_ERROR
, "Regex hint error");
245 np
->mode
= MODE_LINES
;
246 np
->termination
.remaining_lines
= lines
;
249 if(!(np
->nick
= relay_getnick())) {
251 pcre_free(np
->termination
.pcre
.phrase
);
252 if(np
->termination
.pcre
.hint
)
253 pcre_free(np
->termination
.pcre
.hint
);
256 return ri_error(ri
, RELAY_NICK_ERROR
, "Unable to get a nickname!");
259 np
->schedule
= scheduleoneshot(time(NULL
) + MESSAGE_TIMEOUT
, &relay_timeout
, np
);
263 pcre_free(np
->termination
.pcre
.phrase
);
264 if(np
->termination
.pcre
.hint
)
265 pcre_free(np
->termination
.pcre
.hint
);
267 deregisterlocaluser(np
->nick
, NULL
);
269 return ri_error(ri
, RELAY_MEMORY_ERROR
, "Memory error");
277 if(pcre_exec(onickname
.phrase
, onickname
.hint
, dest
->nick
, strlen(dest
->nick
), 0, 0, NULL
, 0) >= 0) {
279 sendsecuremessagetouser(np
->nick
, dest
, serverlist
[dest
->numeric
>>18].name
->content
, "AUTH %s %s", ousername
->content
, opassword
->content
);
283 sendmessagetouser(np
->nick
, dest
, "%s", argv
[i
]);
288 int stats_handler(struct rline
*ri
, int argc
, char **argv
) {
290 char *server
= argv
[0], *command
= argv
[1], *more
;
291 int serverid
= findserver(server
);
292 char targetnumeric
[3];
295 return ri_error(ri
, RELAY_SERVER_NOT_FOUND
, "Server not found");
297 if(!command
|| !command
[0] || (command
[0] == ' ') || (command
[0] == '\r') || (command
[0] == ':'))
298 return ri_error(ri
, RELAY_INVALID_COMMAND
, "Invalid command");
302 if(strchr(more
, '\r'))
303 return ri_error(ri
, RELAY_INVALID_CHARS
, "Invalid character in input");
308 np
= ntmalloc(sizeof(struct rld
));
309 MemCheckR(np
, ri_error(ri
, RELAY_MEMORY_ERROR
, "Memory error"));
312 np
->mode
= MODE_STATS
;
315 if(!(np
->nick
= relay_getnick())) {
317 return ri_error(ri
, RELAY_NICK_ERROR
, "Unable to get a nickname!");
320 np
->schedule
= scheduleoneshot(time(NULL
) + MESSAGE_TIMEOUT
, &relay_timeout
, np
);
323 deregisterlocaluser(np
->nick
, NULL
);
330 memcpy(targetnumeric
, longtonumeric(serverid
, 2), 3);
331 targetnumeric
[2] = '\0';
333 irc_send("%s R %c %s :%s\r\n", longtonumeric(np
->nick
->numeric
,5), command
[0], targetnumeric
, more
);
335 irc_send("%s R %c :%s\r\n", longtonumeric(np
->nick
->numeric
,5), command
[0], targetnumeric
);
341 void relay_messages(nick
*target
, int messagetype
, void **args
) {
342 struct rld
*item
, *prev
= NULL
;
345 for(item
=list
;item
;prev
=item
,item
=item
->next
)
346 if(item
->nick
== target
)
354 switch(messagetype
) {
358 if(!item
->dest
|| (item
->dest
!= (nick
*)args
[0]))
361 if((item
->mode
& MODE_IS_O
) && !(item
->mode
& MODE_O_AUTH2
)) {
362 if(item
->mode
& MODE_O_AUTH1
) {
363 if(!strncmp((char *)args
[1], "Your authlevel is ", 18)) {
364 item
->mode
|=MODE_O_AUTH2
;
366 dispose_rld_prev(item
, prev
);
367 ri_error(ri
, RELAY_O_AUTH_ERROR
, "Unable to auth with O");
370 if(!strcmp((char *)args
[1], "Auth successful.")) {
371 item
->mode
|=MODE_O_AUTH1
;
373 dispose_rld_prev(item
, prev
);
374 ri_error(ri
, RELAY_O_AUTH_ERROR
, "Unable to auth with O");
377 } else if(ri_append(ri
, "%s", (char *)args
[1]) == BF_OVER
) {
378 dispose_rld_prev(item
, prev
);
379 ri_error(ri
, BF_OVER
, "Buffer overflow");
381 if(((item
->mode
& MODE_LINES
) && (!--item
->termination
.remaining_lines
)) || ((item
->mode
& MODE_TAG
) && (pcre_exec(item
->termination
.pcre
.phrase
, item
->termination
.pcre
.hint
, (char *)args
[1], strlen((char *)args
[1]), 0, 0, NULL
, 0) >= 0))) {
382 dispose_rld_prev(item
, prev
);
390 prev
->next
= item
->next
;
394 dispose_rld_dontquit(item
, 1);
395 ri_error(ri
, RELAY_KILLED
, "Killed");
399 if(item
->mode
!= MODE_STATS
)
401 if(ri_append(ri
, "%s", (char *)args
[2]) == BF_OVER
) {
402 dispose_rld_prev(item
, prev
);
403 ri_error(ri
, BF_OVER
, "Buffer overflow");
408 if(item
->mode
!= MODE_STATS
)
411 dispose_rld_prev(item
, prev
);
418 void dispose_rld_prev(struct rld
*item
, struct rld
*prev
) {
420 prev
->next
= item
->next
;
427 void dispose_rld_dontquit(struct rld
*item
, int dontquit
) {
429 deleteschedule(item
->schedule
, &relay_timeout
, item
);
431 deregisterlocaluser(item
->nick
, NULL
);
432 if(item
->mode
& MODE_TAG
) {
433 pcre_free(item
->termination
.pcre
.phrase
);
434 if(item
->termination
.pcre
.hint
)
435 pcre_free(item
->termination
.pcre
.hint
);
440 void relay_timeout(void *arg
) {
441 struct rld
*item
= (struct rld
*)arg
, *lp
= NULL
, *np
;
442 struct rline
*ri
= item
->rline
;
444 item
->schedule
= NULL
;
445 for(np
=list
;np
;lp
=np
,np
=np
->next
) {
447 dispose_rld_prev(item
, lp
);
452 ri_error(ri
, RELAY_TIMEOUT
, "Timed out");
455 void relay_quits(int hook
, void *args
) {
456 nick
*np
= (nick
*)args
;
457 struct rld
*cp
, *lp
, *freed
= NULL
;
459 /* get them out of the list before freeing */
460 for(lp
=NULL
,cp
=list
;cp
;) {
479 /* now free them up */
481 struct rline
*ri
= freed
->rline
;
485 ri_error(ri
, RELAY_TARGET_LEFT
, "Target left QuakeNet");
491 void relay_disconnect(int hook
, void *args
) {
492 struct rld
*np
, *lp
= NULL
;
494 struct rline
*ri
= list
->rline
;
496 dispose_rld_prev(list
, NULL
);
498 ri_error(ri
, RELAY_DISCONNECTED
, "Disconnected from IRC");