Newer
Older

rswindell
committed
/****************************************************************************/
/****************************************************************************/
bool logoutuserdat(scfg_t* cfg, user_t* user, time_t now, time_t logontime)
{
char str[128];
struct tm tm, tm_now;
if(now==0)
now=time(NULL);
tused=(now-logontime)/60;
user->tlast=(ushort)(tused > USHRT_MAX ? USHRT_MAX : tused);
putuserdatetime(cfg,user->number, USER_LASTON, (time32_t)now);
putuserstr(cfg,user->number, USER_TLAST, ultoa(user->tlast,str,10));
adjustuserval(cfg,user->number, USER_TIMEON, user->tlast);
adjustuserval(cfg,user->number, USER_TTODAY, user->tlast);
/* Convert time_t to struct tm */
if(localtime_r(&now,&tm_now)==NULL)
if(localtime_r(&logontime,&tm)==NULL)
/* Reset daily stats if new day */
if(tm.tm_mday!=tm_now.tm_mday)
resetdailyuserdat(cfg, user, /* write: */true);
}

rswindell
committed
/****************************************************************************/
/****************************************************************************/
void resetdailyuserdat(scfg_t* cfg, user_t* user, bool write)

rswindell
committed
{
if(!VALID_CFG(cfg) || user==NULL)
return;

rswindell
committed
/* logons today */
if(write) putuserstr(cfg,user->number, USER_LTODAY, "0");

rswindell
committed
/* e-mails today */
if(write) putuserstr(cfg,user->number, USER_ETODAY, "0");

rswindell
committed
/* posts today */
if(write) putuserstr(cfg,user->number, USER_PTODAY, "0");

rswindell
committed
user->freecdt=cfg->level_freecdtperday[user->level];
if(write) putuserdec64(cfg,user->number, USER_FREECDT, user->freecdt);

rswindell
committed
/* time used today */
user->ttoday=0;
if(write) putuserstr(cfg,user->number, USER_TTODAY, "0");

rswindell
committed
/* extra time today */
user->textra=0;
if(write) putuserstr(cfg,user->number, USER_TEXTRA, "0");

rswindell
committed
}
/****************************************************************************/
/* Get dotted-equivalent email address for user 'name'. */
/* 'addr' is the target buffer for the full address. */
/* Pass cfg=NULL to NOT have "@address" portion appended. */
/****************************************************************************/
char* usermailaddr(scfg_t* cfg, char* addr, const char* name)
{
int i;
if(strchr(name,'@')!=NULL) { /* Avoid double-@ */
strcpy(addr,name);
return(addr);
}
if(strchr(name,'.') && strchr(name,' ')) {
/* convert "Dr. Seuss" to "Dr.Seuss" */
strip_space(name,addr);
} else if(strchr(name,'!')) {
sprintf(addr,"\"%s\"",name);
} else {
strcpy(addr,name);
/* convert "first last" to "first.last" */
for(i=0;addr[i];i++)
if(addr[i]==' ' || addr[i]&0x80)
addr[i]='.';
}
if(VALID_CFG(cfg)) {
strcat(addr,"@");
strcat(addr,cfg->sys_inetaddr);
}
return(addr);
}

Rob Swindell
committed
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
/****************************************************************************/
/* Convert a sender's name/address from a message header into Synchronet */
/* SMTP-server-routable form */
/****************************************************************************/
void smtp_netmailaddr(scfg_t* cfg, smbmsg_t* msg, char* name, size_t namelen, char* addr, size_t addrlen)
{
char addrbuf[256];
if(name != NULL)
snprintf(name, namelen, "\"%s\"", msg->from);
if(msg->from_net.type==NET_QWK && msg->from_net.addr!=NULL)
snprintf(addr, addrlen, "%s!%s"
,(char*)msg->from_net.addr
,usermailaddr(cfg, addrbuf, msg->from));
else if(msg->from_net.type==NET_FIDO && msg->from_net.addr!=NULL) {
faddr_t* faddr = (faddr_t *)msg->from_net.addr;
char faddrstr[128];
if(name != NULL)
snprintf(name, namelen, "\"%s\" (%s)", msg->from, smb_faddrtoa(faddr, faddrstr));
if(faddr->point)
SAFEPRINTF4(faddrstr,"p%hu.f%hu.n%hu.z%hu"FIDO_TLD
,faddr->point, faddr->node, faddr->net, faddr->zone);
else
SAFEPRINTF3(faddrstr,"f%hu.n%hu.z%hu"FIDO_TLD
,faddr->node, faddr->net, faddr->zone);
snprintf(addr, addrlen, "%s@%s", usermailaddr(NULL, addrbuf, msg->from), faddrstr);
} else if(msg->from_net.type!=NET_NONE && msg->from_net.addr!=NULL)
snprintf(addr, addrlen, "%s", (char*)msg->from_net.addr);

Rob Swindell
committed
else
usermailaddr(cfg, addr, msg->from);
}
char* alias(scfg_t* cfg, const char* name, char* buf)
{
char line[128];
char* p;
char* np;
char* tp;
char* vp;
char fname[MAX_PATH+1];
size_t namelen;
size_t cmplen;
FILE* fp;
if(!VALID_CFG(cfg) || name==NULL || buf==NULL)
return(NULL);
SAFEPRINTF(fname,"%salias.cfg",cfg->ctrl_dir);

Rob Swindell
committed
if((fp = fnopen(NULL, fname, O_RDONLY)) == NULL)
while(!feof(fp)) {
if(!fgets(line,sizeof(line),fp))
break;
SKIP_WHITESPACE(np);
if(*np==';' || *np==0) /* no name value, or comment */
continue;
tp=np;
FIND_WHITESPACE(tp);
if(*tp==0) /* no alias value */
continue;
*tp=0;
vp=tp+1;
SKIP_WHITESPACE(vp);
truncsp(vp);
if(*vp==0) /* no value */
continue;
if(*np=='*') {
np++;
cmplen=strlen(np);
namelen=strlen(name);
if(namelen<cmplen)
continue;
if(strnicmp(np,name+(namelen-cmplen),cmplen))
continue;
sprintf(buf,"%.*s%s",(int)(namelen-cmplen),name,vp+1);
strcpy(buf,vp);
p=buf;
break;
}
if(!stricmp(np,name)) {
strcpy(buf,vp);
break;
}
}
fclose(fp);
return(p);
}
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
int newuserdefaults(scfg_t* cfg, user_t* user)
{
int i;
user->sex = ' ';
/* statistics */
user->firston=user->laston=user->pwmod=time32(NULL);
/* security */
user->level=cfg->new_level;
user->flags1=cfg->new_flags1;
user->flags2=cfg->new_flags2;
user->flags3=cfg->new_flags3;
user->flags4=cfg->new_flags4;
user->rest=cfg->new_rest;
user->exempt=cfg->new_exempt;
user->cdt=cfg->new_cdt;
user->min=cfg->new_min;
user->freecdt=cfg->level_freecdtperday[user->level];
if(cfg->new_expire)
user->expire=user->firston+((long)cfg->new_expire*24L*60L*60L);
else
user->expire=0;
/* settings */
if(cfg->total_fcomps)
SAFECOPY(user->tmpext,cfg->fcomp[0]->ext);
else
SAFECOPY(user->tmpext,"zip");
user->shell = cfg->new_shell;
user->misc = cfg->new_misc|(AUTOTERM|COLOR);
user->misc &= ~(DELETED|INACTIVE|QUIET|NETMAIL);
user->prot = cfg->new_prot;
user->qwk = cfg->new_qwk;
user->chat = cfg->new_chat;
for(i=0;i<cfg->total_xedits;i++)
if(!stricmp(cfg->xedit[i]->code,cfg->new_xedit) && chk_ar(cfg,cfg->xedit[i]->ar, user, /* client: */NULL))
break;
if(i<cfg->total_xedits)
user->xedit=i+1;
return 0;
}
int newuserdat(scfg_t* cfg, user_t* user)
{
char str[MAX_PATH+1];
char tmp[128];
int c;
int i;
int err;
int file;
int unum=1;
int last;
FILE* stream;
stats_t stats;
if(!VALID_CFG(cfg) || user==NULL)
return USER_INVALID_ARG;
SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
if(fexist(str)) {
if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
return USER_OPEN_ERROR;
last=(long)filelength(file)/(LEN_ALIAS+2); /* total users */
if(fread(str,LEN_ALIAS+2,1,stream) != 1)
memset(str, ETX, LEN_ALIAS);
for(c=0;c<LEN_ALIAS;c++)
if(str[c]==ETX) break;
str[c]=0;
if(!c) { /* should be a deleted user */
user_t deluser;
deluser.number = unum;
if(getuserdat(cfg, &deluser) == 0) {
if(deluser.misc&DELETED) { /* deleted bit set too */
if((time(NULL)-deluser.laston)/86400>=cfg->sys_deldays)
break; /* deleted long enough ? */
}
}
last=lastuser(cfg); /* Check against data file */
if(unum>last+1) /* Corrupted name.dat? */
unum=last+1;
else if(unum<=last) { /* Overwriting existing user */
user_t deluser;
deluser.number = unum;
if(getuserdat(cfg, &deluser) == 0) {
if(!(deluser.misc&DELETED)) /* Not deleted? Set usernumber to end+1 */
unum=last+1;
}
}
user->number=unum; /* store the new user number */
if((err=putusername(cfg,user->number,user->alias)) != USER_SUCCESS)
if((err=putuserdat(cfg,user)) != USER_SUCCESS)
SAFEPRINTF2(str,"%sfile/%04u.in",cfg->data_dir,user->number); /* delete any files */
delfiles(str, ALLFILES, /* keep: */0); /* waiting for user */
SAFEPRINTF2(str,"%sfile/%04u.out",cfg->data_dir,user->number); /* delete any files */
delfiles(str, ALLFILES, /* keep: */0); /* pending transmit to/by user */
rmdir(str);
SAFEPRINTF(tmp,"%04u.*",user->number);
SAFEPRINTF(str,"%sfile",cfg->data_dir);
delfiles(str,tmp, /* keep: */0);
SAFEPRINTF(str,"%suser",cfg->data_dir);
delfiles(str,tmp, /* keep: */0);
SAFEPRINTF(str,"%smsgs",cfg->data_dir);
delfiles(str,tmp, /* keep: */0);
SAFEPRINTF2(str,"%suser/%04u",cfg->data_dir,user->number);
delfiles(str,ALLFILES, /* keep: */0);
rmdir(str);
SAFEPRINTF2(str,"%suser/ptrs/%04u.ixb",cfg->data_dir,user->number); /* legacy msg ptrs */
/* Update daily statistics database (for system and node) */
for(i=0;i<2;i++) {
FILE* fp = fopen_dstats(cfg, i ? cfg->node_num : 0, /* for_write: */true);
if(fread_dstats(fp, &stats)) {
stats.today.nusers++;
stats.total.nusers++;
fwrite_dstats(fp, &stats, __FUNCTION__);
}
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
size_t user_field_len(enum user_field fnum)
{
user_t user;
switch(fnum) {
case USER_ALIAS: return sizeof(user.alias) - 1;
case USER_NAME: return sizeof(user.name) - 1;
case USER_HANDLE: return sizeof(user.handle) -1;
case USER_NOTE: return sizeof(user.note) - 1;
case USER_IPADDR: return sizeof(user.ipaddr) - 1;
case USER_HOST: return sizeof(user.comp) - 1;
case USER_NETMAIL: return sizeof(user.netmail) - 1;
case USER_ADDRESS: return sizeof(user.address) - 1;
case USER_LOCATION: return sizeof(user.location) - 1;
case USER_ZIPCODE: return sizeof(user.zipcode) - 1;
case USER_PHONE: return sizeof(user.phone) - 1;
case USER_BIRTH: return sizeof(user.birth) - 1;
case USER_GENDER: return sizeof(user.sex);
case USER_COMMENT: return sizeof(user.comment) - 1;
case USER_CONNECTION: return sizeof(user.modem) -1;
// Bit-fields:
case USER_MISC: return sizeof(user.misc);
case USER_QWK: return sizeof(user.qwk);
case USER_CHAT: return sizeof(user.chat);
// Settings:
case USER_ROWS: return sizeof(user.rows);
case USER_COLS: return sizeof(user.cols);
case USER_XEDIT: return sizeof(user.xedit);
case USER_SHELL: return sizeof(user.shell);
case USER_TMPEXT: return sizeof(user.tmpext) - 1;
case USER_PROT: return sizeof(user.prot);
case USER_CURSUB: return sizeof(user.cursub) - 1;
case USER_CURDIR: return sizeof(user.curdir) - 1;
case USER_CURXTRN: return sizeof(user.curxtrn) - 1;
// Date/times:
case USER_LOGONTIME: return sizeof(user.logontime);
case USER_NS_TIME: return sizeof(user.ns_time);
case USER_LASTON: return sizeof(user.laston);
case USER_FIRSTON: return sizeof(user.firston);
// Counting stats:
case USER_LOGONS: return sizeof(user.logons);
case USER_LTODAY: return sizeof(user.ltoday);
case USER_TIMEON: return sizeof(user.timeon);
case USER_TTODAY: return sizeof(user.ttoday);
case USER_TLAST: return sizeof(user.tlast);
case USER_POSTS: return sizeof(user.posts);
case USER_EMAILS: return sizeof(user.emails);
case USER_FBACKS: return sizeof(user.fbacks);
case USER_ETODAY: return sizeof(user.etoday);
case USER_PTODAY: return sizeof(user.ptoday);
// File xfer stats:
case USER_ULB: return sizeof(user.ulb);
case USER_ULS: return sizeof(user.uls);
case USER_DLB: return sizeof(user.dlb);
case USER_DLS: return sizeof(user.dls);
case USER_DLCPS: return sizeof(user.dlcps);
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
case USER_LEECH: return sizeof(user.leech);
// Security:
case USER_PASS: return sizeof(user.pass) - 1;
case USER_PWMOD: return sizeof(user.pwmod);
case USER_LEVEL: return sizeof(user.level);
case USER_FLAGS1: return sizeof(user.flags1);
case USER_FLAGS2: return sizeof(user.flags2);
case USER_FLAGS3: return sizeof(user.flags3);
case USER_FLAGS4: return sizeof(user.flags4);
case USER_EXEMPT: return sizeof(user.exempt);
case USER_REST: return sizeof(user.rest);
case USER_CDT: return sizeof(user.cdt);
case USER_FREECDT: return sizeof(user.freecdt);
case USER_MIN: return sizeof(user.min);
case USER_TEXTRA: return sizeof(user.textra);
case USER_EXPIRE: return sizeof(user.expire);
default: return 0;
}
}
/****************************************************************************/
/* Determine if the specified user can or cannot access the specified sub */
/****************************************************************************/
bool can_user_access_sub(scfg_t* cfg, int subnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))

Rob Swindell
committed
if(!is_valid_subnum(cfg, subnum))
if(!chk_ar(cfg,cfg->grp[cfg->sub[subnum]->grp]->ar,user,client))
}
/****************************************************************************/
/* Determine if the specified user can or cannot read the specified sub */
/****************************************************************************/
bool can_user_read_sub(scfg_t* cfg, int subnum, user_t* user, client_t* client)
{
if(!can_user_access_sub(cfg, subnum, user, client))
return chk_ar(cfg,cfg->sub[subnum]->read_ar,user,client);
}
/****************************************************************************/
/* Determine if the specified user can or cannot post on the specified sub */
/* 'reason' is an (optional) pointer to a text.dat item number, indicating */
/* the reason the user cannot post, when returning false. */
/****************************************************************************/
bool can_user_post(scfg_t* cfg, int subnum, user_t* user, client_t* client, uint* reason)
{
if(reason!=NULL)
*reason=CantPostOnSub;
if(!can_user_access_sub(cfg, subnum, user, client))
if(cfg->sub[subnum]->misc&(SUB_QNET|SUB_FIDO|SUB_PNET|SUB_INET)
&& user->rest&FLAG('N')) /* network restriction? */
if((cfg->sub[subnum]->misc & SUB_NAME)
&& (user->rest & (FLAG('Q') | FLAG('O'))) == FLAG('O'))
if(reason!=NULL)
*reason=R_Post;
if(user->rest&FLAG('P')) /* post restriction? */
if(reason!=NULL)
*reason=TooManyPostsToday;
if(user->ptoday>=cfg->level_postsperday[user->level])
}
/****************************************************************************/
// Determine if the specified user can access one or more directories of lib
/****************************************************************************/
bool can_user_access_lib(scfg_t* cfg, int libnum, user_t* user, client_t* client)
{
uint count = 0;

Rob Swindell
committed
for(int dirnum = 0; dirnum < cfg->total_dirs; dirnum++) {
if(cfg->dir[dirnum]->lib != libnum)
continue;
if(can_user_access_dir(cfg, dirnum, user, client)) // checks lib's AR already
count++;
}
return count >= 1; // User has access to one or more directories of library
}
/****************************************************************************/
// Determine if the specified user can access ALL file libraries
/****************************************************************************/
bool can_user_access_all_libs(scfg_t* cfg, user_t* user, client_t* client)

Rob Swindell
committed
for(int libnum = 0; libnum < cfg->total_libs; libnum++) {
if(!can_user_access_lib(cfg, libnum, user, client))
}
/****************************************************************************/
// Determine if the specified user can all dirs of a lib
/****************************************************************************/
bool can_user_access_all_dirs(scfg_t* cfg, int libnum, user_t* user, client_t* client)
{
uint count = 0;

Rob Swindell
committed
for(int dirnum = 0; dirnum < cfg->total_dirs; dirnum++) {
if(cfg->dir[dirnum]->lib != libnum)
continue;
if(can_user_access_dir(cfg, dirnum, user, client)) // checks lib's AR already
count++;
else
}
return count >= 1; // User has access to one or more directories of library
}
/****************************************************************************/
/* Determine if the specified user can or cannot access the specified dir */
/****************************************************************************/
bool can_user_access_dir(scfg_t* cfg, int dirnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))

Rob Swindell
committed
if(!is_valid_dirnum(cfg, dirnum))
if(!chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->ar,user,client))
if(!chk_ar(cfg,cfg->dir[dirnum]->ar,user,client))
}
/****************************************************************************/
/* Determine if the specified user can or cannot upload files to the dirnum */
/* 'reason' is an (optional) pointer to a text.dat item number, indicating */
/* the reason the user cannot post, when returning false. */
/****************************************************************************/
bool can_user_upload(scfg_t* cfg, int dirnum, user_t* user, client_t* client, uint* reason)
{
if(reason!=NULL)
*reason=CantUploadHere;
if(!can_user_access_dir(cfg, dirnum, user, client))
if(reason!=NULL)
*reason=R_Upload;
if(user->rest&FLAG('U')) /* upload restriction? */
if(user->rest&FLAG('T')) /* transfer restriction? */
if(!(user->exempt&FLAG('U')) /* upload exemption */
&& !is_user_dirop(cfg, dirnum, user, client)) {
if(reason!=NULL)
*reason=CantUploadHere;
if(!chk_ar(cfg, cfg->lib[cfg->dir[dirnum]->lib]->ul_ar, user, client))
if(!chk_ar(cfg, cfg->dir[dirnum]->ul_ar, user, client))
}
/****************************************************************************/
/* Determine if the specified user can or cannot download files from dirnum */
/* 'reason' is an (optional) pointer to a text.dat item number, indicating */
/* the reason the user cannot post, when returning false. */
/****************************************************************************/
bool can_user_download(scfg_t* cfg, int dirnum, user_t* user, client_t* client, uint* reason)
{
if(reason!=NULL)
*reason=CantDownloadFromDir;

Rob Swindell
committed
if(dirnum != cfg->user_dir && !can_user_access_dir(cfg, dirnum, user, client))
if(!chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->dl_ar,user,client))
if(!chk_ar(cfg,cfg->dir[dirnum]->dl_ar,user,client))
if(reason!=NULL)
*reason=R_Download;
if(user->rest&FLAG('D')) /* download restriction? */
if(user->rest&FLAG('T')) /* transfer restriction? */
/****************************************************************************/
/* Determine if the specified user can or cannot send email */
/* 'reason' is an (optional) pointer to a text.dat item number */
/* usernumber==0 for netmail */
/****************************************************************************/
bool can_user_send_mail(scfg_t* cfg, enum smb_net_type net_type, uint usernumber, user_t* user, uint* reason)
{
if(reason!=NULL)
*reason=R_Email;
if(user==NULL || user->number==0)
if(net_type==NET_NONE && usernumber>1 && user->rest&FLAG('E')) /* local mail restriction? */
if(reason!=NULL)
*reason=NoNetMailAllowed;
if(net_type!=NET_NONE && user->rest&FLAG('M')) /* netmail restriction */
if(net_type==NET_FIDO && !(cfg->netmail_misc&NMAIL_ALLOW)) /* Fido netmail globally disallowed */
if(net_type==NET_INTERNET && !(cfg->inetmail_misc&NMAIL_ALLOW)) /* Internet mail globally disallowed */
if(reason!=NULL)
*reason=R_Feedback;
if(net_type==NET_NONE && usernumber==1 && user->rest&FLAG('S')) /* feedback restriction? */
if(reason!=NULL)
*reason=TooManyEmailsToday;
if(user->etoday>=cfg->level_emailperday[user->level] && !(user->exempt&FLAG('M')))
}
/****************************************************************************/
/* Determine if the specified user is a system operator */
/****************************************************************************/
bool is_user_sysop(user_t* user)
return user->level >= SYSOP_LEVEL;
}
/****************************************************************************/
/* Determine if the specified user is a sub-board operator */
/****************************************************************************/
bool is_user_subop(scfg_t* cfg, int subnum, user_t* user, client_t* client)
{
if(user==NULL)
if(!can_user_access_sub(cfg, subnum, user, client))
return cfg->sub[subnum]->op_ar[0]!=0 && chk_ar(cfg,cfg->sub[subnum]->op_ar,user,client);
}
/****************************************************************************/
/* Determine if the specified user is a directory operator */
/****************************************************************************/
bool is_user_dirop(scfg_t* cfg, int dirnum, user_t* user, client_t* client)
{
if(user==NULL)
if(!can_user_access_dir(cfg, dirnum, user, client))
return (cfg->dir[dirnum]->op_ar[0]!=0 && chk_ar(cfg,cfg->dir[dirnum]->op_ar,user,client))
|| (cfg->lib[cfg->dir[dirnum]->lib]->op_ar[0]!=0 && chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->op_ar,user,client));
/****************************************************************************/
/* Determine if downloads from the specified directory are free for the */
/* specified user */
/****************************************************************************/
bool is_download_free(scfg_t* cfg, int dirnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))

Rob Swindell
committed
if(!is_valid_dirnum(cfg, dirnum))
if(cfg->dir[dirnum]->misc&DIR_FREE)
if(user==NULL)
if(user->exempt&FLAG('D'))
if(cfg->lib[cfg->dir[dirnum]->lib]->ex_ar[0] != 0
&& chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->ex_ar,user,client))
/****************************************************************************/
/* Note: This function does not account for timed events! */
/****************************************************************************/
time_t gettimeleft(scfg_t* cfg, user_t* user, time_t starttime)
{
time_t now;
long tleft;
time_t timeleft;
now=time(NULL);
if(user->exempt&FLAG('T')) { /* Time online exemption */
timeleft=cfg->level_timepercall[user->level];
if(timeleft<10) /* never get below 10 minutes for exempt users */
timeleft*=60; /* convert to seconds */
}
else {
tleft=(((long)cfg->level_timeperday[user->level]-user->ttoday)
+user->textra)*60L;
if(tleft<0) tleft=0;
if(tleft>cfg->level_timepercall[user->level]*60)
tleft=cfg->level_timepercall[user->level]*60;
tleft+=user->min*60L;
long tused = (long)MAX(now - starttime, 0);
tleft -= tused;
if(tleft < 0)
tleft = 0;
if(tleft>0x7fffL)
timeleft=0x7fff;
else
return(timeleft);
}
/*************************************************************************/
/* Check a supplied name/alias and see if it's valid by our standards. */
/*************************************************************************/
bool check_name(scfg_t* cfg, const char* name)
{
char tmp[512];
size_t len;
len=strlen(name);
if(len<1)
if ( name[0] <= ' ' /* begins with white-space? */
|| name[len-1] <= ' ' /* ends with white-space */
|| !IS_ALPHA(name[0])
|| !stricmp(name,cfg->sys_id)
|| strchr(name,0xff)
|| matchuser(cfg,name,true /* sysop_alias */)
|| trashcan(cfg,name,"name")
|| alias(cfg,name,tmp)!=name
)
return false;
return true;
/*************************************************************************/
/* Check a supplied real name and see if it's valid by our standards. */
/*************************************************************************/
bool check_realname(scfg_t* cfg, const char* name)
{
if(name == NULL)
return (uchar)name[0]<0x7f && name[1] && IS_ALPHA(name[0]) && strchr(name,' ');
}
/****************************************************************************/
/* Login attempt/hack tracking */
/****************************************************************************/
/****************************************************************************/
link_list_t* loginAttemptListInit(link_list_t* list)
{
return listInit(list, LINK_LIST_MUTEX);
}
/****************************************************************************/
bool loginAttemptListFree(link_list_t* list)
{
return listFree(list);
}
/****************************************************************************/
/* Returns negative value on failure */
/****************************************************************************/
long loginAttemptListCount(link_list_t* list)
if(!listLock(list))
return -1;
count = listCountNodes(list);
listUnlock(list);
return count;
}
/****************************************************************************/
/* Returns number of items (attempts) removed from the list */
/* Returns negative value on failure */
/****************************************************************************/
long loginAttemptListClear(link_list_t* list)
long count;
if(!listLock(list))
return -1;
count=listCountNodes(list);
count-=listFreeNodes(list);
listUnlock(list);
return count;
}
/****************************************************************************/
static list_node_t* login_attempted(link_list_t* list, const union xp_sockaddr* addr)
{
list_node_t* node;
login_attempt_t* attempt;
if(list==NULL)
return NULL;
for(node=list->first; node!=NULL; node=node->next) {
attempt=node->data;
if(attempt->addr.addr.sa_family != addr->addr.sa_family)
continue;
if(memcmp(&attempt->addr.in.sin_addr, &addr->in.sin_addr, sizeof(addr->in.sin_addr)) == 0)
return node;
if(memcmp(&attempt->addr.in6.sin6_addr, &addr->in6.sin6_addr, sizeof(addr->in6.sin6_addr)) == 0)
return node;
}
return NULL;
}
/****************************************************************************/
/* Returns negative value on failure */
/****************************************************************************/
long loginAttempts(link_list_t* list, const union xp_sockaddr* addr)
long count=0;
if(addr->addr.sa_family != AF_INET && addr->addr.sa_family != AF_INET6)
return 0;
if(!listLock(list))
return -1;
if((node=login_attempted(list, addr))!=NULL)
count = ((login_attempt_t*)node->data)->count - ((login_attempt_t*)node->data)->dupes;
listUnlock(list);
return count;
/****************************************************************************/
void loginSuccess(link_list_t* list, const union xp_sockaddr* addr)
{
list_node_t* node;
if(addr->addr.sa_family != AF_INET && addr->addr.sa_family != AF_INET6)
return;
listLock(list);
if((node=login_attempted(list, addr)) != NULL)
listRemoveNode(list, node, /* freeData: */true);
listUnlock(list);
}
/****************************************************************************/
/* Returns number of *unique* login attempts (excludes consecutive dupes) */
/****************************************************************************/
ulong loginFailure(link_list_t* list, const union xp_sockaddr* addr, const char* prot, const char* user, const char* pass, login_attempt_t* details)
{
list_node_t* node;
login_attempt_t* attempt=&first;
ulong count=0;
if(addr->addr.sa_family != AF_INET && addr->addr.sa_family != AF_INET6)
return 0;
if(list==NULL)
return 0;
if(!listLock(list))
return 0;
if((node=login_attempted(list, addr)) != NULL) {
attempt=node->data;
/* Don't count consecutive duplicate attempts (same name and password): */
if((user!=NULL && strcmp(attempt->user,user)==0) && (pass!=NULL && strcmp(attempt->pass,pass)==0))
}
SAFECOPY(attempt->prot,prot);
attempt->time=time32(NULL);
memcpy(&attempt->addr, addr, sizeof(*addr));
if(user != NULL)
SAFECOPY(attempt->user, user);
memset(attempt->pass, 0, sizeof(attempt->pass));
if(pass != NULL)
SAFECOPY(attempt->pass, pass);
attempt->count++;
if(node==NULL) {
attempt->first = attempt->time;
listPushNodeData(list, attempt, sizeof(login_attempt_t));
listUnlock(list);
if (details != NULL)
*details = *attempt;
return count;
}
#if !defined(NO_SOCKET_SUPPORT)
ulong loginBanned(scfg_t* cfg, link_list_t* list, SOCKET sock, const char* host_name
,struct login_attempt_settings settings, login_attempt_t* details)
char ip_addr[128];
char name[(LEN_ALIAS * 2) + 1];
list_node_t* node;
login_attempt_t* attempt;
union xp_sockaddr client_addr;
union xp_sockaddr server_addr;
socklen_t addr_len;
char exempt[MAX_PATH+1];
SAFEPRINTF2(exempt, "%s%s", cfg->ctrl_dir, strIpFilterExemptConfigFile);
if(list==NULL)
return 0;
addr_len=sizeof(server_addr);
if((result=getsockname(sock, &server_addr.addr, &addr_len)) != 0)
return 0;
addr_len=sizeof(client_addr);
if((result=getpeername(sock, &client_addr.addr, &addr_len)) != 0)
return 0;
/* Don't ban connections from the server back to itself */
if(inet_addrmatch(&server_addr, &client_addr))
return 0;
if(inet_addrtop(&client_addr, ip_addr, sizeof(ip_addr)) != NULL
&& find2strs(ip_addr, host_name, exempt, NULL))
return 0;
if(!listLock(list))
return 0;
node = login_attempted(list, &client_addr);
listUnlock(list);
if(node == NULL)
return 0;
attempt = node->data;
SAFECOPY(name, attempt->user);
truncstr(name, "@");
if(((settings.tempban_threshold && (attempt->count - attempt->dupes) >= settings.tempban_threshold)
|| trashcan(cfg, name, "name")) && now < (time32_t)(attempt->time + settings.tempban_duration)) {
if(details != NULL)
*details = *attempt;
return settings.tempban_duration - (now - attempt->time);
/****************************************************************************/
/* Message-new-scan pointer/configuration functions */
/****************************************************************************/
bool getmsgptrs(scfg_t* cfg, user_t* user, subscan_t* subscan, void (*progress)(void*, int, int), void* cbdata)

Rob Swindell
committed
int i;