summaryrefslogtreecommitdiffstats
path: root/urpm/signature.pm
blob: 080cccf16904e0a04123e440e0f6ec2722d80b9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package urpm::signature;


use strict;
use urpm::msg;
use urpm::media;
use urpm::util qw(any basename);


=head1 NAME

urpm::signature - Package signature routines for urpmi

=head1 SYNOPSIS

=head1 DESCRIPTION

=over

=item check($urpm, $sources_install, $sources, %options)

Checks a package signature, return a list of error messages

Options:

=over

=item * basename

whether to show full file paths or only file names in messages (used by rpmdrake)

=item * callback

A callback called on package verification (used by rpmdrake in order to update its progressbar)

=back

=cut

sub check {
    my ($urpm, $sources_install, $sources, %options) = @_;
    sort(_check($urpm, $sources_install, %options),
	 _check($urpm, $sources, %options));
}
sub _check {
    my ($urpm, $sources, %options) = @_;
    my ($medium, %invalid_sources);

    foreach my $id (keys %$sources) {
	my $filepath = $sources->{$id};
	$filepath !~ /\.spec$/ or next;

	$urpm->{debug} and $urpm->{debug}("verifying signature of $filepath");
	#- rpmlib is doing strftime %c, and so the string comes from the current encoding
	#- (URPM::bind_rpm_textdomain_codeset() doesn't help here)
	#- so we have to transform...
	my $verif = urpm::msg::from_locale_encoding(URPM::verify_signature($filepath, $urpm->{urpmi_root}));

	if ($verif =~ /NOT OK/) {
	    $verif =~ s/\n//g;
	    $invalid_sources{$filepath} = N("Invalid signature (%s)", $verif);
	} else {
	    unless ($medium && urpm::media::is_valid_medium($medium) &&
		    $medium->{start} <= $id && $id <= $medium->{end})
	    {
		$medium = undef;
		foreach (@{$urpm->{media}}) {
		    urpm::media::is_valid_medium($_) && $_->{start} <= $id && $id <= $_->{end}
			and $medium = $_, last;
		}
	    }
	    #- no medium found for this rpm ?
	    if (!$medium) {
		if ($verif =~ /OK \(\(none\)\)/) {
	            $verif =~ s/\n//g;
	            $urpm->{info}(N("SECURITY: The following package is _NOT_ signed (%s): %s", $verif, $filepath));
	        }
		next;
	    }
	    #- check whether verify-rpm is specifically disabled for this medium
	    if (defined $medium->{'verify-rpm'} && !$medium->{'verify-rpm'}) {
		$urpm->{info}(N("SECURITY: NOT checking package \"%s\" (due to configuration)", $filepath));
		next;
	    }

	    my $key_ids = $medium->{'key-ids'} || $urpm->{options}{'key-ids'};
	    #- check that the key ids of the medium match the key ids of the package.
	    if ($key_ids) {
		my $valid_ids = 0;
		my $invalid_ids = 0;

		foreach my $key_id ($verif =~ /(?:key id \w{8}|#)(\w+)/gi) {
		    if (any { hex($_) == hex($key_id) } split /[,\s]+/, $key_ids) {
			++$valid_ids;
		    } else {
			++$invalid_ids;
		    }
		}

		if ($invalid_ids) {
		    $invalid_sources{$filepath} = N("Invalid Key ID (%s)", $verif);
		} elsif (!$valid_ids) {
		    $invalid_sources{$filepath} = N("Missing signature (%s)", $verif);
		}
	    } elsif ($urpm::args::options{usedistrib} && $medium->{virtual}) {
		$urpm->{info}(N("SECURITY: Medium \"%s\" has no key (%s)!", $medium->{name}, $verif));
	    } else {
		$invalid_sources{$filepath} = N("Medium without key (%s)", $verif);
	    }
	    #- invoke check signature callback.
	    $options{callback} and $options{callback}->(
		$urpm, $filepath,
		id => $id,
		verif => $verif,
		why => $invalid_sources{$filepath},
	    );
	}
    }
    map { ($options{basename} ? basename($_) : $_) . ": $invalid_sources{$_}" }
      keys %invalid_sources;
}

1;

__END__

=back

=head1 COPYRIGHT

Copyright (C) 2005 MandrakeSoft SA

Copyright (C) 2005-2010 Mandriva SA

=cut