From ee68fb97c24bb1de7276feb3062ef0a856ed4298 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sun, 18 May 2008 14:23:30 +0200 Subject: [PATCH] Add a parser for authorized_keys lines This permits more exact error messages, and we can extract the key type later. --- dowkd.in | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/dowkd.in b/dowkd.in index 2e21961..27040bf 100644 --- a/dowkd.in +++ b/dowkd.in @@ -171,6 +171,59 @@ sub clear_tmp ($) { truncate $tmp, 0 or die "truncate: $!"; } +sub cleanup_ssh_auth_line ($) { + my $line = shift; + + $line =~ /^(?:ssh-(?:rsa|dss)\s|\d+\s+\d+\s+\d)/ and return $line; + + OUTSIDE_STRING: + if ($line =~ /^\s+(.*)/) { + $line = $1; + goto SPACE_SEEN; + } + if ($line =~ /^"(.*)/) { + $line = $1; + goto INSIDE_STRING; + } + if ($line =~ /^\\.(.*)/) { + # It doesn't matter if we don't deal with \000 properly, we + # just need to defuse the backslash character. + $line = $1; + goto OUTSIDE_STRING; + } + if ($line =~ /^[a-zA-Z0-9_=+-]+(.*)/) { + # Skip multiple harmless characters in one go. + $line = $1; + goto OUTSIDE_STRING; + } + if ($line =~ /^.(.*)/) { + # Other characters are stripped one by one. + $line = $1; + goto OUTSIDE_STRING; + } + return undef; # empty string, no key found + + INSIDE_STRING: + if ($line =~ /^"(.*)/) { + $line = $1; + goto OUTSIDE_STRING; + } + if ($line =~ /^\\.(.*)/) { + # See above, defuse the backslash. + $line = $1; + goto INSIDE_STRING; + } + if ($line =~ /^[^\\"]+(.*)/) { + $line = $1; + goto INSIDE_STRING; + } + return undef; # missing closing double quote + + SPACE_SEEN: + $line =~ /^(?:ssh-(?:rsa|dss)\s|\d+\s+\d+\s+\d)/ and return $line; + return undef; +} + sub from_ssh_auth_file ($) { my $name = shift; my $auth; @@ -183,15 +236,24 @@ sub from_ssh_auth_file ($) { chomp $line; next if $line =~ m/^\s*(#|$)/; my $lineno = $.; + + { + my $l = cleanup_ssh_auth_line $line; + $l or goto ERROR; + $line = $l; + } + clear_tmp $tmp; print $tmp "$line\n" or die "print: $!"; $tmp->flush; my ($length, $hash) = ssh_fprint_file "$tmp"; if ($length && $hash) { ssh_fprint_check "$name:$lineno", $length, $hash; - } else { - warn "$name:$lineno: warning: unparsable line\n"; + next; } + + ERROR: + warn "$name:$lineno: warning: unparsable line\n"; } } -- 2.11.4.GIT