diff options
author | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-20 19:33:49 +0800 |
---|---|---|
committer | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-20 19:33:49 +0800 |
commit | 6c7b18b32d87c2a835f7e5c48faac4a8ad44668b (patch) | |
tree | e88e1b2b1007f4ddcd348a4a1bf1d13c515c4564 /mbbsd/mbbsd.c | |
parent | f59699c22c130373cda3cc4cb6fab5bae510bd5a (diff) | |
download | pttbbs-piaip.newlayout.tar pttbbs-piaip.newlayout.tar.gz pttbbs-piaip.newlayout.tar.bz2 pttbbs-piaip.newlayout.tar.lz pttbbs-piaip.newlayout.tar.xz pttbbs-piaip.newlayout.tar.zst pttbbs-piaip.newlayout.zip |
- (internal/exp) first draft of new layoutpiaip.newlayout
git-svn-id: http://opensvn.csie.org/pttbbs/branches/piaip.newlayout@4013 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd/mbbsd.c')
-rw-r--r-- | mbbsd/mbbsd.c | 1832 |
1 files changed, 0 insertions, 1832 deletions
diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c deleted file mode 100644 index 0c561ed1..00000000 --- a/mbbsd/mbbsd.c +++ /dev/null @@ -1,1832 +0,0 @@ -/* $Id$ */ -#include "bbs.h" -#include "banip.h" - -#ifdef __linux__ -# ifdef CRITICAL_MEMORY -# include <malloc.h> -# endif -# ifdef DEBUG -# include <mcheck.h> -# endif -#endif - - -#define SOCKET_QLEN 4 - -static void do_aloha(const char *hello); -static void getremotename(const struct sockaddr_in * from, char *rhost, char *rname); - -#ifdef CONVERT -void big2gb_init(void*); -void gb2big_init(void*); -void big2uni_init(void*); -void uni2big_init(void*); -#endif - -////////////////////////////////////////////////////////////////// -// Site Optimization -// override these macro if you need more optimization, -// based on OS/lib/package... -#ifndef OPTIMIZE_LISTEN_SOCKET -#define OPTIMIZE_LISTEN_SOCKET(sock,sz) -#endif - -#ifndef XAUTH_HOST -#define XAUTH_HOST(x) x -#endif - -#ifndef XAUTH_GETREMOTENAME -#define XAUTH_GETREMOTENAME(x) x -#endif - -#ifndef XAUTH_TRYREMOTENAME -#define XAUTH_TRYREMOTENAME() -#endif - -#if 0 -static jmp_buf byebye; -#endif - -static char remoteusername[40] = "?"; -static unsigned char enter_uflag; -static int use_shell_login_mode = 0; -static int listen_port = 23; - -#ifdef DETECT_CLIENT -Fnv32_t client_code=FNV1_32_INIT; - -void UpdateClientCode(unsigned char c) -{ - FNV1A_CHAR(c, client_code); -} -#endif - -#ifdef USE_RFORK -#define fork() rfork(RFFDG | RFPROC | RFNOWAIT) -#endif - -/* set signal handler, which won't be reset once signal comes */ -static void -signal_restart(int signum, void (*handler) (int)) -{ - struct sigaction act; - act.sa_handler = handler; - memset(&(act.sa_mask), 0, sizeof(sigset_t)); - act.sa_flags = 0; - sigaction(signum, &act, NULL); -} - -static void -start_daemon(void) -{ - int n, fd; - - /* - * More idiot speed-hacking --- the first time conversion makes the C - * library open the files containing the locale definition and time zone. - * If this hasn't happened in the parent process, it happens in the - * children, once per connection --- and it does add up. - */ - time_t dummy = time(NULL); - struct tm *dummy_time = localtime(&dummy); - char buf[32]; - - strftime(buf, sizeof(buf), "%d/%b/%Y:%H:%M:%S", dummy_time); - -#ifndef NO_FORK - if ((n = fork())) { - exit(0); - } -#endif - - /* rocker.011018: it's a good idea to close all unexcept fd!! */ -#ifndef VALGRIND - n = getdtablesize(); - while (n) - close(--n); - - if( ((fd = open("log/stderr", O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) && fd != 2 ){ - dup2(fd, 2); - close(fd); - } -#endif - - if(getenv("SSH_CLIENT")) - unsetenv("SSH_CLIENT"); - - /* - * rocker.011018: we don't need to remember original tty, so request a - * new session id - */ - setsid(); - - /* - * rocker.011018: after new session, we should insure the process is - * clean daemon - */ -#ifndef NO_FORK - if ((n = fork())) { - exit(0); - } -#endif -} - -static void -reapchild(int sig) -{ - int state, pid; - - while ((pid = waitpid(-1, &state, WNOHANG | WUNTRACED)) > 0); -} - -void -log_usies(const char *mode, const char *mesg) -{ - now = time(NULL); - if (!mesg) - log_filef(FN_USIES, LOG_CREAT, - "%s %s %-12s Stay:%d (%s)\n", - Cdate(&now), mode, cuser.userid , - (int)(now - login_start_time) / 60, cuser.nickname); - else - log_filef(FN_USIES, LOG_CREAT, - "%s %s %-12s %s\n", - Cdate(&now), mode, cuser.userid, mesg); - - /* 追蹤使用者 */ - if (HasUserPerm(PERM_LOGUSER)) - log_user("logout"); -} - - -static void -setflags(int mask, int value) -{ - if (value) - cuser.uflag |= mask; - else - cuser.uflag &= ~mask; -} - -void -u_exit(const char *mode) -{ - int diff = (time(0) - login_start_time) / 60; - int dirty = currmode & MODE_DIRTY; - - currmode = 0; - - /* close fd 0 & 1 to terminate network */ - close(0); - close(1); - - assert(strncmp(currutmp->userid,cuser.userid, IDLEN)==0); - if(strncmp(currutmp->userid,cuser.userid, IDLEN)!=0) - return; - - reload_money(); - /* - cuser.goodpost = currutmp->goodpost; - cuser.badpost = currutmp->badpost; - cuser.goodsale = currutmp->goodsale; - cuser.badsale = currutmp->badsale; - */ - - auto_backup(); - setflags(PAGER_FLAG, currutmp->pager != PAGER_ON); - setflags(CLOAK_FLAG, currutmp->invisible); - save_brdbuf(); - brc_finalize(); - - cuser.invisible = currutmp->invisible; - cuser.withme = currutmp->withme; - cuser.pager = currutmp->pager; - memcpy(cuser.mind, currutmp->mind, 4); - setutmpbid(0); - - if (!SHM->GV2.e.shutdown) { - if (!(HasUserPerm(PERM_SYSOP) && HasUserPerm(PERM_SYSOPHIDE)) && - !currutmp->invisible) - do_aloha("<<下站通知>> -- 我走囉!"); - } - - - if ((cuser.uflag != enter_uflag) || dirty || diff) { - if (!diff && cuser.numlogins) - cuser.numlogins = --cuser.numlogins; - /* Leeym 上站停留時間限制式 */ - } - passwd_update(usernum, &cuser); - purge_utmp(currutmp); - log_usies(mode, NULL); -} - -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); -} - -#ifdef GCC_NORETURN -static void abort_bbs_debug(int sig) GCC_NORETURN; -#endif - -/* NOTE: It's better to use signal-safe functions. Avoid to call - * functions with global/static variable -- data may be corrupted */ -static void -abort_bbs_debug(int sig) -{ - int i; - sigset_t sigset; - - switch(sig) { - case SIGINT: STATINC(STAT_SIGINT); break; - case SIGQUIT: STATINC(STAT_SIGQUIT); break; - case SIGILL: STATINC(STAT_SIGILL); break; - case SIGABRT: STATINC(STAT_SIGABRT); break; - case SIGFPE: STATINC(STAT_SIGFPE); break; - case SIGBUS: STATINC(STAT_SIGBUS); break; - case SIGSEGV: STATINC(STAT_SIGSEGV); break; - case SIGXCPU: STATINC(STAT_SIGXCPU); break; - } - /* 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); - - /* unblock */ - sigemptyset(&sigset); - sigaddset(&sigset, SIGINT); - sigaddset(&sigset, SIGQUIT); - sigaddset(&sigset, SIGILL); - sigaddset(&sigset, SIGABRT); - sigaddset(&sigset, SIGFPE); - sigaddset(&sigset, SIGBUS); - sigaddset(&sigset, SIGSEGV); - sigaddset(&sigset, SIGXCPU); - sigprocmask(SIG_UNBLOCK, &sigset, NULL); - -#define CRASH_MSG ANSI_COLOR(0) \ - "\r\n程式異常, 立刻斷線. \r\n" \ - "請洽 " GLOBAL_BUGREPORT " 板詳述問題發生經過。\r\n" - -#define XCPU_MSG ANSI_COLOR(0) \ - "\r\n程式耗用過多計算資源, 立刻斷線。\r\n" \ - "可能是 (a)執行太多耗用資源的動作 或 (b)程式掉入無窮迴圈. "\ - "請洽 " GLOBAL_BUGREPORT " 板詳述問題發生經過。\r\n" - - if(sig==SIGXCPU) - write(1, XCPU_MSG, sizeof(XCPU_MSG)); - else - write(1, CRASH_MSG, sizeof(CRASH_MSG)); - - /* close all file descriptors (including the network connection) */ - for (i = 0; i < 256; ++i) - close(i); - - /* log */ - /* assume vsnprintf() in log_file() is signal-safe, is it? */ - log_filef("log/crash.log", LOG_CREAT, - "%d %d %d %.12s\n", time4(NULL), getpid(), sig, cuser.userid); - - /* try logout... not a good idea, maybe crash again. now disabled */ - /* - if (currmode) { - currmode = 0; - u_exit("AXXED"); - } - */ - -#ifdef DEBUGSLEEP - -#ifndef VALGRIND - setproctitle("debug me!(%d)(%s,%d)", sig, cuser.userid, currstat); -#endif - /* do this manually to prevent broken stuff */ - /* will broken currutmp cause problems here? hope not... */ - if(currutmp && strncmp(cuser.userid, currutmp->userid, IDLEN) == EQUSTR) - currutmp->mode = DEBUGSLEEPING; - - sleep(DEBUGSLEEP_SECONDS); -#endif - - exit(0); -} - -/* 登錄 BBS 程式 */ -static void -mysrand(void) -{ - srandom(time(NULL) + getpid()); /* 時間跟 pid 當 rand 的 seed */ -} - -void -talk_request(int sig) -{ - STATINC(STAT_TALKREQUEST); - bell(); - bell(); - if (currutmp->msgcount) { - char timebuf[100]; - - syncnow(); - move(0, 0); - clrtoeol(); - prints(ANSI_COLOR(33;41) "★%s" ANSI_COLOR(34;47) " [%s] %s " ANSI_COLOR(0) "", - SHM->uinfo[currutmp->destuip].userid, my_ctime(&now,timebuf,sizeof(timebuf)), - (currutmp->sig == 2) ? "重要消息廣播!(請Ctrl-U,l查看熱訊記錄)" - : "呼叫、呼叫,聽到請回答"); - refresh(); - } else { - unsigned char mode0 = currutmp->mode; - char c0 = currutmp->chatid[0]; - screen_backup_t old_screen; - - currutmp->mode = 0; - currutmp->chatid[0] = 1; - scr_dump(&old_screen); - talkreply(); - currutmp->mode = mode0; - currutmp->chatid[0] = c0; - scr_restore(&old_screen); - } -} - -void -show_call_in(int save, int which) -{ - char buf[200]; -#ifdef PLAY_ANGEL - if (currutmp->msgs[which].msgmode == MSGMODE_TOANGEL) - snprintf(buf, sizeof(buf), ANSI_COLOR(1;37;46) "★%s" ANSI_COLOR(37;45) " %s " ANSI_RESET, - currutmp->msgs[which].userid, currutmp->msgs[which].last_call_in); - else -#endif - snprintf(buf, sizeof(buf), ANSI_COLOR(1;33;46) "★%s" ANSI_COLOR(37;45) " %s " ANSI_RESET, - currutmp->msgs[which].userid, currutmp->msgs[which].last_call_in); - outmsg(buf); - - if (save) { - char genbuf[200]; - if (!fp_writelog) { - sethomefile(genbuf, cuser.userid, fn_writelog); - fp_writelog = fopen(genbuf, "a"); - } - if (fp_writelog) { - fprintf(fp_writelog, "%s [%s]\n", buf, Cdatelite(&now)); - } - } -} - -static int -add_history_water(water_t * w, const msgque_t * msg) -{ - memcpy(&w->msg[w->top], msg, sizeof(msgque_t)); - w->top++; - w->top %= WATERMODE(WATER_OFO) ? 5 : MAX_REVIEW; - - if (w->count < MAX_REVIEW) - w->count++; - - return w->count; -} - -static int -add_history(const msgque_t * msg) -{ - int i = 0, j, waterinit = 0; - water_t *tmp; - check_water_init(); - if (WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW)) - add_history_water(&water[0], msg); - if (WATERMODE(WATER_NEW) || WATERMODE(WATER_OFO)) { - for (i = 0; i < 5 && swater[i]; i++) - if (swater[i]->pid == msg->pid -#ifdef PLAY_ANGEL - && swater[i]->msg[0].msgmode == msg->msgmode - /* When throwing waterball to angel directly */ -#endif - ) - break; - if (i == 5) { - waterinit = 1; - i = 4; - memset(swater[4], 0, sizeof(water_t)); - } else if (!swater[i]) { - water_usies = i + 1; - swater[i] = &water[i + 1]; - waterinit = 1; - } - tmp = swater[i]; - - if (waterinit) { - memcpy(swater[i]->userid, msg->userid, sizeof(swater[i]->userid)); - swater[i]->pid = msg->pid; - } - if (!swater[i]->uin) - swater[i]->uin = currutmp; - - for (j = i; j > 0; j--) - swater[j] = swater[j - 1]; - swater[0] = tmp; - add_history_water(swater[0], msg); - } - if (WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW)) { - if (watermode > 0 && - (water_which == swater[0] || water_which == &water[0])) { - if (watermode < water_which->count) - watermode++; - t_display_new(); - } - } - return i; -} - -void -write_request(int sig) -{ - int i, msgcount; - - STATINC(STAT_WRITEREQUEST); -#ifdef NOKILLWATERBALL - if( reentrant_write_request ) /* kill again by shmctl */ - return; - reentrant_write_request = 1; -#endif - syncnow(); - check_water_init(); - if (WATERMODE(WATER_OFO)) { - /* 如果目前正在回水球模式的話, 就不能進行 add_history() , - 因為會改寫 water[], 而使回水球目的爛掉, 所以分成幾種情況考慮. - sig != 0表真的有水球進來, 故顯示. - sig == 0表示沒有水球進來, 不過之前尚有水球還沒寫到 water[]. - */ - static int alreadyshow = 0; - - if( sig ){ /* 真的有水球進來 */ - - /* 若原來正在 REPLYING , 則改成 RECVINREPLYING, - 這樣在回水球結束後, 會再呼叫一次 write_request(0) */ - if( wmofo == REPLYING ) - wmofo = RECVINREPLYING; - - /* 顯示 */ - for( ; alreadyshow < currutmp->msgcount && alreadyshow < MAX_MSGS - ; ++alreadyshow ){ - bell(); - show_call_in(1, alreadyshow); - refresh(); - } - } - - /* 看看是不是要把 currutmp->msg 拿回 water[] (by add_history()) - 須要是不在回水球中 (NOTREPLYING) */ - if( wmofo == NOTREPLYING && - (msgcount = currutmp->msgcount) > 0 ){ - for( i = 0 ; i < msgcount ; ++i ) - add_history(&currutmp->msgs[i]); - if( (currutmp->msgcount -= msgcount) < 0 ) - currutmp->msgcount = 0; - alreadyshow = 0; - } - } else { - if (currutmp->mode != 0 && - currutmp->pager != PAGER_OFF && - cuser.userlevel != 0 && - currutmp->msgcount != 0 && - currutmp->mode != TALK && - currutmp->mode != EDITING && - currutmp->mode != CHATING && - currutmp->mode != PAGE && - currutmp->mode != IDLE && - currutmp->mode != MAILALL && currutmp->mode != MONITOR) { - char c0 = currutmp->chatid[0]; - int currstat0 = currstat; - unsigned char mode0 = currutmp->mode; - - currutmp->mode = 0; - currutmp->chatid[0] = 2; - currstat = HIT; - -#ifdef NOKILLWATERBALL - currutmp->wbtime = 0; -#endif - if( (msgcount = currutmp->msgcount) > 0 ){ - for( i = 0 ; i < msgcount ; ++i ){ - bell(); - show_call_in(1, 0); - add_history(&currutmp->msgs[0]); - - if( (--currutmp->msgcount) < 0 ) - i = msgcount; /* force to exit for() */ - else if( currutmp->msgcount > 0 ) - memmove(&currutmp->msgs[0], - &currutmp->msgs[1], - sizeof(msgque_t) * currutmp->msgcount); - igetch(); - } - } - - currutmp->chatid[0] = c0; - currutmp->mode = mode0; - currstat = currstat0; - } else { - bell(); - show_call_in(1, 0); - add_history(&currutmp->msgs[0]); - - refresh(); - currutmp->msgcount = 0; - } - } -#ifdef NOKILLWATERBALL - reentrant_write_request = 0; - currutmp->wbtime = 0; /* race */ -#endif -} - -static userinfo_t* -getotherlogin(int num) -{ - userinfo_t *ui; - do { - if (!(ui = (userinfo_t *) search_ulistn(usernum, num))) - return NULL; /* user isn't logged in */ - - /* skip sleeping process, this is slow if lots */ - if(ui->mode == DEBUGSLEEPING) - num++; - else if(ui->pid <= 0) - num++; - else if(kill(ui->pid, 0) < 0) - num++; - else - break; - } while (1); - - return ui; -} - -static void -multi_user_check(void) -{ - register userinfo_t *ui; - char genbuf[3]; - - 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; - - getdata(b_lines - 1, 0, "您想刪除其他重複的 login 嗎?[Y/n] ", - genbuf, 3, LCECHO); - - usleep(random()%1000000); - if (genbuf[0] != 'n') { - 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) { - perror("kill SIGHUP fail"); - break; - } - log_usies("KICK ", cuser.nickname); - } else { - fprintf(stderr, "id=%s ui->pid=0\n", cuser.userid); - } - usleep(random()%2000000+1000000); // 1~3s - } while(getotherlogin(3) != NULL); - } else { - /* deny login if still have 3 */ - if (getotherlogin(3) != NULL) - abort_bbs(0); /* Goodbye(); */ - } - } else { - /* allow multiple guest user */ - if (search_ulistn(usernum, MAX_GUEST) != NULL) { - vmsg("抱歉,目前已有太多 guest 在站上, 請用new註冊。"); - exit(1); - } - } -} - -/* bad login */ -static char * const str_badlogin = "logins.bad"; - -static void -logattempt(const char *uid, char type) -{ - char fname[40]; - int fd, len; - char genbuf[200]; - - snprintf(genbuf, sizeof(genbuf), "%c%-12s[%s] %s@%s\n", type, uid, - Cdate(&login_start_time), remoteusername, fromhost); - len = strlen(genbuf); - if ((fd = open(str_badlogin, O_WRONLY | O_CREAT | O_APPEND, 0644)) > 0) { - write(fd, genbuf, len); - close(fd); - } - if (type == '-') { - snprintf(genbuf, sizeof(genbuf), - "[%s] %s\n", Cdate(&login_start_time), fromhost); - len = strlen(genbuf); - sethomefile(fname, uid, str_badlogin); - if ((fd = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0644)) > 0) { - write(fd, genbuf, len); - close(fd); - } - } -} - -void mkuserdir(const char *userid) -{ - char genbuf[200]; - sethomepath(genbuf, userid); - // assume it is a dir, so just check if it is exist - if (access(genbuf, F_OK) != 0) - mkdir(genbuf, 0755); -} - -static void -login_query(void) -{ -#ifdef CONVERT - /* uid 加一位, for gb login */ - char uid[IDLEN + 2], passbuf[PASSLEN]; - int attempts, len; -#else - char uid[IDLEN + 1], passbuf[PASSLEN]; - int attempts; -#endif - resolve_garbage(); - now = time(0); - -#ifdef DEBUG - move(1, 0); - prints("debugging mode\ncurrent pid: %d\n", getpid()); -#else - show_file("etc/Welcome", 1, -1, SHOWFILE_ALLOW_ALL); -#endif - // XXX why output("1", 1); here? - // this output has been here since rev 1... - // output("1", 1); - - attempts = 0; - while (1) { - if (attempts++ >= LOGINATTEMPTS) { - more("etc/goodbye", NA); - pressanykey(); - exit(1); - } - bzero(&cuser, sizeof(cuser)); - -#ifdef DEBUG - move(19, 0); - prints("current pid: %d ", getpid()); -#endif - - if (getdata(20, 0, "請輸入代號,或以[guest]參觀,以[new]註冊: ", - uid, sizeof(uid), DOECHO) < 1) - { - // got nothing - outs("請重新輸入。\n"); - continue; - } - -#ifdef CONVERT - /* switch to gb mode if uid end with '.' */ - len = strlen(uid); - if (uid[0] && uid[len - 1] == '.') { - set_converting_type(CONV_GB); - uid[len - 1] = 0; - redrawwin(); - } - else if (uid[0] && uid[len - 1] == ',') { - set_converting_type(CONV_UTF8); - uid[len - 1] = 0; - redrawwin(); - } - else if (len >= IDLEN + 1) - uid[IDLEN] = 0; -#endif - - if (strcasecmp(uid, str_new) == 0) { -#ifdef LOGINASNEW - new_register(); - mkuserdir(cuser.userid); - reginit_fav(); - break; -#else - outs("本系統目前無法以 new 註冊, 請用 guest 進入\n"); - continue; -#endif - } else if (!is_validuserid(uid)) { - - outs(err_uid); - - } else if (strcasecmp(uid, STR_GUEST) == 0) { /* guest */ - - if (initcuser(uid)< 1) exit (0) ; - cuser.userlevel = 0; - cuser.uflag = PAGER_FLAG | BRDSORT_FLAG | MOVIE_FLAG; - cuser.uflag2= 0; // we don't need FAVNEW_FLAG or anything else. - -#ifdef GUEST_DEFAULT_DBCS_NOINTRESC - cuser.uflag |= DBCS_NOINTRESC; -#endif - // can we prevent mkuserdir() here? - mkuserdir(cuser.userid); - break; - - } else { - - /* normal user */ - getdata(21, 0, MSG_PASSWD, - passbuf, sizeof(passbuf), NOECHO); - passbuf[8] = '\0'; - - move (22, 0); clrtoeol(); - outs("正在檢查密碼..."); - move(22, 0); refresh(); - /* prepare for later */ - clrtoeol(); - - if( initcuser(uid) < 1 || !cuser.userid[0] || - !checkpasswd(cuser.passwd, passbuf) ){ - - if(is_validuserid(cuser.userid)) - logattempt(cuser.userid , '-'); - outs(ERR_PASSWD); - - } else { - - logattempt(cuser.userid, ' '); - outs("密碼正確! 開始登入系統..."); - move(22, 0); refresh(); - clrtoeol(); - - if (strcasecmp(str_sysop, cuser.userid) == 0){ -#ifdef NO_SYSOP_ACCOUNT - exit(0); -#else /* 自動加上各個主要權限 */ - cuser.userlevel = PERM_BASIC | PERM_CHAT | PERM_PAGE | - PERM_POST | PERM_LOGINOK | PERM_MAILLIMIT | - PERM_CLOAK | PERM_SEECLOAK | PERM_XEMPT | - PERM_SYSOPHIDE | PERM_BM | PERM_ACCOUNTS | - PERM_CHATROOM | PERM_BOARD | PERM_SYSOP | PERM_BBSADM; -#endif - } - /* 早該有 home 了, 不知道為何有的帳號會沒有, 被砍掉了? */ - mkuserdir(cuser.userid); - break; - } - } - } - multi_user_check(); -#ifdef DETECT_CLIENT - { - int fd = open("log/client_code",O_WRONLY | O_CREAT | O_APPEND, 0644); - if(fd>=0) { - write(fd, &client_code, sizeof(client_code)); - close(fd); - } - } -#endif -} - -void -add_distinct(const char *fname, const char *line) -{ - FILE *fp; - int n = 0; - - if ((fp = fopen(fname, "a+"))) { - char buffer[80]; - char tmpname[100]; - FILE *fptmp; - - strlcpy(tmpname, fname, sizeof(tmpname)); - strcat(tmpname, "_tmp"); - if (!(fptmp = fopen(tmpname, "w"))) { - fclose(fp); - return; - } - rewind(fp); - while (fgets(buffer, 80, fp)) { - char *p = buffer + strlen(buffer) - 1; - - if (p[-1] == '\n' || p[-1] == '\r') - p[-1] = 0; - if (!strcmp(buffer, line)) - break; - sscanf(buffer + strlen(buffer) + 2, "%d", &n); - fprintf(fptmp, "%s%c#%d\n", buffer, 0, n); - } - - if (feof(fp)) - fprintf(fptmp, "%s%c#1\n", line, 0); - else { - sscanf(buffer + strlen(buffer) + 2, "%d", &n); - fprintf(fptmp, "%s%c#%d\n", buffer, 0, n + 1); - while (fgets(buffer, 80, fp)) { - sscanf(buffer + strlen(buffer) + 2, "%d", &n); - fprintf(fptmp, "%s%c#%d\n", buffer, 0, n); - } - } - fclose(fp); - fclose(fptmp); - rename(tmpname, fname); - } -} - -void -del_distinct(const char *fname, const char *line, int casesensitive) -{ - FILE *fp; - int n = 0; - - if ((fp = fopen(fname, "r"))) { - char buffer[80]; - char tmpname[100]; - FILE *fptmp; - - strlcpy(tmpname, fname, sizeof(tmpname)); - strcat(tmpname, "_tmp"); - if (!(fptmp = fopen(tmpname, "w"))) { - fclose(fp); - return; - } - rewind(fp); - while (fgets(buffer, 80, fp)) { - char *p = buffer + strlen(buffer) - 1; - - if (p[-1] == '\n' || p[-1] == '\r') - p[-1] = 0; - if(casesensitive) - { - if (!strcmp(buffer, line)) - break; - } else { - if (!strcasecmp(buffer, line)) - break; - } - sscanf(buffer + strlen(buffer) + 2, "%d", &n); - fprintf(fptmp, "%s%c#%d\n", buffer, 0, n); - } - - if (!feof(fp)) - while (fgets(buffer, 80, fp)) { - sscanf(buffer + strlen(buffer) + 2, "%d", &n); - fprintf(fptmp, "%s%c#%d\n", buffer, 0, n); - } - fclose(fp); - fclose(fptmp); - rename(tmpname, fname); - } -} - -#ifdef WHERE -static int -where(const char *from) -{ - int i; - - for (i = 0; i < SHM->home_num; i++) { - if ((SHM->home_ip[i] & SHM->home_mask[i]) == (ipstr2int(from) & SHM->home_mask[i])) { - return i; - } - } - return 0; -} -#endif - -static void -check_BM(void) -{ - /* XXX: -_- */ - int i; - - cuser.userlevel &= ~PERM_BM; - for( i = 0 ; i < numboards ; ++i ) - if( is_BM_cache(i + 1) ) /* XXXbid */ - return; - //for (i = 0, bhdr = bcache; i < numboards && !is_BM(bhdr->BM); i++, bhdr++); -} - -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.userlevel = cuser.userlevel; - uinfo.sex = cuser.sex % 8; - uinfo.lastact = time(NULL); - strlcpy(uinfo.userid, cuser.userid, sizeof(uinfo.userid)); - //strlcpy(uinfo.realname, cuser.realname, sizeof(uinfo.realname)); - strlcpy(uinfo.nickname, cuser.nickname, sizeof(uinfo.nickname)); - strip_nonebig5((unsigned char *)uinfo.nickname, sizeof(uinfo.nickname)); - strlcpy(uinfo.from, fromhost, sizeof(uinfo.from)); - uinfo.five_win = cuser.five_win; - uinfo.five_lose = cuser.five_lose; - uinfo.five_tie = cuser.five_tie; - uinfo.chc_win = cuser.chc_win; - uinfo.chc_lose = cuser.chc_lose; - uinfo.chc_tie = cuser.chc_tie; - uinfo.chess_elo_rating = cuser.chess_elo_rating; - uinfo.go_win = cuser.go_win; - uinfo.go_lose = cuser.go_lose; - uinfo.go_tie = cuser.go_tie; - uinfo.invisible = cuser.invisible % 2; - uinfo.pager = cuser.pager % PAGER_MODES; - /* - uinfo.goodpost = cuser.goodpost; - uinfo.badpost = cuser.badpost; - uinfo.goodsale = cuser.goodsale; - uinfo.badsale = cuser.badsale; - */ - if(cuser.withme & (cuser.withme<<1) & (WITHME_ALLFLAG<<1)) - cuser.withme = 0; /* unset all if contradict */ - uinfo.withme = cuser.withme & ~WITHME_ALLFLAG; - memcpy(uinfo.mind, cuser.mind, 4); - strip_nonebig5((unsigned char *)uinfo.mind, 4); -#ifdef WHERE - uinfo.from_alias = where(fromhost); -#endif -#ifndef FAST_LOGIN - setuserfile(buf, "remoteuser"); - - strlcpy(remotebuf, fromhost, sizeof(fromhost)); - strcat(remotebuf, ctime4(&now)); - chomp(remotebuf); - add_distinct(buf, remotebuf); -#endif - if (enter_uflag & CLOAK_FLAG) - uinfo.invisible = YEA; - -#ifdef PLAY_ANGEL - if (REJECT_QUESTION) - uinfo.angel = 1; - uinfo.angel |= ANGEL_STATUS() << 1; -#endif - - getnewutmpent(&uinfo); - currmode = MODE_STARTED; - SHM->UTMPneedsort = 1; - // XXX 不用每 20 才檢查吧 - if (!(cuser.numlogins % 20) && cuser.userlevel & PERM_BM) - check_BM(); /* Ptt 自動取下離職板主權力 */ - -#ifndef _BBS_UTIL_C_ - /* Very, very slow friend_load. */ - if( strcmp(cuser.userid, STR_GUEST) != 0 ) // guest 不處理好友 - friend_load(0); - nice(3); -#endif -} - -inline static void welcome_msg(void) -{ - prints(ANSI_RESET " 歡迎您第 " - ANSI_COLOR(1;33) "%d" ANSI_COLOR(0;37) " 度拜訪本站,上次您是從 " - ANSI_COLOR(1;33) "%s" ANSI_COLOR(0;37) " 連往本站," - ANSI_CLRTOEND "\n" - " 我記得那天是 " ANSI_COLOR(1;33) "%s" ANSI_COLOR(0;37) "。" - ANSI_CLRTOEND "\n" - ANSI_CLRTOEND "\n" - , - ++cuser.numlogins, cuser.lasthost, Cdate(&(cuser.lastlogin))); - pressanykey(); -} - -inline static void check_bad_login(void) -{ - char genbuf[200]; - setuserfile(genbuf, str_badlogin); - if (more(genbuf, NA) != -1) { - move(b_lines - 3, 0); - outs("通常並沒有辦法知道該ip是誰所有, " - "以及其意圖(是不小心按錯或有意測您密碼)\n" - "若您有帳號被盜用疑慮, 請經常更改您的密碼或使用加密連線"); - if (getans("您要刪除以上錯誤嘗試的記錄嗎? [y/N] ") == 'y') - unlink(genbuf); - } -} - -inline static void birthday_make_a_wish(const struct tm *ptime, const struct tm *tmp) -{ - if (tmp->tm_mday != ptime->tm_mday) { - more("etc/birth.post", YEA); - if (enter_board("WhoAmI")==0) { - do_post(); - } - } -} - -inline static void record_lasthost(const char *fromhost) -{ - strlcpy(cuser.lasthost, fromhost, sizeof(cuser.lasthost)); -} - -inline static void check_mailbox_quota(void) -{ - if (chkmailbox()) - m_read(); -} - -static void init_guest_info(void) -{ - int i; - char *nick[13] = { - "椰子", "貝殼", "內衣", "寶特瓶", "翻車魚", - "樹葉", "浮萍", "鞋子", "潛水艇", "魔王", - "鐵罐", "考卷", "大美女" - }; - char *name[13] = { - "大王椰子", "鸚鵡螺", "比基尼", "可口可樂", "仰泳的魚", - "憶", "高岡屋", "AIR Jordon", "紅色十月號", "批踢踢", - "SASAYA椰奶", "鴨蛋", "布魯克鱈魚香絲" - }; - char *addr[13] = { - "天堂樂園", "大海", "綠島小夜曲", "美國", "綠色珊瑚礁", - "遠方", "原本海", "NIKE", "蘇聯", "男八618室", - "愛之味", "天上", "藍色珊瑚礁" - }; - i = login_start_time % 13; - snprintf(cuser.nickname, sizeof(cuser.nickname), - "海邊漂來的%s", nick[(int)i]); - strlcpy(currutmp->nickname, cuser.nickname, - sizeof(currutmp->nickname)); - strlcpy(cuser.realname, name[(int)i], sizeof(cuser.realname)); - strlcpy(cuser.address, addr[(int)i], sizeof(cuser.address)); - cuser.sex = i % 8; - currutmp->pager = PAGER_DISABLE; -} - -#if FOREIGN_REG_DAY > 0 -inline static void foreign_warning(void){ - if ((cuser.uflag2 & FOREIGN) && !(cuser.uflag2 & LIVERIGHT)){ - if (login_start_time - cuser.firstlogin > (FOREIGN_REG_DAY - 5) * 24 * 3600){ - mail_muser(cuser, "[出入境管理局]", "etc/foreign_expired_warn"); - } - else if (login_start_time - cuser.firstlogin > FOREIGN_REG_DAY * 24 * 3600){ - cuser.userlevel &= ~(PERM_LOGINOK | PERM_POST); - vmsg("警告:請至出入境管理局申請永久居留"); - } - } -} -#endif - - -static void -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); - - /* 初始化: random number 增加user跟時間的差異 */ - mysrand(); - - log_usies("ENTER", fromhost); -#ifndef VALGRIND - setproctitle("%s: %s", margs, cuser.userid); -#endif - resolve_fcache(); - /* resolve_boards(); */ - numboards = SHM->Bnumber; - - if(getenv("SSH_CLIENT") != NULL){ - struct sockaddr_in xsin; - char frombuf[50]; - sscanf(getenv("SSH_CLIENT"), "%s", frombuf); - xsin.sin_family = AF_INET; - xsin.sin_port = htons(23); - if (strrchr(frombuf, ':')) - inet_pton(AF_INET, strrchr(frombuf, ':') + 1, &xsin.sin_addr); - else - inet_pton(AF_INET, frombuf, &xsin.sin_addr); - getremotename(&xsin, fromhost, remoteusername); /* RFC931 */ - } - - /* 初始化 uinfo、flag、mode */ - setup_utmp(LOGIN); - enter_uflag = cuser.uflag; - lasttime = *localtime4(&cuser.lastlogin); - redrawwin(); - - /* show welcome_login */ - if( (ifbirth = (ptime.tm_mday == cuser.day && - ptime.tm_mon + 1 == cuser.month)) ){ - char buf[PATHLEN]; - snprintf(buf, sizeof(buf), "etc/Welcome_birth.%d", getHoroscope(cuser.month, cuser.day)); - more(buf, 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; - } - - if (!(HasUserPerm(PERM_SYSOP) && HasUserPerm(PERM_SYSOPHIDE)) && - !currutmp->invisible) - { - /* do_aloha is costly. do it later? */ - do_aloha("<<上站通知>> -- 我來啦!"); - } - - if (SHM->loginmsg.pid){ - if(search_ulist_pid(SHM->loginmsg.pid)) - getmessage(SHM->loginmsg); - else - SHM->loginmsg.pid=0; - } - - if (cuser.userlevel) { /* not guest */ - move(t_lines - 4, 0); - clrtobot(); - welcome_msg(); - resolve_over18(); - - if( ifbirth ){ - birthday_make_a_wish(&ptime, &lasttime); - if( getans("是否要顯示「壽星」於使用者名單上?(y/N)") == 'y' ) - currutmp->birth = 1; - } - check_bad_login(); - check_mailbox_quota(); - check_register(); - record_lasthost(fromhost); - restore_backup(); - - } else if (strcmp(cuser.userid, STR_GUEST) == 0) { /* guest */ - - init_guest_info(); -#if 0 // def DBCSAWARE - u_detectDBCSAwareEvilClient(); -#else - pressanykey(); -#endif - } else { - // XXX no userlevel, no guest - what is this? - // clear(); - // outs("此帳號停權中"); - // pressanykey(); - // exit(1); - - check_mailbox_quota(); - } - - if(ptime.tm_yday!=lasttime.tm_yday) - STATINC(STAT_TODAYLOGIN_MAX); - - if (!PERM_HIDE(currutmp)) { - /* If you wanna do incremental upgrade - * (like, added a function/flag that wants user to confirm againe) - * put it here. - */ - -#if defined(DBCSAWARE) && defined(DBCSAWARE_UPGRADE_STARTTIME) - // define the real time you upgraded in your pttbbs.conf - if(cuser.lastlogin < DBCSAWARE_UPGRADE_STARTTIME) - { - if (u_detectDBCSAwareEvilClient()) - cuser.uflag &= ~DBCSAWARE_FLAG; - else - cuser.uflag |= DBCSAWARE_FLAG; - } -#endif - /* login time update */ - - if(ptime.tm_yday!=lasttime.tm_yday) - STATINC(STAT_TODAYLOGIN_MIN); - - - cuser.lastlogin = login_start_time; - - } - -#if FOREIGN_REG_DAY > 0 - foreign_warning(); -#endif - - passwd_update(usernum, &cuser); - - if(cuser.uflag2 & FAVNEW_FLAG) { - fav_load(); - if (get_fav_root() != NULL) { - int num; - num = updatenewfav(1); - if (num > NEW_FAV_THRESHOLD && - getans("找到 %d 個新看板,確定要加入我的最愛嗎?[Y/n]", num) == 'n') { - fav_free(); - fav_load(); - } - } - } - - for (i = 0; i < NUMVIEWFILE; i++) - if ((cuser.loginview >> i) & 1) - more(loginview_file[(int)i][0], YEA); -} - -static void -do_aloha(const char *hello) -{ - FILE *fp; - char userid[80]; - char genbuf[200]; - - setuserfile(genbuf, "aloha"); - if ((fp = fopen(genbuf, "r"))) { - while (fgets(userid, 80, fp)) { - userinfo_t *uentp; - if ((uentp = (userinfo_t *) search_ulist_userid(userid)) && - isvisible(uentp, currutmp)) { - my_write(uentp->pid, hello, uentp->userid, WATERBALL_ALOHA, uentp); - } - } - fclose(fp); - } -} - -static void -do_term_init(void) -{ - term_init(); - initscr(); - if(use_shell_login_mode) - raise(SIGWINCH); -} - -inline static void -start_client(void) -{ -#ifdef CPULIMIT - struct rlimit rml; - rml.rlim_cur = CPULIMIT * 60 - 5; - rml.rlim_max = CPULIMIT * 60; - setrlimit(RLIMIT_CPU, &rml); -#endif - - STATINC(STAT_LOGIN); - /* system init */ - nice(2); /* Ptt: lower priority */ - login_start_time = time(0); - currmode = 0; - - Signal(SIGHUP, abort_bbs); - Signal(SIGTERM, abort_bbs); - Signal(SIGPIPE, abort_bbs); - - Signal(SIGINT, abort_bbs_debug); - Signal(SIGQUIT, abort_bbs_debug); - Signal(SIGILL, abort_bbs_debug); - Signal(SIGABRT, abort_bbs_debug); - Signal(SIGFPE, abort_bbs_debug); - Signal(SIGBUS, abort_bbs_debug); - Signal(SIGSEGV, abort_bbs_debug); - Signal(SIGXCPU, abort_bbs_debug); - - signal_restart(SIGUSR1, talk_request); - signal_restart(SIGUSR2, write_request); - - dup2(0, 1); - - do_term_init(); - Signal(SIGALRM, abort_bbs); - alarm(600); - - login_query(); /* Ptt 加上login time out */ - m_init(); /* init the user mail path */ - user_login(); - auto_close_polls(); /* 自動開票 */ - - Signal(SIGALRM, SIG_IGN); - main_menu(); -} - -/* 取得 remote user name 以判定身份 */ -/* - * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC - * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote - * host to look up the owner of a connection. The information should not be - * used for authentication purposes. This routine intercepts alarm signals. - * - * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. - */ - -#define RFC931_TIMEOUT 10 -#define RFC931_PORT 113 /* Semi-well-known port */ -#define ANY_PORT 0 /* Any old port will do */ - -#if 0 -/* timeout - handle timeouts */ -static void -timeout(int sig) -{ - longjmp(byebye, sig); -} -#endif - -static void -getremotename(const struct sockaddr_in * from, char *rhost, char *rname) -{ - - /* get remote host name */ - -#ifdef FAST_LOGIN - XAUTH_HOST(strcpy(rhost, (char *)inet_ntoa(from->sin_addr))); -#else - struct sockaddr_in our_sin; - struct sockaddr_in rmt_sin; - unsigned rmt_port, rmt_pt; - unsigned our_port, our_pt; - FILE *fp; - char buffer[512], user[80], *cp; - int s; - static struct hostent *hp; - - - hp = NULL; - if (setjmp(byebye) == 0) { - Signal(SIGALRM, timeout); - alarm(3); - hp = gethostbyaddr((char *)&from->sin_addr, sizeof(struct in_addr), - from->sin_family); - alarm(0); - } - strcpy(rhost, hp ? hp->h_name : (char *)inet_ntoa(from->sin_addr)); - - /* - * Use one unbuffered stdio stream for writing to and for reading from - * the RFC931 etc. server. This is done because of a bug in the SunOS - * 4.1.x stdio library. The bug may live in other stdio implementations, - * too. When we use a single, buffered, bidirectional stdio stream ("r+" - * or "w+" mode) we read our own output. Such behaviour would make sense - * with resources that support random-access operations, but not with - * sockets. - */ - - s = sizeof(our_sin); - if (getsockname(0, (struct sockaddr *) & our_sin, &s) < 0) - return; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return; - - if (!(fp = fdopen(s, "r+"))) { - close(s); - return; - } - /* Set up a timer so we won't get stuck while waiting for the server. */ - if (setjmp(byebye) == 0) { - Signal(SIGALRM, timeout); - alarm(RFC931_TIMEOUT); - - /* - * Bind the local and remote ends of the query socket to the same IP - * addresses as the connection under investigation. We go through all - * this trouble because the local or remote system might have more - * than one network address. The RFC931 etc. client sends only port - * numbers; the server takes the IP addresses from the query socket. - */ - our_pt = ntohs(our_sin.sin_port); - our_sin.sin_port = htons(ANY_PORT); - - rmt_sin = *from; - rmt_pt = ntohs(rmt_sin.sin_port); - rmt_sin.sin_port = htons(RFC931_PORT); - - setbuf(fp, (char *)0); - s = fileno(fp); - - if (bind(s, (struct sockaddr *) & our_sin, sizeof(our_sin)) >= 0 && - connect(s, (struct sockaddr *) & rmt_sin, sizeof(rmt_sin)) >= 0) { - /* - * Send query to server. Neglect the risk that a 13-byte write - * would have to be fragmented by the local system and cause - * trouble with buggy System V stdio libraries. - */ - fprintf(fp, "%u,%u\r\n", rmt_pt, our_pt); - fflush(fp); - /* - * Read response from server. Use fgets()/sscanf() so we can work - * around System V stdio libraries that incorrectly assume EOF - * when a read from a socket returns less than requested. - */ - if (fgets(buffer, sizeof(buffer), fp) && !ferror(fp) - && !feof(fp) - && sscanf(buffer, "%u , %u : USERID :%*[^:]:%79s", &rmt_port, - &our_port, user) == 3 && rmt_pt == rmt_port - && our_pt == our_port) { - - /* - * Strip trailing carriage return. It is part of the - * protocol, not part of the data. - */ - if ((cp = (char *)strchr(user, '\r'))) - *cp = 0; - strlcpy(rname, user, sizeof(user)); - } - } - alarm(0); - } - fclose(fp); -#endif -} - -static int -bind_port(int port) -{ - int sock, on, sz; - struct linger lin; - struct sockaddr_in xsin; - - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - on = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)); - - lin.l_onoff = 0; - setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin)); - - sz = 1024; - setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&sz, sizeof(sz)); - sz = 4096; - setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&sz, sizeof(sz)); - - OPTIMIZE_LISTEN_SOCKET(sock, sz); - - xsin.sin_family = AF_INET; - xsin.sin_addr.s_addr = htonl(INADDR_ANY); - xsin.sin_port = htons(port); - if (bind(sock, (struct sockaddr *) & xsin, sizeof xsin) < 0) { - syslog(LOG_INFO, "bbsd bind_port can't bind to %d", port); - exit(1); - } - if (listen(sock, SOCKET_QLEN) < 0) { - syslog(LOG_INFO, "bbsd bind_port can't listen to %d", port); - exit(1); - } - return sock; -} - - -/*******************************************************/ - - -static int shell_login(int argc, char *argv[], char *envp[]); -static int daemon_login(int argc, char *argv[], char *envp[]); -static int check_ban_and_load(int fd); -static int check_banip(char *host); - -int -main(int argc, char *argv[], char *envp[]) -{ - start_time = time(NULL); - - /* avoid SIGPIPE */ - Signal(SIGPIPE, SIG_IGN); - - /* avoid erroneous signal from other mbbsd */ - Signal(SIGUSR1, SIG_IGN); - Signal(SIGUSR2, SIG_IGN); - -#if defined(__GLIBC__) && defined(CRITICAL_MEMORY) - #define MY__MMAP_THRESHOLD (1024 * 8) - #define MY__MMAP_MAX (0) - #define MY__TRIM_THRESHOLD (1024 * 8) - #define MY__TOP_PAD (0) - - mallopt (M_MMAP_THRESHOLD, MY__MMAP_THRESHOLD); - mallopt (M_MMAP_MAX, MY__MMAP_MAX); - mallopt (M_TRIM_THRESHOLD, MY__TRIM_THRESHOLD); - mallopt (M_TOP_PAD, MY__TOP_PAD); -#endif - - attach_SHM(); - if( (argc == 3 && shell_login(argc, argv, envp)) || - (argc != 3 && daemon_login(argc, argv, envp)) ) - start_client(); - - return 0; -} - -static int -shell_login(int argc, char *argv[], char *envp[]) -{ - int fd; - - STATINC(STAT_SHELLLOGIN); - /* Give up root privileges: no way back from here */ - setgid(BBSGID); - setuid(BBSUID); - chdir(BBSHOME); - -#if defined(linux) && defined(DEBUG) -// mtrace(); -#endif - - use_shell_login_mode = 1; - initsetproctitle(argc, argv, envp); - - snprintf(margs, sizeof(margs), "%s ssh ", argv[0]); - /* - * copy fromindent: Standard input:1138: Error:Unexpected end of file the - * original "bbs" - */ - if (argc > 1) { - strcpy(fromhost, argv[1]); - if (argc > 3) - strlcpy(remoteusername, argv[3], sizeof(remoteusername)); - } - close(2); - /* don't close fd 1, at least init_tty need it */ - if( ((fd = open("log/stderr", O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) && fd != 2 ){ - dup2(fd, 2); - close(fd); - } - - init_tty(); - if (check_ban_and_load(0)) { - sleep(10); - return 0; - } -#ifdef DETECT_CLIENT - FNV1A_CHAR(123, client_code); -#endif - return 1; -} - -static int -daemon_login(int argc, char *argv[], char *envp[]) -{ - int msock, csock; /* socket for Master and Child */ - FILE *fp; - int len_of_sock_addr, overloading = 0, i; - char buf[256]; -#if OVERLOADBLOCKFDS - int blockfd[OVERLOADBLOCKFDS]; - int nblocked = 0; -#endif - struct sockaddr_in xsin; - xsin.sin_family = AF_INET; - - /* setup standalone */ - start_daemon(); - signal_restart(SIGCHLD, reapchild); - - /* choose port */ - if( argc < 2 ) - listen_port = 3006; - else{ -#ifdef NO_FORK - listen_port = atoi(argv[1]); -#else - for( i = 1 ; i < (argc - 1) ; ++i ) - switch( fork() ){ - case -1: - perror("fork()"); - break; - case 0: - goto out; - default: - break; - } - out: - listen_port = atoi(argv[i]); -#endif - } - - /* port binding */ - if( (msock = bind_port(listen_port)) < 0 ){ - syslog(LOG_INFO, "mbbsd bind_port failed.\n"); - exit(1); - } - - /* Give up root privileges: no way back from here */ - setgid(BBSGID); - setuid(BBSUID); - chdir(BBSHOME); - - /* proctitle */ - initsetproctitle(argc, argv, envp); -#ifndef VALGRIND - snprintf(margs, sizeof(margs), "%s %d ", argv[0], listen_port); - setproctitle("%s: listening ", margs); -#endif - - /* It's better to do something before fork */ -#ifdef CONVERT - big2gb_init(NULL); - gb2big_init(NULL); - big2uni_init(NULL); - uni2big_init(NULL); -#endif - -#ifndef NO_FORK -#ifdef PRE_FORK - if( listen_port == 23 ){ // only pre-fork in port 23 - for( i = 0 ; i < PRE_FORK ; ++i ) - if( fork() <= 0 ) - break; - } -#endif -#endif - - snprintf(buf, sizeof(buf), - "run/mbbsd.%d.%d.pid", listen_port, (int)getpid()); - if ((fp = fopen(buf, "w"))) { - fprintf(fp, "%d\n", (int)getpid()); - fclose(fp); - } - - /* main loop */ - while( 1 ){ - len_of_sock_addr = sizeof(xsin); - if( -#if defined(Solaris) && __OS_MAJOR_VERSION__ == 5 && __OS_MINOR_VERSION__ < 7 - (csock = accept(msock, (struct sockaddr *)&xsin, - &len_of_sock_addr)) < 0 -#else - (csock = accept(msock, (struct sockaddr *)&xsin, - (socklen_t *)&len_of_sock_addr)) < 0 -#endif - ) { - if (errno != EINTR) - sleep(1); - continue; - } - - XAUTH_TRYREMOTENAME(); - - overloading = check_ban_and_load(csock); -#if OVERLOADBLOCKFDS - if( (!overloading && nblocked) || - (overloading && nblocked == OVERLOADBLOCKFDS) ){ - for( i = 0 ; i < OVERLOADBLOCKFDS ; ++i ) - if( blockfd[i] != csock && blockfd[i] != msock ) - /* blockfd[i] should not be msock, but it happened */ - close(blockfd[i]); - nblocked = 0; - } -#endif - - if( overloading ){ -#if OVERLOADBLOCKFDS - blockfd[nblocked++] = csock; -#else - close(csock); -#endif - continue; - } - -#ifdef NO_FORK - break; -#else - if (fork() == 0) - break; - else - close(csock); -#endif - } - /* here is only child running */ - -#ifndef VALGRIND - setproctitle("%s: ...login wait... ", margs); -#endif - close(msock); - dup2(csock, 0); - close(csock); - - XAUTH_GETREMOTENAME(getremotename(&xsin, fromhost, remoteusername)); - - if( check_banip(fromhost) ){ - sleep(10); - exit(0); - } - telnet_init(); - return 1; -} - -/* - * check if we're banning login and if the load is too high. if login is - * permitted, return 0; else return -1; approriate message is output to fd. - */ -static int -check_ban_and_load(int fd) -{ - FILE *fp; - static time4_t chkload_time = 0; - static int overload = 0; /* overload or banned, update every 1 - * sec */ - static int banned = 0; - -#ifdef INSCREEN - write(fd, INSCREEN, sizeof(INSCREEN)); -#else -#define BANNER \ -"【" BBSNAME "】◎ 台大流行網 ◎(" MYHOSTNAME ") 調幅(" MYIP ") \r\n" - write(fd, BANNER, sizeof(BANNER)); -#endif - - if ((time(0) - chkload_time) > 1) { - overload = 0; - banned = 0; - - if(cpuload(NULL) > MAX_CPULOAD) - overload = 1; - else if (SHM->UTMPnumber >= MAX_ACTIVE -#ifdef DYMAX_ACTIVE - || (SHM->GV2.e.dymaxactive > 2000 && - SHM->UTMPnumber >= SHM->GV2.e.dymaxactive) -#endif - ) { - ++SHM->GV2.e.toomanyusers; - overload = 2; - } else if(!access(BBSHOME "/" BAN_FILE, R_OK)) - banned = 1; - - chkload_time = time(0); - } - - if(overload == 1) - write(fd, "系統過載, 請稍後再來\r\n", 22); - else if(overload == 2) - write(fd, "由於人數過多,請您稍後再來。", 28); - else if (banned && (fp = fopen(BBSHOME "/" BAN_FILE, "r"))) { - char buf[256]; - while (fgets(buf, sizeof(buf), fp)) - write(fd, buf, strlen(buf)); - fclose(fp); - } - - if (banned || overload) - return -1; - - return 0; -} - -static int check_banip(char *host) -{ - unsigned int thisip = 0; - char *ptr, *myhost = strdup(host); - char *strtok_pos = NULL; - - for( ptr = strtok_r(myhost, ".", &strtok_pos) ; ptr != NULL ; ptr = strtok_r(NULL, ".", &strtok_pos) ) - thisip = thisip * 256 + atoi(ptr); - free(myhost); - - return uintbsearch(thisip, &banip[1], banip[0]) ? 1 : 0; -} - -/* vim: sw=4 - */ |