7 use POSIX
qw(strftime);
9 my $logfile = "/var/log/pveam.log";
10 my $aplinfodir = "/var/lib/pve-manager/apl-info";
12 # Default list of GPG keys allowed to sign aplinfo
14 #pub 1024D/5CAC72FE 2004-06-24
15 # Key fingerprint = 9ABD 7E02 AD24 3AD3 C2FB BCCC B0C1 CC22 5CAC 72FE
16 #uid Proxmox Support Team <support@proxmox.com>
17 #pub 2048R/A16EB94D 2008-08-15 [expires: 2023-08-12]
18 # Key fingerprint = 694C FF26 795A 29BA E07B 4EB5 85C2 5E95 A16E B94D
19 #uid Turnkey Linux Release Key <release@turnkeylinux.com>
22 '9ABD7E02AD243AD3C2FBBCCCB0C1CC225CAC72FE' => 1, # fingerprint support@proxmox.com
23 '25CAC72FE' => 1, # keyid support@proxmox.com
24 '694CFF26795A29BAE07B4EB585C25E95A16EB94D' => 1, # fingerprint release@turnkeylinux.com
25 'A16EB94D' => 1, # keyid release@turnkeylinux.com
30 my @keyfiles = ('support@proxmox.com.pubkey', 'release@turnkeylinux.com.pubkey');
32 foreach my $key (@keyfiles) {
33 my $fn = "/usr/share/doc/pve-manager/$key";
34 system ("/usr/bin/gpg --batch --no-tty --status-fd=1 -q " .
35 "--logger-fd=1 --import $fn >>$logfile");
40 my ($logfd, $msg) = @_;
44 my $tstr = strftime
("%b %d %H:%M:%S", localtime);
46 foreach my $line (split (/\n/, $msg)) {
47 print $logfd "$tstr $line\n";
51 sub read_aplinfo_from_fh
{
52 my ($fh, $list, $source, $update) = @_;
56 while (my $rec = <$fh>) {
63 if ($rec =~ s/^Description:\s*([^\n]*)(\n\s+.*)*$//si) {
64 $res->{headline
} = $1;
69 $res->{description
} = $long;
70 } elsif ($rec =~ s/^Version:\s*(.*\S)\s*\n//i) {
72 if ($version =~ m/^(\d[a-zA-Z0-9\.\+\-\:\~]*)(-(\d+))?$/) {
73 $res->{version
} = $version;
75 my $msg = "unable to parse appliance record: version = '$version'\n";
76 $update ?
die $msg : warn $msg;
78 } elsif ($rec =~ s/^Type:\s*(.*\S)\s*\n//i) {
80 if ($type =~ m/^(openvz|lxc)$/) {
83 my $msg = "unable to parse appliance record: unknown type '$type'\n";
84 $update ?
die $msg : warn $msg;
86 } elsif ($rec =~ s/^([^:]+):\s*(.*\S)\s*\n//) {
89 my $msg = "unable to parse appliance record: $rec\n";
90 $update ?
die $msg : warn $msg;
96 if ($res->{'package'} eq 'pve-web-news' && $res->{description
}) {
97 $list->{'all'}->{$res->{'package'}} = $res;
101 $res->{section
} = 'unknown' if !$res->{section
};
103 if ($res->{'package'} && $res->{type
} && $res->{os
} && $res->{version
} &&
106 if ($res->{location
}) {
107 $template = $res->{location
};
108 $template =~ s
|.*/([^/]+.tar
.[gx
]z
)$|$1|;
109 if ($res->{location
} !~ m
|^([a-zA-Z
]+)\
://|) {
110 # relative localtion (no http:// prefix)
111 $res->{location
} = "$source/$res->{location}";
114 my $arch = $res->{architecture
} || 'i386';
115 $template = "$res->{os}-$res->{package}_$res->{version}_$arch.tar.gz";
116 $template =~ s/$res->{os}-$res->{os}-/$res->{os}-/;
117 $res->{location
} = "$source/$res->{section}/$template";
119 $res->{source
} = $source;
120 $res->{template
} = $template;
121 $list->{$res->{section
}}->{$template} = $res;
122 $list->{'all'}->{$template} = $res;
124 my $msg = "found incomplete appliance records\n";
125 $update ?
die $msg : warn $msg;
131 my ($filename, $list, $source, $update) = @_;
133 my $fh = IO
::File-
>new("<$filename") ||
134 die "unable to open file '$filename' - $!\n";
136 eval { read_aplinfo_from_fh
($fh, $list, $source, $update); };
147 my ($ua, $url, $file, $logfh) = @_;
149 my $req = HTTP
::Request-
>new(GET
=> $url);
151 logmsg
($logfh, "start download $url");
152 my $res = $ua->request($req, $file);
154 if ($res->is_success) {
155 logmsg
($logfh, "download finished: " . $res->status_line);
159 logmsg
($logfh, "download failed: " . $res->status_line);
164 sub download_aplinfo
{
165 my ($ua, $aplurl, $host, $logfd) = @_;
167 my $aplsrcurl = "$aplurl/aplinfo.dat.gz";
168 my $aplsigurl = "$aplurl/aplinfo.dat.asc";
170 my $tmp = "$aplinfodir/pveam-${host}.tmp.$$";
171 my $tmpgz = "$tmp.gz";
172 my $sigfn = "$tmp.asc";
176 if (url_get
($ua, $aplsigurl, $sigfn, $logfd) != 0) {
177 die "update failed - no signature file '$sigfn'\n";
180 if (url_get
($ua, $aplsrcurl, $tmpgz, $logfd) != 0) {
181 die "update failed - no data file '$aplsrcurl'\n";
184 if (system("zcat -f $tmpgz >$tmp 2>/dev/null") != 0) {
185 die "update failed: unable to unpack '$tmpgz'\n";
190 my $cmd = "/usr/bin/gpg --verify --trust-model always --batch --no-tty --status-fd=1 -q " .
191 "--logger-fd=1 $sigfn $tmp";
193 open(CMD
, "$cmd|") ||
194 die "unable to execute '$cmd': $!\n";
198 while (defined($line = <CMD
>)) {
200 logmsg
($logfd, $line);
202 # code borrowed from SA
203 next if $line !~ /^\Q[GNUPG:]\E (?:VALID|GOOD)SIG (\S{8,40})/;
206 # we want either a keyid (8) or a fingerprint (40)
207 if (length $key > 8 && length $key < 40) {
208 substr($key, 8) = '';
210 # use the longest match we can find
211 $signer = $key if (length $key > length $signer) && $valid_keys->{$key};
216 die "unable to verify signature\n" if !$signer;
218 logmsg
($logfd, "signature valid: $signer");
222 my $fh = IO
::File-
>new("<$tmp") ||
223 die "unable to open file '$tmp' - $!\n";
224 read_aplinfo
($tmp, {}, $aplurl, 1);
227 die "update failed: $@" if $@;
229 if (system("mv $tmp $aplinfodir/$host 2>/dev/null") != 0) {
230 die "update failed: unable to store data\n";
233 logmsg
($logfd, "update sucessful");
245 sub get_apl_sources
{
248 push @$urls, "http://download.proxmox.com/images";
249 push @$urls, "http://releases.turnkeylinux.org/pve";
258 if (($size = (-s
$logfile) || 0) > (1024*50)) {
259 system ("mv $logfile $logfile.0");
261 my $logfd = IO
::File-
>new (">>$logfile");
262 logmsg
($logfd, "starting update");
266 # ensure that always use the same socket class
267 local $ENV{PERL_NET_HTTPS_SSL_SOCKET_CLASS
} = "IO::Socket::SSL";
269 # this code works for ftp and http
270 # always use passive ftp
271 local $ENV{FTP_PASSIVE
} = 1;
272 my $ua = LWP
::UserAgent-
>new;
273 $ua->agent("PVE/1.0");
276 $ua->proxy(['http', 'https'], $proxy);
281 my $urls = get_apl_sources
();
286 foreach my $aplurl (@$urls) {
288 my $uri = URI-
>new($aplurl);
289 my $host = $uri->host();
290 download_aplinfo
($ua, $aplurl, $host, $logfd);
293 logmsg
($logfd, $err);
294 push @dlerr, $aplurl;
300 return 0 if scalar(@dlerr);
307 my $urls = get_apl_sources
();
311 foreach my $aplurl (@$urls) {
315 my $uri = URI-
>new($aplurl);
316 my $host = $uri->host();
317 read_aplinfo
("$aplinfodir/$host", $list, $aplurl);