blob: e681f820ec94d2363c8141f79e2921ff1fd1d2d9 [file] [log] [blame]
// MorgenGrauen MUDlib
//
// master/network.c - UDP-Handling
//
// $Id: network.c 8934 2014-09-10 21:57:12Z Zesstra $
#pragma strict_types
#include "/secure/master.h"
#define BBMASTER "/secure/bbmaster"
/*
#undef DEBUG
#define DEBUG(x) if (call_sefun("find_player","zesstra")) \
tell_object(call_sefun("find_player","zesstra"),x);
*/
//ich will hieraus momentan kein Debug, ist zuviel. Zesstra
#ifdef DEBUG
#undef DEBUG
#endif
#define DEBUG(x)
nosave int mails_last_hour;
static string mail_normalize( string str )
{
str = regreplace( str, "[^<]*<(.*)>[^>]*", "\\1", 0);
return regreplace( str, " *([^ ][^ ]*).*", "\\1", 0);
}
static string *mk_rec_list( string str )
{
return map( explode( lower_case(str), "," ) - ({""}),
"mail_normalize", this_object() );
}
static int CheckPasswd( string name, string passwd ) {
mixed *uinf;
if (!stringp(passwd) || !sizeof(passwd))
return 0;
if ( sizeof(uinf = get_full_userinfo(name)) < 2 )
return 0;
string pwhash = uinf[USER_PASSWORD+1];
if (sizeof(pwhash) > 13) {
// MD5-Hash
passwd = md5_crypt(passwd, pwhash);
}
else if (sizeof(pwhash) > 2) {
// Crypt-Hash
passwd = crypt(passwd, pwhash[0..1]);
}
else return 0;
return (passwd == pwhash);
}
static void FtpAccess( string host, string message, int port )
{
string *comp, reply, head;
#if __EFUN_DEFINED__(send_udp)
comp = efun::explode( message, "\t" );
#define FTP_ID 0
#define FTP_SEQ 1
#define FTP_TAG 2
#define FTP_CMD 3
#define FTP_ARG1 4
#define FTP_ARG2 5
#define FTP_ARG3 6
if ( sizeof(comp) <= FTP_CMD || lower_case(comp[FTP_TAG]) != "req" ){
log_file( "IMP_MSGS", "Host: " + host + ":" + port + " - '" +
message + "'\n" );
return;
}
reply = "INVALID";
head = sprintf( "%s\t%s\tRPLY\t%s\t",
comp[FTP_ID], comp[FTP_SEQ], comp[FTP_CMD] );
switch ( lower_case(comp[FTP_CMD]) ){
case "user":
if ( sizeof(comp) <= FTP_ARG1 )
break;
if ( IS_LEARNER(lower_case(comp[FTP_ARG1])) )
reply = "/players/" + lower_case(comp[FTP_ARG1]);
else
reply = "NONE";
break;
case "pass":
if ( sizeof(comp) <= FTP_ARG2 )
break;
comp[FTP_ARG1] = lower_case(comp[FTP_ARG1]);
if ( IS_LEARNER(comp[FTP_ARG1]) &&
!"/secure/master"->QueryTBanished(comp[FTP_ARG1]) ){
if ( CheckPasswd( comp[FTP_ARG1], comp[FTP_ARG2] ) )
reply = "OK";
else {
if ( get_wiz_level( comp[FTP_ARG1] ) < ARCH_LVL )
log_file( "LOGINFAIL",
sprintf( "PASSWORD: (FTP) %s %s\n",
comp[FTP_ARG1],
ctime(time()) ) );
else
log_file( "ARCH/LOGINFAIL",
sprintf( "PASSWORD: (FTP) %s %s\n",
comp[FTP_ARG1],
ctime(time()) ) );
}
}
else
reply = "FAIL";
break;
case "read":
DEBUG("-FtpAccess----\nHost:"+host+"Message:\n"+message+"\n--------------\n");
if ( sizeof(comp) <= FTP_ARG2 )
break;
if ( comp[FTP_ARG2][0] == '/' &&
valid_read( comp[FTP_ARG2], lower_case(comp[FTP_ARG1]),
"read_file", 0 ) ){
BBMASTER->ftpbb( lower_case(comp[FTP_ARG1]),
"read " + comp[FTP_ARG2] + "\n" );
reply = "OK";
}
else
reply = "FAIL";
break;
case "writ":
DEBUG("-FtpAccess----\nHost:"+host+"Message:\n"+message+"\n--------------\n");
if ( sizeof(comp) <= FTP_ARG2 )
break;
if ( comp[FTP_ARG2][0] == '/' &&
valid_write( comp[FTP_ARG2], lower_case(comp[FTP_ARG1]),
"write_file", 0 ) ){
BBMASTER->ftpbb( lower_case(comp[FTP_ARG1]),
"write " + comp[FTP_ARG2] + "\n" );
reply = "OK";
}
else
reply = "FAIL";
break;
case "list":
DEBUG("-FtpAccess----\nHost:"+host+"Message:\n"+message+"\n--------------\n");
if ( sizeof(comp) <= FTP_ARG2 )
break;
if ( comp[FTP_ARG2][0] == '/' &&
valid_read( comp[FTP_ARG2], lower_case(comp[FTP_ARG1]),
"read_file", 0 ) )
reply = "OK";
else
reply = "FAIL";
break;
default:
DEBUG("-FtpAccess----\nHost:"+host+"Message:\n"+message+"\n--------------\n");
log_file( "IMP_MSGS", "Host: " + host + ":" + port + " - '" +
message + "'\n" );
break;
}
send_udp( host, port, head+reply );
#endif
}
static int doReadMail( string file )
{
string str, *lines, *parts, *tmp;
mixed *message;
int i, j;
if ( (i = file_size(file)) > 50000 || i < 5 ){
rm(file);
DEBUG( "Mail size invalid\n" );
return -1;
}
if ( !(str = read_bytes( file, 0, 50000 )) )
return -1;
if ( !(j = sizeof(lines = explode( str, "\n" ))) )
return -2;
i = 0;
while ( i < j && lines[i] != "" )
i++;
if ( i == j )
return -2;
DEBUG( sprintf( "Have %d headerlines:\n", i ) );
message= allocate(9);
message[MSG_CC] = ({});
message[MSG_BCC] = ({});
message[MSG_BODY] = implode( lines[i..], "\n" );
for ( j = 0; j < i; j++ ){
parts = explode( lines[j], ":" );
if ( sizeof(parts) > 1 ){
str = lower_case(parts[0]);
parts[0] = implode( parts[1..], ":" );
switch (str){
case "subject":
message[MSG_SUBJECT] = parts[0];
break;
case "from":
DEBUG( "Found from\n" );
DEBUG( sprintf( "PARTS[0]=%s\n", parts[0] ) );
message[MSG_FROM] = mail_normalize(parts[0]);
message[MSG_SENDER] = parts[0];
DEBUG( sprintf( "FROM: %s\nSENDER: %s\n",
message[MSG_FROM],
message[MSG_SENDER] ) );
break;
case "cc":
DEBUG( sprintf("FOUND CC: %O\n", parts[0]) );
message[MSG_CC] += mk_rec_list(parts[0]);
break;
case "bcc":
DEBUG( sprintf("FOUND BCC: %O\n", parts[0]) );
message[MSG_BCC] += mk_rec_list(parts[0]);
break;
case "to":
DEBUG( sprintf("FOUND TO: %O\n", parts[0]) );
tmp = mk_rec_list(parts[0]);
if ( !message[MSG_RECIPIENT] )
message[MSG_RECIPIENT] = tmp[0];
message[MSG_CC] += tmp;
break;
// Das MUD-TO: wird vom Perlskript als erste Headerzeile eingefuegt
case "mud-to":
DEBUG( sprintf("FOUND MUD-TO: %O\n", parts[0]) );
message[MSG_RECIPIENT] = mail_normalize(lower_case(parts[0]));
break;
}
}
}
// Eigentlichen Empfaenger aus CC: loeschen
message[MSG_CC] -= ({ message[MSG_RECIPIENT],
message[MSG_RECIPIENT]+"@mg.mud.de",
message[MSG_RECIPIENT]+"@morgengrauen.mud.de" });
DEBUG( sprintf( "TO: %O\n", message[MSG_RECIPIENT] ) );
DEBUG( sprintf( "CC: %O\n", message[MSG_CC] ) );
DEBUG( sprintf( "BCC: %O\n", message[MSG_BCC] ) );
if ( !stringp(message[MSG_FROM]) )
return -2;
if ( !stringp(message[MSG_RECIPIENT]) ){
str = explode( file, "/" )[<1];
i = 0;
j = sizeof(str);
while ( i < j && str[i] <= '9' && str[i] >= '0' )
i++;
if ( i >= j )
return -2;
message[MSG_RECIPIENT] = str[i..];
DEBUG( sprintf( "EMERGENCY RECIPIENT=%s\n", str[i..] ) );
}
rm(file);
// Da vom Master besser nichts von ausserhalb /secure #include't wird,
// direkt die '5'. Normalerweise hiesse der Aufruf:
// DeliverMail( message, NO_USER_ALIASES|NO_CARBON_COPIES );
"/secure/mailer"->DeliverMail( message, 5 );
return 1;
}
public void mailread()
{
string *files;
int i;
DEBUG( "mailread called\n" );
if ( mails_last_hour >= MAX_MAILS_PER_HOUR )
return;
files = (get_dir( "/mail/inbound/*" )||({})) - ({ "..", "." });
i = sizeof(files);
while ( i-- && mails_last_hour < MAX_MAILS_PER_HOUR ){
DEBUG( "FOUND FILE \"" + files[i] + "\" ...\n" );
mails_last_hour++;
if ( doReadMail( "/mail/inbound/" + files[i]) < -1 ){
mixed message;
message = allocate(9);
mails_last_hour++;
rename( "/mail/inbound/" + files[i],
"/secure/ARCH/MAIL/" + files[i] );
message[MSG_SENDER] = geteuid();
message[MSG_FROM] = getuid();
message[MSG_SUBJECT] = "Fehlerhafte Mail: /secure/ARCH/MAIL/" +
files[i];
message[MSG_RECIPIENT] = "mud@mg.mud.de";
message[MSG_BODY] = "Bitte Ueberpruefen!\n";
// NO_SYSTEM_ALIASES|NO_USER_ALIASES == 3
"/secure/mailer"->DeliverMail( message, 3 );
}
}
}
static void udp_query( string query, string host, int port )
{
#if __EFUN_DEFINED__(send_udp)
string *mess;
mixed *data;
int i, j;
mess = explode( query, " " );
switch ( mess[1] ){
case "wholist":
case "who":
data = (string *)"/obj/werliste"->QueryWhoListe();
break;
case "uptime":
data = ({ call_sefun("uptime") });
break;
case "finger":
if ( sizeof(mess) < 3 )
data = ({ "Error: Wen soll ich fingern ?" });
else
data = explode( (string)"p/daemon/finger"->
finger_single( lower_case(mess[2]), 0 ), "\n" );
break;
case "mailread":
data = ({ "Okay" });
mailread();
break;
default:
data = ({ "Error: unknown request " + mess[1] + "\n" });
}
send_udp( host, port, sprintf( "%s 0 %d", mess[0], sizeof(data) ) );
for ( i = 0, j = sizeof(data); i < j; i++ )
send_udp( host, port, sprintf( "%s %d %s", mess[0], i+1, data[i] ) );
#endif
}
#define UDP_DEBUG(x)
//#define UDP_DEBUG(x) (write_file("/log/ARCH/udp.log",(x)))
void receive_udp(string host, string message, int port)
{
mixed *tmp;
UDP_DEBUG(sprintf("%s %s:%d: %s\n",strftime(),host,port,message));
if (message[0..6]=="EXTREQ:"
|| message[0..5]=="IPNAME"
|| message[0..3]=="AUTH"
) {
return;
}
if( message[0..8]=="IPLOOKUP\n" ) {
"/p/daemon/iplookup"->update( message );
return;
}
if( message[0..9]=="DNSLOOKUP\n" ) {
"/p/daemon/dnslookup"->update( message );
return;
}
if (message[0..4]=="NFTPD") {
#if __HOST_NAME__==MUDHOST
if (host!=FTPD_IP) {
DEBUG(sprintf("INVALID HOST: %s\n",host));
return;
}
#endif
FtpAccess(host,message,port);
return;
}
if (message[0..9]=="udp_query:") {
return udp_query(message[10..],host,port);
}
"secure/inetd"->_receive_udp(host, message);
}