1 /* tool/set_localid.c -- Add local identity credential
3 * Provide a config, a NAI and a type of credential. The command erases all
4 * old entries that match and replaces them with what is provided, if anything.
5 * The provided information should be a PKCS #11 URI and a binary file holding
6 * public credentials (not a base64 / Armoured / PEM notation).
8 * From: Rick van Rein <rick@openfortress.nl>
17 #include <sys/types.h>
24 #include <arpa/inet.h>
28 #include <tlspool/internal.h>
32 "Usage: %s tlspool.conf [user@]fqdn type [p11priv pubdata...]\n"
33 " - tlspool.conf is the configuration file for the TLS Pool\n"
34 " - user@fqdn or fqdn is a network access identifier\n"
35 " - type X.509,OpenPGP,Kerberos,valexp,client,server,nop11,chained\n"
36 " - p11priv is a PKCS #11 URI string for the private key\n"
37 " - pubdata is a file name string for the public key package\n"
38 "The pairs of p11priv and pubdata replace the old content. An empty list of\n"
39 "pairs is nothing special; it replaces the old content with zero entries.\n";
47 struct typemap_t typemap [] = {
64 /* Setup and tear down management */
65 int setup_management (char *cfgfile, DB_ENV **dbenv, DB_TXN **txn, DB **dbh) {
66 char *dbenv_dir = tlspool_configvar (cfgfile, "dbenv_dir");
67 char *dblid_fnm = tlspool_configvar (cfgfile, "db_localid");
68 if (dbenv_dir == NULL) {
69 fprintf (stderr, "Please configure database environment directory\n");
72 if (dblid_fnm == NULL) {
73 fprintf (stderr, "Please configure localid database name\n");
76 if (db_env_create (dbenv, 0) != 0) {
77 fprintf (stderr, "Failed to create database environment");
80 if ((*dbenv)->open (*dbenv, dbenv_dir, DB_CREATE | DB_RECOVER | DB_INIT_TXN | DB_INIT_LOG | DB_INIT_LOCK | DB_THREAD | DB_INIT_MPOOL, S_IRUSR | S_IWUSR) != 0) {
81 fprintf (stderr, "Failed to open database environment");
84 if ((*dbenv)->txn_begin (*dbenv, NULL, txn, 0) != 0) {
85 fprintf (stderr, "Failed to start transaction\n");
88 if (db_create (dbh, *dbenv, 0) != 0) {
89 fprintf (stderr, "Failed to create localid database\n");
92 if ((*dbh)->set_flags (*dbh, DB_DUP) != 0) {
93 fprintf (stderr, "Failed to setup localid database for duplicate entries\n");
96 if ((*dbh)->open (*dbh, *txn, dblid_fnm, NULL, DB_HASH, DB_CREATE | DB_THREAD, 0) != 0) {
97 fprintf (stderr, "Failed to open localid database\n");
103 /* Cleanup maangement structures */
104 void cleanup_management (DB_ENV *dbenv, DB *db) {
106 dbenv->close (dbenv, 0);
109 int main (int argc, char *argv []) {
110 char *localid = NULL;
111 char *partstr = NULL;
112 char *saveptr = NULL;
114 uint8_t e_buf [5000];
131 if ((argc < 4) || ((argc % 2) != 0)) {
132 fprintf (stderr, usage, argv [0]);
136 // Initialise the modules taken from the src directory
139 // Prepare variables from arguments
142 partstr = strtok_r (argv [3], ",", &saveptr);
143 if (partstr == NULL) {
144 fprintf (stderr, "Flags must not be empty\n");
147 while (partstr != NULL) {
148 struct typemap_t *walker = typemap;
149 while (walker->name != NULL) {
150 if (strcasecmp (walker->name, partstr) == 0) {
151 flags |= walker->bits;
156 if (walker->name == NULL) {
157 fprintf (stderr, "Flag name %s not recognised\n", partstr);
160 partstr = strtok_r (NULL, ",", &saveptr);
162 if ((flags & 0x000000ff) != 5) {
164 while (argi < argc) {
165 if (strncmp (argv [argi], "pkcs11:", 7) != 0) {
166 fprintf (stderr, "PKCS #11 URIs must start with \"pkcs11:\"\n");
173 // Now modify the matching entries
174 if (!setup_management (cfgfile, &dbenv, &txn, &dbh)) {
177 if (dbh->cursor (dbh, txn, &crs, 0) != 0) {
178 fprintf (stderr, "Failed to open cursor on localid.db\n");
181 memset (&k_localid, 0, sizeof (k_localid));
182 k_localid.data = localid;
183 k_localid.size = strlen (localid);
184 nomore = crs->get (crs, &k_localid, &e_value, DB_SET);
185 while (nomore == 0) {
186 uint32_t e_flags = 0;
187 char *e_p11uri = NULL;
190 if (e_value.size < 4) {
191 fprintf (stderr, "Found too-short entry?!?\n");
195 e_flags = ntohl (* (uint32_t *) e_value.data);
196 e_p11uri = (char *) & ((uint32_t *) e_value.data) [1];
197 e_bindata = (uint8_t *)(e_p11uri + strnlen (e_p11uri, e_value.size - 4) + 1);
198 e_binlen = e_value.size - 4 - strnlen (e_p11uri, e_value.size - 4) - 1;
200 fprintf (stderr, "Error retrieving binary data;\n");
202 printf ("Object flags are 0x%x\n", e_flags);
203 if ((e_flags & 0xff) == (flags & 0xff)) {
204 printf ("Deleting old entry 0x%x, %s, #%d\n",
205 e_flags, e_p11uri, e_binlen);
206 if (crs->del (crs, 0) != 0) {
207 fprintf (stderr, "Failed to delete record\n");
211 printf ("Deleted this old record\n");
214 printf ("Won't remove, type is 0x%x and not 0x%x\n",
215 e_flags & 255, flags & 255);
217 nomore = crs->get (crs, &k_localid, &e_value, DB_NEXT_DUP);
220 if (nomore != DB_NOTFOUND) {
221 fprintf (stderr, "Database error encountered while iterating\n");
225 // Now append any new values
227 while (argi < argc) {
228 p11len = strlen (argv [argi]);
229 if (stat (argv [argi+1], &statbuf) != 0) {
230 fprintf (stderr, "Failed to stat %s: %s\n",
231 argv [argi+1], strerror (errno));
234 filesz = statbuf.st_size;
235 if (4 + p11len + 1 + filesz > sizeof (e_buf)) {
236 fprintf (stderr, "Out of buffer memory trying to fill %s\n",
240 * (uint32_t *) e_buf = htonl (flags);
241 strcpy ((char *) & ((uint32_t *) e_buf) [1], argv [argi]);
242 fd = open (argv [argi+1], O_RDONLY);
244 fprintf (stderr, "Failed to open %s: %s\n",
245 argv [argi+1], strerror (errno));
248 if (read (fd, &e_buf [4 + p11len + 1], filesz) != filesz) {
249 fprintf (stderr, "Failed to read from %s: %s\n",
250 argv [argi+1], strerror (errno));
255 e_value.data = e_buf;
256 e_value.size = 4 + p11len + 1 + filesz;
257 if (dbh->put (dbh, txn, &k_localid, &e_value, 0) != 0) {
258 fprintf (stderr, "Failed to write record to database\n");
261 printf ("Written %s and %s\n", argv [argi], argv [argi+1]);
264 if (txn->commit (txn, 0) != 0) {
265 fprintf (stderr, "Failed to commit transaction\n");
268 fprintf (stderr, "Committed transaction\n");
271 // Finish up and report success
273 cleanup_management (dbenv, dbh);
276 // Handle failure during database interactions
278 fprintf (stderr, "Rolling back transaction\n");
280 cleanup_management (dbenv, dbh);