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