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 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 self.Entropy.resources_remove_lock() 741 return 4 742 743 # lock 744 self.Entropy.resources_create_lock() 745 try: 746 rc_lock = self.__run_fetch() 747 except: 748 self.Entropy.resources_remove_lock() 749 raise 750 if rc_lock != 0: 751 return rc_lock 752 753 self.Entropy.resources_remove_lock() 754 755 if self.advisories_changed: 756 advtext = "%s: %s" % ( 757 bold(_("Security Advisories")), 758 darkgreen(_("updated successfully")), 759 ) 760 else: 761 advtext = "%s: %s" % ( 762 bold(_("Security Advisories")), 763 darkgreen(_("already up to date")), 764 ) 765 766 if do_cache and self.Entropy.xcache: 767 self.get_advisories_metadata() 768 self.Entropy.updateProgress( 769 advtext, 770 importance = 2, 771 type = "info", 772 header = red(" @@ ") 773 ) 774 775 return 0
776
777 - def __run_fetch(self):
778 # prepare directories 779 self.__prepare_unpack() 780 781 # download package 782 status = self.__download_glsa_package() 783 self.lastfetch = status 784 if not status: 785 mytxt = "%s: %s." % ( 786 bold(_("Security Advisories")), 787 darkred(_("unable to download the package, sorry")), 788 ) 789 self.Entropy.updateProgress( 790 mytxt, 791 importance = 2, 792 type = "error", 793 header = red(" ## ") 794 ) 795 self.Entropy.resources_remove_lock() 796 return 1 797 798 mytxt = "%s: %s %s" % ( 799 bold(_("Security Advisories")), 800 blue(_("Verifying checksum")), 801 red("..."), 802 ) 803 self.Entropy.updateProgress( 804 mytxt, 805 importance = 1, 806 type = "info", 807 header = red(" # "), 808 back = True 809 ) 810 811 # download digest 812 status = self.__download_glsa_package_cksum() 813 if not status: 814 mytxt = "%s: %s." % ( 815 bold(_("Security Advisories")), 816 darkred(_("cannot download the checksum, sorry")), 817 ) 818 self.Entropy.updateProgress( 819 mytxt, 820 importance = 2, 821 type = "error", 822 header = red(" ## ") 823 ) 824 self.Entropy.resources_remove_lock() 825 return 2 826 827 # verify digest 828 status = self.__verify_checksum() 829 830 if status == 1: 831 mytxt = "%s: %s." % ( 832 bold(_("Security Advisories")), 833 darkred(_("cannot open packages, sorry")), 834 ) 835 self.Entropy.updateProgress( 836 mytxt, 837 importance = 2, 838 type = "error", 839 header = red(" ## ") 840 ) 841 self.Entropy.resources_remove_lock() 842 return 3 843 elif status == 2: 844 mytxt = "%s: %s." % ( 845 bold(_("Security Advisories")), 846 darkred(_("cannot read the checksum, sorry")), 847 ) 848 self.Entropy.updateProgress( 849 mytxt, 850 importance = 2, 851 type = "error", 852 header = red(" ## ") 853 ) 854 self.Entropy.resources_remove_lock() 855 return 4 856 elif status == 3: 857 mytxt = "%s: %s." % ( 858 bold(_("Security Advisories")), 859 darkred(_("digest verification failed, sorry")), 860 ) 861 self.Entropy.updateProgress( 862 mytxt, 863 importance = 2, 864 type = "error", 865 header = red(" ## ") 866 ) 867 self.Entropy.resources_remove_lock() 868 return 5 869 elif status == 0: 870 mytxt = "%s: %s." % ( 871 bold(_("Security Advisories")), 872 darkgreen(_("verification Successful")), 873 ) 874 self.Entropy.updateProgress( 875 mytxt, 876 importance = 1, 877 type = "info", 878 header = red(" # ") 879 ) 880 else: 881 mytxt = _("Return status not valid") 882 raise InvalidData("InvalidData: %s." % (mytxt,)) 883 884 # save downloaded md5 885 if os.path.isfile(self.download_package_checksum) and \ 886 os.path.isdir(etpConst['dumpstoragedir']): 887 888 if os.path.isfile(self.old_download_package_checksum): 889 os.remove(self.old_download_package_checksum) 890 shutil.copy2(self.download_package_checksum, 891 self.old_download_package_checksum) 892 self.Entropy.setup_default_file_perms( 893 self.old_download_package_checksum) 894 895 # now unpack in place 896 status = self.__unpack_advisories() 897 if status != 0: 898 mytxt = "%s: %s." % ( 899 bold(_("Security Advisories")), 900 darkred(_("digest verification failed, try again later")), 901 ) 902 self.Entropy.updateProgress( 903 mytxt, 904 importance = 2, 905 type = "error", 906 header = red(" ## ") 907 ) 908 self.Entropy.resources_remove_lock() 909 return 6 910 911 mytxt = "%s: %s %s" % ( 912 bold(_("Security Advisories")), 913 blue(_("installing")), 914 red("..."), 915 ) 916 self.Entropy.updateProgress( 917 mytxt, 918 importance = 1, 919 type = "info", 920 header = red(" # ") 921 ) 922 923 # clear previous 924 self.__clear_previous_advisories() 925 # copy over 926 self.__put_advisories_in_place() 927 # remove temp stuff 928 self.__cleanup_garbage() 929 return 0
930