| 1 |
Subtext: a multi-user BBS server for Macintosh |
| 2 |
Written by joshua stein <jcs@jcs.org> - http://jcs.org/subtext |
| 3 |
|
| 4 |
Subtext is free software; see the LICENSE file for copyright/licensing. |
| 5 |
|
| 6 |
Introduction |
| 7 |
================================================================== |
| 8 |
Subtext is a multi-user BBS server that is developed and runs on Macintosh |
| 9 |
System 6 and above. It supports dialin access through a serial modem and |
| 10 |
Telnet access through MacTCP. |
| 11 |
|
| 12 |
Features |
| 13 |
================================================================== |
| 14 |
- Multithreaded, multi-user BBS server that runs on System 6+ |
| 15 |
- Telnet support through MacTCP |
| 16 |
- Direct serial modem support (no Communications Toolbox) |
| 17 |
- Multiple threaded message boards |
| 18 |
- FTN (FidoNet) EchoMail and NetMail support with Binkp hub synching |
| 19 |
- Multi-user interactive chat |
| 20 |
- Private messaging/mail |
| 21 |
- File uploading and downloading with ZMODEM support |
| 22 |
- Integrated ANSI-capable local console |
| 23 |
- Local log window with smart screen blanking |
| 24 |
- Remote syslog (RFC3164) support |
| 25 |
- Secure user password storage with SHA256 |
| 26 |
- View/menu templates with variable expansion |
| 27 |
- Configurable main menu key shortcuts |
| 28 |
- Telnet brute-force IP banning by sending messages to a firewall host |
| 29 |
- Offline IP geolocation database support for connecting telnet IPs |
| 30 |
|
| 31 |
Setup |
| 32 |
================================================================== |
| 33 |
Most of the administration is done through the BBS itself, by logging in as |
| 34 |
a sysop and accessing the sysop menu. BBS settings, file areas, message |
| 35 |
boards, and user accounts can all be modified through this menu. |
| 36 |
|
| 37 |
Editing view tepmlates is done by editing plaintext files in the "views" |
| 38 |
directory created where the BBS database lives. |
| 39 |
|
| 40 |
When first run, Subtext will ask to open an existing BBS database. Clicking |
| 41 |
Cancel will prompt to save a new database. On subsequent runs, Subtext |
| 42 |
will automatically try to open the last database that it successfully opened |
| 43 |
unless the Command key is held down at startup. |
| 44 |
|
| 45 |
When creating a new database, Subtext will create a default sysop user |
| 46 |
with the username "sysop" and password "p4ssw0rd". It will also fill in |
| 47 |
some defaults such as an example BBS name and hostname. |
| 48 |
|
| 49 |
On launch, Subtext will open its logger window and initialize its connection |
| 50 |
methods, which are only the console by default. Clicking the BBS menu and |
| 51 |
then Open Console will open a sysop session. Pressing ! will access the |
| 52 |
Sysop menu, and then S will enter the BBS Settings menu. |
| 53 |
|
| 54 |
To enable dialin access, change the Modem Port setting to 1 for the modem |
| 55 |
port or 2 for the printer port depending on where the modem is connected. |
| 56 |
An appropriate Modem Init String can also be configured, though it should |
| 57 |
*not* be configured for Auto-Answer. The number of rings after which an |
| 58 |
"ATA" is issued can be configured in the settings menu. |
| 59 |
|
| 60 |
To enable Telnet access, set the Telnet Port to anything other than 0, such |
| 61 |
as the standard telnet port of 23. Enabling Telnet requires MacTCP to be |
| 62 |
installed and configured. |
| 63 |
|
| 64 |
View Templates |
| 65 |
================================================================== |
| 66 |
In the "views" directory automatically created where the BBS database |
| 67 |
lives are a number of text files that are used throughout the BBS: |
| 68 |
|
| 69 |
- issue.txt: Pre-login welcome screen ("issue" file) |
| 70 |
- menu.txt: Main menu |
| 71 |
- menu_options.txt: Menu commands, see Main Menu Configuration below |
| 72 |
- no_free_nodes.txt: "No Free Nodes" message shown through telnet |
| 73 |
- page_sysop.txt: Text shown before paging the sysop |
| 74 |
- short_menu.txt: Short menu shown after user has seen the main menu |
| 75 |
- signoff.txt: Session signoff |
| 76 |
- signup.txt: Account signup text |
| 77 |
|
| 78 |
After editing view text files, they must be reloaded through the BBS's |
| 79 |
console menu option, or through the sysop menu when logged in. |
| 80 |
|
| 81 |
Views support expansion of variables, which are put inside {{ and }} |
| 82 |
characters, such as "You are connected to {{node}}." Supported variables: |
| 83 |
|
| 84 |
- {{B}} |
| 85 |
Enable bold attribute if the user's terminal supports ANSI (otherwise |
| 86 |
it prints nothing). |
| 87 |
- {{/B}} |
| 88 |
Resets ANSI attributes (including bold) if the user's terminal supports |
| 89 |
ANSI. |
| 90 |
- {{#}} |
| 91 |
Stops varible expansion for the rest of the template. Useful when |
| 92 |
printing untrusted data (mostly used internally). |
| 93 |
- {{center_XX}} |
| 94 |
Print spaces of length equal to the user's terminal width minus XX, divided |
| 95 |
by two. For example, if the user's terminal is 80 characters wide and the |
| 96 |
variable {{center_50}} is used before a 50-character-wide menu line, 15 |
| 97 |
space characters will be printed. This is useful for centering a menu on |
| 98 |
wide terminals but preventing empty space on narrower terminals. |
| 99 |
- {{logged_in_time}} |
| 100 |
The amount of time the user has been logged in (still usable in |
| 101 |
signoff template), such as "7m20s". |
| 102 |
- {{new_mail}} |
| 103 |
If the user has any new, unread mail messages, the count such as |
| 104 |
"(4 New)". Otherwise it is blank. |
| 105 |
- {{node}} |
| 106 |
The current node, such as "ttyt0". |
| 107 |
- {{phone_number}} |
| 108 |
The system's configured phone number, such as "(312) 555-1212". |
| 109 |
- {{time}} |
| 110 |
The current system time in 24-hour format, such as "23:59". |
| 111 |
- {{timezone}} |
| 112 |
The system's configured "Timezone (Abbrev)". |
| 113 |
- {{username}} |
| 114 |
The currently logged-in user's username, or "guest". |
| 115 |
- {{"string"}} |
| 116 |
Print the literal string "string". This is useful in conditionals. |
| 117 |
|
| 118 |
Variable results can also be truncated or padded to a particular length, |
| 119 |
which can be helpful when creating menus with columns. This is done with |
| 120 |
the pipe character and the length, such as: |
| 121 |
|
| 122 |
{{ username|10 }} |
| 123 |
|
| 124 |
Conditionals are also supported with ternary operators "?" and ":" to print |
| 125 |
something if the condition is true (or non-null), otherwise print something |
| 126 |
else. The following conditionals are supported: |
| 127 |
|
| 128 |
- user |
| 129 |
True if the current user is logged in as a non-guest. |
| 130 |
- sysop |
| 131 |
True if the current user is a sysop. |
| 132 |
|
| 133 |
For example, the following would print one string in menu if the user is |
| 134 |
a sysop, otherwise it prints something else. |
| 135 |
|
| 136 |
{{ sysop ? "Answer sysop page" : "Page the sysop" }} |
| 137 |
|
| 138 |
Or when printing mail for the user: |
| 139 |
|
| 140 |
{{ user ? new_mail : "Guests cannot access mail." }} |
| 141 |
|
| 142 |
Main Menu Configuration |
| 143 |
================================================================== |
| 144 |
In addition to creating a custom menu layout, it may be desirable to change |
| 145 |
the mapping of keys to functions. This can be done by editing the |
| 146 |
menu_options.txt file and then reloading it through the BBS. The mapping is |
| 147 |
one action per line, with the Action, Menu Key, All Keys list, and Label, |
| 148 |
separated by a colon. Blank lines and those starting with # are ignored. |
| 149 |
|
| 150 |
When there is no custom Main Menu view defined, a list of options will be |
| 151 |
programmatically generated by showing all menu options with a Menu Key |
| 152 |
defined with the Menu Key and Label. Options with no Menu Key defined are |
| 153 |
still accessible by any key in the All Keys field, but are not shown. |
| 154 |
|
| 155 |
The default mapping is: |
| 156 |
|
| 157 |
# Action:Menu Key:All Keys:Label |
| 158 |
BOARD_LIST_FTN_AREAS:A:Aa:List FTN Areas |
| 159 |
BOARD_SHOW_FIRST:B:Bb:Message Board |
| 160 |
BOARD_SHOW_1::1:Message Board 1 |
| 161 |
BOARD_SHOW_2::2:Message Board 2 |
| 162 |
BOARD_SHOW_3::3:Message Board 3 |
| 163 |
BOARD_SHOW_4::4:Message Board 4 |
| 164 |
BOARD_SHOW_5::5:Message Board 5 |
| 165 |
BOARD_SHOW_6::6:Message Board 6 |
| 166 |
BOARD_SHOW_7::7:Message Board 7 |
| 167 |
BOARD_SHOW_8::8:Message Board 8 |
| 168 |
BOARD_SHOW_9::9:Message Board 9 |
| 169 |
BOARD_SHOW_10::10:Message Board 10 |
| 170 |
CHAT:C:Cc:Multi-User Chat |
| 171 |
FILES_MENU:F:Ff:File Areas |
| 172 |
GOODBYE:G:GgXx:Goodbye |
| 173 |
RECENT_LOGINS:L:Ll:Recent Logins |
| 174 |
MAIL_COMPOSE:N:Nn:Compose New Mail |
| 175 |
MAIL_MENU:M:Mm:Private Mail {{ user ? new_mail : "" }} |
| 176 |
MOTD:O:Oo:Message Of The Day |
| 177 |
PAGE_SEND_OR_ANSWER:P:Pp:{{ sysop ? "Answer Page" : "Page Sysop" }} |
| 178 |
SETTINGS_OR_SIGNUP:S:Ss:{{ user ? "Settings" : "Signup For Account" }} |
| 179 |
WHOS_ONLINE:W:Ww:Who's Online |
| 180 |
SHOW_MENU:?:?:List Menu Options |
| 181 |
SYSOP_MENU::!:Sysop Menu |
| 182 |
|
| 183 |
FTN (FidoNet) Support |
| 184 |
================================================================== |
| 185 |
Subtext supports FTN EchoMail (distributed message boards) and NetMail |
| 186 |
(relayed mail to a user at another node) by way of a Binkp hub. |
| 187 |
Directly-delivered "CrashMail" is not supported. Subtext has a built-in |
| 188 |
scanner/tosser with limited support for PKZIP archives of FTN packets. |
| 189 |
|
| 190 |
To get started, configure the FTN Hub Binkp hostname, port, and password |
| 191 |
settings. The network name, hub node address (e.g., "21:3/100"), local node |
| 192 |
address, and packet passwords must also be set. This is enough to enable |
| 193 |
NetMail, so users can send mail to a user@XX:X/XXX and have it delivered |
| 194 |
through the hub. Likewise, any incoming NetMail for valid usernames are |
| 195 |
delivered, or bounced to the Sysop. |
| 196 |
|
| 197 |
To enable EchoMail areas, create local boards in the Sysop menu and set the |
| 198 |
"FTN Area Name" field to match each desired area name exactly. Note that |
| 199 |
once a board has its FTN area name set, it cannot be removed later due to |
| 200 |
FTN boards using a different database structure than local, threaded boards. |
| 201 |
|
| 202 |
Once Binkp polling is enabled, Subtext will attempt to login to the Binkp hub |
| 203 |
at the configured interval and retrieve any packets sent from the hub, saving |
| 204 |
them to the "binkp:inbox" directory. After fetching any outstanding files, |
| 205 |
packets in the "binkp:outbox" directory are sent to the hub. |
| 206 |
|
| 207 |
Packets (or PKZIP archives of packets) in the inbox are tossed and NetMail is |
| 208 |
delivered. Any EchoMail packets for areas that match the FTN Area Name set |
| 209 |
in a local board are imported. Packets that cannot be tossed properly are |
| 210 |
moved to the "binkp:bad" directory. If the "FTN Hub Binkp Delete After |
| 211 |
Processing" option is enabled, packets are moved to the "binkp:processed" |
| 212 |
directory upon completion, which can be useful during testing. Otherwise, |
| 213 |
processed packets are deleted. |
| 214 |
|
| 215 |
To minimize latency, the Binkp poller will not start while there are any |
| 216 |
users logged in. This means that NetMail messages sent locally will not be |
| 217 |
sent out right away unless a Sysop manually triggers Binkp polling from the |
| 218 |
Sysop menu. This comes into play when communicating back and forth with |
| 219 |
an FTN AreaFix bot to configure which area messages should be delivered |
| 220 |
through the Binkp hub. |
| 221 |
|
| 222 |
Trusted Host |
| 223 |
================================================================== |
| 224 |
While Subtext can handle direct TCP connections for Telnet, it will likely |
| 225 |
be behind a firewall/trusted host. To limit brute-force login attempts, |
| 226 |
Subtext has a hard-coded list of banned account names that most bots will |
| 227 |
try in rapid succession, such as "root", "admin", etc. When a Telnet client |
| 228 |
tries one of these usernames, Subtext can send a UDP packet to the trusted |
| 229 |
host containing the IP to be banned (in dotted-quad plaintext format, such |
| 230 |
as "192.168.1.1"). The trusted host IP and port can be configured in the |
| 231 |
Sysop menu. If either value is empty/zero, this functionality is disabled. |
| 232 |
Since there is no authentication with this mechanism, ensure the trusted |
| 233 |
host is only listening for UDP packets on the interface facing the Subtext |
| 234 |
server! |
| 235 |
|
| 236 |
Also during Telnet negotiation, if the IP of the connecting client matches |
| 237 |
the trusted host's IP, Subtext will honor the "REMOTE_ADDR" value present |
| 238 |
in the NEWENV variable list and use it as the client's connecting IP address |
| 239 |
in logs. This is useful if the trusted host is acting as a web proxy and can |
| 240 |
pass the IP of the web client through to Subtext over Telnet. |
| 241 |
|
| 242 |
When transferring files to and from a host connecting through the trusted |
| 243 |
host, Subtext will use its custom NoModem protocol instead of ZMODEM. |
| 244 |
This makes it easier to implement file transfers through a web or other |
| 245 |
custom frontend. |
| 246 |
|
| 247 |
IP Geolocation |
| 248 |
================================================================== |
| 249 |
When configured with the path of an appropriate IP geolocation database, |
| 250 |
Subtext will use it to lookup connecting IPs. If a location is found, it will |
| 251 |
be logged to the logger and stored in the session log, which will also make |
| 252 |
it visible from the "who's online" and "recent logins' screens, so users can |
| 253 |
see where other users are connecting from. |
| 254 |
|
| 255 |
The format of this database is specified in the ipdb.c file. Free pre-built |
| 256 |
databases generated from public IP geolocation data can be downloaded |
| 257 |
from the Subtext website. These databases can be quite large (>40MB) and |
| 258 |
may be updated frequently, so they are not distributed with Subtext. |
| 259 |
|
| 260 |
Screen Blanking |
| 261 |
================================================================== |
| 262 |
When running on compact Macs, it is recommended to enable Subtext's |
| 263 |
screen blanking option to prevent the log window from burning into the |
| 264 |
CRT. When the system is idle for a configured amount of time, it will blank |
| 265 |
the entire screen for a configured amount of time, immediately unblanking |
| 266 |
as soon as a new connection comes in, or when a key is pressed or a mouse |
| 267 |
button is clicked. This is better than using a dedicated screen saver which |
| 268 |
will not unblank after a period of time, and may be wasting CPU time |
| 269 |
drawing flying toasters while Subtext needs to process user activity. |
| 270 |
|
| 271 |
Run on Startup (System 6) |
| 272 |
================================================================== |
| 273 |
To run Subtext when your Mac starts up, select the Subtext application in |
| 274 |
Finder, then open the Special -> Set Startup... menu. Under "Upon startup, |
| 275 |
automatically open:" select Subtext. |