summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-rw-r--r--daemon/logind/logind.c174
1 files changed, 137 insertions, 37 deletions
diff --git a/daemon/logind/logind.c b/daemon/logind/logind.c
index 6cc8b79b..50134092 100644
--- a/daemon/logind/logind.c
+++ b/daemon/logind/logind.c
@@ -24,17 +24,23 @@
#include <signal.h>
#include <event.h>
+// XXX should we need to keep this definition?
#define _BBS_UTIL_C_
+
#include "bbs.h"
#include "banip.h"
#include "logind.h"
-#ifndef OPTIMIZE_SOCKET
-#define OPTIMIZE_SOCKET(sock) do {} while(0)
+#ifndef LOGIND_REGULAR_CHECK_DURATION
+#define LOGIND_REGULAR_CHECK_DURATION (15)
+#endif
+
+#ifndef LOGIND_MAX_FDS
+#define LOGIND_MAX_FDS (100000)
#endif
-#ifndef SOCKET_QLEN
-#define SOCKET_QLEN (10)
+#ifndef LOGIND_SOCKET_QLEN
+#define LOGIND_SOCKET_QLEN (10)
#endif
#ifndef AUTHFAIL_SLEEP_SEC
@@ -53,25 +59,26 @@
#define IDLE_TIMEOUT_SEC (20*60)
#endif
+#ifndef MAX_TEXT_SCREEN_LINES
#define MAX_TEXT_SCREEN_LINES (24)
+#endif
-#ifndef MAX_FDS
-#define MAX_FDS (100000)
+#ifndef OPTIMIZE_SOCKET
+#define OPTIMIZE_SOCKET(sock) do {} while(0)
#endif
// to prevent flood trying services...
-#ifndef MAX_RETRY_SERVICE
-#define MAX_RETRY_SERVICE (100)
+#ifndef LOGIND_MAX_RETRY_SERVICE
+#define LOGIND_MAX_RETRY_SERVICE (15)
#endif
+// local definiions
#define MY_SVC_NAME "logind"
#define LOG_PREFIX "[logind] "
///////////////////////////////////////////////////////////////////////
// global variables
int g_tunnel; // tunnel for service daemon
-int g_reload_data = 1; // request to reload data
-time4_t g_welcome_mtime;
// server status
int g_overload = 0;
@@ -83,6 +90,12 @@ int g_opened_fd= 0;
char g_retry_cmd[PATHLEN];
int g_retry_times;
+// cache data
+int g_reload_data = 1; // request to reload data
+time4_t g_welcome_mtime;
+int g_guest_usernum = 0; // numeric uid of guest account
+int g_guest_too_many = 0; // 1 if exceed MAX_GUEST
+
///////////////////////////////////////////////////////////////////////
// login context, constants and states
@@ -100,7 +113,8 @@ enum {
LOGIN_HANDLE_PROMPT_PASSWD,
LOGIN_HANDLE_START_AUTH,
- AUTH_RESULT_STOP = -2,
+ AUTH_RESULT_STOP = -3,
+ AUTH_RESULT_FREEID_TOOMANY = -2,
AUTH_RESULT_FREEID = -1,
AUTH_RESULT_FAIL = 0,
AUTH_RESULT_RETRY = AUTH_RESULT_FAIL,
@@ -531,6 +545,10 @@ _set_bind_opt(int sock)
///////////////////////////////////////////////////////////////////////
// Draw Screen
+#ifndef SITE_BANNER
+#define SITE_BANNER ANSI_RESET "\r\n【" BBSNAME "】◎(" MYHOSTNAME ", " MYIP ") \r\n"
+#endif
+
#ifdef STR_GUEST
# define MSG_GUEST ",或以[" STR_GUEST "]參觀"
#else
@@ -566,6 +584,14 @@ _set_bind_opt(int sock)
#define OVERLOAD_USER_MSG ANSI_RESET " 由於人數過多,請您稍後再來... "
#define OVERLOAD_USER_YX BOTTOM_YX
+#define REJECT_FREE_UID_MSG ANSI_RESET " 抱歉,此帳號或服務已達上限。 "
+#define REJECT_FREE_UID_YX BOTTOM_YX
+
+#ifdef STR_GUEST
+#define TOO_MANY_GUEST_MSG ANSI_RESET " 抱歉,目前已有太多 " STR_GUEST " 在站上。 "
+#define TOO_MANY_GUEST_YX BOTTOM_YX
+#endif
+
#define FN_WELCOME BBSHOME "/etc/Welcome"
#define FN_GOODBYE BBSHOME "/etc/goodbye"
#define FN_BAN BBSHOME "/" BAN_FILE
@@ -799,11 +825,26 @@ draw_overload(login_conn_ctx *conn, int type)
}
}
+static void
+draw_reject_free_userid(login_conn_ctx *conn, const char *freeid)
+{
+ _mt_move_yx(conn, PASSWD_CHECK_YX); _mt_clrtoeol(conn);
+#ifdef STR_GUEST
+ if (strcasecmp(freeid, STR_GUEST) == 0)
+ {
+ _mt_move_yx(conn, TOO_MANY_GUEST_YX); _mt_clrtoeol(conn);
+ _buff_write(conn, TOO_MANY_GUEST_MSG, sizeof(TOO_MANY_GUEST_MSG)-1);
+ return;
+ }
+#endif
+ _mt_move_yx(conn, REJECT_FREE_UID_YX); _mt_clrtoeol(conn);
+ _buff_write(conn, REJECT_FREE_UID_MSG, sizeof(REJECT_FREE_UID_MSG)-1);
+
+}
+
///////////////////////////////////////////////////////////////////////
// BBS Logic
-#define REGULAR_CHECK_DURATION (5)
-
static void
regular_check()
{
@@ -811,12 +852,14 @@ regular_check()
static time_t last_check_time = 0;
time_t now = time(0);
- if ( now - last_check_time < REGULAR_CHECK_DURATION)
+ if ( now - last_check_time < LOGIND_REGULAR_CHECK_DURATION)
return;
last_check_time = now;
g_overload = 0;
g_banned = 0;
+ g_guest_too_many = 0;
+ g_guest_usernum = 0;
if (cpuload(NULL) > MAX_CPULOAD)
{
@@ -873,6 +916,56 @@ auth_is_free_userid(const char *userid)
return NULL;
}
+static int
+auth_check_free_userid_allowance(const char *userid)
+{
+#ifdef STR_REGNEW
+ // accept all 'new' command.
+ if (strcasecmp(userid, STR_REGNEW) == 0)
+ return 1;
+#endif
+
+#ifdef STR_GUEST
+ if (strcasecmp(userid, STR_GUEST) == 0)
+ {
+# ifndef MAX_GUEST
+ g_guest_too_many = 0;
+# else
+ // if already too many guest, fast reject until next regular check.
+ if (g_guest_too_many)
+ return 0;
+
+ // now, load guest account information.
+ if (!g_guest_usernum)
+ {
+ if (g_verbose) fprintf(stderr, LOG_PREFIX " reload guest information\r\n");
+
+ // reload guest information
+ g_guest_usernum = searchuser(STR_GUEST, NULL);
+
+ if (g_guest_usernum < 1 || g_guest_usernum > MAX_USERS)
+ g_guest_usernum = 0;
+
+ // if guest is not created, it's administrator's problem...
+ assert(g_guest_usernum);
+ }
+
+ // update the 'too many' status.
+ g_guest_too_many =
+ (!g_guest_usernum || (search_ulistn(g_guest_usernum, MAX_GUEST) != NULL));
+ if (g_verbose) fprintf(stderr, LOG_PREFIX " guests are %s\r\n",
+ g_guest_too_many ? "TOO MANY" : "ok.");
+
+# endif // MAX_GUEST
+ return g_guest_too_many ? 0 : 1;
+ }
+#endif // STR_GUEST
+
+ // shall never reach here.
+ assert(0);
+ return 0;
+}
+
// NOTE ctx->passwd will be destroyed (must > PASSLEN+1)
// NOTE ctx->userid may be changed (must > IDLEN+1)
@@ -917,11 +1010,11 @@ retry_service()
if (!*g_retry_cmd)
return;
- if (g_retry_times >= MAX_RETRY_SERVICE)
+ if (g_retry_times >= LOGIND_MAX_RETRY_SERVICE)
{
fprintf(stderr, LOG_PREFIX
"retry too many times (>%d), stop and wait manually maintainance.\r\n",
- MAX_RETRY_SERVICE);
+ LOGIND_MAX_RETRY_SERVICE);
return;
}
@@ -976,7 +1069,7 @@ static int
auth_start(int fd, login_conn_ctx *conn)
{
login_ctx *ctx = &conn->ctx;
- int isfree = 1, was_valid_uid = 0;
+ int isfree = 0, was_valid_uid = 0;
draw_check_passwd(conn);
if (is_validuserid(ctx->userid))
@@ -989,11 +1082,21 @@ auth_start(int fd, login_conn_ctx *conn)
logattempt(ctx->userid , '-', time(0), ctx->hostip);
break;
- case AUTH_RESULT_OK:
- isfree = 0;
- logattempt(ctx->userid , ' ', time(0), ctx->hostip);
- // share FREEID case, no break here!
case AUTH_RESULT_FREEID:
+ isfree = 1;
+ // share FREEID case, no break here!
+ case AUTH_RESULT_OK:
+ if (!isfree)
+ {
+ logattempt(ctx->userid , ' ', time(0), ctx->hostip);
+ }
+ else if (!auth_check_free_userid_allowance(ctx->userid))
+ {
+ // XXX since the only case of free
+ draw_reject_free_userid(conn, ctx->userid);
+ return AUTH_RESULT_STOP;
+ }
+
draw_auth_success(conn, isfree);
if (!start_service(fd, ctx))
@@ -1283,33 +1386,30 @@ listen_cb(int lfd, short event, void *arg)
if (g_banned || check_banip(conn->ctx.hostip) )
{
// draw ban screen, if available. (for banip, this is empty).
- draw_text_screen(conn, ban_screen);
+ draw_text_screen (conn, ban_screen);
login_conn_remove(conn, fd, BAN_SLEEP_SEC);
return;
}
// draw banner
// XXX for systems that needs high performance, you must reduce the
- // string in INSCREEN/banner.
- // if you have your own banner, define as INSCREEN in pttbbs.conf
- // if you don't want anny benner, define NO_INSCREEN
-#ifndef NO_INSCREEN
-# ifndef INSCREEN
-# define INSCREEN "【" BBSNAME "】◎(" MYHOSTNAME ", " MYIP ") \r\n"
-# endif
- _mt_clear(conn);
- _buff_write(conn, INSCREEN, sizeof(INSCREEN));
-#endif
+ // string in banner.
+ _buff_write(conn, SITE_BANNER, sizeof(SITE_BANNER));
// XXX check system load here.
if (g_overload)
{
- draw_overload(conn, g_overload);
+ // let's draw the big INSCREEN if defined.
+#ifdef INSCREEN
+ _mt_clear (conn);
+ _buff_write(conn, INSCREEN, sizeof(INSCREEN));
+#endif
+ draw_overload (conn, g_overload);
login_conn_remove(conn, fd, OVERLOAD_SLEEP_SEC);
return;
} else {
- draw_text_screen(conn, welcome_screen);
+ draw_text_screen (conn, welcome_screen);
draw_userid_prompt(conn, NULL, 0);
}
}
@@ -1342,7 +1442,7 @@ bind_port(int port)
snprintf(buf, sizeof(buf), "*:%d", port);
fprintf(stderr, LOG_PREFIX "binding to port: %d...", port);
- if ( (sfd = tobindex(buf, SOCKET_QLEN, _set_bind_opt, 1)) < 0 )
+ if ( (sfd = tobindex(buf, LOGIND_SOCKET_QLEN, _set_bind_opt, 1)) < 0 )
{
fprintf(stderr, LOG_PREFIX "cannot bind to port: %d. abort.\r\n", port);
return -1;
@@ -1510,10 +1610,10 @@ main(int argc, char *argv[])
}
}
- struct rlimit r = {.rlim_cur = MAX_FDS, .rlim_max = MAX_FDS};
+ struct rlimit r = {.rlim_cur = LOGIND_MAX_FDS, .rlim_max = LOGIND_MAX_FDS};
if (setrlimit(RLIMIT_NOFILE, &r) < 0)
{
- fprintf(stderr, LOG_PREFIX "warning: cannot increase max fd to %u...\r\n", MAX_FDS);
+ fprintf(stderr, LOG_PREFIX "warning: cannot increase max fd to %u...\r\n", LOGIND_MAX_FDS);
}
chdir(BBSHOME);