chiark / gitweb /
bin/*: Use plain `/usr/bin/tclsh' in shebang lines.
[ca] / bin / add
1 #! /usr/bin/tclsh
2 ### -*-tcl-*-
3 ###
4 ### Insert a certificate request into the database.
5 ###
6 ### (c) 2011 Mark Wooding
7 ###
8
9 ###----- Licensing notice ---------------------------------------------------
10 ###
11 ### This program is free software; you can redistribute it and/or modify
12 ### it under the terms of the GNU General Public License as published by
13 ### the Free Software Foundation; either version 2 of the License, or
14 ### (at your option) any later version.
15 ###
16 ### This program is distributed in the hope that it will be useful,
17 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ### GNU General Public License for more details.
20 ###
21 ### You should have received a copy of the GNU General Public License
22 ### along with this program; if not, write to the Free Software Foundation,
23 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 ## Find the common utilities.
26 source [file join [file dirname $argv0] "../lib/func.tcl"]
27
28 ## Parse the command line.
29 set O(replace) false
30 set usage "usage: $argv0 \[-replace\] PROFILE TAG FILE"
31 for {set i 0} {$i < [llength $argv]} {incr i} {
32   switch -glob -- [lindex $argv $i] {
33     "-replace" {
34       set O(replace) true
35     }
36     "--" {
37       incr i
38       break
39     }
40     "-*" {
41       puts stderr $usage
42       exit 1
43     }
44     default {
45       break
46     }
47   }
48 }
49 set args [lrange $argv $i end]
50 if {[llength $args] != 3} {
51   puts stderr $usage
52   exit 1
53 }
54 lassign $args profile tag file
55
56 ## Open the database.
57 sqlite3 db "$CERTROOT/state/ca.db"
58
59 ## Do most of the work in a transaction.
60 db transaction {
61   with-cleanup {
62
63     ## Check whether this tag is already taken.
64     if {!$O(replace) && [db exists {
65       SELECT 1 FROM request
66       WHERE tag = $tag AND st = 'active';
67     }]} {
68       error "request `$tag' already active"
69     }
70
71     ## Check whether the profile exists.
72     if {![db exists {
73       SELECT 1 FROM profile WHERE label = $profile AND tombstone = 0;
74     }]} {
75       error "unknown profile `$profile'"
76     }
77
78     ## Copy the file away.
79     fresh-temp "$CERTROOT/tmp" tmp {
80       exec openssl req -text -in $file -out $tmp
81     }
82     cleanup { file delete $tmp }
83
84     ## Get lots of information about the request.
85     set dn [req-dn $tmp]
86     set hash [req-key-hash $tmp]
87
88     ## Get an id number for the new request.
89     db eval {
90       UPDATE meta
91       SET request_seq = request_seq + 1;
92     }
93     set id [db eval {
94       SELECT request_seq FROM meta;
95     }]
96
97     ## Insert the new record into the request table.
98     db eval {
99       UPDATE request SET st = 'withdrawn' WHERE tag = $tag AND st = 'active';
100       INSERT INTO request(id, tag, dn, hash, st, profile)
101       VALUES ($id, $tag, $dn, @hash, 'active', $profile);
102     }
103
104     ## Link the file into the right place.
105     file link -hard "$CERTROOT/req/by-id/$id" $tmp
106     exec ln -sf "../by-id/$id" "$CERTROOT/req/active/$tag"
107   }
108
109   ## Issue a shiny new certificate.
110   issue-cert $id [now]
111 }
112
113 ## Publish any necessary changes.
114 update-hook