Esempio n. 1
0
def killStupidProcesses():
    '''A nasty bit of hackery to get Adobe CS5 AAMEE packages to install
    when at the loginwindow.'''
    stupid_processes = ["Adobe AIR Installer",
                        "Adobe AIR Application Installer",
                        "InstallAdobeHelp",
                        "open -a /Library/Application Support/Adobe/SwitchBoard/SwitchBoard.app"]

    for procname in stupid_processes:
        pid = utils.getPIDforProcessName(procname)
        if pid:
            if not pid in secondsToLive:
                secondsToLive[pid] = 30
            else:
                secondsToLive[pid] = secondsToLive[pid] - 1
                if secondsToLive[pid] == 0:
                    # it's been running too long; kill it
                    munkicommon.log("Killing PID %s: %s" % (pid, procname))
                    try:
                        os.kill(int(pid), 9)
                    except OSError:
                        pass
                    # remove this PID from our list
                    del secondsToLive[pid]
                    # only kill one process per invocation
                    return
Esempio n. 2
0
def availableUpdatesAreDownloaded():
    '''Verifies that applicable/available Apple updates have
    been downloaded. Returns False if one or more product directories
    are missing, True otherwise (including when there are no available
    updates).'''

    appleUpdates = getSoftwareUpdateInfo()
    if not appleUpdates:
        return True

    try:
        downloadIndex = FoundationPlist.readPlist(
            '/Library/Updates/index.plist')
        downloaded = downloadIndex.get('ProductPaths', [])
    except FoundationPlist.FoundationPlistException:
        munkicommon.log('Apple downloaded update index is invalid. '
                        '/Library/Updates/index.plist')
        return False

    for update in appleUpdates:
        productKey = update.get('productKey')
        if productKey:
            if (productKey not in downloaded or not os.path.isdir(
                    os.path.join('/Library/Updates', downloaded[productKey]))):
                munkicommon.log('Apple Update product directory for %s is '
                                'missing.' % update['name'])
                return False
    return True
Esempio n. 3
0
def downloadAvailableUpdates():
    '''Downloads the available Apple updates using our local
    filtered sucatalog. Returns True if successful, False otherwise.'''
    msg = "Downloading available Apple Software Updates..."
    if munkicommon.munkistatusoutput:
        munkistatus.message(msg)
        munkistatus.detail("")
        munkistatus.percent(-1)
        munkicommon.log(msg)
    else:
        munkicommon.display_status(msg)

    # use our filtered local catalog
    catalogpath = os.path.join(swupdCacheDir(),
                               'content/catalogs/local_download.sucatalog')
    if not os.path.exists(catalogpath):
        munkicommon.display_error(
            'Missing local Software Update catalog at %s', catalogpath)
        return False

    catalogURL = 'file://localhost' + urllib2.quote(catalogpath)
    # get the OS version
    osvers = int(os.uname()[2].split('.')[0])
    if osvers == 9:
        retcode = leopardDownloadAvailableUpdates(catalogURL)
    else:
        retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-d', '-a'])

    if retcode:
        # there was an error
        munkicommon.display_error("softwareupdate error: %s" % retcode)
        return False
    return True
Esempio n. 4
0
def availableUpdatesAreDownloaded():
    '''Verifies that applicable/available Apple updates have
    been downloaded. Returns False if one or more product directories
    are missing, True otherwise (including when there are no available
    updates).'''

    appleUpdates = getSoftwareUpdateInfo()
    if not appleUpdates:
        return True

    try:
        downloadIndex = FoundationPlist.readPlist(
            '/Library/Updates/index.plist')
        downloaded = downloadIndex.get('ProductPaths', [])
    except FoundationPlist.FoundationPlistException:
        munkicommon.log('Apple downloaded update index is invalid. '
                        '/Library/Updates/index.plist')
        return False

    for update in appleUpdates:
        productKey = update.get('productKey')
        if productKey:
            if (productKey not in downloaded or
                not os.path.isdir(
                    os.path.join('/Library/Updates',
                                 downloaded[productKey]))):
                munkicommon.log('Apple Update product directory for %s is '
                                'missing.' % update['name'])
                return False
    return True
Esempio n. 5
0
def downloadAvailableUpdates():
    '''Downloads the available Apple updates using our local
    filtered sucatalog. Returns True if successful, False otherwise.'''
    msg = "Downloading available Apple Software Updates..."
    if munkicommon.munkistatusoutput:
        munkistatus.message(msg)
        munkistatus.detail("")
        munkistatus.percent(-1)
        munkicommon.log(msg)
    else:
        munkicommon.display_status(msg)

    # use our filtered local catalog
    catalogpath = os.path.join(swupdCacheDir(),
        'content/catalogs/local_download.sucatalog')
    if not os.path.exists(catalogpath):
        munkicommon.display_error(
            'Missing local Software Update catalog at %s', catalogpath)
        return False

    catalogURL = 'file://localhost' + urllib2.quote(catalogpath)
    # get the OS version
    osvers = int(os.uname()[2].split('.')[0])
    if osvers == 9:
        retcode = leopardDownloadAvailableUpdates(catalogURL)
    else:
        retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-d', '-a'])

    if retcode:
        # there was an error
        munkicommon.display_error("softwareupdate error: %s" % retcode)
        return False
    return True
Esempio n. 6
0
def getAvailableUpdates():
    '''Returns a list of product IDs of available Apple updates'''
    msg = "Checking for available Apple Software Updates..."
    if munkicommon.munkistatusoutput:
        munkistatus.message(msg)
        munkistatus.detail("")
        munkistatus.percent(-1)
        munkicommon.log(msg)
    else:
        munkicommon.display_status(msg)

    applicable_updates = os.path.join(swupdCacheDir(),
                                      'ApplicableUpdates.plist')
    if os.path.exists(applicable_updates):
        # remove any old item
        try:
            os.unlink(applicable_updates)
        except (OSError, IOError):
            pass

    # use our locally-cached Apple catalog
    catalogpath = os.path.join(swupdCacheDir(),
                               'content/catalogs/apple_index.sucatalog')
    catalogURL = 'file://localhost' + urllib2.quote(catalogpath)
    su_options = ['--CatalogURL', catalogURL, '-l', '-f', applicable_updates]

    retcode = run_softwareupdate(su_options)
    if retcode:
        # there was an error
        osvers = int(os.uname()[2].split('.')[0])
        if osvers == 9:
            # always a non-zero retcode on Leopard
            pass
        else:
            munkicommon.display_error("softwareupdate error: %s" % retcode)
            return []

    if os.path.exists(applicable_updates):
        try:
            updatelist = FoundationPlist.readPlist(applicable_updates)
            if updatelist:
                results_array = updatelist.get('phaseResultsArray', [])
                return [
                    item['productKey'] for item in results_array
                    if 'productKey' in item
                ]
        except FoundationPlist.NSPropertyListSerializationException:
            return []
    return []
Esempio n. 7
0
def getAvailableUpdates():
    '''Returns a list of product IDs of available Apple updates'''
    msg = "Checking for available Apple Software Updates..."
    if munkicommon.munkistatusoutput:
        munkistatus.message(msg)
        munkistatus.detail("")
        munkistatus.percent(-1)
        munkicommon.log(msg)
    else:
        munkicommon.display_status(msg)

    applicable_updates = os.path.join(swupdCacheDir(),
                                      'ApplicableUpdates.plist')
    if os.path.exists(applicable_updates):
        # remove any old item
        try:
            os.unlink(applicable_updates)
        except (OSError, IOError):
            pass

    # use our locally-cached Apple catalog
    catalogpath = os.path.join(swupdCacheDir(),
        'content/catalogs/apple_index.sucatalog')
    catalogURL = 'file://localhost' + urllib2.quote(catalogpath)
    su_options = ['--CatalogURL', catalogURL, '-l', '-f', applicable_updates]

    retcode = run_softwareupdate(su_options)
    if retcode:
        # there was an error
        osvers = int(os.uname()[2].split('.')[0])
        if osvers == 9:
            # always a non-zero retcode on Leopard
            pass
        else:
            munkicommon.display_error("softwareupdate error: %s" % retcode)
            return []

    if os.path.exists(applicable_updates):
        try:
            updatelist = FoundationPlist.readPlist(applicable_updates)
            if updatelist:
                results_array = updatelist.get('phaseResultsArray', [])
                return [item['productKey'] for item in results_array
                        if 'productKey' in item]
        except FoundationPlist.NSPropertyListSerializationException:
            return []
    return []
Esempio n. 8
0
def getResourceIfChangedAtomically(url,
                                   destinationpath,
                                   custom_headers=None,
                                   expected_hash=None,
                                   message=None,
                                   resume=False,
                                   verify=False,
                                   follow_redirects=False):
    """Gets file from a URL.
       Checks first if there is already a file with the necessary checksum.
       Then checks if the file has changed on the server, resuming or
       re-downloading as necessary.

       If the file has changed verify the pkg hash if so configured.

       Supported schemes are http, https, file.

       Returns True if a new download was required; False if the
       item is already in the local cache.

       Raises a MunkiDownloadError derived class if there is an error."""

    changed = False

    # If we already have a downloaded file & its (cached) hash matches what
    # we need, do nothing, return unchanged.
    if resume and expected_hash and os.path.isfile(destinationpath):
        xattr_hash = getxattr(destinationpath, XATTR_SHA)
        if not xattr_hash:
            xattr_hash = writeCachedChecksum(destinationpath)
        if xattr_hash == expected_hash:
            #File is already current, no change.
            return False
        elif munkicommon.pref('PackageVerificationMode').lower() in [
                'hash_strict', 'hash'
        ]:
            try:
                os.unlink(destinationpath)
            except OSError:
                pass
        munkicommon.log('Cached payload does not match hash in catalog, '
                        'will check if changed and redownload: %s' %
                        destinationpath)
        #continue with normal if-modified-since/etag update methods.

    if follow_redirects != True:
        # If we haven't explicitly said to follow redirect, the preference decides
        follow_redirects = munkicommon.pref('FollowHTTPRedirects')

    url_parse = urlparse.urlparse(url)
    if url_parse.scheme in ['http', 'https']:
        changed = getHTTPfileIfChangedAtomically(
            url,
            destinationpath,
            custom_headers=custom_headers,
            message=message,
            resume=resume,
            follow_redirects=follow_redirects)
    elif url_parse.scheme == 'file':
        changed = getFileIfChangedAtomically(url_parse.path, destinationpath)
    else:
        raise MunkiDownloadError('Unsupported scheme for %s: %s' %
                                 (url, url_parse.scheme))

    if changed and verify:
        (verify_ok, fhash) = verifySoftwarePackageIntegrity(destinationpath,
                                                            expected_hash,
                                                            always_hash=True)
        if not verify_ok:
            try:
                os.unlink(destinationpath)
            except OSError:
                pass
            raise PackageVerificationError()
        if fhash:
            writeCachedChecksum(destinationpath, fhash=fhash)

    return changed
Esempio n. 9
0
def getResourceIfChangedAtomically(url, 
                                   destinationpath,
                                   cert_info=None,
                                   custom_headers=None,
                                   expected_hash=None,
                                   message=None, 
                                   resume=False,
                                   verify=False,
                                   follow_redirects=False):
    """Gets file from a URL.
       Checks first if there is already a file with the necessary checksum.
       Then checks if the file has changed on the server, resuming or
       re-downloading as necessary.

       If the file has changed verify the pkg hash if so configured.

       Supported schemes are http, https, file.

       Returns True if a new download was required; False if the
       item is already in the local cache.

       Raises a MunkiDownloadError derived class if there is an error."""

    changed = False

    # If we already have a downloaded file & its (cached) hash matches what
    # we need, do nothing, return unchanged.
    if resume and expected_hash and os.path.isfile(destinationpath):
        xattr_hash = getxattr(destinationpath, XATTR_SHA)
        if not xattr_hash:
            xattr_hash = writeCachedChecksum(destinationpath)
        if xattr_hash == expected_hash:
            #File is already current, no change.
            return False
        elif munkicommon.pref('PackageVerificationMode').lower() in \
                                                    ['hash_strict', 'hash']:
            try:
                os.unlink(destinationpath)
            except OSError:
                pass
        munkicommon.log('Cached payload does not match hash in catalog, '
                'will check if changed and redownload: %s' % destinationpath)
        #continue with normal if-modified-since/etag update methods.

    url_parse = urlparse.urlparse(url)
    if url_parse.scheme in ['http', 'https']:
        changed = getHTTPfileIfChangedAtomically(
            url, destinationpath,
            cert_info=cert_info, custom_headers=custom_headers,
            message=message, resume=resume, follow_redirects=follow_redirects)
    elif url_parse.scheme == 'file':
        changed = getFileIfChangedAtomically(url_parse.path, destinationpath)
    else:
        raise MunkiDownloadError(
                'Unsupported scheme for %s: %s' % (url, url_parse.scheme))

    if changed and verify:
        (verify_ok, fhash) = verifySoftwarePackageIntegrity(destinationpath,
                                                          expected_hash,
                                                          always_hash=True)
        if not verify_ok:
            try:
                os.unlink(destinationpath)
            except OSError:
                pass
            raise PackageVerificationError()
        if fhash:
            writeCachedChecksum(destinationpath, fhash=fhash)

    return changed
Esempio n. 10
0
def installAppleUpdates():
    '''Uses /usr/sbin/softwareupdate to install previously
    downloaded updates. Returns True if a restart is needed
    after install, False otherwise.'''
    msg = "Installing available Apple Software Updates..."
    if munkicommon.munkistatusoutput:
        munkistatus.message(msg)
        munkistatus.detail("")
        munkistatus.percent(-1)
        munkicommon.log(msg)
    else:
        munkicommon.display_status(msg)
    restartneeded = restartNeeded()
    # use our filtered local catalog
    catalogpath = os.path.join(swupdCacheDir(),
                               'content/catalogs/local_install.sucatalog')
    if not os.path.exists(catalogpath):
        munkicommon.display_error(
            'Missing local Software Update catalog at %s', catalogpath)
        # didn't do anything, so no restart needed
        return False

    installlist = getSoftwareUpdateInfo()
    installresults = {'installed': [], 'download': []}

    catalogURL = 'file://localhost' + urllib2.quote(catalogpath)
    retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-i', '-a'],
                                 mode='install',
                                 results=installresults)

    if not 'InstallResults' in munkicommon.report:
        munkicommon.report['InstallResults'] = []

    for item in installlist:
        rep = {}
        rep['name'] = item.get('display_name')
        rep['version'] = item.get('version_to_install', '')
        rep['applesus'] = True
        rep['productKey'] = item.get('productKey', '')
        message = "Apple Software Update install of %s-%s: %s"
        if rep['name'] in installresults['installed']:
            rep['status'] = 0
            install_status = 'SUCCESSFUL'
        elif rep['name'] in installresults['download']:
            rep['status'] = -1
            install_status = 'FAILED due to missing package.'
            munkicommon.display_warning(
                'Apple update %s, %s failed. A sub-package was missing '
                'on disk at time of install.' %
                (rep['name'], rep['productKey']))
        else:
            rep['status'] = -2
            install_status = 'FAILED for unknown reason'
            munkicommon.display_warning(
                'Apple update %s, %s failed to install. No record of '
                'success or failure.' % (rep['name'], rep['productKey']))

        munkicommon.report['InstallResults'].append(rep)
        log_msg = message % (rep['name'], rep['version'], install_status)
        munkicommon.log(log_msg, "Install.log")

    if retcode:
        # there was an error
        munkicommon.display_error("softwareupdate error: %s" % retcode)
    # clean up our now stale local cache
    cachedir = os.path.join(swupdCacheDir())
    if os.path.exists(cachedir):
        unused_retcode = subprocess.call(['/bin/rm', '-rf', cachedir])
    # remove the now invalid appleUpdatesFile
    try:
        os.unlink(appleUpdatesFile())
    except OSError:
        pass
    # Also clear our pref value for last check date. We may have
    # just installed an update which is a pre-req for some other update.
    # Let's check again soon.
    munkicommon.set_pref('LastAppleSoftwareUpdateCheck', None)

    return restartneeded
Esempio n. 11
0
         percent = -1
     munkicommon.display_percent_done(percent, 100)
 elif output.startswith('Software Update Tool'):
     # don't display this
     pass
 elif output.startswith('Copyright 2'):
     # don't display this
     pass
 elif output.startswith('Installing ') and mode == 'install':
     item = output[11:]
     if item:
         if munkicommon.munkistatusoutput:
             munkistatus.message(output)
             munkistatus.detail("")
             munkistatus.percent(-1)
             munkicommon.log(output)
         else:
             munkicommon.display_status(output)
 elif output.startswith('Installed '):
     # 10.6 / 10.7. Successful install of package name.
     if mode == 'install':
         munkicommon.display_status(output)
         results['installed'].append(output[10:])
     else:
         pass
         # don't display.
         # softwareupdate logging "Installed" at the end of a
         # successful download-only session is odd.
 elif output.startswith('Done '):
     # 10.5. Successful install of package name.
     munkicommon.display_status(output)
Esempio n. 12
0
def installAppleUpdates():
    '''Uses /usr/sbin/softwareupdate to install previously
    downloaded updates. Returns True if a restart is needed
    after install, False otherwise.'''
    msg = "Installing available Apple Software Updates..."
    if munkicommon.munkistatusoutput:
        munkistatus.message(msg)
        munkistatus.detail("")
        munkistatus.percent(-1)
        munkicommon.log(msg)
    else:
        munkicommon.display_status(msg)
    restartneeded = restartNeeded()
    # use our filtered local catalog
    catalogpath = os.path.join(swupdCacheDir(),
        'content/catalogs/local_install.sucatalog')
    if not os.path.exists(catalogpath):
        munkicommon.display_error(
            'Missing local Software Update catalog at %s', catalogpath)
        # didn't do anything, so no restart needed
        return False

    installlist = getSoftwareUpdateInfo()
    installresults = {'installed':[], 'download':[]}

    catalogURL = 'file://localhost' + urllib2.quote(catalogpath)
    retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-i', '-a'],
                                 mode='install', results=installresults)

    if not 'InstallResults' in munkicommon.report:
        munkicommon.report['InstallResults'] = []

    for item in installlist:
        rep = {}
        rep['name'] = item.get('display_name')
        rep['version'] = item.get('version_to_install', '')
        rep['applesus'] = True
        rep['productKey'] = item.get('productKey', '')
        message = "Apple Software Update install of %s-%s: %s"
        if rep['name'] in installresults['installed']:
            rep['status'] = 0
            install_status = 'SUCCESSFUL'
        elif rep['name'] in installresults['download']:
            rep['status'] = -1
            install_status = 'FAILED due to missing package.'
            munkicommon.display_warning(
                'Apple update %s, %s failed. A sub-package was missing '
                'on disk at time of install.'
                % (rep['name'], rep['productKey']))
        else:
            rep['status'] = -2
            install_status = 'FAILED for unknown reason'
            munkicommon.display_warning(
                'Apple update %s, %s failed to install. No record of '
                'success or failure.' % (rep['name'],rep['productKey']))

        munkicommon.report['InstallResults'].append(rep)
        log_msg = message % (rep['name'], rep['version'], install_status)
        munkicommon.log(log_msg, "Install.log")

    if retcode:
        # there was an error
        munkicommon.display_error("softwareupdate error: %s" % retcode)
    # clean up our now stale local cache
    cachedir = os.path.join(swupdCacheDir())
    if os.path.exists(cachedir):
        unused_retcode = subprocess.call(['/bin/rm', '-rf', cachedir])
    # remove the now invalid appleUpdatesFile
    try:
        os.unlink(appleUpdatesFile())
    except OSError:
        pass
    # Also clear our pref value for last check date. We may have
    # just installed an update which is a pre-req for some other update.
    # Let's check again soon.
    munkicommon.set_pref('LastAppleSoftwareUpdateCheck', None)

    return restartneeded
Esempio n. 13
0
         percent = -1
     munkicommon.display_percent_done(percent, 100)
 elif output.startswith('Software Update Tool'):
     # don't display this
     pass
 elif output.startswith('Copyright 2'):
     # don't display this
     pass
 elif output.startswith('Installing ') and mode == 'install':
     item = output[11:]
     if item:
         if munkicommon.munkistatusoutput:
             munkistatus.message(output)
             munkistatus.detail("")
             munkistatus.percent(-1)
             munkicommon.log(output)
         else:
             munkicommon.display_status(output)
 elif output.startswith('Installed '):
     # 10.6 / 10.7. Successful install of package name.
     if mode == 'install':
         munkicommon.display_status(output)
         results['installed'].append(output[10:])
     else:
         pass
         # don't display.
         # softwareupdate logging "Installed" at the end of a
         # successful download-only session is odd.
 elif output.startswith('Done '):
     # 10.5. Successful install of package name.
     munkicommon.display_status(output)