/* ftpdsupp.h: ftpd support _code_ */
#ifndef _FTPDSUPP_H
#define _FTPDSUPP_H
/*
* debugging macros
*/
#ifdef DEBUG
#define TP(STR) if ( find_player( TP_CRE ) ) \
tell_object( find_player( TP_CRE ), STR )
#define DEBUG_SEND /* define to debug data_write_callback() */
#else
#define TP(STR)
#define DEBUG_SEND
#endif /* DEBUG */
#define CHECK_LOGIN() \
if ( !socket_info[ fd ][ LOGGED_IN ] ) { \
socket_write( fd, "530 Please login with USER and PASS.\n" ); \
break; \
}
#define CHECK_CMD(x) \
if ( sizeof(command) == x) { \
socket_write( fd, sprintf("500 '%s': command not understood.\n", \
command[ 0 ]) ); \
break; \
}
/*
* check_access determines who is allowed to use ftp (assuming the correct
* password is known). if check_access() returns 0 then the user is
* disallowed even if the user knows the password.
*/
int
check_access(string name)
{
string file;
#ifdef FTP_USERS
if (!sizeof(FTP_USERS))
return 0;
return (member_array(name, FTP_USERS) != -1) ? 1 : 0;
#else
#ifdef ANONYMOUS_FTP
if ( member_array(name, ANONYMOUS_FTP) != -1)
return 1;
#endif /* ANONYMOUS_FTP */
#ifdef GUEST_WIZARD_FTP
// TMI-2 allows those wizards w/o directories to log in
file = PDATA_DIR + name[0..0] + "/" + name + __SAVE_EXTENSION__;
return ( file_exists( file ) &&
( sscanf( read_file( file ), "%*swizard 1%*s" ) == 2 ) );
#else
// This is if you require users to have a home directory
// in order to use ftp.
return directory_exists(HOME_DIR(name)); /* tmi-2 simul_efun */
#endif
#endif /* FTP_USERS */
}
/*
* return 1 if user named 'name' has password of 'plaintext'
*/
int
check_password(string name, string plaintext)
{
string fancytext, cpass;
object login_ob;
#ifdef ANONYMOUS_FTP
if ( name == "anonymous" ) {
// Currently guest's email address is not verified from USITE;
// consider supporting:
// name@some.ip.dot.address (from USITE and/or socket_address(fd))
// name@some.domain.name (from USITE)
// name@some-mud (reverse DNS lookup)
if (!plaintext || plaintext == "")
return 0;
else if (member_array(plaintext, ({ "none", "guest", "anon",
"anonymous", "none@none"}) ) != -1)
return 0;
else
return 1;
}
#endif /* ANONYMOUS_FTP */
/*
* This is a good example of differences in mudlib design
* 1) export_uid() vs creator_file() on setting a new object's uid
* 2) query_password() vs query("password")
*/
#if 0
seteuid(name)
login_ob = new(PLAYER_OB);
seteuid(getuid());
login_ob->load_me(name);
fancytext = (string)login_ob->query_password();
#else
seteuid(getuid());
login_ob = new(CONNECTION);
// set login object's uid
seteuid(name);
export_uid(login_ob);
// now set login object's name
seteuid( getuid() );
login_ob->set("name", name);
// get login object's password
login_ob->restore();
fancytext = (string)login_ob->query("password");
#endif
reload_object(login_ob);
destruct(login_ob);
if (!fancytext || !plaintext) {
return 0;
}
cpass = crypt(plaintext, fancytext);
return (cpass == fancytext);
}
/*
* determines if "who" is allowed to connect from this site
* by using the same args used by the user in his/her .login file for
* the sitecheck command
*/
#ifdef CHECK_SITE
/*
* compare dot portions (address components) of ip number (dotted decimal/
* dotted quad) with an ip number pattern (ie containing wildcard(s))
* - returns 1 if a match, 0 otherwise
*/
static int dot_match(string *site, string *pattern, int flag) {
int i, j;
j = sizeof(pattern);
if (j != 4)
return 0;
while (j--) {
if (flag) {
/*
* match any octect
*/
if (pattern[j] == "*")
continue;
} else {
/*
* be strict (last octect only)
*/
if (j == 3 && pattern[3] == "*")
continue;
}
/*
* component doesn't match
*/
if (site[j] != pattern[j])
return 0;
}
/*
* by process of elimination...it must match
*/
return 1;
}
int check_site(string who, int fd) {
int wildcard_flag;
string site, site_num;
string arg;
string *sites;
object ob;
int i, s, l1, l2;
string *site_dots, *match_dots;
site = USITE;
/*
* get site list (if any)
*/
if (site && site != "" && file_size(HOME_DIR(who)) == -2 &&
file_size(HOME_DIR(who) + ".login") > 0) {
arg = read_file(HOME_DIR(who) + ".login");
if (arg && strlen(arg)) {
sites = explode(arg, "\n");
sites = regexp(sites, "^sitecheck ");
if (sites && sizeof(sites)) {
arg = sites[0][10..<1];
/*
* parse command line args
*/
arg = replace_string(arg, ",", " ");
sites = explode(lower_case(arg), " ");
/*
* check for options
*/
if (sites[0][0] == '-') {
// at the moment, we don't respect the presence of
// the -t (test) flag (ie allow the user to login
// anyways), and we don't respect the absense of the
// -d (destruct) flag, choosing to always drop the
// connection if the site check fails
if (strsrch(sites[0], 'w') != -1)
wildcard_flag = 1;
}
/*
* check list of accepted sites
* 1) check for perfect match
*/
site = lower_case(site);
if (member_array(site, sites) != -1)
return 1;
/*
* 2) check ip number (from ip name)
*/
if (sscanf(site, "%*d.%*d.%*d.%*d") != 4) {
site_num = socket_address(fd);
sscanf( site_num, "%s %*s", site_num );
if (member_array(site_num, sites) != -1)
return 1;
} else {
site_num = site;
site = 0;
}
/*
* LAST: loop through wildcards in sites[]
* Note: sites[] is altered
*/
if (strsrch(arg, '*') != -1) {
/*
* here's a quick filter :)
*/
sites = regexp(sites, "\\*");
if (sites && (s = sizeof(sites))) {
/*
* check site ip name;
* default only allows '*' as a prefix,
* ie "*.domain.name"
*/
if (site) {
l1 = strlen(site);
i = s;
while (i--) {
l2 = strlen(sites[i]) - 1;
if (l2 > 1 && l1 > l2 &&
sites[i][0..1] == "*." &&
strcmp(site[l1-l2..<1],
sites[i][1..<1]) == 0)
return 1;
}
if (wildcard_flag) {
/*
* handle '*' as suffix
*/
i = s;
while (i--) {
l2 = strlen(sites[i]) - 2;
if (l2 > 0 && l1 > l2 &&
sites[i][l2..<1] == ".*" &&
strcmp(site[0..l2],
sites[i][0..l2]) == 0)
return 1;
}
}
}
/*
* check site ip number
*/
if (site_num) {
site_dots = explode(site_num, ".");
i = s;
while (i--) {
match_dots = explode(sites[i], ".");
if (dot_match(site_dots, match_dots,
wildcard_flag))
return 1;
}
}
}
}
return 0;
}
}
}
return 1;
}
#endif /* SITE_CHECK */
#endif /* _FTPDSUPP_H */