User Guide To ACEDB 4_9 Sockets-based Client/Server

> ### ACEDB Version 4_9

> # User Guide To Sockets-based Client/Server

> ## Background

> The first implementation of the ACEDB client/server code used `RPC` for inter process communication (`IPC`). This method was originally chosen because it offered the promise and portable means of making requests between the client and server. In practice `RPC` suffered from several major disadvantages:

> - although `RPC` was offered by all major unix vendors, their implementations turned out to be buggy, in different ways (ironically, this was especially true of Suns implementation).
> - although `RPC` offers a very simple function call interface for `IPC`, error handling is not so simple and does not offer the fine grained control that other methods of `IPC` do.
> - `RPC` for MS Windows is not robust.
> - `DCE RPC` using the DCE version of RPC would help with portability for both Unix and MS Windows, but the DCE version is often not available for free.
> - many other code subsytems offer sockets communication (e.g. Perl) but not `RPC`.
> - On unix at least `RPC` requires several daemons to be running (portmapper, inetd) and this makes the system susceptible to system set up/reboot problems.
> The decision was taken to switch to socket based `IPC` because it overcomes the above difficulties. Sockets of course present their own difficulties because the interface to them is more complex to program than `RPC`, it's greater flexibility/portability and ubiquitousness made this a worthwhile trade off.

> ## Overview

> The sockets based version of the server offers the same interface as the current RPC based version of the client/server but there have been several additions to the code that are either indirectly or not directly related to sockets:

> - NO_RESTART option & fix for the "phoenix" bug
> - READ/WRITE options for setting global access permissions to a database
> - MD5 password based authentification for users
> - domain name group authorisation (NO_HOSTNAME_RESOLUTION option)
> - a new "admin" class of user with a set of "admin" commands
> - READ ONLY database support
> - DEBUG option

> This document describes these new features and then goes on to describe how to:

> - set up a database for use with the sockets server
> - server start up options
> - foreground and inetd startup of the server
> - client start up

> ## Setting up a database

> The following is a brief summary to get you started, it should let you get the server/client going, after that you can tinker around to get more security etc.:

> ### 1) Options in wspec/serverconfig.wrm:

> NO_RESTART
>   - turns ON no restart of server after a crash/shutdown.
> NO_HOSTNAME_RESOLUTION
>   - turns OFF checking for user being in a domain specified as having permission to log in, e.g. sanger.ac.uk
> DEBUG
>   - turns ON server debugging output to database/server.log
> WRITE/READ
>   - set the basic database access permission levels for the read and write groups (admin users always have write access). Default is PASSWD, but NONE & WORLD can also be set.
> READONLY_DATABASE
>   - allows the server to run on a database where all the file permissions have been set to read-only (unix only) for extra security.

> Unless you have special needs, the default settings are suitable for either testing or a production database, but you must create the empty file wspec/serverconfig.wrm.

> See Configuration options for more details.

> ### 2) Passwords in wspec/serverpasswd.wrm:

> This file contains two types of record: groups/associated users records and individual user records. There are three groups: admin, write and read and to set up a database to run with the new socket server there needs to be at least one user in the admin group.

> To 'bootstrap' an admin user so you can access the database via the client you need to:

> 1. choose your admin userid (this does _not_ need to be an existing Unix userid, it can be any name you want), e.g. joebloggs
> 2. alter the admin group line in `serverpasswd.wrm` so it looks like this:

>               admin: joebloggs

> 3. now use the acedb utility program makeUserPasswd to create the user entry for joebloggs (note that you won't see the password you type):

>               > bin.whatever/makeUserPasswd joebloggs
>               // Please enter passwd: jumbo10
>               // Please re-enter passwd: jumbo10
>               // The following line is a valid entry for wspec/serverpasswd.wrm

>               joebloggs ccc5b9abf592836076410cdee518c518

>               >

>    cut and paste the entry into a separate line in the `serverpasswd.wrm` file.

> The resulting wspec/serverpasswd.wrm file would look like this:

>            admin: joebloggs
>            joebloggs ccc5b9abf592836076410cdee518c518

> Once the initial admin user has been set up, all other users can be set up from the admin userid via the new admin commands.

> You should now be in a position to test the server and client, it is recommended that you test the server in the foreground before trying to set it up to be run by inetd.

> ## Server start up options

> saceserver command line options are:

>     saceserver database_path <:port_number clientT:serverT:maxReq:autoS>

>                database_path    mandatory, gives path to the database
>                  port_number    defaults to 23100
>                      clientT    client time out (secs), default = 600
>                      serverT    server time out (secs), default = 600
>                       maxReply  maximum reply size (Kbytes) that server should return
>                        autoS    time between autosaves of database (secs), default = 600

> ### timeout values

> The meaning of the timeouts is:

> clientT
>   the server will disconnect any clients who have not been active for this length of time.
> serverT
>   once all clients are disconnected, the server will timeout after this length of time.

> So if, for instance, you wanted to allow clients to be dormant for an hour but have the server close down as soon as the last client quit you could start the server like this:

>     saceserver your_database_path your_port 3600:1

> Note that clientT and serverT can take the special value zero which means the timeout is infinite, i.e. neither the client or server will ever be timed out. This special value is provided for testing and is specifically not recommended for normal use.

> ### maximum request size

> The meaning of the maximum request field is:

> maxReply
>   If the reply to a client exceeds this threshold then the server "slices" the reply up and returns it a piece at a time. This prevents a single client from hogging the server.

> Note that maxReply can take the special value zero which means that there is no maximum reply threshold and the server will return in one piece the entire reply. This special value is provided for circumstances where the user wants to get large replies back in one piece, you should note that other clients requests will not be processed while a large reply is being sent.

> ### port numbers

> IANA (Internet Assigned Numbers Authority) has set aside certain ranges of port numbers for certain uses:

>     Port No. range          Usage
>     --------------          -----

>     0 - 1023                "well-known" ports, you need super user authority
>                             to use these and they are reserved for ftp, http,
>                             X windows and basic operating system services.
>                             DO NOT USE THESE.

>     1024 - 49151            "registered" ports, if you setting up the server to
>                             be run by inetd you should use one of these.
>                             But you will need to check in /etc/services
>                             that your number does not clash with one already there.

>     49152 - 65535           "dynamic" ports, are for dynamically assigned/ephemeral
>                             use. You should use one of these if you are just trying
>                             out the server from an xterm in the foreground.

> Actually its all more confused than this, not all operating systems stick to the IANA recommendations, but it is generally true that you cannot use a port less then 1024 without root permission and you should not in general choose these ports.

> You should also not choose a port larger than 65535. If you do, the port number may be truncated in a way that leaves it in the range 0 - 1023 which are reserved for superuser use for well-known services.

> Typically you will see these sorts of errors if you choose a port that is either below 1024 or already in use (you may have to look in the database logfile to see the error if the server is inetd started):

>     typical server error:

>     % saceserver /mydatabase 777
>     // Database directory: /data1/GrainGenes
>     // #### Server starts 2000-04-03_11:29:49
>     // #### host=(unknown)  port=777  ACEDB=/data1/GrainGenes
>     // #### clientTimeout=600 serverTimeout=600 maxKbytes=0 autoSaveInterval=600

>     // FATAL ERROR (www on gn) reported by program aceserver (ACEDB 4_9c), in file a
>     cesocket.c, at line 657: Cannot bind to server listening socket system error 13
>      - Permission denied
>     // Sorry for the crash, please report it, if it is reproducible

>     // NB: changes made since the last explicit save have NOT been saved

>     typical client error:

>     % saceclient localhost -port 777
>     FATAL ERROR (www on gn) reported by program saceclient (ACEDB 4_9c), in file ace
>     socketlib.c, at line 269: connect error system error 146 - Connection refused

> ## Running the Server

> ### in the foreground

> To run the server in the foreground, type the following at the prompt in an xterm:

>       saceserver <your/data/base>  <your_port_number> <time_out_options>

> If the server starts correctly your xterm will "hang" because the server will be sitting waiting for clients to connect. If something goes wrong acedb will print an error message and then exit. You should correct the error and then try again.

> Once the server is starting correctly then try accessing it using the client:

>     saceclient <host_where_server_is_running> -port <port_number_from_above>
>     acedb> status
>     acedb> quit

> If you can connect correctly then you are ready to try running the server under the control of one of the unix inetd or xinetd controller programs.

> ### under inetd

> You can now run saceserver against any existing acedb database and/or register it under inetd by adding lines to the following files (you will need root access):

> For this example we assume:

>     nickname for server/database -  MyfirstDB
>                  port for server -  20113
>             user owning database -  mieg
>            path to server binary -  /usr/local/bin/saceserver
>                 path to database -  /home/databases/aardvarkDB
>        timeout values for server -  200:200:0

> In /etc/services add the line:

>     MyfirstDB  20113/tcp

> in /etc/inetd.conf add the line

>     MyfirstDB stream tcp wait mieg  /usr/local/bin/saceserver saceserver /home/databases/aardvarkDB 200:200:0

> Where:

>                     MyfirstDB  seen in both files, a random name of your choice to name the database server
>               stream tcp wait  mandatory, this is the way the daemon must be declared
>                          mieg  user name under which the daemon runs, avoid root,
>                                choose some local user owning /home/databases/aardvarkDB
>     /usr/local/bin/saceserver  full path to saceserver executable
>                    saceserver  repeat the name of the execuatble so that it is found as argv[0] by the code
>      /home/databases/aardvark  the database directory
>                     200:200:0  server and client time out in seconds, then a blocking factor
>                                (default zero is ok)

> Now get inetd to reread /etc/inetd.conf and pick up the information for MyfirstDB (you will probably need to be root to do this):

> 1. find out the process id of inetd

>        > ps -A | grep inetd

>           545 ??       I        0:00.62 /usr/sbin/inetd

> 2. Send inetd the interrupt signal

>        > kill -HUP 545

> Sending this signal should be enough but on some old systems a reboot may be necessary.

> Then access the server by starting up a client:

>     saceclient <host_where_server_is_running> -port 20113

> ### under xinetd

> xinetd is an open source replacement for inetd, it provides many more features and much security than inetd, you can read more about it at the xinetd website.

> Its configuration is a bit different from inetd and is as follows:

> For this example we assume the following:

>     nickname for server/database -  MyfirstDB
>                  port for server -  20113
>             user owning database -  mieg
>            path to server binary -  /usr/local/bin/saceserver
>                 path to database -  /home/databases/aardvarkDB
>        timeout values for server -  200:200:0

> In /etc/services add the line:

>     MyfirstDB  20113/tcp

> xinetd keeps its configuration files in the directory /etc/xinetd.d. Create a file in this directory giving it some meaningful name such as acedb and add the following lines:

>     # file: /etc/xinetd.d/acedb
>     # default: on
>     # description: wormbase acedb database
>     service acedb
>     {
>                    protocol                = tcp
>                    socket_type             = stream
>                    port                    = 20113
>                    flags                   = REUSE
>                    wait                    = yes
>                    user                    = mieg
>                    group                   = mieg
>                    log_on_success          += USERID DURATION
>                    log_on_failure          += USERID HOST
>                    server                  = /usr/local/bin/saceserver
>                    server_args             = /home/databases/aardvarkDB 200:200:0
>     }

> Note that you will need to change the port, user, group, server and server_args fields for you setup.

> Warning: In the past there have been a number of problems with the way xinetd worked which prevented users from running the acedb servers with xinetd. Currently the following combination of Linux, xinetd and acedb is known to work:

> Linux: Red Hat Linux release 7.3 (Valhalla), kernal: 2.4.18-27.7.xbigmem

> xinetd: xinetd-2.3.7-4.7x

> acedb: 4_9m

> If you find that you cannot get acedb working under xinetd control then you should first check that you have up to date software.

> ## Running the client

>     Usage: saceclient <host> [-port pn] [-time_out ] [-ace_out] [-ace_in] [-f file_name parms]

>     host: is a machine where the server runs or is a registered service.
>     pn: is the port number described in the server setup section.
>     nn: is a number of seconds to wait to receive a server answer, it defaults to 300.
>     -ace_out: implies a clean output: .ace files or clean tables
>     -ace_in: if the input to the client is an ace file to be parsed by the server.
>     -f filename: say for mailing, a command file which is echoed on stdout except
>      that %1 %2 ... %9 will be macro substituted by the parms parameters and
>      that the construction %(xxx) where xxx is a client command will be evaluated

> ## Introduction of MD5 password encryption based authentification for users

> The sockets based version comes with a new password based system. The previous versions of the server used a file based system that while not requiring users to user passwords, did require that both client and server could "see" the directory where the "magic" files used by the server for authentification were stored. This has obvious problems when the client and server are separated by a firewall, are very remote from each other or either is running on a system that does not support shared file systems.

> The new system uses passwords much like any Unix system does, users have their own unique userid and must supply a password to gain access to the database. Note that userids are 'global' to a database, e.g. if two users on different machines by chance have the same userid, they cannot both use that userid to gain access to the database, one or the other will have to use a different userid for the database. This is the same restriction as applies to Unix login ids.

> The new system uses a "challenge-response" protocol: the client contacts the server, the server sends the client a key, the client must then encrypt their userid, password and the key and send it back to ther server. The server then encrypts its copy of the encrypted userid/password with the key and compares them with what its been sent. At no time does the password pass in plain text across the network, nor is it stored in plain text. Furthermore, they key is changed every time the user logs on, making it more difficult to crack the password. While not perfect this method offers at least as much (actually more) security than the Unix password system. This is also essentially the method of security used in the http protocol.

> There is a new file, `wspec/serverpasswd.wrm`, which holds the userids and associated passwords and also which group a userid belongs to. There are three groups of users:

> read
>   users who can get read access to the database
> write
>   users who can get read/write access to the database
> admin
>   users who can get read/write access to the database and run administrative commands on the database (e.g. add new users, shutdown the database etc.)

> Entries in this file are of two sorts: group entries and userid entries, below is a sample `wspec/serverpasswd.wrm` showing both group and userid entries (as usual lines beginning with "//" are comments):

>     // User groups
>     //
>     admin:  edgrif
>     write: simon
>     read: jean richard sanger.ac.uk

>     // users and passwords
>     //
>     edgrif 38a6557860893d95c7e738c0e5cd233d
>     simon 7d61c0b3fb23c97f6970f07683a03649
>     jean 52af4f5526e16c855ca14a40287d1be1
>     richard 9dee3b01e9adeb11f8acac16fb368d76

> Initially an admin user must create a new entry for a user, complete with password (see admin user section), after this a user can change their own password using the `passwd` command from the saceclient:

>     acedb> passwd
>     enter new passwd:
>     reenter new passwd:

> Only rudimentary password checking is done, it is up to users/administrators to ensure that good passwords are chosen.

> ## Introduction of domain name group authorisation and the NO_HOSTNAME_RESOLUTION option

> The previous section described the format of entries in `wspec/serverpasswd.wrm`, the "read" and "write" group entries can also contain domain names:

>     // User groups
>     //
>     admin:  edgrif
>     write: simon
>     read: jean richard sanger.ac.uk

> The "read" group entry contains the entry "sanger.ac.uk", this allows any user whose internet address ends with this sub-domain to log in with read access, e.g. johnsmith@linuxbox.sanger.ac.uk, janebrown@sanger.ac.uk etc. This makes it possible to give access to groups of people logging in from different sites. This only happens if the access level for a group is `PASSWD` and the userid of the connecting client cannot be found in the group.

> When a client connects, the server only has the numeric version of the clients internet address, since the lookup required to convert this to the text form can be both error prone and slow, it is possible to globally disable this lookup by setting the `NO_HOSTNAME_RESOLUTION` option in `wspec/serverconfig.wrm`. If this option is set, the server will not attempt to resolve the text form of a clients internet address and match it to group name entries.

> ## Introduction of an "admin" class of user and a set of "admin" commands

> The introduction of a password system made it necessary to introduce some extra commands to the command line interface: because users passwords are relatively long and must be copied into the password file correctly, this is only really feasible via a program. It also became clear that there should be a special class of user who would be allowed to run these commands and not just any user with write access as in previous servers.

> Some "admin" commands already existed e.g. shutdown, these commands have been supplemented with additional commands including:

> shutdown [now] [norestart]
>   Shuts down the server, by default this is when the last client quits but if the now option is specified, clients connections are terminated immediately and the server is shut down. If the norestart is specified then the server will not restart until the lock file `database/SERVER_SHUTDOWN_LOCKFILE.wrm` is removed.
> who
>   display how many clients are currently connected.
> data_version
>   data served now, as stated in wspec/server.wrm
> wspec
>   export wspec directory as a tar file
> user passwd|group|new|delete userid [password group]
>   This command has several forms enabling an admin user to create/update/delete userids:
>   - Create: user new new_userid new_group (you will be prompted for the passwd)
>   - Delete: user delete userid
>   - Change group: user group userid new_group
>   - Change password: user passwd userid (you will be prompted for the passwd)
> global read|write none|passwd|world
>   Change global read/write permissions for database
> domain group|new|delete domain-name [group]
>   This command is similar to the user command but enables the admin user to create/update/delete domain names:
>   - Create: domain new new_domain new_group
>   - Delete: domain delete domain
>   - Change group: domain group domain new_group

> ## Server Configuration Options

> #### NO_RESTART (and the "phoenix" bug)

> This option can be specified in `wspec/serverconfig.wrm` and will prevent the database from restarting after either a controlled shutdown or a server crash. If the option is specified then the server will leave a lockfile in the `database/` on shutdown or when it crashes (either in a trappable or non-trappable way). The name of the lockfile indicates whether the file was written as a result of a crash or a shutdown:

>     For a crash that was detected by the acedb code:

>     database/SERVER_CRASH_LOCKFILE.wrm

>     for a crash that could not be detected by the acedb code:

>     database/SERVER_UNDETECTABLECRASH_LOCKFILE.wrm

>     and for a shutdown:

>     database/SERVER_SHUTDOWN_LOCKFILE.wrm

> The server cannot be restarted either manually or automatically by inetd until the lockfile is removed from the directory (the directory would normally be set up so that only admin users would have permission to do this).

> Previous acedb servers have suffered from an irritating bug when run under the control of inetd. This bug (aka the "phoenix" bug) seemed to occur sometimes when the server crashed, the system would get into a loop with the server crashing, inetd respawning the server, the server crashing, inetd respawning the server, etc. etc. The advantage of the socket based server is that the greater degree of control over the port allowed debugging to show that this happens when a client has connected, but the server crashes before it has cleared the listening socket on which the client connected. In this case, inetd finds that there is still data on the listening socket and so it restarts the server which of course crashes again before clearing the listening socket. The new server has as part of its crash routine some code to clear the listening socket and thus put a stop to inetd trying to restart the server. Note however that this bug can still occur if the server crashes in an untrappable way, this loophole will be fixed at some time in the future.

> #### READ/WRITE options for setting global access permissions to a database

> The `READ` and `WRITE` options can be specified in `wspec/serverconfig.wrm` and allow 'global' control of the access level for all users in the read or write groups.

> Three levels of control are available:

> WORLD
>   any user can have access, including users not specified in `wspec/serverpasswd.wrm`
> PASSWD
>   only users specified in `wspec/serverpasswd.wrm` can gain access (with a password)
> NONE
>   no users can have access

> The access level is specified on the same line as the keywords `READ` or `WRITE`, e.g. to give read access to everyone and write access to no one, `wspec/serverconfig.wrm` should contain the lines:

>     READ WORLD
>     WRITE NONE

> Admin group users always have write access to the database but this access is via a password.

> #### READONLY_DATABASE option

> Normally the server must have read/write access to at least some of the files and directories within an acedb database (e.g. for logging). This option allows the server to run on a database where it only has read permission for all directories and files within the database. This can be useful as extra level of security for a database which has been made available as a "read only" copy, perhaps to any user anywhere on the internet.

> You should note that when this option is specified, the server will not do any logging of requests or crashes, so there will be no record of users interactions with the server.

> #### DEBUG option

> This option can be specified in `wspec/serverconfig.wrm` and will cause the server to send debugging output to `database/server.log`, if the server is being run in the foreground then the output will also be sent to stderr. Currently this information is patchy but this release of the server includes the basic mechanism (setting up callback routines for the messout/messerror routines) for easy output of debugging messages which was missing in previous servers.

> ### ACEDB Version 4_9

> Last modified: Tue Apr 22 16:41:50 BST 2003