From 68fb6de868a5e0daf128998cd60fe582f02dc287 Mon Sep 17 00:00:00 2001 From: kcwu Date: Sat, 1 Apr 2006 14:28:03 +0000 Subject: make it harder to multi-login by race condition. prevent logout function reenter. git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3319 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- mbbsd/mbbsd.c | 74 +++++++++++++++++++++++++++++++++++++---------------------- mbbsd/talk.c | 15 ++++++++---- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c index 31369b04..13b764d2 100644 --- a/mbbsd/mbbsd.c +++ b/mbbsd/mbbsd.c @@ -196,6 +196,13 @@ u_exit(const char *mode) void abort_bbs(int sig) { + /* ignore normal signals */ + Signal(SIGALRM, SIG_IGN); + Signal(SIGUSR1, SIG_IGN); + Signal(SIGUSR2, SIG_IGN); + Signal(SIGHUP, SIG_IGN); + Signal(SIGTERM, SIG_IGN); + Signal(SIGPIPE, SIG_IGN); if (currmode) u_exit("ABORTED"); exit(0); @@ -257,7 +264,7 @@ abort_bbs_debug(int sig) /* log */ /* assume vsnprintf() in log_file() is signal-safe, is it? */ log_file("log/crash.log", LOG_VF|LOG_CREAT, - "%ld %d\n", time4(NULL), getpid()); + "%ld %d %d %.12s\n", time4(NULL), getpid(), sig, cuser.userid); /* try logout... not a good idea, maybe crash again. now disabled */ /* @@ -532,7 +539,13 @@ getotherlogin(int num) /* skip sleeping process, this is slow if lots */ if(ui->mode == DEBUGSLEEPING) num++; - } while (ui->mode == DEBUGSLEEPING); + else if(ui->pid <= 0) + num++; + else if(kill(ui->pid, 0) < 0) + num++; + else + break; + } while (1); return ui; } @@ -546,28 +559,29 @@ multi_user_check(void) if (HasUserPerm(PERM_SYSOP)) return; /* don't check sysops */ + srandom(getpid()); + // race condition here, sleep may help..? if (cuser.userlevel) { + usleep(random()%1000000); // 0~1s ui = getotherlogin(1); if(ui == NULL) return; - if (!ui->pid /* || (kill(pid, 0) == -1) */ ) - return; /* stale entry in utmp file */ getdata(b_lines - 1, 0, "您想刪除其他重複的 login (Y/N)嗎?[Y] ", genbuf, 3, LCECHO); + usleep(random()%1000000); if (genbuf[0] != 'n') { - // race condition here, sleep may help..? - srandom(getpid()); - usleep(random()%1000000+100000); // 0.1~1.1s do { // scan again, old ui may be invalid ui = getotherlogin(1); if(ui==NULL) return; if (ui->pid > 0) { - if(kill(ui->pid, SIGHUP)<0) + if(kill(ui->pid, SIGHUP)<0) { + perror("kill SIGHUP fail"); break; + } log_usies("KICK ", cuser.nickname); } else { fprintf(stderr, "id=%s ui->pid=0\n", cuser.userid); @@ -878,12 +892,12 @@ check_BM(void) static void setup_utmp(int mode) { + /* NOTE, 在 getnewutmpent 之前不應該有任何 slow/blocking function */ userinfo_t uinfo; memset(&uinfo, 0, sizeof(uinfo)); uinfo.pid = currpid = getpid(); uinfo.uid = usernum; uinfo.mode = currstat = mode; - uinfo.alerts |= load_mailalert(cuser.userid); uinfo.userlevel = cuser.userlevel; uinfo.sex = cuser.sex % 8; @@ -1049,6 +1063,9 @@ user_login(void) struct tm ptime, lasttime; int nowusers, ifbirth = 0, i; + /* NOTE! 在 setup_utmp 之前, 不應該有任何 blocking/slow function, + * 否則可藉機 race condition 達到 multi-login */ + /* get local time */ ptime = *localtime4(&now); @@ -1062,25 +1079,6 @@ user_login(void) ((ptime.tm_mon+1) == cuser.month && ptime.tm_mday > cuser.day))) ) over18 = 1; - /* show welcome_login */ - if( (ifbirth = (ptime.tm_mday == cuser.day && - ptime.tm_mon + 1 == cuser.month)) ){ - more("etc/Welcome_birth", NA); - } - else { -#ifndef MULTI_WELCOME_LOGIN - more("etc/Welcome_login", NA); -#else - if( SHM->GV2.e.nWelcomes ){ - char buf[80]; - snprintf(buf, sizeof(buf), "etc/Welcome_login.%d", - (int)login_start_time % SHM->GV2.e.nWelcomes); - more(buf, NA); - } -#endif - } - refresh(); - log_usies("ENTER", fromhost); #ifndef VALGRIND setproctitle("%s: %s", margs, cuser.userid); @@ -1110,6 +1108,26 @@ user_login(void) enter_uflag = cuser.uflag; lasttime = *localtime4(&cuser.lastlogin); + /* show welcome_login */ + if( (ifbirth = (ptime.tm_mday == cuser.day && + ptime.tm_mon + 1 == cuser.month)) ){ + more("etc/Welcome_birth", NA); + } + else { +#ifndef MULTI_WELCOME_LOGIN + more("etc/Welcome_login", NA); +#else + if( SHM->GV2.e.nWelcomes ){ + char buf[80]; + snprintf(buf, sizeof(buf), "etc/Welcome_login.%d", + (int)login_start_time % SHM->GV2.e.nWelcomes); + more(buf, NA); + } +#endif + } + refresh(); + currutmp->alerts |= load_mailalert(cuser.userid); + if ((nowusers = SHM->UTMPnumber) > SHM->max_user) { SHM->max_user = nowusers; SHM->max_time = now; diff --git a/mbbsd/talk.c b/mbbsd/talk.c index abfd0e52..cde23af9 100644 --- a/mbbsd/talk.c +++ b/mbbsd/talk.c @@ -265,16 +265,19 @@ int sync_outta_server(int sfd) if(res<0) return -1; if(res==2) { + close(sfd); outs("登入太頻繁, 為避免系統負荷過重, 請稍後再試\n"); refresh(); - sleep(10); - abort_bbs(0); + sleep(30); + log_usies("REJECTLOGIN", NULL); + memset(currutmp, 0, sizeof(userinfo_t)); + exit(0); } verbose_progress(0, &iBar, &dir, barMax); if(toread(sfd, &nfs, sizeof(nfs))<0) return -1; - if(nfs<0 || nfs>=MAX_FRIEND) { + if(nfs<0 || nfs>MAX_FRIEND*2) { fprintf(stderr, "invalid nfs=%d\n",nfs); return -1; } @@ -282,6 +285,8 @@ int sync_outta_server(int sfd) if(toread(sfd, fs, sizeof(fs[0])*nfs)<0) return -1; + close(sfd); + verbose_progress(0, &iBar, &dir, barMax); for(i=0; iuinfo[fs[i].index].uid != fs[i].uid ) @@ -317,9 +322,9 @@ void login_friend_online(void) sfd = toconnect(OUTTACACHEHOST, OUTTACACHEPORT); if(sfd>=0) { int res=sync_outta_server(sfd); - close(sfd); - if(res==0) + if(res==0) // sfd will be closed if return 0 return; + close(sfd); } #endif -- cgit v1.2.3