summaryrefslogtreecommitdiffstats
path: root/mbbsd/mbbsd.c
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2009-06-07 17:16:11 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2009-06-07 17:16:11 +0800
commit05baed35cab034b942d3c162d2991875d3652607 (patch)
treee9f3a01eda2cf985fa36f4a5716787b1e6992ebd /mbbsd/mbbsd.c
parentb7a5122870ebb28255d0ff64bf6b0a1f6c60b88f (diff)
downloadpttbbs-05baed35cab034b942d3c162d2991875d3652607.tar
pttbbs-05baed35cab034b942d3c162d2991875d3652607.tar.gz
pttbbs-05baed35cab034b942d3c162d2991875d3652607.tar.bz2
pttbbs-05baed35cab034b942d3c162d2991875d3652607.tar.lz
pttbbs-05baed35cab034b942d3c162d2991875d3652607.tar.xz
pttbbs-05baed35cab034b942d3c162d2991875d3652607.tar.zst
pttbbs-05baed35cab034b942d3c162d2991875d3652607.zip
* refine login procedure (support+prepare for tunnel mode)
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4509 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd/mbbsd.c')
-rw-r--r--mbbsd/mbbsd.c345
1 files changed, 266 insertions, 79 deletions
diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c
index f7fc9dd5..a89d6e3b 100644
--- a/mbbsd/mbbsd.c
+++ b/mbbsd/mbbsd.c
@@ -1,6 +1,7 @@
/* $Id$ */
#include "bbs.h"
#include "banip.h"
+#include "logind.h"
#ifdef __linux__
# ifdef CRITICAL_MEMORY
@@ -21,8 +22,8 @@ static void getremotename(const struct in_addr from, char *rhost);
// 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)
+#ifndef OPTIMIZE_SOCKET
+#define OPTIMIZE_SOCKET(sock) do {} while (0)
#endif
#ifndef XAUTH_HOST
@@ -41,19 +42,31 @@ enum TermMode {
TermMode_TELNET,
TermMode_TTY,
};
+
struct ProgramOption {
bool daemon_mode;
+ bool tunnel_mode;
enum TermMode term_mode;
int nport;
int port[MAX_BINDPORT];
int flag_listenfd;
+ char* flag_tunnel_path;
bool flag_bypass;
- char flag_user[IDLEN+1];
bool flag_fork;
bool flag_checkload;
+ char flag_user[IDLEN+1];
};
+static void
+free_program_option(struct ProgramOption *opt)
+{
+ if (!opt)
+ return;
+ free(opt->flag_tunnel_path);
+ free(opt);
+}
+
#ifdef DETECT_CLIENT
Fnv32_t client_code=FNV1_32_INIT;
@@ -650,7 +663,8 @@ multi_user_check(void)
}
}
-void mkuserdir(const char *userid)
+void
+mkuserdir(const char *userid)
{
char genbuf[PATHLEN];
sethomepath(genbuf, userid);
@@ -659,8 +673,76 @@ void mkuserdir(const char *userid)
mkdir(genbuf, 0755);
}
+static int
+load_current_user(const char *uid)
+{
+ // userid should be already normalized.
+
+ // ----------------------------------------------------- NEW ACCOUNT
+
+#ifdef STR_REGNEW
+ if (strcasecmp(uid, STR_REGNEW) == 0)
+ {
+
+# ifndef LOGINASNEW
+ assert(false);
+ exit(0);
+# endif // !LOGINASNEW
+
+ new_register();
+ mkuserdir(cuser.userid);
+ reginit_fav();
+ } else
+#endif
+
+ // --------------------------------------------------- GUEST ACCOUNT
+
+#ifdef STR_GUEST
+ if (strcasecmp(uid, STR_GUEST) == 0)
+ {
+ if (initcuser(STR_GUEST)< 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);
+ } else
+#endif
+
+ // ---------------------------------------------------- USER ACCOUNT
+ {
+ if (!cuser.userid[0] && initcuser(uid) < 1) exit(0);
+
+#ifdef LOCAL_LOGIN_MOD
+ LOCAL_LOGIN_MOD();
+#endif
+ if (strcasecmp(str_sysop, cuser.userid) == 0){
+#ifdef NO_SYSOP_ACCOUNT
+ exit(0);
+#else /* 自動加上各個主要權限 */
+ // TODO only allow in local connection?
+ 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);
+ }
+
+ // check multi user
+ multi_user_check();
+ return 1;
+}
+
static void
-login_query(void)
+login_query(char *ruid)
{
#ifdef CONVERT
/* uid 加一位, for gb login */
@@ -724,38 +806,33 @@ login_query(void)
uid[IDLEN] = 0;
#endif
-#ifdef STR_REGNEW
- if (strcasecmp(uid, STR_REGNEW) == 0) {
-# ifdef LOGINASNEW
- new_register();
- mkuserdir(cuser.userid);
- reginit_fav();
- break;
-# else // !LOGINASNEW
- outs("本系統目前無法以 " STR_REGNEW " 註冊, 請用 guest 進入\n");
- continue;
-# endif // !LOGINASNEW
- } else
-#endif // STR_REGNEW
-
if (!is_validuserid(uid)) {
outs(err_uid);
+#ifdef STR_GUEST
} 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;
+ strlcpy(ruid, STR_GUEST, IDLEN+1);
+ break;
#endif
- // can we prevent mkuserdir() here?
- mkuserdir(cuser.userid);
+
+#ifdef STR_REGNEW
+ } else if (strcasecmp(uid, STR_REGNEW) == 0) {
+# ifndef LOGINASNEW
+ outs("本系統目前無法以 " STR_REGNEW " 註冊"
+# ifdef STR_GUEST
+ ", 請用 " STR_GUEST " 進入"
+# endif // STR_GUEST
+ "\n");
+ continue;
+# endif // !LOGINASNEW
+
+ strlcpy(ruid, STR_REGNEW, IDLEN+1);
break;
+#endif // STR_REGNEW
+
} else {
/* normal user */
@@ -766,6 +843,7 @@ login_query(void)
move (22, 0); clrtoeol();
outs("正在檢查密碼...");
move(22, 0); refresh();
+
/* prepare for later */
clrtoeol();
@@ -779,33 +857,17 @@ login_query(void)
} else {
+ strlcpy(ruid, cuser.userid, IDLEN+1);
logattempt(cuser.userid, ' ', login_start_time, fromhost);
outs("密碼正確! 開始登入系統...");
move(22, 0); refresh();
clrtoeol();
-
-#ifdef LOCAL_LOGIN_MOD
- LOCAL_LOGIN_MOD();
-#endif
-
- 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();
+
+ // auth ok.
#ifdef DETECT_CLIENT
{
int fd = open("log/client_code",O_WRONLY | O_CREAT | O_APPEND, 0644);
@@ -1332,8 +1394,8 @@ do_term_init(enum TermMode term_mode)
raise(SIGWINCH);
}
-inline static int
-start_client(void)
+static int
+start_client(struct ProgramOption *option)
{
#ifdef CPULIMIT
struct rlimit rml;
@@ -1364,20 +1426,25 @@ start_client(void)
signal_restart(SIGUSR1, talk_request);
signal_restart(SIGUSR2, write_request);
-
Signal(SIGALRM, abort_bbs);
alarm(600);
mysrand(); /* 初始化: random number 增加user跟時間的差異 */
- login_query(); /* Ptt 加上login time out */
+ // if flag_user contains an uid, it is already authorized.
+ if (!option->flag_user[0])
+ {
+ // query user
+ login_query(option->flag_user);
+ }
+ // process new, register, and load user data
+ load_current_user(option->flag_user);
+
m_init(); /* init the user mail path */
user_login();
auto_close_polls(); /* 自動開票 */
Signal(SIGALRM, SIG_IGN);
- main_menu();
-
return 0;
}
@@ -1388,28 +1455,46 @@ getremotename(const struct in_addr fromaddr, char *rhost)
XAUTH_HOST(strcpy(rhost, (char *)inet_ntoa(fromaddr)));
}
-static int
-bind_port(int port)
+static int
+set_connection_opt(int sock)
{
- int sock, on, sz;
- struct linger lin;
- struct sockaddr_in xsin;
+ const int szrecv = 1024, szsend=4096;
+ const struct linger lin = {0};
+
+ // keep alive: server will check target connection.
+ // const int on = 1;
+ // setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on));
+
+ // fast close
+ setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin));
+ // adjust transmission window
+ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&szrecv, sizeof(szrecv));
+ setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&szsend, sizeof(szsend));
+ OPTIMIZE_SOCKET(sock);
- sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ return 0;
+}
+
+static int
+set_bind_opt(int sock)
+{
+ const int on = 1;
- on = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
- setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on));
+ set_connection_opt(sock);
- lin.l_onoff = 0;
- setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin));
+ return 0;
+}
- sz = 1024;
- setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&sz, sizeof(sz));
- sz = 4096;
- setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&sz, sizeof(sz));
+static int
+bind_port(int port)
+{
+ int sock;
+ struct sockaddr_in xsin;
- OPTIMIZE_LISTEN_SOCKET(sock, sz);
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ set_bind_opt(sock);
xsin.sin_family = AF_INET;
xsin.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -1429,10 +1514,12 @@ bind_port(int port)
/*******************************************************/
-static int shell_login(char *argv0, struct ProgramOption *option);
-static int daemon_login(char *argv0, struct ProgramOption *option);
+static int shell_login (char *argv0, struct ProgramOption *option);
+static int daemon_login (char *argv0, struct ProgramOption *option);
+static int tunnel_login (char *argv0, struct ProgramOption *option);
static int check_ban_and_load(int fd, struct ProgramOption *option);
-static int check_banip(char *host);
+static int start_client ( struct ProgramOption *option);
+static int check_banip (char *host);
static void init(void)
{
@@ -1470,6 +1557,7 @@ static void usage(char *argv0)
"\n"
"daemon mode\n"
"\t-d use daemon mode, imply -t telnet\n"
+ "\t-n tunnel enable tunnel mode, imply -d\n"
"\t-p port listen port\n"
"\t-l fd pre-listen fd\n"
"\n"
@@ -1501,8 +1589,12 @@ bool parse_argv(int argc, char *argv[], struct ProgramOption *option)
option->flag_listenfd = -1;
option->flag_checkload = true;
- while ((ch = getopt(argc, argv, "dp:l:Dt:h:e:bu:FC")) != -1) {
+ while ((ch = getopt(argc, argv, "dn:p:l:Dt:h:e:bu:FC")) != -1) {
switch (ch) {
+ case 'n':
+ option->tunnel_mode = true;
+ option->flag_tunnel_path = strdup(optarg);
+ // reuse 'd' mode, no break here.
case 'd':
given_mode = true;
option->daemon_mode = true;
@@ -1588,7 +1680,12 @@ bool parse_argv(int argc, char *argv[], struct ProgramOption *option)
}
}
- if (option->nport == 0) {
+ if ( option->tunnel_mode && option->nport != 0) {
+ fprintf(stderr, "you cannot bind ports port in tunnel mode.\n");
+ return false;
+ }
+
+ if (!option->tunnel_mode && option->nport == 0) {
fprintf(stderr, "don't forget specify port number (-p)\n");
return false;
}
@@ -1620,19 +1717,24 @@ main(int argc, char *argv[], char *envp[])
attach_SHM();
- if (option->daemon_mode)
- oklogin = daemon_login(argv[0], option);
+ if (!option->daemon_mode)
+ oklogin = shell_login (argv[0], option);
+ else if (option->tunnel_mode)
+ oklogin = tunnel_login(argv[0], option);
else
- oklogin = shell_login(argv[0], option);
+ oklogin = daemon_login(argv[0], option);
+
if (!oklogin) {
- free(option);
+ free_program_option(option);
return 0;
}
do_term_init(option->term_mode);
- free(option);
+ start_client(option);
+ free_program_option(option);
- return start_client();
+ // tail recursion!
+ return main_menu();
}
static int
@@ -1678,6 +1780,91 @@ shell_login(char *argv0, struct ProgramOption *option)
}
static int
+tunnel_login(char *argv0, struct ProgramOption *option)
+{
+ int tunnel = 0, csock = 0, success = 1;
+ struct login_data dat = {0};
+ char buf[PATHLEN];
+ FILE *fp;
+
+ /* setup standalone */
+ start_daemon(option);
+ signal_restart(SIGCHLD, reapchild);
+
+ assert( option->flag_tunnel_path &&
+ *option->flag_tunnel_path);
+
+ tunnel = toconnect(option->flag_tunnel_path);
+ if (tunnel < 0)
+ {
+ syslog(LOG_ERR, "mbbsd tunnel connection failed: %s\n",
+ option->flag_tunnel_path);
+ exit(1);
+ }
+
+ /* Give up root privileges: no way back from here */
+ setgid(BBSGID);
+ setuid(BBSUID);
+ chdir(BBSHOME);
+
+ /* proctitle */
+#ifndef VALGRIND
+ snprintf(margs, sizeof(margs), "%s tunnel=%u ", argv0, (unsigned int)getpid());
+ setproctitle("%s: listening ", margs);
+#endif
+
+ // log pid
+ snprintf(buf, sizeof(buf),
+ "run/mbbsd.%s.%u.pid", "tunnel", (unsigned int)getpid());
+ if ((fp = fopen(buf, "w"))) {
+ fprintf(fp, "%d\n", (int)getpid());
+ fclose(fp);
+ }
+
+ /* main loop */
+ while( 1 )
+ {
+ csock = recv_remote_fd(tunnel);
+
+ // XXX use continue or return herer?
+ if (csock < 0)
+ {
+ return 0;
+ }
+ if (toread (tunnel, &dat, sizeof(dat)) < sizeof(dat) ||
+ towrite(tunnel, &success, sizeof(success)) < sizeof(success))
+ return 0;
+
+ // optimize connection
+ set_connection_opt(csock);
+
+ if (option->flag_fork) {
+ if (fork() == 0)
+ break;
+ else
+ close(csock);
+ }
+ }
+ /* here is only child running */
+
+#ifndef VALGRIND
+ setproctitle("%s: ...login wait... ", margs);
+#endif
+ close(tunnel);
+ dup2(csock, 0);
+ close(csock);
+ dup2(0, 1);
+
+ strlcpy(fromhost, dat.hostip, sizeof(fromhost));
+ strlcpy(option->flag_user, dat.userid, sizeof(option->flag_user));
+ if (dat.encoding)
+ set_converting_type(dat.encoding);
+ resizeterm(dat.t_lines, dat.t_cols);
+ telnet_init();
+ return 1;
+}
+
+static int
daemon_login(char *argv0, struct ProgramOption *option)
{
int msock = 0, csock; /* socket for Master and Child */