mirroring: add individual foreign vcs mirror control
[girocco.git] / cgi / usercert.cgi
blob01ec5469ec6257e718abce56677c542f903fec0a
1 #!/usr/bin/perl
3 # usercert.cgi -- user push authentication certificate retrieval
4 # Copyright (c) 2013 Kyle J. McKay. All rights reserved.
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 # Version 1.2
22 use strict;
23 use warnings;
25 use lib ".";
26 use Girocco::CGI;
27 use Girocco::Config;
28 use Girocco::User;
29 use Girocco::Util;
30 use Girocco::SSHUtil;
32 sub notfound
34 my $mesg = shift || "<p>404 - Not found</p>";
35 my $gcgi = Girocco::CGI->new('User HTTPS Push Authentication Certificate');
36 print $mesg;
37 exit;
40 sub mtime
42 my $fname = shift;
43 my (undef,undef,undef,undef,undef,undef,undef,undef,undef,$mtime) = stat $fname;
44 return $mtime;
47 sub readfile
49 my $fname = shift;
50 local $/;
51 open(FILE, '<', $fname) or return undef;
52 my $contents = <FILE>;
53 close(FILE);
54 return $contents;
57 notfound unless $Girocco::Config::clientcert && $Girocco::Config::clientkey;
58 notfound unless -f $Girocco::Config::clientcert && -f $Girocco::Config::clientkey;
59 notfound unless -r $Girocco::Config::clientcert && -r $Girocco::Config::clientkey;
61 my $cgi = CGI->new;
63 notfound if $cgi->request_method() ne 'GET' && $cgi->request_method() ne 'HEAD';
64 notfound "<p>Go away, bot.</p>" if $cgi->param('mail');
66 my $nick = $Girocco::Config::nickname;
68 my $name = $cgi->param('name');
69 $name =~ s/^\s*(.*?)\s*$/$1/ if $name;
70 my $line = $cgi->param('line');
71 $line =~ s/^\s*(.*?)\s*$/$1/ if $line;
72 my $view = $cgi->param('view');
73 $view =~ s/^\s*(.*?)\s*$/$1/ if $view;
75 notfound if $cgi->path_info() && ($name || $line);
77 if ($cgi->path_info() =~ m,/([^/]+)/([^/]+)/([^/]+)$,) {
78 my ($tn,$tl,$tp) = ($1,$2,$3);
79 if ("${nick}_${tn}_user_$tl.pem" eq $tp) {
80 $name = $tn;
81 $line = $tl;
85 notfound unless $name && $line && $line =~ /^[1-9][0-9]*$/;
86 $line += 0;
88 notfound unless Girocco::User::valid_name($name) && Girocco::User::does_exist($name);
89 my $user = Girocco::User->load($name) or notfound;
91 my @keys = split(/\r?\n/, $user->{keys});
92 $line <= @keys or notfound;
93 my ($type, $bits, $fingerprint, $comment) = sshpub_validate($keys[$line-1]);
94 $type && $type eq 'ssh-rsa' or notfound;
96 my $sshkeys = jailed_file($user->_sshkey_path);
97 my $kname = "${nick}_${name}_user_$line.pem";
98 my $sshcert = jailed_file("/etc/sshcerts/$kname");
99 my $sshkeysmtime = mtime($sshkeys);
100 notfound unless $sshkeysmtime;
101 my $sshcertmtime = mtime($sshcert);
102 if (!$sshcertmtime || $sshkeysmtime >= $sshcertmtime) {
103 unlink $sshcert;
104 my @args = (
105 "$Girocco::Config::basedir/bin/CACreateCert", "--quiet", "--client",
106 "--cert", $Girocco::Config::clientcert,
107 "--key", $Girocco::Config::clientkey,
108 "--out", $sshcert
110 push(@args, "--suffix", $Girocco::Config::clientcertsuffix)
111 if $Girocco::Config::clientcertsuffix;
112 push(@args, "--dnq", $user->{uuid}, $name);
113 open(PIPE, "|-", @args) or notfound;
114 print PIPE $keys[$line-1], "\n";
115 close(PIPE) or notfound;
116 chmod(0664, $sshcert);
118 notfound unless -r $sshcert;
119 my $certdata = readfile($sshcert);
120 notfound unless $certdata;
121 my $isviewonly = 0;
122 $isviewonly = 0 + $view if $view && $view =~ /^[01]$/;
123 if ($isviewonly) {
124 print "Content-Type: text/plain\r\n"
125 } else {
126 print "Content-Type: application/octet-stream\r\n";
127 print "Content-Disposition: attachment; filename=\"$kname\"\r\n";
129 print "\r\n";
130 print $certdata unless $cgi->request_method() eq 'HEAD';
132 exit 0;