Almost a complete rewrite.
[ca] / bin / add
diff --git a/bin/add b/bin/add
new file mode 100755 (executable)
index 0000000..1c2ae81
--- /dev/null
+++ b/bin/add
@@ -0,0 +1,111 @@
+#! /usr/bin/tclsh8.5
+### -*-tcl-*-
+###
+### Insert a certificate request into the database.
+###
+### (c) 2011 Mark Wooding
+###
+
+###----- Licensing notice ---------------------------------------------------
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License as published by
+### the Free Software Foundation; either version 2 of the License, or
+### (at your option) any later version.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software Foundation,
+### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+## Find the common utilities.
+source [file join [file dirname $argv0] "../lib/func.tcl"]
+
+## Parse the command line.
+set O(replace) false
+set usage "usage: $argv0 \[-replace\] PROFILE TAG FILE"
+for {set i 0} {$i < [llength $argv]} {incr i} {
+  switch -glob -- [lindex $argv $i] {
+    "-replace" {
+      set O(replace) true
+    }
+    "--" {
+      incr i
+      break
+    }
+    "-*" {
+      puts stderr $usage
+      exit 1
+    }
+    default {
+      break
+    }
+  }
+}
+set args [lrange $argv $i end]
+if {[llength $args] != 3} {
+  puts stderr $usage
+  exit 1
+}
+lassign $args profile tag file
+
+## Open the database.
+sqlite3 db "$CERTROOT/state/ca.db"
+
+## Do most of the work in a transaction.
+db transaction {
+  with-cleanup {
+
+    ## Check whether this tag is already taken.
+    if {!$O(replace) && [db exists {
+      SELECT 1 FROM request
+      WHERE tag = $tag AND st = 'active';
+    }]} {
+      error "request `$tag' already active"
+    }
+
+    ## Check whether the profile exists.
+    if {![db exists {
+      SELECT 1 FROM profile WHERE label = $profile;
+    }]} {
+      error "unknown profile `$profile'"
+    }
+
+    ## Copy the file away.
+    fresh-temp "$CERTROOT/tmp" tmp {
+      file copy $file $tmp
+    }
+    cleanup { file delete $tmp }
+
+    ## Get lots of information about the request.
+    set dn [req-dn $tmp]
+    set hash [req-key-hash $tmp]
+
+    ## Get an id number for the new request.
+    db eval {
+      UPDATE meta
+      SET request_seq = request_seq + 1;
+    }
+    set id [db eval {
+      SELECT request_seq FROM meta;
+    }]
+
+    ## Insert the new record into the request table.
+    db eval {
+      UPDATE request SET st = 'withdrawn' WHERE tag = $tag AND st = 'active';
+      INSERT INTO request(id, tag, dn, hash, st, profile)
+      VALUES ($id, $tag, $dn, @hash, 'active', $profile);
+    }
+
+    ## Link the file into the right place.
+    file link -hard "$CERTROOT/req/by-id/$id" $tmp
+    exec ln -sf "../by-id/$id" "$CERTROOT/req/active/$tag"
+  }
+
+  ## Issue a shiny new certificate.
+  issue-cert $id [now]
+}