VirtualBox

Changeset 75725 in vbox


Ignore:
Timestamp:
Nov 25, 2018 7:18:32 PM (6 years ago)
Author:
vboxsync
Message:

IPRT/RTProcCreateEx: Quick darwin implementation using PAM. bugref:4802

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp

    r69111 r75725  
    6464#ifdef RT_OS_DARWIN
    6565# include <mach-o/dyld.h>
    66 #endif
     66# include <security/pam_appl.h>
     67# include <stdlib.h>
     68# include <dlfcn.h>
     69# include <iprt/asm.h>
     70#endif
     71
    6772#ifdef RT_OS_SOLARIS
    6873# include <limits.h>
     
    8893#include <iprt/err.h>
    8994#include <iprt/file.h>
     95#include <iprt/log.h>
    9096#include <iprt/path.h>
    9197#include <iprt/pipe.h>
     
    94100#include <iprt/mem.h>
    95101#include "internal/process.h"
     102
     103
     104/*********************************************************************************************************************************
     105*   Structures and Typedefs                                                                                                      *
     106*********************************************************************************************************************************/
     107#ifdef RT_OS_DARWIN
     108/** For passing info between rtCheckCredentials and rtPamConv. */
     109typedef struct RTPROCPAMARGS
     110{
     111    const char *pszUser;
     112    const char *pszPassword;
     113} RTPROCPAMARGS;
     114/** Pointer to rtPamConv argument package. */
     115typedef RTPROCPAMARGS *PRTPROCPAMARGS;
     116#endif
     117
     118
     119#ifdef RT_OS_DARWIN
     120/**
     121 * Worker for rtCheckCredentials that feeds password and maybe username to PAM.
     122 *
     123 * @returns PAM status.
     124 * @param   cMessages       Number of messages.
     125 * @param   papMessages     Message vector.
     126 * @param   ppaResponses    Where to put our responses.
     127 * @param   pvAppData       Pointer to RTPROCPAMARGS.
     128 */
     129static int rtPamConv(int cMessages, const struct pam_message **papMessages, struct pam_response **ppaResponses, void *pvAppData)
     130{
     131    LogFlow(("rtPamConv: cMessages=%d\n", cMessages));
     132    PRTPROCPAMARGS pArgs = (PRTPROCPAMARGS)pvAppData;
     133    AssertPtrReturn(pArgs, PAM_CONV_ERR);
     134
     135    struct pam_response *paResponses = (struct pam_response *)calloc(cMessages, sizeof(paResponses[0]));
     136    AssertReturn(paResponses,  PAM_CONV_ERR);
     137    for (int i = 0; i < cMessages; i++)
     138    {
     139        LogFlow(("rtPamConv: #%d: msg_style=%d msg=%s\n", i, papMessages[i]->msg_style, papMessages[i]->msg));
     140
     141        paResponses[i].resp_retcode = 0;
     142        if (papMessages[i]->msg_style == PAM_PROMPT_ECHO_OFF)
     143            paResponses[i].resp = strdup(pArgs->pszPassword);
     144        else if (papMessages[i]->msg_style == PAM_PROMPT_ECHO_ON)
     145            paResponses[i].resp = strdup(pArgs->pszUser);
     146        else
     147        {
     148            paResponses[i].resp = NULL;
     149            continue;
     150        }
     151        if (paResponses[i].resp == NULL)
     152        {
     153            while (i-- > 0)
     154                free(paResponses[i].resp);
     155            free(paResponses);
     156            LogFlow(("rtPamConv: out of memory\n"));
     157            return PAM_CONV_ERR;
     158        }
     159    }
     160
     161    *ppaResponses = paResponses;
     162    return PAM_SUCCESS;
     163}
     164#endif /* RT_OS_DARWIN */
    96165
    97166
     
    107176static int rtCheckCredentials(const char *pszUser, const char *pszPasswd, gid_t *pGid, uid_t *pUid)
    108177{
    109 #if defined(RT_OS_LINUX)
     178#if defined(RT_OS_DARWIN)
     179    RTLogPrintf("rtCheckCredentials\n");
     180
     181    /*
     182     * Resolve user to UID and GID.
     183     */
     184    char            szBuf[_4K];
     185    struct passwd   Pw;
     186    struct passwd  *pPw;
     187    if (getpwnam_r(pszUser, &Pw, szBuf, sizeof(szBuf), &pPw) != 0)
     188        return VERR_AUTHENTICATION_FAILURE;
     189    if (!pPw)
     190        return VERR_AUTHENTICATION_FAILURE;
     191
     192    *pUid = pPw->pw_uid;
     193    *pGid = pPw->pw_gid;
     194
     195    /*
     196     * Use PAM for the authentication.
     197     * Note! libpam.2.dylib was introduced with 10.6.x (OpenPAM).
     198     */
     199    void *hModPam = dlopen("libpam.dylib", RTLD_LAZY | RTLD_GLOBAL);
     200    if (hModPam)
     201    {
     202        int (*pfnPamStart)(const char *, const char *, struct pam_conv *, pam_handle_t **);
     203        int (*pfnPamAuthenticate)(pam_handle_t *, int);
     204        int (*pfnPamAcctMgmt)(pam_handle_t *, int);
     205        int (*pfnPamSetItem)(pam_handle_t *, int, const void *);
     206        int (*pfnPamEnd)(pam_handle_t *, int);
     207        *(void **)&pfnPamStart        = dlsym(hModPam, "pam_start");
     208        *(void **)&pfnPamAuthenticate = dlsym(hModPam, "pam_authenticate");
     209        *(void **)&pfnPamAcctMgmt     = dlsym(hModPam, "pam_acct_mgmt");
     210        *(void **)&pfnPamSetItem      = dlsym(hModPam, "pam_set_item");
     211        *(void **)&pfnPamEnd          = dlsym(hModPam, "pam_end");
     212        ASMCompilerBarrier();
     213        if (   pfnPamStart
     214            && pfnPamAuthenticate
     215            && pfnPamAcctMgmt
     216            && pfnPamSetItem
     217            && pfnPamEnd)
     218        {
     219#define pam_start           pfnPamStart
     220#define pam_authenticate    pfnPamAuthenticate
     221#define pam_acct_mgmt       pfnPamAcctMgmt
     222#define pam_set_item        pfnPamSetItem
     223#define pam_end             pfnPamEnd
     224
     225            /* Do the PAM stuff.
     226               Note! Abusing 'login' here for now... */
     227            pam_handle_t   *hPam        = NULL;
     228            RTPROCPAMARGS   PamConvArgs = { pszUser, pszPasswd };
     229            struct pam_conv PamConversation;
     230            RT_ZERO(PamConversation);
     231            PamConversation.appdata_ptr = &PamConvArgs;
     232            PamConversation.conv        = rtPamConv;
     233            int rc = pam_start("login", pszUser, &PamConversation, &hPam);
     234            if (rc == PAM_SUCCESS)
     235            {
     236                rc = pam_set_item(hPam, PAM_RUSER, pszUser);
     237                if (rc == PAM_SUCCESS)
     238                    rc = pam_authenticate(hPam, 0);
     239                if (rc == PAM_SUCCESS)
     240                {
     241                    rc = pam_acct_mgmt(hPam, 0);
     242                    if (   rc == PAM_SUCCESS
     243                        || rc == PAM_AUTHINFO_UNAVAIL /*??*/)
     244                    {
     245                        pam_end(hPam, PAM_SUCCESS);
     246                        dlclose(hModPam);
     247                        return VINF_SUCCESS;
     248                    }
     249                    Log(("rtCheckCredentials: pam_acct_mgmt -> %d\n", rc));
     250                }
     251                else
     252                    Log(("rtCheckCredentials: pam_authenticate -> %d\n", rc));
     253                pam_end(hPam, rc);
     254            }
     255            else
     256                Log(("rtCheckCredentials: pam_start -> %d\n", rc));
     257        }
     258        else
     259            Log(("rtCheckCredentials: failed to resolve symbols: %p %p %p %p %p\n",
     260                 pfnPamStart, pfnPamAuthenticate, pfnPamAcctMgmt, pfnPamSetItem, pfnPamEnd));
     261        dlclose(hModPam);
     262    }
     263    else
     264        Log(("rtCheckCredentials: Loading libpam.dylib failed\n"));
     265    return VERR_AUTHENTICATION_FAILURE;
     266
     267#elif defined(RT_OS_LINUX)
    110268    struct passwd *pw;
    111269
     
    172330}
    173331
    174 
    175332#ifdef RT_OS_SOLARIS
     333
    176334/** @todo the error reporting of the Solaris process contract code could be
    177335 * a lot better, but essentially it is not meant to run into errors after
     
    451609{
    452610    int rc;
     611    LogFlow(("RTProcCreateEx: pszExec=%s pszAsUser=%s\n", pszExec, pszAsUser));
    453612
    454613    /*
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette