summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2010-10-24 00:06:14 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2010-10-24 00:06:14 +0800
commit8456e939e055be247bca74fd53594baa72098d2e (patch)
tree46936e612d780230ebd63522f5a08c82764d3428
parent50bab622bc5c6a3407ac03b6ec1fc5daa54d5b48 (diff)
downloadpttbbs-8456e939e055be247bca74fd53594baa72098d2e.tar
pttbbs-8456e939e055be247bca74fd53594baa72098d2e.tar.gz
pttbbs-8456e939e055be247bca74fd53594baa72098d2e.tar.bz2
pttbbs-8456e939e055be247bca74fd53594baa72098d2e.tar.lz
pttbbs-8456e939e055be247bca74fd53594baa72098d2e.tar.xz
pttbbs-8456e939e055be247bca74fd53594baa72098d2e.tar.zst
pttbbs-8456e939e055be247bca74fd53594baa72098d2e.zip
new ban system
git-svn-id: http://opensvn.csie.org/pttbbs/trunk@5149 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--pttbbs/include/common.h4
-rw-r--r--pttbbs/include/proto.h7
-rw-r--r--pttbbs/mbbsd/Makefile2
-rw-r--r--pttbbs/mbbsd/acl.c258
-rw-r--r--pttbbs/mbbsd/bbs.c9
-rw-r--r--pttbbs/mbbsd/board.c6
-rw-r--r--pttbbs/mbbsd/cache.c35
7 files changed, 309 insertions, 12 deletions
diff --git a/pttbbs/include/common.h b/pttbbs/include/common.h
index 9cbd7465..baead6ee 100644
--- a/pttbbs/include/common.h
+++ b/pttbbs/include/common.h
@@ -21,7 +21,9 @@
#define FN_MONEY "etc/money"
#define FN_OVERRIDES "overrides"
#define FN_REJECT "reject"
-#define FN_WATER "water"
+#define FN_WATER "water" // 舊水桶
+#define FN_BANNED "banned" // 新水桶
+#define FN_BANNED_HISTORY "banned.history" // 新水桶之歷史記錄
#define FN_CANVOTE "can_vote"
#define FN_VISABLE "visable" // 不知道是誰拼錯的,將錯就錯吧...
#define FN_USIES "usies" /* BBS log */
diff --git a/pttbbs/include/proto.h b/pttbbs/include/proto.h
index 8bca64ee..43d46661 100644
--- a/pttbbs/include/proto.h
+++ b/pttbbs/include/proto.h
@@ -51,6 +51,12 @@ int a_menu(const char *maintitle, const char *path, int lastlevel, int lastbid,
void a_copyitem(const char* fpath, const char* title, const char* owner, int mode);
int Announce(void);
+/* acl */
+time4_t is_user_banned_by_board(const char *user, const char *board);
+time4_t is_banned_by_board(const char *board);
+int ban_user_for_board(const char *user, const char *board, time4_t expire, const char *reason);
+int edit_banned_list_for_board(const char *board);
+
/* assess */
int inc_badpost(const char *, int num);
int bad_comment(const char *fn);
@@ -118,6 +124,7 @@ char*getuserid(int num);
int getuser(const char *userid, userec_t *xuser);
int searchnewuser(int mode);
int count_logins(int uid, int show);
+void invalid_board_permission_cache(const char *board);
int is_BM_cache(int);
int apply_boards(int (*func)(boardheader_t *));
int haspostperm(const char *bname);
diff --git a/pttbbs/mbbsd/Makefile b/pttbbs/mbbsd/Makefile
index a77dee71..31f0d71a 100644
--- a/pttbbs/mbbsd/Makefile
+++ b/pttbbs/mbbsd/Makefile
@@ -9,7 +9,7 @@ SRCROOT= ..
PROG= mbbsd
COREOBJS = bbs.o announce.o read.o board.o brc.o mail.o record.o fav.o
-ACCOBJS = user.o register.o passwd.o emaildb.o
+ACCOBJS = user.o acl.o register.o passwd.o emaildb.o
NETOBJS = mbbsd.o io.o term.o telnet.o
TALKOBJS = friend.o talk.o ccw.o
UTILOBJS = stuff.o kaede.o convert.o name.o syspost.o cache.o cal.o
diff --git a/pttbbs/mbbsd/acl.c b/pttbbs/mbbsd/acl.c
new file mode 100644
index 00000000..0eed630c
--- /dev/null
+++ b/pttbbs/mbbsd/acl.c
@@ -0,0 +1,258 @@
+/* $Id$ */
+#include "bbs.h"
+
+// Access Control List
+// Holder of all access / permission related stuff
+//
+// Author: Hung-Te Lin (piaip)
+
+///////////////////////////////////////////////////////////////////////////
+// New ban system (store in user home)
+
+#define BANNED_OBJECT_TYPE_USER 'u'
+#define BANNED_OBJECT_TYPE_BORAD 'b'
+
+static void
+banned_make_tag_filename(const char *who, const char *object, char object_type,
+ size_t szbuf, char *buf, int create_folder) {
+ char prefix[3] = { object_type, '_', 0 };
+
+ if (!who)
+ setuserfile(buf, FN_BANNED "/");
+ else
+ sethomefile(buf, who, FN_BANNED "/");
+ if (create_folder && !dashd(buf)) {
+ mkdir(buf, 0755);
+ }
+ strlcat(buf, prefix, szbuf);
+ strlcat(buf, object, szbuf);
+}
+
+static int
+banned_get_info(const char *filename,
+ time4_t *pexpire, size_t szreason, char *reason) {
+ FILE *fp = fopen(filename, "rt");
+ int ts = 0;
+ char buf[STRLEN];
+
+ if(!fp)
+ return 0;
+
+ // banned file format:
+ // EXPIRE_TIME
+ // REASON
+ fgets(buf, sizeof(buf), fp);
+ if (pexpire) {
+ sscanf(buf, "%u", &ts);
+ *pexpire = (time4_t) ts;
+ }
+ fgets(buf, sizeof(buf), fp);
+ if (szreason && reason) {
+ chomp(buf);
+ strlcpy(reason, buf, szreason);
+ }
+ fclose(fp);
+ return 1;
+}
+
+static int
+banned_set_info(const char *filename, time4_t expire, const char *reason) {
+ FILE *fp = fopen(filename, "wt");
+ if (!fp)
+ return 0;
+ if (!reason)
+ reason = "";
+
+ fprintf(fp, "%u\n%s\n", (unsigned)expire, reason);
+ fclose(fp);
+ return 1;
+}
+
+// return if 'who (NULL=self)' is banned by 'object'
+static time4_t
+is_banned_by(const char *who, const char *object, char object_type) {
+ char tag_fn[PATHLEN];
+ time4_t expire = 0;
+
+ banned_make_tag_filename(who, object, object_type, sizeof(tag_fn),tag_fn,0);
+ if (!dashf(tag_fn))
+ return 0;
+
+ // check expire
+ if (banned_get_info(tag_fn, &expire, 0, NULL) && now > expire) {
+ unlink(tag_fn);
+ return 0;
+ }
+ return expire;
+}
+
+// add 'who (NULL=self)' to the ban list of 'object'
+static int
+ban_user_as(const char *who, const char *object, char object_type,
+ time_t expire, const char *reason) {
+ char tag_fn[PATHLEN];
+
+ banned_make_tag_filename(who, object, object_type, sizeof(tag_fn),tag_fn,1);
+ return banned_set_info(tag_fn, expire, reason);
+}
+
+time4_t
+is_user_banned_by_board(const char *user, const char *board) {
+ return is_banned_by(user, board, BANNED_OBJECT_TYPE_BORAD);
+}
+
+time4_t
+is_banned_by_board(const char *board) {
+ return is_user_banned_by_board(cuser.userid, board);
+}
+
+int
+ban_user_for_board(const char *user, const char *board,
+ time4_t expire, const char *reason) {
+ return ban_user_as(user, board, BANNED_OBJECT_TYPE_BORAD, expire, reason);
+}
+
+int
+unban_user_for_board(const char *user, const char *board) {
+ char tag_fn[PATHLEN];
+
+ banned_make_tag_filename(user, board, BANNED_OBJECT_TYPE_BORAD,
+ sizeof(tag_fn), tag_fn, 0);
+ return unlink(tag_fn) == 0;
+}
+
+int
+edit_banned_list_for_board(const char *board) {
+ // TODO generalize this.
+ int result;
+ char uid[IDLEN+1], ans[3];
+ char history_log[PATHLEN];
+ char reason[STRLEN];
+ char datebuf[STRLEN];
+ time4_t expire = now;
+
+ if (!board || !*board || getbnum(board) < 1)
+ return 0;
+
+ setbfile(history_log, board, FN_BANNED_HISTORY);
+
+ while (1) {
+ clear();
+ vs_hdr2f(" 設定看板水桶 \t 看板: %s", board);
+ getdata(1, 0, "要 (A)增加 (D)提前清除 (L)列出水桶歷史 (Q)結束? [Q] ",
+ ans, sizeof(ans), LCECHO);
+ if (*ans == 'q' || !*ans)
+ break;
+
+ switch (*ans) {
+ case 'a':
+ move(1, 0);
+ usercomplete(msg_uid, uid);
+ if (!*uid || !searchuser(uid, uid))
+ continue;
+ if (is_user_banned_by_board(uid, board)) {
+ vmsg("使用者已在水桶中。");
+ continue;
+ }
+ move(1, 0); clrtobot();
+ prints("將使用者 %s 加入看板 %s 的水桶。", uid, board);
+ syncnow();
+ move(4, 0);
+ outs("目前接受的格式是 [數字][單位]。 單位有: 年(y), 月(m), 天(d)\n");
+ outs("範例: 3m (三個月), 180d (180天), 10y (10年)\n");
+ outs("注意不可混合輸入(ex: 沒有三個半月這種東西,要換算成天數\n");
+ getdata(2, 0, "請以數字跟單位(預設為天)輸入期限: ", datebuf, 8, DOECHO);
+ trim(datebuf);
+ if (!*datebuf) {
+ vmsg("未輸入期限,放棄。");
+ continue;
+ } else {
+ int val = atoi(datebuf);
+ switch(tolower(datebuf[strlen(datebuf)-1])) {
+ case 'y':
+ val *= 365;
+ break;
+ case 'm':
+ val *= 30;
+ break;
+ case 'd':
+ default:
+ break;
+ }
+ if (val < 1) {
+ vmsg("日期格式輸入錯誤或是小於一天無法處理。");
+ continue;
+ }
+ expire = now + val * DAY_SECONDS;
+ move(4, 0); clrtobot();
+ prints("水桶期限將設定為 %d 天後: %s",
+ val, Cdatelite(&expire));
+ }
+
+ assert(sizeof(reason) >= TTLEN);
+ // maybe race condition here, but fine.
+ getdata(5, 0, "請輸入理由(空白可取消): ", reason, TTLEN,DOECHO);
+ if (!*reason) {
+ vmsg("未輸入理由,無法受理。");
+ continue;
+ }
+
+ sprintf(datebuf, "%s", Cdatelite(&expire));
+ move(1, 0); clrtobot();
+ prints("\n使用者 %s 即將加入水桶 (解除時間: %s)\n"
+ "理由: %s\n", uid, datebuf, reason);
+
+ // last chance
+ getdata(5, 0, "確認以上資料全部正確嗎? [y/N]: ",
+ ans, sizeof(ans), LCECHO);
+ if (ans[0] != 'y') {
+ vmsg("請重新輸入");
+ continue;
+ }
+
+ result = ban_user_for_board(uid, board, expire, reason);
+ log_filef(history_log, LOG_CREAT,
+ "%s %s%s 將 %s 加入水桶 (解除時間: %s),理由: %s\n",
+ Cdatelite(&now),
+ result ? "" : "(未成功\)",
+ cuser.userid, uid, datebuf, reason);
+ vmsg(result ? "已將使用者加入水桶" : "失敗,請向站長報告");
+ invalid_board_permission_cache(board);
+ break;
+
+ case 'd':
+ move(1, 0);
+ usercomplete(msg_uid, uid);
+ if (!*uid || !searchuser(uid, uid))
+ continue;
+ if (!is_user_banned_by_board(uid, board)) {
+ vmsg("使用者未被水桶。");
+ continue;
+ }
+ move(1, 0); clrtobot();
+ prints("提前解除使用者 %s 於看板 %s 的水桶。", uid, board);
+ assert(sizeof(reason) >= TTLEN);
+ getdata(2, 0, "請輸入理由(空白可取消解除): ",reason,TTLEN,DOECHO);
+ if (!*reason) {
+ vmsg("未輸入理由,無法受理。");
+ continue;
+ }
+ unban_user_for_board(uid, board);
+ log_filef(history_log, LOG_CREAT,
+ "%s %s 解除 %s 的水桶,理由: %s\n",
+ Cdatelite(&now), cuser.userid, uid, reason);
+ vmsg("使用者水桶已解除。");
+ invalid_board_permission_cache(board);
+ break;
+
+ case 'l':
+ if (more(history_log, YEA) == -1)
+ vmsg("目前尚無水桶記錄。");
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/pttbbs/mbbsd/bbs.c b/pttbbs/mbbsd/bbs.c
index d468237a..af045bcb 100644
--- a/pttbbs/mbbsd/bbs.c
+++ b/pttbbs/mbbsd/bbs.c
@@ -130,7 +130,8 @@ add_to_post_history(
int fd = 0, last_index = 0;
setdirpath(hist_file, direct, FN_EDITHISTORY "/");
- mkdir(hist_file, 0755);
+ if (!dashd(hist_file))
+ mkdir(hist_file, 0755);
strlcat(hist_file, basename, sizeof(hist_file));
if ((fd = open(hist_file, O_RDWR|O_CREAT, 0644)) >= 0) {
@@ -3573,10 +3574,8 @@ view_post_history(int ent, const fileheader_t * fhdr, const char *direct)
strlcat(hist_file, fhdr->filename, sizeof(hist_file));
}
- // TODO check if hist_file is a valid file (directoy gives fake result)
-
- fd = open(hist_file, O_RDONLY);
- if (fd < 0) {
+ if (!dashf(hist_file) ||
+ (fd = open(hist_file, O_RDONLY)) < 0) {
vmsg(err_no_history);
return FULLUPDATE;
}
diff --git a/pttbbs/mbbsd/board.c b/pttbbs/mbbsd/board.c
index f53fc35a..ccf51f22 100644
--- a/pttbbs/mbbsd/board.c
+++ b/pttbbs/mbbsd/board.c
@@ -541,7 +541,7 @@ b_config(void)
if (!isBM) outs(" (需板主權限)");
outs(aRst);
move_ansi(ipostres++, COLPOSTRES);
- prints("%sw%s)水桶名單 %sv%s)可見會員名單 ",
+ prints("%sw%s)設定水桶 %sv%s)可見會員名單 ",
aHot, aRst, aHot, aRst);
move_ansi(ipostres++, COLPOSTRES);
prints("%sm%s)舉辦投票 %so%s)投票名單 ",
@@ -740,7 +740,11 @@ b_config(void)
case 'w':
clear();
+#ifdef USE_NEW_BAN_SYSTEM
+ edit_banned_list_for_board(currboard);
+#else
friend_edit(BOARD_WATER);
+#endif
clear();
break;
diff --git a/pttbbs/mbbsd/cache.c b/pttbbs/mbbsd/cache.c
index f4b80fe4..bf10e577 100644
--- a/pttbbs/mbbsd/cache.c
+++ b/pttbbs/mbbsd/cache.c
@@ -125,6 +125,18 @@ getutmpmode(void)
* section - board
*/
+void
+invalid_board_permission_cache(const char *board) {
+ boardheader_t *bp = NULL;
+ int bid = getbnum(board);
+
+ assert(0<=bid-1 && bid-1<MAX_BOARD);
+ bp = getbcache(bid);
+ bp->perm_reload = now;
+ substitute_record(fn_board, bp, sizeof(boardheader_t), bid);
+}
+
+
/* HasBoardPerm() in board.c... */
int
apply_boards(int (*func) (boardheader_t *))
@@ -176,7 +188,6 @@ const char *
postperm_msg(const char *bname)
{
register int i;
- char buf[PATHLEN];
boardheader_t *bp = NULL;
if (!(i = getbnum(bname)))
@@ -189,9 +200,25 @@ postperm_msg(const char *bname)
if (HasUserPerm(PERM_SYSOP))
return NULL;
- setbfile(buf, bname, fn_water);
- if (file_exist_record(buf, cuser.userid))
- return "使用者水桶中";
+#ifdef USE_NEW_BAN_SYSTEM
+ {
+ // static is bad, but this is faster...
+ static char ban_msg[STRLEN];
+ time4_t expire = is_banned_by_board(bname);
+ if (expire > now) {
+ sprintf(ban_msg, "使用者水桶中(尚有%d天)",
+ ((expire - now) / DAY_SECONDS) +1);
+ return ban_msg;
+ }
+ }
+#else
+ {
+ char buf[PATHLEN];
+ setbfile(buf, bname, fn_water);
+ if (file_exist_record(buf, cuser.userid))
+ return "使用者水桶中";
+ }
+#endif
if (!strcasecmp(bname, DEFAULT_BOARD))
return NULL;