5 # complete rewrite of the sshkeys-lint program. Usage has changed, see
6 # usage() function or run without arguments.
7 use lib
$ENV{GL_LIBDIR
};
14 GetOptions
( 'admin|a=s' => \
$admin, 'quiet|q' => \
$quiet, 'help|h' => \
$help );
17 $Data::Dumper
::Deepcopy
= 1;
20 my $in_gl_section = 0;
22 my $KEYTYPE_REGEX = qr/\b(?:ssh-(?:rsa|dss|ed25519)|ecdsa-sha2-nistp(?:256|384|521))\b/;
26 return if $quiet and not $warning;
27 $warnings++ if $warning;
28 print "sshkeys-lint: " . ( $warning ?
"WARNING: " : "" ) . $_ for @_;
33 our @pubkeyfiles = @ARGV; @ARGV = ();
34 my $kd = "$ENV{HOME}/.gitolite/keydir";
35 if ( not @pubkeyfiles ) {
36 chomp( @pubkeyfiles = `find $kd -type f -name "*.pub" | sort` );
40 @ARGV = ("$ENV{HOME}/.ssh/authorized_keys");
43 # ------------------------------------------------------------------------
48 msg
0, "==== checking authkeys file:\n";
49 fill_authkeys
(); # uses up STDIN
52 my $fp = fprint
("$admin.pub");
53 my $fpu = ( $fp && $seen_fprints{$fp}{user
} || 'no access' );
54 # dbg("fpu = $fpu, admin=$admin");
56 die "\t\t*** FATAL ***\n" .
57 "$admin.pub maps to $fpu, not $admin.\n" .
58 "You will not be able to access gitolite with this key.\n" .
59 "Look for the 'ssh troubleshooting' link in http://gitolite.com/gitolite/ssh.html.\n"
60 if $fpu ne "user $admin";
64 msg
0, "==== checking pubkeys:\n" if @pubkeyfiles;
65 for my $pkf (@pubkeyfiles) {
66 # get the short name for the pubkey file
67 ( my $pkfsn = $pkf ) =~ s
(^$kd/)();
69 my $fp = fprint
($pkf);
71 msg
1, "$pkfsn appears to be a COPY of $pkf_by_fp{$fp}\n" if $pkf_by_fp{$fp};
72 $pkf_by_fp{$fp} ||= $pkfsn;
73 my $fpu = ( $seen_fprints{$fp}{user
} || 'no access' );
74 msg
0, "$pkfsn maps to $fpu\n";
78 print "\n$warnings warnings found\n";
83 # ------------------------------------------------------------------------
87 next if ak_comment
($_); # also sets/clears $in_gl_section global
91 check
( $seq, $fp, $user );
93 $authkeys[$seq]{fprint
} = $fp;
94 $authkeys[$seq]{ustatus
} = $user;
99 my ( $seq, $fp, $user ) = @_;
101 msg
1, "line $seq, $user key found *outside* gitolite section!\n"
102 if $user =~ /^user / and not $in_gl_section;
104 msg
1, "line $seq, $user key found *inside* gitolite section!\n"
105 if $user !~ /^user / and $in_gl_section;
107 if ( $seen_fprints{$fp} ) {
109 msg
1, "authkeys line $seq ($user) will be ignored by sshd; " .
110 "same key found on line " .
111 $seen_fprints{$fp}{seq
} . " (" .
112 $seen_fprints{$fp}{user
} . ")\n";
117 $seen_fprints{$fp}{seq
} = $seq;
118 $seen_fprints{$fp}{user
} = $user;
123 $user ||= "user $1" if /^command=.*gitolite-shell (.*?)"/;
124 $user ||= "unknown command" if /^command/;
125 $user ||= "shell access" if /$KEYTYPE_REGEX/;
132 $in_gl_section = 1 if /^# gitolite start/;
133 $in_gl_section = 0 if /^# gitolite end/;
134 die "gitosis? what's that?\n" if /^#.*gitosis/;
141 if ( /$KEYTYPE_REGEX/ ) {
142 # an actual key was passed. ssh-keygen CAN correctly handle options on
143 # the front of the key, so don't bother to strip them at all.
144 ($fp, $output) = ssh_fingerprint_line
($_);
146 # a filename was passed
147 ($fp, $output) = ssh_fingerprint_file
($_);
148 # include the line of input as well, as it won't always be included by the ssh-keygen command
149 warn "Bad line: $_\n" unless $fp;
151 # sshkeys-lint should only be run by a trusted admin, so we can give the output here.
152 warn "$output\n" unless $fp;
156 # ------------------------------------------------------------------------
159 Usage: gitolite sshkeys-lint [-q] [optional list of pubkey filenames]
160 (optionally, STDIN can be a pipe or redirected from a file; see below)
162 Look for potential problems in ssh keys.
164 sshkeys-lint expects:
165 - the contents of an authorized_keys file via STDIN, otherwise it uses
166 \$HOME/.ssh/authorized_keys
167 - one or more pubkey filenames as arguments, otherwise it uses all the keys
168 found (recursively) in \$HOME/.gitolite/keydir
170 The '-q' option will print only warnings instead of all mappings.
172 Note that this runs ssh-keygen -l for each line in the authkeys file and each
173 pubkey in the argument list, so be wary of running it on something huge. This
174 is meant for troubleshooting.