Newer
Older
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
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
/****************************************************************************/
/* 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);
}
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
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(-1);
SAFEPRINTF(str,"%suser/name.dat",cfg->data_dir);
if(fexist(str)) {
if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
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))!=0)
return(err);
if((err=putuserdat(cfg,user))!=0)
return(err);
SAFEPRINTF2(str,"%sfile/%04u.in",cfg->data_dir,user->number); /* delete any files */
delfiles(str, ALLFILES, /* keep: */0); /* waiting for user */
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(fp == NULL)
if(fread_dstats(fp, &stats)) {
stats.today.nusers++;
stats.total.nusers++;
fwrite_dstats(fp, &stats);
}
fclose_dstats(fp);
}
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
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);
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
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 */
/****************************************************************************/

Rob Swindell
committed
BOOL can_user_access_sub(scfg_t* cfg, int subnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))
return FALSE;

Rob Swindell
committed
if(!is_valid_subnum(cfg, subnum))
return FALSE;
if(!chk_ar(cfg,cfg->grp[cfg->sub[subnum]->grp]->ar,user,client))
return FALSE;
return FALSE;
return TRUE;
}
/****************************************************************************/
/* Determine if the specified user can or cannot read the specified sub */
/****************************************************************************/

Rob Swindell
committed
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 FALSE;
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. */
/****************************************************************************/

Rob Swindell
committed
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))
return FALSE;
return FALSE;
if(cfg->sub[subnum]->misc&(SUB_QNET|SUB_FIDO|SUB_PNET|SUB_INET)
&& user->rest&FLAG('N')) /* network restriction? */
return FALSE;
if((cfg->sub[subnum]->misc & SUB_NAME)
&& (user->rest & (FLAG('Q') | FLAG('O'))) == FLAG('O'))
return FALSE;
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])
return FALSE;
return TRUE;
}
/****************************************************************************/
// Determine if the specified user can access one or more directories of lib
/****************************************************************************/

Rob Swindell
committed
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))
return FALSE;
}
return TRUE;
}
/****************************************************************************/
// Determine if the specified user can all dirs of a lib
/****************************************************************************/

Rob Swindell
committed
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 FALSE;
}
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 */
/****************************************************************************/

Rob Swindell
committed
BOOL can_user_access_dir(scfg_t* cfg, int dirnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))
return FALSE;

Rob Swindell
committed
if(!is_valid_dirnum(cfg, dirnum))
return FALSE;
if(!chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->ar,user,client))
return FALSE;
if(!chk_ar(cfg,cfg->dir[dirnum]->ar,user,client))
return FALSE;
return TRUE;
}
/****************************************************************************/
/* 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. */
/****************************************************************************/

Rob Swindell
committed
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))
return FALSE;
if(reason!=NULL)
*reason=R_Upload;
if(user->rest&FLAG('U')) /* upload restriction? */
return FALSE;
if(user->rest&FLAG('T')) /* transfer restriction? */
return FALSE;
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))
return FALSE;
if(!chk_ar(cfg, cfg->dir[dirnum]->ul_ar, user, client))
return FALSE;
}
return TRUE;
}
/****************************************************************************/
/* 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. */
/****************************************************************************/

Rob Swindell
committed
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))
return FALSE;
if(!chk_ar(cfg,cfg->dir[dirnum]->dl_ar,user,client))
return FALSE;
if(reason!=NULL)
*reason=R_Download;
if(user->rest&FLAG('D')) /* download restriction? */
return FALSE;
if(user->rest&FLAG('T')) /* transfer restriction? */
return FALSE;
return TRUE;
}
/****************************************************************************/
/* 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)
return FALSE;
if(net_type==NET_NONE && usernumber>1 && user->rest&FLAG('E')) /* local mail restriction? */
return FALSE;
if(reason!=NULL)
*reason=NoNetMailAllowed;
if(net_type!=NET_NONE && user->rest&FLAG('M')) /* netmail restriction */
return FALSE;
if(net_type==NET_FIDO && !(cfg->netmail_misc&NMAIL_ALLOW)) /* Fido netmail globally disallowed */
return FALSE;
if(net_type==NET_INTERNET && !(cfg->inetmail_misc&NMAIL_ALLOW)) /* Internet mail globally disallowed */
return FALSE;
if(reason!=NULL)
*reason=R_Feedback;
if(net_type==NET_NONE && usernumber==1 && user->rest&FLAG('S')) /* feedback restriction? */
return FALSE;
if(reason!=NULL)
*reason=TooManyEmailsToday;
if(user->etoday>=cfg->level_emailperday[user->level] && !(user->exempt&FLAG('M')))
return FALSE;
return TRUE;
}
/****************************************************************************/
/* Determine if the specified user is a system operator */
/****************************************************************************/
BOOL is_user_sysop(user_t* user)
{
if(user == NULL)
return FALSE;
return user->level >= SYSOP_LEVEL;
}
/****************************************************************************/
/* Determine if the specified user is a sub-board operator */
/****************************************************************************/

Rob Swindell
committed
BOOL is_user_subop(scfg_t* cfg, int subnum, user_t* user, client_t* client)
{
if(user==NULL)
return FALSE;
if(!can_user_access_sub(cfg, subnum, user, client))
return FALSE;
return TRUE;
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 */
/****************************************************************************/

Rob Swindell
committed
BOOL is_user_dirop(scfg_t* cfg, int dirnum, user_t* user, client_t* client)
{
if(user==NULL)
return FALSE;
if(!can_user_access_dir(cfg, dirnum, user, client))
return FALSE;
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 */
/****************************************************************************/

Rob Swindell
committed
BOOL is_download_free(scfg_t* cfg, int dirnum, user_t* user, client_t* client)
{
if(!VALID_CFG(cfg))
return(FALSE);

Rob Swindell
committed
if(!is_valid_dirnum(cfg, dirnum))
return(FALSE);
if(cfg->dir[dirnum]->misc&DIR_FREE)
return(TRUE);
if(user==NULL)
return(FALSE);
if(user->exempt&FLAG('D'))
return(TRUE);
if(cfg->lib[cfg->dir[dirnum]->lib]->ex_ar[0] != 0
&& chk_ar(cfg,cfg->lib[cfg->dir[dirnum]->lib]->ex_ar,user,client))
return TRUE;
return(FALSE);
/****************************************************************************/
/* 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)
return FALSE;
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 FALSE;
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;
BOOL result = FALSE;
time32_t now = time32(NULL);
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;
int file;
long length;
FILE* stream;
/* Initialize to configured defaults */
for(i=0;i<cfg->total_subs;i++) {
subscan[i].ptr=subscan[i].sav_ptr=0;
subscan[i].last=subscan[i].sav_last=0;
subscan[i].cfg=0xff;
if(!(cfg->sub[i]->misc&SUB_NSDEF))
subscan[i].cfg&=~SUB_CFG_NSCAN;
if(!(cfg->sub[i]->misc&SUB_SSDEF))
subscan[i].cfg&=~SUB_CFG_SSCAN;
subscan[i].sav_cfg=subscan[i].cfg;
if(user->number == 0)
return 0;
if(user->rest&FLAG('G'))
return initmsgptrs(cfg, subscan, cfg->guest_msgscan_init, progress, cbdata);
/* New way: */
SAFEPRINTF2(path,"%suser/%4.4u.subs", cfg->data_dir, user->number);
FILE* fp = fnopen(NULL, path, O_RDONLY|O_TEXT);
if (fp != NULL) {
str_list_t ini = iniReadFile(fp);
for(i = 0; i < cfg->total_subs; i++) {
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
str_list_t keys = iniGetSection(ini, cfg->sub[i]->code);
if(keys == NULL)
continue;
subscan[i].ptr = iniGetUInt32(keys, NULL, "ptr" , subscan[i].ptr);
subscan[i].last = iniGetUInt32(keys, NULL, "last" , subscan[i].last);
subscan[i].cfg = iniGetShortInt(keys, NULL, "cfg" , subscan[i].cfg);
subscan[i].cfg &= (SUB_CFG_NSCAN|SUB_CFG_SSCAN|SUB_CFG_YSCAN); // Sanitize the 'cfg' value
subscan[i].sav_ptr = subscan[i].ptr;
subscan[i].sav_last = subscan[i].last;
subscan[i].sav_cfg = subscan[i].cfg;
iniFreeStringList(keys);
iniRemoveSection(&ini, cfg->sub[i]->code);
}
iniFreeStringList(ini);
fclose(fp);
if(progress != NULL)
progress(cbdata, i, cfg->total_subs);
return TRUE;
}
/* Old way: */
SAFEPRINTF2(path,"%suser/ptrs/%4.4u.ixb", cfg->data_dir, user->number);
if((stream=fnopen(&file,path,O_RDONLY))==NULL) {
if(fexist(path))
return(FALSE); /* file exists, but couldn't be opened? */
return initmsgptrs(cfg, subscan, cfg->new_msgscan_init, progress, cbdata);