IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API, COM et SDKs Delphi Discussion :

Comportement bizarre sur appel à "ImpersonateLoggedOnUser"


Sujet :

API, COM et SDKs Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut Comportement bizarre sur appel à "ImpersonateLoggedOnUser"
    Bonjour à tous,


    Voilà mon problème : j'essai d'élever les droits de ma thread (démarrée dans le contexte d'un compte utilisateur classique), pour cela j'appelle "LogonUser" avec les données d'authentification d'un compte admin puis avec le jeton (token) récupéré j'appelle "ImpersonateLoggedOnUser" pour que ma thread récupère les droits de ce compte.
    A priori sur MSDN il est indiqué qu'aucun privilège n'est nécessaire pour appeler "ImpersonateLoggedOnUser", il suffit d'un "primary or impersonnation token", ce que me retourne justement "LogonUser".

    Sauf que lors de l'appel à "ImpersonateLoggedOnUser" j'ai un comportement tout à fait inattendu que je ne parviens à expliquer ni à contourner malheureusement...

    En effet c'est comme si lors de cet appel ma fonction était interrompue et retournait brutalement à l'appelant sans aucun change de poursuivre l'exécution. J'ai tenté de remplacer mon implémentation en utilisant le couple DuplicateTokenEx/SetThreadToken( nil,... ) à la place de ImpersonateLoggedOnUser mais le résultat est exactement le même lors de l'appel à "SetThreadToken".


    Alors là où c'est fort et que cela semble aller à l'encontre même de la sémantique Delphi c'est que dans mon code j'ai ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Result:= GetErrorCode( SafeLogonUser( AnUser, ADomain, MyPassword,
                                                               LOGON32_PROVIDER_DEFAULT, AdminToken ) );
    if ( Result = ERROR_SUCCESS ) then begin
       try
          WriteLogToFile( 'C:\test.log', 'avant ImpersonateLoggedOnUser...'+sLineBreak );
          Result:= GetErrorCode( ImpersonateLoggedOnUser( DuplicateToken ) );
       finally
          WriteLogToFile( 'C:\test.log', 'après ImpersonateLoggedOnUser...'+sLineBreak );
       end;
    end;

    à la fin de l'exécution dans mon fichier log j'ai "'avant ImpersonateLoggedOnUser..." mais jamais "après ImpersonateLoggedOnUser..." !!!

    Le traitement se poursuit par contre au niveau de la fonction appelante.. je ne comprends pas, surtout qu'évidemment l'élévation de privilège semble échouer car je me tape un code erreur = ERROR_BAD_IMPERSONATION_LEVEL sur le prochain appel (je crois, en tout cas c'est ce code erreur qui remonte mais vu que le traitement est interrompu je ne pense pas qu'il soit récupéré directement depuis l'appel à "ImpersonateLoggedOnUser").

    J'ai trouvé sur Google un occurrence du problème mais avec un autre langage :
    http://forums.iis.net/t/1203009.aspx


    Quelqu'un peut-il m'expliquer ce phénomène ? Que puis-je faire pour contourner ce problème ?

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Personne, snif... vous êtes mon dernier espoir car là je sèche personnellement

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 941
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 941
    Par défaut
    SafeLogonUser, jamais entendu parlé
    (Je passe sur le fait que tu utilises une fois AdminToken et une fois DuplicateToken. Une erreur de copie sans doute)

    Sinon, j'ai fait un essai avec LogonUser et pas de problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var
      Token :THandle;
    begin
      if LogonUser(PChar(User), nil, PChar(Password), LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, Token) and
         ImpersonateLoggedOnUser(Token) then
      begin
        //...
        RevertToSelf;
      end
      else RaiseLastOSError;
    end;
    Lorsqu'une procédure se termine abruptement comme tu le décris, c'est qu'il y a un problème de registres. Ce SafeLogonUser mettrait le bazar que cela ne me surprendrait pas.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Merci Andnotor pour ta réponse !! je ne suis plus seul !

    Euh alors oui désolé : "SafeLogonUser" est simplement une méthode interne qui tente 3 formes d'appel différentes de "LogonUser" (avec "LOGON32_LOGON_NETWORK", puis "LOGON32_LOGON_BATCH" et enfin "LOGON32_LOGON_INTERACTIVE", un peu bourrin j'admet mais cela permet de gérer les cas où on nous refuse la premiere voir la seconde forme).
    Le problème n'est pas là car j'avais en réalité remplacé directement par "LogonUser" sur la forme "LOGON32_LOGON_NETWORK" puisque cela passait... je vais mettre à jour le post.

    Evidemment le cas ne se reproduit pas systématiquement, chez la plupart de nos clients le code fonctionne très bien, mais chez l'un d'eux cela coince. Pourtant les infos du compte passées à "Logon" fonctionnent très bien avec la commande "RunAs" en ligne de commande sur le poste en question... et l'erreur semble bien provoquée lors de l'appel à "ImpersonateLoggedOnUser" qui est une API Windows et j'ai du mal à comprendre ce qu'il se passe... peut-être Delphi importe la mauvaise version de l'API (Unicode ou je ne sais quoi) qui pourrait provoquer ce comportement de manière aléatoire ? Cela serait tout de même étonnant surtout que j'ai EXACTEMENT le même comportement en utilisant à la place le couple "DuplicateTokenEx"/"SetThreadToken" (qui explique le mauvais copié/collé avec "DuplicateToken") lors de l'appel à "SetThreadToken" donc ce n'est pas une simple coïncidence à mon avis... et il faut voir aussi que je ne suis pas le seul à avoir observé ce phénomène (et dans l'autre cas ce n'est pas du tout avec du Delphi).

    [Edit] je ne peux plus éditer mon premier post après coup mince, donc il faut considérer que j'utilise bien "LogonUser" et non "SafeLogonUser" et c'est bien "AdminToken" le token que je passe à "ImpersonateLoggedOnUser"...

  5. #5
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 941
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 941
    Par défaut
    Citation Envoyé par ZZZzzz2 Voir le message
    chez la plupart de nos clients le code fonctionne très bien, mais chez l'un d'eux cela coince.
    Et ce client utilise bien XP SP2 minimum ?
    ImpersonateLoggedOnUser est déclaré en statique dans Delphi mais en XP SP1 cette fonction n'existe pas. Cela expliquerait l'erreur de registres, l'appel d'un point d'entrée inexistant.

    Pour test, tu pourrais passer par un LoadLibrary de advapi32.dll, tester la présence de la fonction par GetProcAddress et le cas échéant, lever une exception.

    EDIT
    En fait c'est le privilège SeImpersonatePrivilege qui n'est pas supporté sous SP1. Donc pas sûr que ce que je raconte ci-dessus soit correct (mais un test par LoadLibrary ne mange pas de pain)

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Merci pour ta réponse et désolé pour la réponse tardive mais je suis en congés donc je n'ai pas planché de nouveau sur le soucis...

    De mémoire (car je ne peux pas le vérifier là) il s'agit de postes Windows 7, et comme tu le dis la fonction disponible à partir de Windows XP SP2 n'est pas la même : il s'agit de "SeImpersonatePrivilege " que je n'utilise pas... s'il y avait une erreur lors du chargement de la fonction d'une part on l'aurait au lancement de l'appli je pense (car les "externals" sont chargées au lancement sauf à utiliser le mot clé "delayed"), d'autre part les gars d'Embarcadero (ou CodeGear, ou Borland, je ne sais pas quand elle a fait son apparition dans Delphi) ne l'auraient probablement pas lié "statiquement" s'il y avait une possibilité que la fonction n'existe pas...

    Je penserai bien à un problème de convention d'appels qui n'est pas bon, mais alors pourquoi cela n'affecte que certains postes ? Est-il possible que la DLL système "Advapi32" soit alors dans une version qui utilise une convention d'appel différente de WINAPI sur cette fonction, ou peut-être un argument en moins ou plus ou je ne sais quoi qui décale le pointeur de la pile ou ce genre de choses ?...

Discussions similaires

  1. Listbox: comportement bizarre sur sélection
    Par jacquesprogram dans le forum Windows Presentation Foundation
    Réponses: 1
    Dernier message: 22/10/2014, 18h12
  2. Comportement bizarre sur un TEdit
    Par SergioMaster dans le forum Composants VCL
    Réponses: 3
    Dernier message: 27/09/2014, 08h15
  3. [ByRef Error] Erreur Bizarre sur appel de sub
    Par |DUCATI| DesMo dans le forum VBA Access
    Réponses: 1
    Dernier message: 21/05/2007, 11h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo