Initial commit

This commit is contained in:
Deon George 2019-04-07 15:36:28 +10:00
commit 829a2d67b2
22 changed files with 436 additions and 0 deletions

57
Dockerfile Normal file
View File

@ -0,0 +1,57 @@
# NAME leenooks/mbse
# VERSION 1.0.7.12
FROM debian:stretch-slim
RUN apt-get update \
&& apt-get install -y \
curl python-pip supervisor xinetd telnetd openssh-server webfs procps less \
zip tar arj unrar-free lhasa arc zoo lrzsz unzip logrotate joe \
&& rm -rf /var/lib/apt/lists/* /tmp/*
RUN mkdir -p /run/sshd
# Add in Leenooks' apt repository
RUN curl -s http://apt.leenooks.net/setup.sh | sh
RUN apt-get update \
&& apt-get install --allow-unauthenticated -yqq mbse makenl goldedplus \
&& rm -rf /var/lib/apt/lists/* /tmp/*
ENV MBSE_ROOT /opt/mbse
WORKDIR ${MBSE_ROOT}
RUN mkdir ${MBSE_ROOT}/template; \
for dir in share home etc var log tmp ftp html; do \
mv ${MBSE_ROOT}/${dir} ${MBSE_ROOT}/template; \
ln -s data/${dir} ${MBSE_ROOT}/${dir}; \
done
EXPOSE 23 80 24554 60177 60179
VOLUME [ "${MBSE_ROOT}/data" ]
COPY python-mbse /root/python-mbse
RUN cd /root/python-mbse; pip install .
COPY xinetd.d /etc/xinetd.d
COPY supervisord.d /etc/supervisor/conf.d/
COPY logrotate.d /etc/logrotate.d/
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf", "-n"]
COPY mbse.cron /etc/cron.d/mbse
COPY golded.sh /usr/bin
COPY init /sbin/init
ENTRYPOINT [ "/sbin/init" ]
RUN ln -sf /usr/share/zoneinfo/Australia/Melbourne /etc/localtime
# Add ZeroTier
RUN echo "deb http://download.zerotier.com/debian/stretch stretch main" > /etc/apt/sources.list.d/zerotier.list
COPY zt-gpg-key /tmp/
RUN apt-key add /tmp/zt-gpg-key
RUN apt-get update \
&& apt-get install -yq zerotier-one \
&& rm -rf /var/lib/apt/lists/* /tmp/*
VOLUME [ "/var/lib/zerotier-one" ]

3
golded.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
gedlnx -C${MBSE_ROOT}/etc/golded.inc

38
init Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
: ${MBSE_ROOT=/opt/mbse}
PATH=${MBSE_ROOT}/bin:$PATH
export PATH
if [ ! -d "${MBSE_ROOT}/etc" ]; then
echo "* Installing MBSE data files into ${MBSE_ROOT}/data"
cp -a ${MBSE_ROOT}/template/* ${MBSE_ROOT}/data
fi
if [ -f "${MBSE_ROOT}/data/etc/users.data" ]; then
echo "* Restoring passwords"
mbse-pwfix
fi
for keytype in rsa ecdsa ed25519; do
if [ ! -f /etc/ssh/ssh_host_${keytype}_key ]; then
echo "* Generating ${keytype} ssh key"
/usr/libexec/openssh/sshd-keygen ${keytype}
fi
done
# clear out state and lockfiles from previous instance
rm -f ${MBSE_ROOT}/data/var/sema/*
rm -f ${MBSE_ROOT}/data/var/run/*
rm -f ${MBSE_ROOT}/data/tmp/*
chown -R mbse:bbs ${MBSE_ROOT}/data
if [ -x /usr/sbin/zerotier-one -a -n "${ENABLE_ZT}" ]; then
echo "* Starting ZeroTier"
mkdir /dev/net && mknod /dev/net/tun -m 666 c 10 200
/usr/sbin/zerotier-one -d
fi
exec "$@"

7
logrotate.d/mbse Normal file
View File

@ -0,0 +1,7 @@
/opt/mbse/data/log/*.log {
daily
compress
rotate 31
olddir /opt/mbse/data/log/old
su mbse bbs
}

1
mbse.cron Normal file
View File

@ -0,0 +1 @@
00 06 * * * mbse /opt/mbse/etc/maint

View File

View File

View File

@ -0,0 +1,79 @@
import argparse
import logging
import os
import pwd
import subprocess
from mbse.parser import parse_struct
import mbse.fmt.users_data as users_data
def parse_args():
p = argparse.ArgumentParser()
p.add_argument('--mbse-root', '-r', default='/opt/mbse')
p.add_argument('--users', '-u')
p.add_argument('--shell', '-S')
p.add_argument('--home', '-H')
return p.parse_args()
def main():
args = parse_args()
logging.basicConfig(level='INFO')
log = logging.getLogger(__name__)
if args.users is None:
args.users = os.path.join(args.mbse_root, 'etc', 'users.data')
if args.shell is None:
args.shell = os.path.join(args.mbse_root, 'bin', 'mbsebbs')
if args.home is None:
args.home = os.path.join(args.mbse_root, 'home')
with open(args.users, 'r') as fd:
hdr = parse_struct(users_data.fmt_userhdr, fd)
while True:
try:
user = parse_struct(users_data.fmt_userrec, fd)
# skip deleted users
if user['flags1'] & users_data.FLAG_DELETED:
continue
user['Name'] = user['Name'].rstrip('\0')
user['sUserName'] = user['sUserName'].rstrip('\0')
user['Password'] = user['Password'].rstrip('\0')
# check if users exists
try:
pwd.getpwnam(user['Name'])
log.info('user %s already exists', user['Name'])
except KeyError:
log.info('creating user %s', user['Name'])
subprocess.check_call([
'useradd',
'-c', user['sUserName'],
'-d', os.path.join(args.home, user['Name']),
'-s', args.shell,
'-g', 'bbs',
'-M', '-N',
user['Name']
])
log.info('fixing permissions on home directory')
subprocess.check_call([
'chown', '-R', user['Name'],
os.path.join(args.home, user['Name'])])
log.info('setting password for user %s', user['Name'])
p = subprocess.Popen(['chpasswd'], stdin=subprocess.PIPE)
p.communicate(input=user['Name']+':'+user['Password'])
except EOFError:
break
if __name__ == '__main__':
main()

View File

View File

@ -0,0 +1,96 @@
fmt_userhdr = (
('hdrsize', 'I'),
('recsize', 'I'),
)
fmt_securityrec = (
('level', 'I'),
('flags', 'I'),
('notflags', 'I'),
)
fmt_userrec = (
('sUserName', '36s'),
('Name', '9s'),
('xPassword', 'I'),
('sVoicePhone', '20s'),
('sDataPhone', '20s'),
('sLocation', '28s'),
('sAddress', ('41s',)*3),
('sDataOfBirth', '12s'),
('tFirstLoginDate', 'I'),
('tLastLoginDate', 'I'),
('Security', None, fmt_securityrec),
('sComment', '81s'),
('sExpiryDate', '12s'),
('ExpirySec', None, fmt_securityrec),
('sSex', '8s'),
('flags1', 'B'),
('flags2', 'B'),
('iTotalCalls', 'I'),
('iTimeLeft', 'I'),
('iConnectTime', 'I'),
('iTimeUsed', 'I'),
('xScreenLen', 'I'),
('tLastPwdChange', 'I'),
('xHangUps', 'I'),
('Credit', 'I'),
('Paged', 'I'),
('MsgEditor', 'I'),
('LastPktNum', 'I'),
('Archiver', '6s'),
('iLastFileArea', 'I'),
('iLastFileGroup', 'I'),
('sProtocol', '21s'),
('Downloads', 'I'),
('Uploads', 'I'),
('UploadK', 'I'),
('DownloadK', 'I'),
('DownloadKToday', 'I'),
('UploadKToday', 'I'),
('iLastMsgArea', 'I'),
('iTransferTime', 'I'),
('iLastMsgGroup', 'I'),
('iPosted', 'I'),
('iLanguage', 'I'),
('sHandle', '36s'),
('iStatus', 'I'),
('DownloadsToday', 'I'),
('CrtDef', 'I'),
('Protocol', 'I'),
('flags3', 'B'),
('Password', '15s'),
('Charset', 'I'),
('OLRext', 'I'),
('OLRlast', '12s'),
)
# flags2
FLAG_HIDDEN = 1
FLAG_HOTKEYS = 1 << 1
FLAG_XGRAPHMODE = 1 << 2
FLAG_DELETED = 1 << 3
FLAG_NEVERDELETE = 1 << 4
FLAG_XCHAT = 1 << 5
FLAG_LOCKEDOUT = 1 << 6
FLAG_DONOTDISTURB = 1 << 7
# flags2
FLAG_CLS = 1
FLAG_MORE = 1 << 1
FLAG_XFSMSGED = 1 << 2
FLAG_MAILSCAN = 1 << 3
FLAG_GUEST = 1 << 4
FLAG_OL_EXTINFO = 1 << 5
# flags3
FLAG_IEMSI = 1
FLAG_IEMNU = 1 << 1
FLAG_IETAB = 1 << 2
FLAG_IEASCII8 = 1 << 3
FLAG_IENEWS = 1 << 4
FLAG_IEFILE = 1 << 5
FLAG_EMAIL = 1 << 6
FLAG_FSEMACS = 1 << 7

View File

@ -0,0 +1,35 @@
import struct
def read_one(name, spec, fd):
rsize = struct.calcsize(spec)
raw = fd.read(rsize)
if not len(raw):
raise EOFError()
if len(raw) != rsize:
raise ValueError('read %d bytes, expected %d' % (len(raw), rsize))
data = struct.unpack(spec, raw)[0]
return data
def parse_struct(spec, fd):
parsed = {}
for fldspec in spec:
try:
fld, spec, sub = fldspec
except ValueError:
sub = None
fld, spec = fldspec
if sub:
data = parse_struct(sub, fd)
elif isinstance(spec, tuple):
data = [read_one(fld, s, fd) for s in spec]
else:
data = read_one(fld, spec, fd)
parsed[fld] = data
return parsed

12
python-mbse/setup.py Normal file
View File

@ -0,0 +1,12 @@
import setuptools
setuptools.setup(
version='1.0.0',
name='mbse',
packages=setuptools.find_packages(),
entry_points={
'console_scripts': [
'mbse-pwfix = mbse.cmd.pwfix:main',
],
}
)

3
supervisord.d/bbs.conf Normal file
View File

@ -0,0 +1,3 @@
[program:mbtask]
command=%(ENV_MBSE_ROOT)s/bin/mbtask -nd
user=mbse

2
supervisord.d/cron.conf Normal file
View File

@ -0,0 +1,2 @@
[program:cron]
command=/usr/sbin/cron -f

View File

@ -0,0 +1,2 @@
[program:sshd]
command=/usr/sbin/sshd -D

View File

@ -0,0 +1,2 @@
[program:webfs]
command=/usr/bin/webfsd -Fp 80 -r /opt/mbse/data/html -f index.html

View File

@ -0,0 +1,2 @@
[program:xinetd]
command=/usr/sbin/xinetd -dontfork

10
xinetd.d/binkp Normal file
View File

@ -0,0 +1,10 @@
service binkp
{
socket_type = stream
protocol = tcp
wait = no
user = mbse
instances = 10
server = /opt/mbse/bin/mbcico
server_args = -t ibn
}

10
xinetd.d/fido Normal file
View File

@ -0,0 +1,10 @@
service fido
{
socket_type = stream
protocol = tcp
wait = no
user = mbse
instances = 10
server = /opt/mbse/bin/mbcico
server_args = -t ifc
}

15
xinetd.d/telnet Normal file
View File

@ -0,0 +1,15 @@
service telnet
{
disable = no
protocol = tcp
instances = 10
flags = REUSE
log_on_failure += USERID
socket_type = stream
user = root
server = /usr/sbin/in.telnetd
server_args = -L /opt/mbse/bin/mblogin
wait = no
}

10
xinetd.d/tfido Normal file
View File

@ -0,0 +1,10 @@
service tfido
{
socket_type = stream
protocol = tcp
wait = no
user = mbse
instances = 10
server = /opt/mbse/bin/mbcico
server_args = -t itn
}

52
zt-gpg-key Normal file
View File

@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org
mQINBFdQq7oBEADEVhyRiaL8dEjMPlI/idO8tA7adjhfvejxrJ3Axxi9YIuIKhWU
5hNjDjZAiV9iSCMfJN3TjC3EDA+7nFyU6nDKeAMkXPbaPk7ti+Tb1nA4TJsBfBlm
CC14aGWLItpp8sI00FUzorxLWRmU4kOkrRUJCq2kAMzbYWmHs0hHkWmvj8gGu6mJ
WU3sDIjvdsm3hlgtqr9grPEnj+gA7xetGs3oIfp6YDKymGAV49HZmVAvSeoqfL1p
pEKlNQ1aO9uNfHLdx6+4pS1miyo7D1s7ru2IcqhTDhg40cHTL/VldC3d8vXRFLIi
Uo2tFZ6J1jyQP5c1K4rTpw3UNVne3ob7uCME+T1+ePeuM5Y/cpcCvAhJhO0rrlr0
dP3lOKrVdZg4qhtFAspC85ivcuxWNWnfTOBrgnvxCA1fmBX+MLNUEDsuu55LBNQT
5+WyrSchSlsczq+9EdomILhixUflDCShHs+Efvh7li6Pg56fwjEfj9DJYFhRvEvQ
7GZ7xtysFzx4AYD4/g5kCDsMTbc9W4Jv+JrMt3JsXt2zqwI0P4R1cIAu0J6OZ4Xa
dJ7Ci1WisQuJRcCUtBTUxcYAClNGeors5Nhl4zDrNIM7zIJp+GfPYdWKVSuW10mC
r3OS9QctMSeVPX/KE85TexeRtmyd4zUdio49+WKgoBhM8Z9MpTaafn2OPQARAQAB
tFBaZXJvVGllciwgSW5jLiAoWmVyb1RpZXIgU3VwcG9ydCBhbmQgUmVsZWFzZSBT
aWduaW5nIEtleSkgPGNvbnRhY3RAemVyb3RpZXIuY29tPokCNwQTAQoAIQUCV1Cr
ugIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRAWVxmII+UqYViGEACnC3+3
lRzfv7f7JLWo23FSHjlF3IiWfYd+47BLDx706SDih1H6Qt8CqRy706bWbtictEJ/
xTaWgTEDzY/lRalYO5NAFTgK9h2zBP1t8zdEA/rmtVPOWOzd6jr0q3l3pKQTeMF0
6g+uaMDG1OkBz6MCwdg9counz6oa8OHK76tXNIBEnGOPBW375z1O+ExyddQOHDcS
IIsUlFmtIL1yBa7Q5NSfLofPLfS0/o2FItn0riSaAh866nXHynQemjTrqkUxf5On
65RLM+AJQaEkX17vDlsSljHrtYLKrhEueqeq50e89c2Ya4ucmSVeC9lrSqfyvGOO
P3aT/hrmeE9XBf7a9vozq7XhtViEC/ZSd1/z/oeypv4QYenfw8CtXP5bW1mKNK/M
8xnrnYwo9BUMclX2ZAvu1rTyiUvGre9fEGfhlS0rjmCgYfMgBZ+R/bFGiNdn6gAd
PSY/8fP8KFZl0xUzh2EnWe/bptoZ67CKkDbVZnfWtuKA0Ui7anitkjZiv+6wanv4
+5A3k/H3D4JofIjRNgx/gdVPhJfWjAoutIgGeIWrkfcAP9EpsR5swyc4KuE6kJ/Y
wXXVDQiju0xE1EdNx/S1UOeq0EHhOFqazuu00ojATekUPWenNjPWIjBYQ0Ag4ycL
KU558PFLzqYaHphdWYgxfGR+XSgzVTN1r7lW87kCDQRXUKu6ARAA2wWOywNMzEiP
ZK6CqLYGZqrpfx+drOxSowwfwjP3odcK8shR/3sxOmYVqZi0XVZtb9aJVz578rNb
e4Vfugql1Yt6w3V84z/mtfj6ZbTOOU5yAGZQixm6fkXAnpG5Eer/C8Aw8dH1EreP
Na1gIVcUzlpg2Ql23qjr5LqvGtUB4BqJSF4X8efNi/y0hj/GaivUMqCF6+Vvh3GG
fhvzhgBPku/5wK2XwBL9BELqaQ/tWOXuztMw0xFH/De75IH3LIvQYCuv1pnM4hJL
XYnpAGAWfmFtmXNnPVon6g542Z6c0G/qi657xA5vr6OSSbazDJXNiHXhgBYEzRrH
napcohTQwFKEA3Q4iftrsTDX/eZVTrO9x6qKxwoBVTGwSE52InWAxkkcnZM6tkfV
n7Ukc0oixZ6E70Svls27zFgaWbUFJQ6JFoC6h+5AYbaga6DwKCYOP3AR+q0ZkcH/
oJIdvKuhF9zDZbQhd76b4gK3YXnMpVsj9sQ9P23gh61RkAQ1HIlGOBrHS/XYcvpk
DcfIlJXKC3V1ggrG+BpKu46kiiYmRR1/yM0EXH2n99XhLNSxxFxxWhjyw8RcR6iG
ovDxWAULW+bJHjaNJdgb8Kab7j2nT2odUjUHMP42uLJgvS5LgRn39IvtzjoScAqg
8I817m8yLU/91D2f5qmJIwFI6ELwImkAEQEAAYkCHwQYAQoACQUCV1CrugIbDAAK
CRAWVxmII+UqYWSSEACxaR/hhr8xUIXkIV52BeD+2BOS8FNOi0aM67L4fEVplrsV
Op9fvAnUNmoiQo+RFdUdaD2Rpq+yUjQHHbj92mlk6Cmaon46wU+5bAWGYpV1Uf+o
wbKw1Xv83Uj9uHo7zv9WDtOUXUiTe/S792icTfRYrKbwkfI8iCltgNhTQNX0lFX/
Sr2y1/dGCTCMEuA/ClqGKCm9lIYdu+4z32V9VXTSX85DsUjLOCO/hl9SHaelJgmi
IJzRY1XLbNDK4IH5eWtbaprkTNIGt00QhsnM5w+rn1tO80giSxXFpKBE+/pAx8PQ
RdVFzxHtTUGMCkZcgOJolk8y+DJWtX8fP+3a4Vq11a3qKJ19VXk3qnuC1aeW7OQF
j6ISyHsNNsnBw5BRaS5tdrpLXw6Z7TKr1eq+FylmoOK0pIw5xOdRmSVoFm4lVcI5
e5EwB7IIRF00IFqrXe8dCT0oDT9RXc6CNh6GIs9D9YKwDPRD/NKQlYoegfa13Jz7
S3RIXtOXudT1+A1kaBpGKnpXOYD3w7jW2l0zAd6a53AAGy4SnL1ac4cml76NIWiF
m2KYzvMJZBk5dAtFa0SgLK4fg8X6Ygoo9E0JsXxSrW9I1JVfo6Ia//YOBMtt4XuN
Awqahjkq87yxOYYTnJmr2OZtQuFboymfMhNqj3G2DYmZ/ZIXXPgwHx0fnd3R0Q==
=JgAv
-----END PGP PUBLIC KEY BLOCK-----