Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* DoorParty RLogin Proxy Service for Synchronet BBS
- echicken@bbs.electronicchicken.com, October 2016
- This service listens for connections from RLogin clients, then ensures that
- an account exists for the connecting user before sending them to the BBS.
- Setup:
- Place a copy of this file in the 'mods' directory. (If you don't have
- a 'mods' directory, create one at the top level of your Synchronet BBS
- installation, alongside 'exec', 'ctrl', 'data', etc.)
- Shut down the BBS.
- Edit ctrl/sbbs.ini, and change the RLoginPort value in the [BBS]
- section to 10513.
- I would also advise adding the NO_HOST_LOOKUP option to the Options
- value in the [BBS] section of sbbs.ini. This can speed up the login
- process and make the connection to your server closer to seamless.
- Edit ctrl/services.ini, and add the following section at the bottom:
- [RLoginProxy]
- Port=513
- Options=NO_HOST_LOOKUP
- Command=doorparty-rlogin-proxy.js
- Start the BBS back up again.
- Notes:
- RLogin clients send three strings immediately after connecting: the
- local username, the remote username, and the terminal type & speed. None
- of these fields was actually meant to carry a password, but occasionally
- that's what they're used for.
- Some clients (SyncTERM) send the password first, then the username, then
- the terminal type & speed; other clients may send the username first and
- the password second. The server needs to know which field is which. If
- the alias that's being set for a new user is not what you're expecting,
- try swapping the values of the USERNAME_FIELD and PASSWORD_FIELD
- settings below.
- The 'password' sent by the RLogin client is being ignored and is not
- being compared with the user's password on this BBS (if they already
- exist here). What I've gleaned from the DoorParty wiki suggests this is
- appropriate, and that inbound RLogin connections are 'trusted' because
- they come from authenticated systems via an SSH tunnel.
- A different random password is being generated for each new user and is
- not based on anything that was sent by the RLogin client.
- If you find that the BBS is still prompting new users for more info when
- they first connect, this script can be adjusted to populate more user
- data fields so that these questions appear to have been answered.
- I have commented the shit out of this script for the benefit of anyone
- who needs to work on it in the future, including myself.
- If you're not maskreet and you've stumbled upon this script by accident,
- I would not advise setting it up on the Synchronet BBS that you may or
- may not operate. This script serves a very specific purpose for an
- uncommon situation and would not be wise to run on a 'normal' BBS.
- */
- // Configuration
- const RLOGIN_PORT = 10513; // The port that your actual RLogin server is on
- const PROXY_PORT = 513; // The port that you want this server to listen on
- const LOGIN_TIMEOUT = 30; // Seconds to wait for RLogin client details
- const USERNAME_FIELD = 1; // '1' if clients send username first, '2' otherwise
- const PASSWORD_FIELD = 2; // '1' if clients send password first, '2' otherwise
- const MAX_READ = 512; // This probably doesn't need to be changed, but you
- // can tweak it up or down and see if it reduces lag
- // or improves responsiveness.
- // Don't edit below this line.
- load('sbbsdefs.js');
- // If running via jsexec, set up a server and wait for a client
- if (typeof js.global.server === 'undefined') {
- load('sockdefs.js');
- var s = {};
- s.socket = new Socket(SOCK_STREAM, 'RLOGIN-PROXY');
- s.socket.bind(PROXY_PORT);
- s.socket.listen();
- var client = s.socket.accept();
- }
- // However this was launched, 'client' should now be our client's Socket object
- // Global constants
- const NUL = ascii(0);
- const START_TIME = time();
- const STATE_INIT_CLIENT = 0;
- const STATE_INIT_USER = 1;
- const STATE_INIT_PROXY = 2;
- const STATE_PROXY = 3;
- // Global variables
- var proxy, username, password, terminal;
- var state = STATE_INIT_CLIENT, from_client = '';
- // Crappy but good enough
- function generatePassword(len) {
- var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.split('');
- var pass = '';
- while (pass.length < len) {
- pass += chars[Math.floor(Math.random() * chars.length)];
- }
- return pass;
- }
- // The client has just connected, and we're waiting for their initial string
- while (state === STATE_INIT_CLIENT && !js.terminated && client.socket.is_connected) {
- try {
- if (client.socket.nread > 0) from_client += client.socket.recv(MAX_READ);
- var matches = from_client.split(NUL);
- // If we've received four null-terminated values, parse them
- if (matches.length >= 4) {
- username = matches[USERNAME_FIELD];
- password = matches[PASSWORD_FIELD];
- terminal = matches[3];
- from_client = undefined; // We don't need this anymore
- client.socket.sendBin(0, 1); // Acknowledge that we got the client's data
- // Proceed to user lookup/creation
- state = STATE_INIT_USER;
- log(
- LOG_INFO,
- format(
- '%s/%s/%s connected from %s',
- username, password, terminal, client.socket.remote_ip_address
- )
- );
- // If we've been waiting too long for user details, throw an exception
- } else if (time() - START_TIME >= LOGIN_TIMEOUT) {
- throw 'Login timeout exceeded.';
- }
- yield(); // Don't set the compooter on fire.
- } catch (err) {
- log(LOG_ERR, 'INIT_CLIENT: ' + err);
- }
- }
- // If the client successfully initiated the session, find or create the user
- if (state === STATE_INIT_USER) {
- try {
- var un = system.matchuser(username); // Try to find the specified user
- // If a match was found, grab the user's actual password
- if (un > 0) {
- var u = new User(un);
- // Otherwise create a new user and set the password
- } else {
- var u = system.new_user(username);
- u.alias = username;
- u.name = username;
- u.handle = username;
- u.security.password = generatePassword(8);
- // We may need to populate other user data here if the BBS keeps asking questions upon connect
- log(LOG_INFO, 'Created user #' + u.number + ', ' + u.alias);
- }
- password = u.security.password;
- // Proceed with connecting to the RLogin server
- state = STATE_INIT_PROXY;
- } catch (err) {
- log(LOG_ERR, 'INIT_USER: ' + err)
- }
- }
- // We now have an existing user to log in as; connect to the RLogin server
- if (state === STATE_INIT_PROXY) {
- try {
- proxy = new Socket();
- proxy.connect('127.0.0.1', RLOGIN_PORT);
- // If we were able to connect to the RLogin server, send the user's info
- if (proxy.is_connected) {
- proxy.send(NUL + password + NUL + username + NUL + terminal + NUL);
- // Proceed to the proxying stage
- state = STATE_PROXY;
- // If we were unable to connect to the RLogin server, throw an exception
- } else {
- throw 'Failed to connect to RLogin server';
- }
- } catch (err) {
- log(LOG_ERR, 'INIT_PROXY: ' + err);
- }
- }
- // If we made it to STATE_PROXY, enter the proxy loop
- if (state === STATE_PROXY) {
- try {
- // Pass traffic between the client and the rlogin server
- while (!js.terminated && client.socket.is_connected && proxy.is_connected) {
- if (proxy.nread > 0) client.socket.send(proxy.recv(MAX_READ));
- if (client.socket.nread > 0) proxy.send(client.socket.recv(MAX_READ));
- yield();
- }
- } catch (err) {
- log(LOG_ERR, 'PROXY: ' + err);
- }
- }
- // Clean up
- if (proxy && proxy.is_connected) proxy.close();
- if (client.socket.is_connected) client.socket.close();
- exit(0);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement