2009-11-22 1 views
0

J'espère que quelqu'un ici peut faire la lumière sur mon problème: DProblèmes liés au service Windows Python - Fonctionne avec l'argument de débogage mais pas lors de son démarrage en tant que service?

J'ai créé un service Windows XP en python qui est conçu pour surveiller/réparer les paramètres Windows/Application/Service sélectionnés, atm je me suis concentré sur paramètres DCOM par défaut.

L'idée est de sauvegarder notre configuration par défaut dans une autre clé de registre pour référence. Toutes les 30 minutes (actuellement toutes les 30 secondes pour les tests), j'aimerais que le service interroge les paramètres DCOM par défaut actuels de Windows à partir du registre et compare les résultats à la configuration par défaut. Si des anomalies sont détectées, le service remplacera les paramètres Windows actuels par les paramètres de configuration personnalisés.

J'ai déjà créé/testé ma classe pour gérer le registre de vérification/réparation et jusqu'ici il fonctionne parfaitement ... Jusqu'à ce que je le compile à un exe et l'exécute comme un service. Le service lui-même démarre très bien et il semble faire une boucle toutes les 30 secondes comme défini, mais mon module pour gérer la vérification/réparation du registre ne semble pas fonctionner comme spécifié.

J'ai créé un fichier journal et a été en mesure d'obtenir l'erreur suivante:

retraçage (appel le plus récent en dernier):
Fichier "DCOMMon.pyc", ligne 52, dans RepairDCOM
Fichier « DCOMMon. pyc », ligne 97, dans GetDefaultDCOM
fichier "pywmi.pyc", ligne 396, dans appel
fichier "pywmi.pyc", ligne 189, dans handle_com_error
x_wmi: -0x7ffdfff7 - Exception a eu lieu.
Erreur dans: SWbemObjectEx
-0x7ffbfe10 -

Quand j'arrête le service et exécuter l'exe manuellement, en spécifiant l'argument de débogage: DCOMMon.exe débogage, le service démarre et fonctionne correctement, effectuer toutes les tâches comme prévu. Les seules différences que je peux voir est que le service démarre le processus en tant qu'utilisateur SYSTEM à la place de l'utilisateur connecté ce qui me laisse croire (juste deviner ici) qu'il pourrait être une sorte de permission/stratégie manquée pour l'utilisateur SYSTEM? J'ai testé le fonctionnement du service comme un autre utilisateur, mais il n'y avait pas de différence là non plus. D'autres pensées ont été d'ajouter le service wmi aux dépendances de mon service mais honnêtement, je n'ai aucune idée de ce que cela ferait: P C'est la première fois que j'ai essayé de créer un service Windows en python, sans utiliser quelque chose comme srvany.exe. J'ai passé la meilleure partie de la nuit dernière et aujourd'hui essayer de google autour et trouver des informations concernant la compatibilité py2exe et wmi, mais jusqu'à présent, les suggestions que j'ai trouvées n'ont pas aidé à résoudre le problème ci-dessus.

Toutes les suggestions seraient appréciées. PS: Ne me détestez pas pour la mauvaise journalisation, j'ai coupé/collé mon enregistreur à partir d'un script différent et je n'ai pas fait les changements appropriés, il pourrait doubler chaque ligne: P. Le fichier journal peut être trouvé ici: "% WINDIR% \ system32 \ DCOMMon.log »

MISE À JOUR

J'ai essayé de diviser ce projet en deux fichiers exe au lieu d'un. Laissez-le faire de service et appel externe à l'autre exe pour exécuter la partie de registre wmi. Encore une fois, quand en cours d'exécution avec le débogage arg cela fonctionne très bien, mais quand je commence comme un service qu'il enregistre le même message d'erreur. de plus en plus cela commence à ressembler à un problème d'autorisation d'un pas un problème de programme :(

MISE À JOUR

DCOMMon.py - Nécessite pywin32, wmi (renommé pywmi),

# DCOMMon.py 


import win32api, win32service, win32serviceutil, win32event, win32evtlogutil, win32traceutil 
import logging, logging.handlers, os, re, sys, thread, time, traceback, pywmi # pywmi == wmi module renamed as suggested in online post 
import _winreg as reg 


DCOM_DEFAULT_CONFIGURATION  = ["EnableDCOM", "EnableRemoteConnect", "LegacyAuthenticationLevel", "LegacyImpersonationLevel", "DefaultAccessPermission", 
            "DefaultLaunchPermission", "MachineAccessRestriction", "MachineLaunchRestriction"] 

DCOM_DEFAULT_ACCESS_PERMISSION = [1, 0, 4, 128, 92, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 3, 0, 0, 0, 0, 0, 24, 0, 7, 0, 0, 0, 1, 2, 
            0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 20, 0, 7, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 0, 20, 0, 7, 
            0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 
            0, 0, 0, 32, 2, 0, 0] 

DCOM_DEFAULT_LAUNCH_PERMISSION = [1, 0, 4, 128, 132, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 5, 0, 0, 0, 0, 0, 24, 0, 31, 0, 0, 0, 1, 
            2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 20, 0, 31, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 0, 20, 0, 
            31, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 20, 0, 31, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 4, 0, 0, 0, 0, 0, 20, 0, 
            31, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 
            32, 0, 0, 0, 32, 2, 0, 0] 

DCOM_MACHINE_ACCESS_RESTRICTION = [1, 0, 4, 128, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 48, 0, 2, 0, 0, 0, 0, 0, 20, 0, 3, 0, 0, 0, 1, 1, 
            0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 0, 20, 0, 7, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 
            0, 0, 32, 2, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 

DCOM_MACHINE_LAUNCH_RESTRICTION = [1, 0, 4, 128, 72, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 2, 0, 0, 0, 0, 0, 24, 0, 31, 0, 0, 0, 1, 
            2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 20, 0, 31, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 
            0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 

COMPUTER = os.environ["COMPUTERNAME"] 
REGISTRY = pywmi.WMI(COMPUTER, namespace="root/default").StdRegProv 
LOGFILE = os.getcwd() + "\\DCOMMon.log" 


def Logger(title, filename): 
    logger = logging.getLogger(title) 
    logger.setLevel(logging.DEBUG) 
    handler = logging.handlers.RotatingFileHandler(filename, maxBytes=0, backupCount=0) 
    handler.setLevel(logging.DEBUG) 
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") 
    handler.setFormatter(formatter) 
    logger.addHandler(handler) 
    return logger 


def LogIt(filename=LOGFILE): 
    #try: 
    # if os.path.exists(filename): 
    #  os.remove(filename) 
    #except: 
    # pass 
    log = Logger("DCOMMon", filename) 
    tb = str(traceback.format_exc()).split("\n") 
    log.error("") 
    for i, a in enumerate(tb): 
     if a.strip() != "": 
      log.error(a) 

class Monitor: 

    def RepairDCOM(self): 
     try: 
      repaired = {} 
      dict1 = self.GetDefaultDCOM() 
      dict2 = self.GetCurrentDCOM() 
      compared = self.CompareDCOM(dict1, dict2) 

      for dobj in DCOM_DEFAULT_CONFIGURATION: 
       try: 
        compared[dobj] 
        if dobj == "LegacyAuthenticationLevel" or dobj == "LegacyImpersonationLevel": 
         REGISTRY.SetDWORDValue(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole", sValueName=dobj, uValue=dict1[dobj]) 
        elif dobj == "DefaultAccessPermission" or dobj == "DefaultLaunchPermission" or \ 
         dobj == "MachineAccessRestriction" or dobj == "MachineLaunchRestriction": 
         REGISTRY.SetBinaryValue(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole", sValueName=dobj, uValue=dict1[dobj]) 
        elif dobj == "EnableDCOM" or dobj == "EnableRemoteConnect": 
         REGISTRY.SetStringValue(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole", sValueName=dobj, sValue=dict1[dobj]) 
       except KeyError: 
        pass 
     except: 
      LogIt(LOGFILE) 

    def CompareDCOM(self, dict1, dict2): 
     compare = {} 
     for (key, value) in dict2.iteritems(): 
      try: 
       if dict1[key] != value: 
        compare[key] = value 
      except KeyError: 
       compare[key] = value 
     return compare 

    def GetCurrentDCOM(self): 
     current = {} 
     for name in REGISTRY.EnumValues(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole")[1]: 
      value = REGISTRY.GetStringValue(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole", sValueName=str(name))[1] 
      if value: 
       current[str(name)] = str(value) 
      else: 
       value = REGISTRY.GetDWORDValue(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole", sValueName=str(name))[1] 
       if not value: 
        value = REGISTRY.GetBinaryValue(hDefKey=reg.HKEY_LOCAL_MACHINE, sSubKeyName="SOFTWARE\\Microsoft\\Ole", sValueName=str(name))[1] 
      current[str(name)] = value 
     return current 

    def GetDefaultDCOM(self): 
     default = {} 
     # Get Default DCOM Settings 
     for name in REGISTRY.EnumValues(hDefKey=reg.HKEY_CURRENT_USER, sSubKeyName="Software\\DCOMMon")[1]: 
      value = REGISTRY.GetStringValue(hDefKey=reg.HKEY_CURRENT_USER, sSubKeyName="Software\\DCOMMon", sValueName=str(name))[1] 
      if value: 
       default[str(name)] = str(value) 
      else: 
       value = REGISTRY.GetDWORDValue(hDefKey=reg.HKEY_CURRENT_USER, sSubKeyName="Software\\DCOMMon", sValueName=str(name))[1] 
       if not value: 
        value = REGISTRY.GetBinaryValue(hDefKey=reg.HKEY_CURRENT_USER, sSubKeyName="Software\\DCOMMon", sValueName=str(name))[1] 
      default[str(name)] = value 
     return default 

class DCOMMon(win32serviceutil.ServiceFramework): 
    _svc_name_   = "DCOMMon" 
    _svc_display_name_ = "DCOM Monitoring Service" 
    _svc_description_ = "DCOM Monitoring Service" 
    _svc_deps_   = ["EventLog"] 

    def __init__(self, args): 
     win32serviceutil.ServiceFramework.__init__(self, args) 
     self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) 
     self.isAlive = True 

    def SvcDoRun(self): 
     import servicemanager 
     servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, 
           (self._svc_name_, ': DCOM Monitoring Service - Service Started')) 
     self.timeout=30000 # In milliseconds 
     while self.isAlive: 
      rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout) 
      if rc == win32event.WAIT_OBJECT_0: 
       break 
      else: 
       servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, 
             (self._svc_name_, ': DCOM Monitoring Service - Examining DCOM Configuration')) 
       Monitor().RepairDCOM() 
     servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STOPPED, 
           (self._svc_name_, ': DCOM Monitoring Service - Service Stopped')) 
     return 

    def SvcStop(self): 
     self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
     win32event.SetEvent(self.hWaitStop) 
     LOG.close() 
     self.isAlive = False 
     return 

#def ctrlHandler(ctrlType): 
# return True 

if __name__ == '__main__': 
# win32api.SetConsoleCtrlHandler(ctrlHandler, True) 
    #print Monitor().RepairDCOM() 
    win32serviceutil.HandleCommandLine(DCOMMon) 

DCOMMon_setup.py - Nécessite py2exe (auto exécutable, pas besoin de py2exe arg)

# DCOMMon_setup.py (self executable, no need for py2exe arg) 

# Usage: 
# DCOMMon.exe install 
# DCOMMon.exe start 
# DCOMMon.exe stop 
# DCOMMon.exe remove 
# DCOMMon.exe debug 

# you can see output of this program running python site-packages\win32\lib\win32traceutil 



try: 
    # (snippet I found somewhere, searching something??) 
    # if this doesn't work, try import modulefinder 
    import py2exe.mf as modulefinder 
    import win32com, sys 
    for p in win32com.__path__[1:]: 
     modulefinder.AddPackagePath("win32com", p) 
    for extra in ["win32com.shell"]: #,"win32com.mapi" 
     __import__(extra) 
     m = sys.modules[extra] 
     for p in m.__path__[1:]: 
      modulefinder.AddPackagePath(extra, p) 
except ImportError: 
    print "NOT FOUND" 


from distutils.core import setup 
import py2exe, sys 

if len(sys.argv) == 1: 
    sys.argv.append("py2exe") 
    #sys.argv.append("-q") 

class Target: 
    def __init__(self, **kw): 
     self.__dict__.update(kw) 
     # for the versioninfo resources 
     self.version  = "1.0.0.1" 
     self.language  = "English (Canada)" 
     self.company_name = "Whoever" 
     self.copyright = "Nobody" 
     self.name   = "Nobody Home" 


myservice = Target(
    description = 'DCOM Monitoring Service', 
    modules = ['DCOMMon'], 
    cmdline_style='pywin32' 
    #dest_base = 'DCOMMon' 
) 

setup(
    options = {"py2exe": {"compressed": 1, "bundle_files": 1, "ascii": 1, "packages": ["encodings"]} }, 
    console=["DCOMMon.py"], 
    zipfile = None, 
    service=[myservice] 
) 
+0

Je n'ai pas écrémé dans l'ensemble dumps ci-dessus (et je ne suis pas un grand utilisateur Windows/développeur) mais sur Linux je pourrais soupçonner des choses comme les autorisations qui sont différentes lors de l'exécution en mode démon sous un autre utilisateur. Peut-être que cela pourrait être un indice? – jldupont

+0

Jusqu'à présent, j'ai ajouté des permanentes complètes pour le compte système dans wmimgmt.msc, j'ai ajouté SYSTEM aux paramètres WMI dans dcomcnfg, essayé d'exécuter le service en tant qu'utilisateur actuel, et maintenant je suis à court d'idées. Je ne sais pas quoi d'autre reste à vérifier? L'erreur SWbemObjectEx que je reçois me porte à croire que c'est une erreur wmi, mais normalement l'erreur aurait plus de détails comme 'Accès refusé'. Cette fois, il est vide .. :( Étant donné que c'est ma première tentative de création d'un service si quelqu'un peut faire la lumière sur les différences de perm entre l'utilisateur connecté et l'utilisateur du système, il serait apprécié – AWainb

Répondre

0

Je crois qu'il est temps d'admettre ma stupidité ....: P

Il se trouve cela n'a pas été un problème de python, question py2exe, ni un problème WMI. :(

C'était plus ou moins une question simple permission. Si simple pour que je négligé la meilleure partie d'un mois. :(

Règle générale, si vous voulez créer un service qui appelle à particulier clés de registre pour obtenir (dans ce cas) les paramètres de configuration par défaut ....

... peut-être juste peut-être ....

Il faut placer leur clé par défaut dans le « HKEY_LOCAL_MACHINE », au lieu de "HKEY_CURRENT_USER" ?? : P

Ouais, il est aussi simple que cela ...

Je me suis souvenu de cette règle d'autres projets que j'ai travaillé dans le passé. Lorsque vous exécutez le compte système local, simplement, il n'y a pas de sous-clé "HKEY_CURRENT_USER" pour accéder. Si vous devez absolument accéder à la sous-clé "HKEY_CURRENT_USER" d'un utilisateur spécifique, je suppose que la seule façon serait d'usurper l'identité de l'utilisateur. Heureusement pour moi, ce n'est pas nécessaire pour ce que je tente d'accomplir.

Le lien ci-dessous m'a donné ce que je devais faire du jogging ma mémoire et résoudre le problème:

http://msdn.microsoft.com/en-us/library/ms684190%28VS.85%29.aspx

Donc, pour faire une histoire courte, je migré toutes mes valeurs par défaut sur la " HKEY_LOCAL_MACHINE \ SOFTWARE " sous-clé et mon service fonctionne parfaitement. : D

Merci pour votre aide les gars, mais ce problème est résolu;)

+0

** MISE À JOUR ** J'ai pu accéder à la clé de l'utilisateur en utilisant la ruche HKEY_USERS. Il est un peu difficile que vous devez obtenir le SID de l'utilisateur actuel pour accéder à la sous-clé appropriée: Travaux de compte SYSTEM: « HKEY_USERS \ \ Software \ kMonitor » Ne fonctionne pas de compte SYSTEM: "HKEY_CURRENT_USER \ Software \ kMonitor" – AWainb

0

Je ne suis pas un expert à ce sujet, mais voici mes deux cents de valeur:

This article me dit que vous devrez peut-être connecté en tant que som eone avec les autorisations du système cible requises.

Cependant, je trouve cela un peu excessif. Avez-vous essayé de compiler votre script à partir de la ligne de commande tout en exécutant l'invite de commande en tant qu'administrateur de l'ordinateur - pour pouvoir déverrouiller toutes les autorisations (sous Windows Vista et Windows 7, cliquez avec le bouton droit de la souris sur démarrer le menu et cliquer sur "Exécuter en tant qu'administrateur").

Hope this helps

+0

Merci pour votre réponse: DI a essayé de le compiler à partir d'une invite cmd Admin mais je n'ai toujours pas eu de chance Le problème ne vient pas de la façon dont il a été compilé, le service lui-même fonctionne très bien, les appels wmi mon compte était déjà un admin de toute façon, et le service fonctionne comme SYSTEM pas administrateur, mais vous ne savez jamais, je vais essayer n'importe quoi à ce stade;) FYI, c'est un service XP, j'aurais probablement dû le mentionner auparavant. – AWainb

Questions connexes