SourceForge.net Logo

This is a pointer to the sourceforge home of rgdbm, the remote gnu database management client (GDBM) service. GDBM(3) is the classic Unix transaction-oriented database system, incorporating Berkeley DBM. It's fast and simple, and rgdbm allows it to be used over the net.

Downloadable archives for rgdbm will be found on the sourceforge site (click on the "project" tab and then on the big rectangular green button at mid left marked "download ...").

This page will get extended as time goes by.

Downloads are also available from the ftp server at my home site. I've listed them below as a convenience. The following are currently available:

Downloads (tgz)
home site sourceforge date size
rgdbm 2.1.29 rgdbm 2.1.29 03/06/07 44KB
rgdbm 2.1.30 rgdbm 2.1.30 04/06/07 45KB
rgdbm 2.1.31 rgdbm 2.1.31 05/06/07 46KB
rgdbm 2.1.32 rgdbm 2.1.32 05/06/07 50KB
rgdbm 2.1.33 rgdbm 2.1.33 08/06/07 58KB
rgdbm 2.1.34 rgdbm 2.1.34 11/06/07 62KB
rgdbm 2.1.35 rgdbm 2.1.35 13/06/07 77KB
rgdbm 2.1.36 rgdbm 2.1.36 15/06/07 104KB
rgdbm 2.1.37 rgdbm 2.1.37 16/06/07 136KB
rgdbm 2.1.38 rgdbm 2.1.38 18/06/07 122KB
rgdbm 2.1.39 rgdbm 2.1.39 21/06/07 123KB
rgdbm 2.1.40 rgdbm 2.1.40 22/06/07 125KB
rgdbm 2.1.41 rgdbm 2.1.41 25/06/07 136KB

To setup after installation (these notes are for 2.1.33 or later), let make install do what it can, and then:

  1. (Done by make install) Create a user, gdbm, on the server machine with home in /var/lib/gdbm.
  2. (Done by make install) Create /var/lib/gdbm and change owner to gdbm.
  3. (Done by make install) Also create /var/lib/gdbm/data, /var/lib/gdbm/ctrl, /var/lib/gdbm/certs and change owner to gdbm.
  4. Copy those parts of /etc/passwd belonging to users who should be able to access the daemon to /var/lib/gdbm/ctrl/passwd. This is entirely in your hands.

    NB. If you are using "shadow" passwords, then the password data is in your /etc/shadow, not /etc/passwd. The latter will just have an "x" in the password field. You want to dig the encrypted password out of /etc/shadow for /var/lib/gdbmbm/ctrl/passwd. Alternatively you can unshadow your password file with pwunconv(8), and later shadow it again with pwconv(8). While it is temporarily unshadowed, you can make a straight copy.

  5. Likewise for /etc/group to /var/lib/gdbm/ctrl/group.
  6. Start the daemon as gdbm with some command like "sudo -u gdbm /usr/sbin/gdbmd", or "su -c /usr/sbin/gdbmd gdbm". The install will not start it for you, nor does it presently install a system startup script for it in /etc/init.d or elsewhere.
  7. Write an application on the client that uses the standard gdbm_* calls in the GNU GDBM(3) manpage, but replace the gdbm_ calls with rgdbm_ calls. The install routine does do that ... or perhaps I lie.

That's about it! Apart from setting up for SSL if you want to use that and I'll give some further indications as to how to do that below.

One has to add two extra calls in the application over and above what was there already for gdbm(3) usage; one to rgdbm_connect() and another to rgdbm_disconnect(), respectively to begin and end the session, as detailed in the rgdbm(3) man page.

An Example

Sample code ... start by making the connection:

rgdbm_connect(host, dir, user, 0);

Then open the desired database in that directory:

RGDBM_FILE dbf = rgdbm_open(dbname, 1024, RGDBM_WRCREAT, 0640, NULL);

Now the rgdbm(3) ops are available.

    fprintf(stdout, "Database contains ...\n");
    datum key = rgdbm_firstkey(dbf);
    if (key.dptr) {
        datum content = rgdbm_fetch(dbf, key);
        fprintf(stdout, "key %s content %s\n", key.dptr, content.dptr);
        while (key = rgdbm_nextkey(dbf, key), key.dptr) {
            fprintf(stdout, "key %s content %s\n", key.dptr, content.dptr);

Terminate by closing:


and disconnect from the session:


Setting up the daemon to work over SSL

SSL is a secure transport layered above TCP, and provided that the code was compiled against openssl development headers and library, the daemon will use SSL if it is able to. The advantage is that nobody can see the data being exchanged, or alter it on the wire. But if your net is entirely local you may prefer not to use SSL, as it is somewhat slower than pure TCP and has a compute overhead both sides.

Even if the daemon code was compiled against openssl, however, that isn't enough to get it to use it. First you need a server certificate.

The server certificate can be obtained from commercial Certificate Authorities (CAs, for short) like Verisign or Thawte on the web. Or you can make one yourself, signed by yourself as CA. That's good enough if both server and client are yours and all you want is security against eavesdroppers, tamperers and man-in-the-middle attacks.

When you've got it, you need to put the server certificate in

on the server. If it's encrypted, you need to put the key alongside it in

That's all. The server daemon will find it there and use it.

Making a self-signed server certificate with openssl

I got the cookbook instructions as to how to make a self-signed certificate with openssl from selfsign.html on the web. I daresay there are many more spots on the web like that that a search engine will uncover.

The crucial point is that one first has to make a CA certificate for oneself. One eventually puts that in

on the client side, since the client needs to verify the server's certificate with it. It does not really matter what it is called. I know a suffix of .crt works fine although most of the files I have in that directory have suffix .pem.

After placing the file there one has to run

in order to create a soft link pointing to it, named by its digital signature. The openssl library functions will find it with that link.

To make the self-signed certificate, the complete cookbook goes like this:

  1. openssl genrsa -des3 -out ca.key 4096
    openssl req -new -x509 -days 365 -key ca.key -out ca.crt

    I opted instead for 1024 bit keys and 10000 days duration, as I was impatient and my net is an enclosed internal one. 4096 bits is banking grade security, good for what the banks estimate is 100 years of cracking attempts with the whole world's resources.

    When openssl asks you for the common name for the certificate, you must add some meaningless mumble that marks it out from the eventual server certificate. Don't put the same here for server and CA. Eg:
    Common Name (CN): www.somesite.edu CA

  2. openssl genrsa -des3 -out server.key 4096
    openssl req -new -key server.key -out server.csr

    This time you must put the correct DNS name of the server in the common name field when asked.
    Common Name (CN): www.somesite.edu

  3. Now you get to sign the server certificate with the CA certificate:

    openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

    I preferred 10000 days again, as my net is internal.

  4. You can make the server certificate insecure (which is convenient, as you're the one who needs it, and you're the one who stores it!) as follows:

    openssl rsa -in server.key -out server.key.insecure
    mv server.key server.key.secure
    mv server.key.insecure server.key

  5. Now, on the server (copy over the files first):

    mv server.crt /var/lib/gdbm/certs/gdbmd.crt
    mv server.key /var/lib/gdbm/certs/gdbmd.key

    On the client (also copy the files over first):

    mv ca.crt /etc/ssl/certs/me-as-ca.crt
    mv ca.key /etc/ssl/certs/me-as-ca.key

    and run

    c_rehash /etc/ssl/certs

That's it again.

Allowing the client to use SSL

It's up to the client if it accepts the server's certificate or if it even asks to use SSL at all.

The client specifies what transport protocols it wants to use in the flags argument of the rgdbm_connect call.

A value of 0 in the connect call is a synonym for "RGDBM_CRYPTO_ANY", which means to use anything the server wants to try. If you are sending a password over, you may not want to allow that, since a dumb server may try plain TCP instead of SSL. Even so, the password goes encrypted, but the encryption is not as strong as SSL's RSA encryption. For example, If both the client and the server only have classic unix crypt (not md5-sum) capability in their passwd file mechanisms, then there are only 4096 different defenses against a password replay attack before an attacker will strike lucky and see an encryption type requested that he has already recorded. If md5-sum passwords are available, then that number becomes astronomical (2 to the power of 48).

"RGDBM_CRYPTO_SSL" means to use SSL only, and "RGDBM_CRYPTO_NONE" means to use plain TCP only. RGDBM_CRYPTO_SSL alone is the recommended choice.

The flags can be or'ed together.

Fun with a terminal shell

From about 2.1.37 on I've included a terminal shell, gdbmsql in the contrib directory of the distribution. It's not in the main archive because I haven't yet made a big effort to make sure it will compile on multiple platforms, and because compiling it really needs significantly more support materials than the rest of the suite does. It works fine on ia32 linux is about all I can say at the moment.

But it's fun.

One connects with a command line like

gdbmsql -H server.somewhere.edu -U someperson/somepass myworkdirname

and then one is straight into the interactive session. The first thing to do is open a database for work:

open foo as wrcreat with mode = 0640;

should give you write permissions on a new database. You can then write to it:

insert (hello,world) in foo;

(all commands end with a semicolon and newlines just count as ordinary white space) and read the results back:

fetch content from foo where key = hello;

Full details are in the manual page in the contrib subdirectory. One should terminate by closing and disconnecting:

close foo;

The disconnect and other "high-level" commands are preceded by a backslash and don't need a closing semicolon. \? will provide a succinct command guide, for example.

myworkdir> \?
metacommands (begin with a '\'):
    \? for help
    \q to quit
commands (end with a ';'):
    insert (k, c) in db;
    replace (k, c) in db;
    (in the following 'e' may be key or key,content, or content)
    fetch (e) from db where key = k;
    fetch first (e) from db;
    fetch next (e) from db after key = k;
    exists (e) in db where key = k;
    delete from db where key = k;
    sync db;
    reorganize db;
    (in the following 'opt' may be cachesize, fastmode, ... )
    setopt opt = val for db;
    (in the following 'who' may be reader, writer, ... )
    open db as who [ with mode = val ];
    close db;