Package entropy :: Module security

Source Code for Module entropy.security

  1  # -*- coding: utf-8 -*- 
  2  """ 
  3   
  4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
  5      @contact: lxnay@sabayonlinux.org 
  6      @copyright: Fabio Erculiani 
  7      @license: GPL-2 
  8   
  9      B{Entropy Framework Security module}. 
 10   
 11      This module contains Entropy GLSA-based Security interfaces. 
 12       
 13   
 14  """ 
 15  import os 
 16  import shutil 
 17  from entropy.exceptions import IncorrectParameter, InvalidData 
 18  from entropy.const import etpConst, etpCache, etpUi, const_setup_perms 
 19  from entropy.i18n import _ 
 20  from entropy.output import blue, bold, red, darkgreen, darkred 
 21   
22 -class SecurityInterface:
23 24 """ 25 ~~ GIVES YOU WINGS ~~ 26 """ 27 28 """ 29 @note: thanks to Gentoo "gentoolkit" package, License below: 30 @note: This program is licensed under the GPL, version 2 31 32 @note: WARNING: this code is not intended to replace any Security mechanism, 33 @note: but it's just a way to handle Gentoo GLSAs. 34 @note: There are possible security holes and probably bugs in this code. 35 36 This class implements the Entropy packages Security framework. 37 It can be used to retrieve security advisories, get information 38 about unapplied advisories, etc. 39 40 """ 41 42 import entropy.tools as entropyTools
43 - def __init__(self, entropy_client_instance):
44 45 """ 46 SecurityInterface constructor. 47 48 @param entropy_client_instance: a valid entropy.client.interfaces.Client 49 instance 50 @type entropy_client_instance: entropy.client.interfaces.Client instance 51 """ 52 53 # disabled for now 54 from entropy.client.interfaces import Client 55 if not isinstance(entropy_client_instance, Client): 56 mytxt = _("A valid Client interface instance is needed") 57 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 58 59 self.Entropy = entropy_client_instance 60 from entropy.cache import EntropyCacher 61 self.__cacher = EntropyCacher() 62 from entropy.core.settings.base import SystemSettings 63 self.SystemSettings = SystemSettings() 64 self.lastfetch = None 65 self.previous_checksum = "0" 66 self.advisories_changed = None 67 self.adv_metadata = None 68 self.affected_atoms = set() 69 70 from xml.dom import minidom 71 self.minidom = minidom 72 73 self.op_mappings = { 74 "le": "<=", 75 "lt": "<", 76 "eq": "=", 77 "gt": ">", 78 "ge": ">=", 79 "rge": ">=", # >=~ 80 "rle": "<=", # <=~ 81 "rgt": ">", # >~ 82 "rlt": "<" # <~ 83 } 84 85 security_url = \ 86 self.SystemSettings['repositories']['security_advisories_url'] 87 security_file = os.path.basename(security_url) 88 md5_ext = etpConst['packagesmd5fileext'] 89 90 self.unpackdir = os.path.join(etpConst['entropyunpackdir'], 91 "security-%s" % (self.entropyTools.get_random_number(),)) 92 self.security_url = security_url 93 self.unpacked_package = os.path.join(self.unpackdir, "glsa_package") 94 self.security_url_checksum = security_url + md5_ext 95 96 self.download_package = os.path.join(self.unpackdir, security_file) 97 self.download_package_checksum = self.download_package + md5_ext 98 self.old_download_package_checksum = os.path.join( 99 etpConst['dumpstoragedir'], os.path.basename(security_url) 100 ) + md5_ext 101 102 self.security_package = os.path.join(etpConst['securitydir'], 103 os.path.basename(security_url)) 104 self.security_package_checksum = self.security_package + md5_ext 105 106 try: 107 108 if os.path.isfile(etpConst['securitydir']) or \ 109 os.path.islink(etpConst['securitydir']): 110 os.remove(etpConst['securitydir']) 111 112 if not os.path.isdir(etpConst['securitydir']): 113 os.makedirs(etpConst['securitydir'], 0775) 114 115 except OSError: 116 pass 117 const_setup_perms(etpConst['securitydir'], etpConst['entropygid']) 118 119 if os.access(self.old_download_package_checksum, os.F_OK | os.R_OK): 120 f_down = open(self.old_download_package_checksum) 121 try: 122 self.previous_checksum = f_down.readline().strip().split()[0] 123 except (IndexError, OSError, IOError,): 124 pass 125 f_down.close()
126
127 - def __prepare_unpack(self):
128 """ 129 Prepare GLSAs unpack directory and its permissions. 130 """ 131 if os.path.isfile(self.unpackdir) or os.path.islink(self.unpackdir): 132 os.remove(self.unpackdir) 133 134 if os.path.isdir(self.unpackdir): 135 shutil.rmtree(self.unpackdir, True) 136 try: 137 os.rmdir(self.unpackdir) 138 except OSError: 139 pass 140 141 os.makedirs(self.unpackdir, 0775) 142 const_setup_perms(self.unpackdir, etpConst['entropygid'])
143
144 - def __download_glsa_package(self):
145 """ 146 Download GLSA compressed package from a trusted source. 147 """ 148 return self.__generic_download(self.security_url, self.download_package)
149
151 """ 152 Download GLSA compressed package checksum (md5) from a trusted source. 153 """ 154 return self.__generic_download(self.security_url_checksum, 155 self.download_package_checksum, show_speed = False)
156
157 - def __generic_download(self, url, save_to, show_speed = True):
158 """ 159 Generic, secure, URL download method. 160 161 @param url: download URL 162 @type url: string 163 @param save_to: path to save file 164 @type save_to: string 165 @keyword show_speed: if True, download speed will be shown 166 @type show_speed: bool 167 @return: download status (True if download succeeded) 168 @rtype: bool 169 """ 170 fetcher = self.Entropy.urlFetcher(url, save_to, resume = False, 171 show_speed = show_speed) 172 fetcher.progress = self.Entropy.progress 173 rc_fetch = fetcher.download() 174 del fetcher 175 if rc_fetch in ("-1", "-2", "-3", "-4"): 176 return False 177 # setup permissions 178 self.Entropy.setup_default_file_perms(save_to) 179 return True
180
181 - def __verify_checksum(self):
182 """ 183 Verify downloaded GLSA checksum against downloaded GLSA package. 184 """ 185 # read checksum 186 if not os.path.isfile(self.download_package_checksum) or \ 187 not os.access(self.download_package_checksum, os.R_OK): 188 return 1 189 190 f_down = open(self.download_package_checksum) 191 read_err = False 192 try: 193 checksum = f_down.readline().strip().split()[0] 194 except (OSError, IOError, IndexError,): 195 read_err = True 196 197 f_down.close() 198 if read_err: 199 return 2 200 201 self.advisories_changed = True 202 if checksum == self.previous_checksum: 203 self.advisories_changed = False 204 205 md5res = self.entropyTools.compare_md5(self.download_package, checksum) 206 if not md5res: 207 return 3 208 return 0
209
210 - def __unpack_advisories(self):
211 """ 212 Unpack downloaded GLSA package containing GLSA advisories. 213 """ 214 rc_unpack = self.entropyTools.uncompress_tar_bz2( 215 self.download_package, 216 self.unpacked_package, 217 catchEmpty = True 218 ) 219 const_setup_perms(self.unpacked_package, etpConst['entropygid']) 220 return rc_unpack
221
223 """ 224 Remove previously installed GLSA advisories. 225 """ 226 if os.listdir(etpConst['securitydir']): 227 shutil.rmtree(etpConst['securitydir'], True) 228 if not os.path.isdir(etpConst['securitydir']): 229 os.makedirs(etpConst['securitydir'], 0775) 230 const_setup_perms(self.unpackdir, etpConst['entropygid'])
231
233 """ 234 Place unpacked advisories in place (into etpConst['securitydir']). 235 """ 236 for advfile in os.listdir(self.unpacked_package): 237 from_file = os.path.join(self.unpacked_package, advfile) 238 to_file = os.path.join(etpConst['securitydir'], advfile) 239 try: 240 os.rename(from_file, to_file) 241 except OSError: 242 shutil.move(from_file, to_file)
243
244 - def __cleanup_garbage(self):
245 """ 246 Remove GLSA unpack directory. 247 """ 248 shutil.rmtree(self.unpackdir, True)
249
250 - def clear(self, xcache = False):
251 """ 252 Clear SecurityInterface cache (RAM and on-disk). 253 254 @keyword xcache: also remove Entropy on-disk cache if True 255 @type xcache: bool 256 """ 257 self.adv_metadata = None 258 if xcache: 259 self.Entropy.clear_dump_cache(etpCache['advisories'])
260
261 - def get_advisories_cache(self):
262 """ 263 Return cached advisories information metadata. It first tries to load 264 them from RAM and, in case of failure, it tries to gather the info 265 from disk, using EntropyCacher. 266 """ 267 if self.adv_metadata != None: 268 return self.adv_metadata 269 270 if self.Entropy.xcache: 271 dir_checksum = self.entropyTools.md5sum_directory( 272 etpConst['securitydir']) 273 c_hash = "%s%s" % ( 274 etpCache['advisories'], hash("%s|%s|%s" % ( 275 hash(self.SystemSettings['repositories']['branch']), 276 hash(dir_checksum), 277 hash(etpConst['systemroot']), 278 )), 279 ) 280 adv_metadata = self.__cacher.pop(c_hash) 281 if adv_metadata != None: 282 self.adv_metadata = adv_metadata.copy() 283 return self.adv_metadata
284
285 - def set_advisories_cache(self, adv_metadata):
286 """ 287 Set advisories information metadata cache. 288 289 @param adv_metadata: advisories metadata to store 290 @type adv_metadata: dict 291 """ 292 if self.Entropy.xcache: 293 dir_checksum = self.entropyTools.md5sum_directory( 294 etpConst['securitydir']) 295 c_hash = "%s%s" % ( 296 etpCache['advisories'], hash("%s|%s|%s" % ( 297 hash(self.SystemSettings['repositories']['branch']), 298 hash(dir_checksum), 299 hash(etpConst['systemroot']), 300 )), 301 ) 302 self.__cacher.push(c_hash, adv_metadata)
303
304 - def _get_advisories_list(self):
305 """ 306 Return a list of advisory files. Internal method. 307 """ 308 if not self.check_advisories_availability(): 309 return [] 310 xmls = os.listdir(etpConst['securitydir']) 311 xmls = sorted([x for x in xmls if x.endswith(".xml") and \ 312 x.startswith("glsa-")]) 313 return xmls
314
315 - def get_advisories_metadata(self):
316 """ 317 Get security advisories metadata. 318 319 @return: advisories metadata 320 @rtype: dict 321 """ 322 cached = self.get_advisories_cache() 323 if cached != None: 324 return cached 325 326 adv_metadata = {} 327 xmls = self._get_advisories_list() 328 maxlen = len(xmls) 329 count = 0 330 for xml in xmls: 331 332 count += 1 333 if not etpUi['quiet']: 334 self.Entropy.updateProgress(":: " + \ 335 str(round((float(count)/maxlen)*100,1)) + "% ::", 336 importance = 0, type = "info", back = True) 337 338 xml_metadata = None 339 exc_string = "" 340 exc_err = "" 341 try: 342 xml_metadata = self.__get_xml_metadata(xml) 343 except KeyboardInterrupt: 344 return {} 345 except Exception, err: 346 exc_string = unicode(Exception) 347 exc_err = unicode(err) 348 if xml_metadata == None: 349 more_info = "" 350 if exc_string: 351 mytxt = _("Error") 352 more_info = " %s: %s: %s" % (mytxt, exc_string, exc_err,) 353 mytxt = "%s: %s: %s! %s" % ( 354 blue(_("Warning")), 355 bold(xml), 356 blue(_("advisory broken")), 357 more_info, 358 ) 359 self.Entropy.updateProgress( 360 mytxt, 361 importance = 1, 362 type = "warning", 363 header = red(" !!! ") 364 ) 365 continue 366 elif not xml_metadata: 367 continue 368 adv_metadata.update(xml_metadata) 369 370 adv_metadata = self.filter_advisories(adv_metadata) 371 self.set_advisories_cache(adv_metadata) 372 self.adv_metadata = adv_metadata.copy() 373 return adv_metadata
374
375 - def filter_advisories(self, adv_metadata):
376 """ 377 This function filters advisories metadata dict removing non-applicable 378 ones. 379 380 @param adv_metadata: security advisories metadata dict 381 @type adv_metadata: dict 382 @return: filtered security advisories metadata 383 @rtype: dict 384 """ 385 keys = adv_metadata.keys() 386 for key in keys: 387 valid = True 388 if adv_metadata[key]['affected']: 389 affected = adv_metadata[key]['affected'] 390 affected_keys = affected.keys() 391 valid = False 392 skipping_keys = set() 393 for a_key in affected_keys: 394 match = self.Entropy.atom_match(a_key) 395 if match[0] != -1: 396 # it's in the repos, it's valid 397 valid = True 398 else: 399 skipping_keys.add(a_key) 400 if not valid: 401 del adv_metadata[key] 402 for a_key in skipping_keys: 403 try: 404 del adv_metadata[key]['affected'][a_key] 405 except KeyError: 406 continue 407 try: 408 if not adv_metadata[key]['affected']: 409 del adv_metadata[key] 410 except KeyError: 411 continue 412 413 return adv_metadata
414
415 - def is_affected(self, adv_key, adv_data = None):
416 """ 417 Determine whether the system is affected by vulnerabilities listed 418 in the provided security advisory identifier. 419 420 @param adv_key: security advisories identifier 421 @type adv_key: string 422 @keyword adv_data: use the provided security advisories instead of 423 the stored one. 424 @type adv_data: dict 425 @return: True, if system is affected by vulnerabilities listed in the 426 provided security advisory. 427 @rtype: bool 428 """ 429 if not adv_data: 430 adv_data = self.get_advisories_metadata() 431 if adv_key not in adv_data: 432 return False 433 mydata = adv_data[adv_key].copy() 434 del adv_data 435 436 if not mydata['affected']: 437 return False 438 439 for key in mydata['affected']: 440 441 vul_atoms = mydata['affected'][key][0]['vul_atoms'] 442 unaff_atoms = mydata['affected'][key][0]['unaff_atoms'] 443 unaffected_atoms = set() 444 if not vul_atoms: 445 return False 446 for atom in unaff_atoms: 447 matches = self.Entropy.clientDbconn.atomMatch(atom, 448 multiMatch = True) 449 for idpackage in matches[0]: 450 unaffected_atoms.add((idpackage, 0)) 451 452 for atom in vul_atoms: 453 match = self.Entropy.clientDbconn.atomMatch(atom) 454 if (match[0] != -1) and (match not in unaffected_atoms): 455 self.affected_atoms.add(atom) 456 return True 457 return False
458
459 - def get_vulnerabilities(self):
460 """ 461 Return advisories metadata for installed packages containing 462 vulnerabilities. 463 464 @return: advisories metadata for vulnerable packages. 465 @rtype: dict 466 """ 467 return self.__get_affection()
468
470 """ 471 Return advisories metadata for installed packages not affected 472 by any vulnerability. 473 474 @return: advisories metadata for NON-vulnerable packages. 475 @rtype: dict 476 """ 477 return self.__get_affection(affected = False)
478
479 - def __get_affection(self, affected = True):
480 """ 481 If not affected: not affected packages will be returned. 482 If affected: affected packages will be returned. 483 """ 484 adv_data = self.get_advisories_metadata() 485 adv_data_keys = adv_data.keys() 486 valid_keys = set() 487 for adv in adv_data_keys: 488 is_affected = self.is_affected(adv, adv_data) 489 if affected == is_affected: 490 valid_keys.add(adv) 491 # we need to filter our adv_data and return 492 for key in adv_data_keys: 493 if key not in valid_keys: 494 try: 495 del adv_data[key] 496 except KeyError: 497 pass 498 # now we need to filter packages in adv_dat 499 for adv in adv_data: 500 for key in adv_data[adv]['affected'].keys(): 501 atoms = adv_data[adv]['affected'][key][0]['vul_atoms'] 502 applicable = True 503 for atom in atoms: 504 if atom in self.affected_atoms: 505 applicable = False 506 break 507 if applicable == affected: 508 del adv_data[adv]['affected'][key] 509 return adv_data
510
511 - def get_affected_atoms(self):
512 """ 513 Return a list of package atoms affected by vulnerabilities. 514 515 @return: list (set) of package atoms affected by vulnerabilities 516 @rtype: set 517 """ 518 adv_data = self.get_advisories_metadata() 519 adv_data_keys = adv_data.keys() 520 del adv_data 521 self.affected_atoms.clear() 522 for key in adv_data_keys: 523 self.is_affected(key) 524 return self.affected_atoms
525
526 - def __get_xml_metadata(self, xmlfilename):
527 """ 528 Parses a Gentoo GLSA XML file extracting advisory metadata. 529 530 @param xmlfilename: GLSA filename 531 @type xmlfilename: string 532 @return: advisory metadata extracted 533 @rtype: dict 534 """ 535 xml_data = {} 536 xmlfile = os.path.join(etpConst['securitydir'], xmlfilename) 537 try: 538 xmldoc = self.minidom.parse(xmlfile) 539 except (IOError, OSError, TypeError, AttributeError,): 540 return None 541 542 # get base data 543 glsa_tree = xmldoc.getElementsByTagName("glsa")[0] 544 glsa_product = glsa_tree.getElementsByTagName("product")[0] 545 if glsa_product.getAttribute("type") != "ebuild": 546 return {} 547 548 glsa_id = glsa_tree.getAttribute("id") 549 glsa_title = glsa_tree.getElementsByTagName("title")[0] 550 glsa_title = glsa_title.firstChild.data 551 glsa_synopsis = glsa_tree.getElementsByTagName("synopsis")[0] 552 glsa_synopsis = glsa_synopsis.firstChild.data 553 glsa_announced = glsa_tree.getElementsByTagName("announced")[0] 554 glsa_announced = glsa_announced.firstChild.data 555 glsa_revised = glsa_tree.getElementsByTagName("revised")[0] 556 glsa_revised = glsa_revised.firstChild.data 557 558 xml_data['filename'] = xmlfilename 559 xml_data['url'] = "http://www.gentoo.org/security/en/glsa/%s" % ( 560 xmlfilename,) 561 xml_data['title'] = glsa_title.strip() 562 xml_data['synopsis'] = glsa_synopsis.strip() 563 xml_data['announced'] = glsa_announced.strip() 564 xml_data['revised'] = glsa_revised.strip() 565 xml_data['bugs'] = ["https://bugs.gentoo.org/" + \ 566 x.firstChild.data.strip() for x in \ 567 glsa_tree.getElementsByTagName("bug")] 568 569 try: 570 glsa_access = glsa_tree.getElementsByTagName("access")[0] 571 xml_data['access'] = glsa_access.firstChild.data.strip() 572 except IndexError: 573 xml_data['access'] = "" 574 575 # references 576 references = glsa_tree.getElementsByTagName("references")[0] 577 xml_data['references'] = [x.getAttribute("link").strip() for x in \ 578 references.getElementsByTagName("uri")] 579 580 try: 581 xml_data['description_items'] = [] 582 desc = glsa_tree.getElementsByTagName("description")[0] 583 desc = desc.getElementsByTagName("p")[0].firstChild.data.strip() 584 xml_data['description'] = desc 585 items = glsa_tree.getElementsByTagName("description")[0] 586 for item in items.getElementsByTagName("ul"): 587 li_items = item.getElementsByTagName("li") 588 for li_item in li_items: 589 xml_data['description_items'].append(' '.join( 590 [x.strip() for x in \ 591 li_item.firstChild.data.strip().split("\n")]) 592 ) 593 except IndexError: 594 xml_data['description'] = "" 595 xml_data['description_items'] = [] 596 597 try: 598 workaround = glsa_tree.getElementsByTagName("workaround")[0] 599 workaround_p = workaround.getElementsByTagName("p")[0] 600 xml_data['workaround'] = workaround_p.firstChild.data.strip() 601 except IndexError: 602 xml_data['workaround'] = "" 603 604 try: 605 xml_data['resolution'] = [] 606 resolution = glsa_tree.getElementsByTagName("resolution")[0] 607 p_elements = resolution.getElementsByTagName("p") 608 for p_elem in p_elements: 609 xml_data['resolution'].append(p_elem.firstChild.data.strip()) 610 except IndexError: 611 xml_data['resolution'] = [] 612 613 try: 614 impact = glsa_tree.getElementsByTagName("impact")[0] 615 impact_p = impact.getElementsByTagName("p")[0] 616 xml_data['impact'] = impact_p.firstChild.data.strip() 617 except IndexError: 618 xml_data['impact'] = "" 619 impact_type = glsa_tree.getElementsByTagName("impact")[0] 620 xml_data['impacttype'] = impact_type.getAttribute("type").strip() 621 622 try: 623 background = glsa_tree.getElementsByTagName("background")[0] 624 background_p = background.getElementsByTagName("p")[0] 625 xml_data['background'] = background_p.firstChild.data.strip() 626 except IndexError: 627 xml_data['background'] = "" 628 629 # affection information 630 affected = glsa_tree.getElementsByTagName("affected")[0] 631 affected_packages = {} 632 # we will then filter affected_packages using repositories information 633 # if not affected_packages: advisory will be dropped 634 for pkg in affected.getElementsByTagName("package"): 635 name = pkg.getAttribute("name") 636 if not affected_packages.has_key(name): 637 affected_packages[name] = [] 638 639 pdata = {} 640 pdata["arch"] = pkg.getAttribute("arch").strip() 641 pdata["auto"] = (pkg.getAttribute("auto") == "yes") 642 pdata["vul_vers"] = [self.__make_version(v) for v in \ 643 pkg.getElementsByTagName("vulnerable")] 644 pdata["unaff_vers"] = [self.__make_version(v) for v in \ 645 pkg.getElementsByTagName("unaffected")] 646 pdata["vul_atoms"] = [self.__make_atom(name, v) for v \ 647 in pkg.getElementsByTagName("vulnerable")] 648 pdata["unaff_atoms"] = [self.__make_atom(name, v) for v \ 649 in pkg.getElementsByTagName("unaffected")] 650 affected_packages[name].append(pdata) 651 xml_data['affected'] = affected_packages.copy() 652 653 return {glsa_id: xml_data}
654
655 - def __make_version(self, vnode):
656 """ 657 creates from the information in the I{versionNode} a 658 version string (format <op><version>). 659 660 @param vnode: a <vulnerable> or <unaffected> Node that 661 contains the version information for this atom 662 @type vnode: xml.dom.Node 663 @return: the version string 664 @rtype: string 665 """ 666 return self.op_mappings[vnode.getAttribute("range")] + \ 667 vnode.firstChild.data.strip()
668
669 - def __make_atom(self, pkgname, vnode):
670 """ 671 creates from the given package name and information in the 672 I{versionNode} a (syntactical) valid portage atom. 673 674 @param pkgname: the name of the package for this atom 675 @type pkgname: string 676 @param vnode: a <vulnerable> or <unaffected> Node that 677 contains the version information for this atom 678 @type vnode: xml.dom.Node 679 @return: the portage atom 680 @rtype: string 681 """ 682 return str(self.op_mappings[vnode.getAttribute("range")] + pkgname + \ 683 "-" + vnode.firstChild.data.strip())
684
686 """ 687 Return whether security advisories are available. 688 689 @return: availability 690 @rtype: bool 691 """ 692 if not os.path.lexists(etpConst['securitydir']): 693 return False 694 if not os.path.isdir(etpConst['securitydir']): 695 return False 696 else: 697 return True 698 return False
699
700 - def fetch_advisories(self, do_cache = True):
701 """ 702 This is the service method for remotely fetch advisories metadata. 703 704 @keyword do_cache: generates advisories cache 705 @type do_cache: bool 706 @return: execution status (0 means all file) 707 @rtype: int 708 """ 709 mytxt = "%s: %s" % ( 710 bold(_("Security Advisories")), 711 blue(_("testing service connection")), 712 ) 713 self.Entropy.updateProgress( 714 mytxt, 715 importance = 2, 716 type = "info", 717 header = red(" @@ "), 718 footer = red(" ...") 719 ) 720 721 mytxt = "%s: %s %s" % ( 722 bold(_("Security Advisories")), 723 blue(_("getting latest GLSAs")), 724 red("..."), 725 ) 726 self.Entropy.updateProgress( 727 mytxt, 728 importance = 2, 729 type = "info", 730 header = red(" @@ ") 731 ) 732 733 gave_up = self.Entropy.lock_check( 734 self.Entropy.resources_check_lock) 735 if gave_up: 736 return 7 737 738 locked = self.Entropy.application_lock_check() 739 if locked: 740 return 4 741 742 # lock 743 acquired = self.Entropy.resources_create_lock() 744 if not acquired: 745 return 4 # app locked during lock acquire 746 try: 747 rc_lock = self.__run_fetch() 748 except: 749 self.Entropy.resources_remove_lock() 750 raise 751 if rc_lock != 0: 752 return rc_lock 753 754 self.Entropy.resources_remove_lock() 755 756 if self.advisories_changed: 757 advtext = "%s: %s" % ( 758 bold(_("Security Advisories")), 759 darkgreen(_("updated successfully")), 760 ) 761 else: 762 advtext = "%s: %s" % ( 763 bold(_("Security Advisories")), 764 darkgreen(_("already up to date")), 765 ) 766 767 if do_cache and self.Entropy.xcache: 768 self.get_advisories_metadata() 769 self.Entropy.updateProgress( 770 advtext, 771 importance = 2, 772 type = "info", 773 header = red(" @@ ") 774 ) 775 776 return 0
777
778 - def __run_fetch(self):
779 # prepare directories 780 self.__prepare_unpack() 781 782 # download package 783 status = self.__download_glsa_package() 784 self.lastfetch = status 785 if not status: 786 mytxt = "%s: %s." % ( 787 bold(_("Security Advisories")), 788 darkred(_("unable to download the package, sorry")), 789 ) 790 self.Entropy.updateProgress( 791 mytxt, 792 importance = 2, 793 type = "error", 794 header = red(" ## ") 795 ) 796 self.Entropy.resources_remove_lock() 797 return 1 798 799 mytxt = "%s: %s %s" % ( 800 bold(_("Security Advisories")), 801 blue(_("Verifying checksum")), 802 red("..."), 803 ) 804 self.Entropy.updateProgress( 805 mytxt, 806 importance = 1, 807 type = "info", 808 header = red(" # "), 809 back = True 810 ) 811 812 # download digest 813 status = self.__download_glsa_package_cksum() 814 if not status: 815 mytxt = "%s: %s." % ( 816 bold(_("Security Advisories")), 817 darkred(_("cannot download the checksum, sorry")), 818 ) 819 self.Entropy.updateProgress( 820 mytxt, 821 importance = 2, 822 type = "error", 823 header = red(" ## ") 824 ) 825 self.Entropy.resources_remove_lock() 826 return 2 827 828 # verify digest 829 status = self.__verify_checksum() 830 831 if status == 1: 832 mytxt = "%s: %s." % ( 833 bold(_("Security Advisories")), 834 darkred(_("cannot open packages, sorry")), 835 ) 836 self.Entropy.updateProgress( 837 mytxt, 838 importance = 2, 839 type = "error", 840 header = red(" ## ") 841 ) 842 self.Entropy.resources_remove_lock() 843 return 3 844 elif status == 2: 845 mytxt = "%s: %s." % ( 846 bold(_("Security Advisories")), 847 darkred(_("cannot read the checksum, sorry")), 848 ) 849 self.Entropy.updateProgress( 850 mytxt, 851 importance = 2, 852 type = "error", 853 header = red(" ## ") 854 ) 855 self.Entropy.resources_remove_lock() 856 return 4 857 elif status == 3: 858 mytxt = "%s: %s." % ( 859 bold(_("Security Advisories")), 860 darkred(_("digest verification failed, sorry")), 861 ) 862 self.Entropy.updateProgress( 863 mytxt, 864 importance = 2, 865 type = "error", 866 header = red(" ## ") 867 ) 868 self.Entropy.resources_remove_lock() 869 return 5 870 elif status == 0: 871 mytxt = "%s: %s." % ( 872 bold(_("Security Advisories")), 873 darkgreen(_("verification Successful")), 874 ) 875 self.Entropy.updateProgress( 876 mytxt, 877 importance = 1, 878 type = "info", 879 header = red(" # ") 880 ) 881 else: 882 mytxt = _("Return status not valid") 883 raise InvalidData("InvalidData: %s." % (mytxt,)) 884 885 # save downloaded md5 886 if os.path.isfile(self.download_package_checksum) and \ 887 os.path.isdir(etpConst['dumpstoragedir']): 888 889 if os.path.isfile(self.old_download_package_checksum): 890 os.remove(self.old_download_package_checksum) 891 shutil.copy2(self.download_package_checksum, 892 self.old_download_package_checksum) 893 self.Entropy.setup_default_file_perms( 894 self.old_download_package_checksum) 895 896 # now unpack in place 897 status = self.__unpack_advisories() 898 if status != 0: 899 mytxt = "%s: %s." % ( 900 bold(_("Security Advisories")), 901 darkred(_("digest verification failed, try again later")), 902 ) 903 self.Entropy.updateProgress( 904 mytxt, 905 importance = 2, 906 type = "error", 907 header = red(" ## ") 908 ) 909 self.Entropy.resources_remove_lock() 910 return 6 911 912 mytxt = "%s: %s %s" % ( 913 bold(_("Security Advisories")), 914 blue(_("installing")), 915 red("..."), 916 ) 917 self.Entropy.updateProgress( 918 mytxt, 919 importance = 1, 920 type = "info", 921 header = red(" # ") 922 ) 923 924 # clear previous 925 self.__clear_previous_advisories() 926 # copy over 927 self.__put_advisories_in_place() 928 # remove temp stuff 929 self.__cleanup_garbage() 930 return 0
931