VirtualBox

Ignore:
Timestamp:
Aug 26, 2011 12:32:27 PM (13 years ago)
Author:
vboxsync
Message:

pam_vbox: Implemented threaded waiting without the need to explicitly set a beacon.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/pam/pam_vbox.cpp

    r38486 r38545  
    4747#include <iprt/stream.h>
    4848#include <iprt/string.h>
     49#include <iprt/thread.h>
     50#include <iprt/time.h>
    4951
    5052#include <VBox/VBoxGuestLib.h>
     
    6567static int g_verbosity = 0;
    6668#endif
     69
     70/**
     71 * User-provided thread data for the credentials waiting thread.
     72 */
     73typedef struct PAMVBOXTHREAD
     74{
     75    /** The PAM handle. */
     76    pam_handle_t *hPAM;
     77    /** The timeout (in ms) to wait for credentials. */
     78    uint32_t      uTimeoutMS;
     79    /** The overall result of the thread operation. */
     80    int           rc;
     81} PAMVBOXTHREAD, *PPAMVBOXTHREAD;
    6782
    6883/**
     
    261276    if (RT_FAILURE(rc))
    262277    {
    263         if (rc == VERR_NOT_FOUND)
     278        if (rc != VERR_NOT_FOUND)
     279            pam_vbox_error(hPAM, "pam_vbox_check_creds: could not query for credentials! rc=%Rrc. Aborting\n", rc);
     280#ifdef DEBUG
     281        else
    264282            pam_vbox_log(hPAM, "pam_vbox_check_creds: no credentials available\n");
    265         else
    266             pam_vbox_error(hPAM, "pam_vbox_check_creds: could not query for credentials! rc=%Rrc. Aborting\n", rc);
     283#endif
    267284    }
    268285    else
     
    300317                    pam_vbox_error(hPAM, "pam_vbox_check_creds: could not set password! pamrc=%d, msg=%s. Aborting\n",
    301318                                   pamrc, pam_strerror(hPAM, pamrc));
     319
    302320            }
    303321            /** @todo Add handling domains as well. */
    304 
    305322            VbglR3CredentialsDestroy(pszUsername, pszPassword, pszDomain,
    306323                                     3 /* Three wipe passes */);
    307            pam_vbox_log(hPAM, "pam_vbox_check_creds: returned with pamrc=%d, msg=%s\n",
    308                         pamrc, pam_strerror(hPAM, pamrc));
    309         }
    310     }
    311 
     324            pam_vbox_log(hPAM, "pam_vbox_check_creds: returned with pamrc=%d, msg=%s\n",
     325                         pamrc, pam_strerror(hPAM, pamrc));
     326        }
     327    }
     328
     329#ifdef DEBUG
    312330    pam_vbox_log(hPAM, "pam_vbox_check_creds: returned with rc=%Rrc\n", rc);
     331#endif
    313332    return rc;
    314333}
    315334
     335
    316336#ifdef VBOX_WITH_GUEST_PROPS
    317 static int pam_vbox_wait_for_creds(pam_handle_t *hPAM, uint32_t uClientID, uint32_t uTimeoutMS)
    318 {
    319     int rc;
    320 
    321     /* The buffer for storing the data and its initial size.  We leave a bit
    322      * of space here in case the maximum values are raised. */
    323     void *pvBuf = NULL;
    324     uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K;
    325 
    326     pam_vbox_log(hPAM, "Waiting for credentials (%dms) ...\n", uTimeoutMS);
    327 
    328     int i;
    329     for (i = 0; i < 10; i++)
    330     {
    331         void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
    332         if (pvTmpBuf)
    333         {
    334             char *pszName = NULL;
    335             char *pszValue = NULL;
    336             uint64_t u64TimestampOut = 0;
    337             char *pszFlags = NULL;
    338 
    339             pvBuf = pvTmpBuf;
    340             rc = VbglR3GuestPropWait(uClientID, "/VirtualBox/GuestAdd/PAM/CredsChanged", pvBuf, cbBuf,
    341                                      0 /* Last timestamp; just wait for next event */, uTimeoutMS,
    342                                      &pszName, &pszValue, &u64TimestampOut,
    343                                      &pszFlags, &cbBuf);
    344         }
    345         else
    346             rc = VERR_NO_MEMORY;
    347 
    348         switch (rc)
    349         {
    350             case VINF_SUCCESS:
    351                 pam_vbox_error(hPAM, "Got notification for supplied credentials\n");
    352                 break;
    353 
    354             case VERR_BUFFER_OVERFLOW:
    355             {
    356                 /* Buffer too small, try it with a bigger one next time. */
    357                 cbBuf += _1K;
    358                 continue; /* Try next round. */
    359             }
    360 
    361             case VERR_INTERRUPTED:
    362                 pam_vbox_error(hPAM, "The credentials notification request timed out or was interrupted\n");
    363                 break;
    364 
    365             case VERR_TIMEOUT:
    366                 pam_vbox_error(hPAM, "Credentials did not arrive within time (%dms)\n", uTimeoutMS);
    367                 break;
    368 
    369             case VERR_TOO_MUCH_DATA:
    370                 pam_vbox_error(hPAM, "Temporarily unable to get credentials notification\n");
    371                 break;
    372 
    373             default:
    374                 pam_vbox_error(hPAM, "The credentials notification request failed with rc=%Rrc\n", rc);
    375                 break;
    376         }
    377 
    378         /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
    379         break;
    380     }
    381 
    382     pam_vbox_log(hPAM, "Waiting for credentials returned with rc=%Rrc\n", rc);
    383     return rc;
    384 }
    385 
    386337static int pam_vbox_read_prop(pam_handle_t *hPAM, uint32_t uClientID,
    387338                              const char *pszKey, bool fReadOnly,
    388339                              char *pszValue, size_t cbValue)
    389340{
     341    AssertPtrReturn(hPAM, VERR_INVALID_POINTER);
    390342    AssertReturn(uClientID, VERR_INVALID_PARAMETER);
    391343    AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
     
    474426    return rc;
    475427}
    476 #endif
     428
     429
     430static int pam_vbox_wait_prop(pam_handle_t *hPAM, uint32_t uClientID,
     431                              const char *pszKey, uint32_t uTimeoutMS)
     432{
     433    AssertPtrReturn(hPAM, VERR_INVALID_POINTER);
     434    AssertReturn(uClientID, VERR_INVALID_PARAMETER);
     435    AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
     436
     437    int rc;
     438
     439    /* The buffer for storing the data and its initial size.  We leave a bit
     440     * of space here in case the maximum values are raised. */
     441    void *pvBuf = NULL;
     442    uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K;
     443
     444    for (int i = 0; i < 10; i++)
     445    {
     446        void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
     447        if (pvTmpBuf)
     448        {
     449            char *pszName = NULL;
     450            char *pszValue = NULL;
     451            uint64_t u64TimestampOut = 0;
     452            char *pszFlags = NULL;
     453
     454            pvBuf = pvTmpBuf;
     455            rc = VbglR3GuestPropWait(uClientID, pszKey, pvBuf, cbBuf,
     456                                     0 /* Last timestamp; just wait for next event */, uTimeoutMS,
     457                                     &pszName, &pszValue, &u64TimestampOut,
     458                                     &pszFlags, &cbBuf);
     459        }
     460        else
     461            rc = VERR_NO_MEMORY;
     462
     463        if (rc == VERR_BUFFER_OVERFLOW)
     464        {
     465            /* Buffer too small, try it with a bigger one next time. */
     466            cbBuf += _1K;
     467            continue; /* Try next round. */
     468        }
     469
     470        /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
     471        break;
     472    }
     473
     474    return rc;
     475}
     476#endif
     477
     478
     479static DECLCALLBACK(int) pam_vbox_wait_thread(RTTHREAD ThreadSelf, void *pvUser)
     480{
     481    PPAMVBOXTHREAD pUserData = (PPAMVBOXTHREAD)pvUser;
     482    AssertPtr(pUserData);
     483
     484    int rc = VINF_SUCCESS;
     485    /* Get current time stamp to later calculate rest of timeout left. */
     486    uint64_t u64StartMS = RTTimeMilliTS();
     487
     488#ifdef VBOX_WITH_GUEST_PROPS
     489    uint32_t uClientID = 0;
     490    rc = VbglR3GuestPropConnect(&uClientID);
     491    if (RT_FAILURE(rc))
     492    {
     493        pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: Unable to connect to guest property service, rc=%Rrc\n", rc);
     494    }
     495    else
     496    {
     497        pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: clientID=%u\n", uClientID);
     498#endif
     499        for (;;)
     500        {
     501#ifdef VBOX_WITH_GUEST_PROPS
     502            if (uClientID)
     503            {
     504                rc = pam_vbox_wait_prop(pUserData->hPAM, uClientID,
     505                                        "/VirtualBox/GuestAdd/PAM/CredsWaitAbort",
     506                                        500 /* Wait 500ms, same as VBoxGINA/VBoxCredProv. */);
     507                switch (rc)
     508                {
     509                    case VINF_SUCCESS:
     510                        /* Somebody (guest/host) wants to abort waiting for credentials. */
     511                        break;
     512
     513                    case VERR_INTERRUPTED:
     514                        pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: The abort notification request timed out or was interrupted\n");
     515                        break;
     516
     517                    case VERR_TIMEOUT:
     518                        /* We did not receive an abort message within time. */
     519                        break;
     520
     521                    case VERR_TOO_MUCH_DATA:
     522                        pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: Temporarily unable to get abort notification\n");
     523                        break;
     524
     525                    default:
     526                        pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: The abort notification request failed with rc=%Rrc\n", rc);
     527                        break;
     528                }
     529
     530                if (RT_SUCCESS(rc)) /* Abort waiting. */
     531                {
     532                    pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: Got notification to abort waiting\n");
     533                    rc = VERR_CANCELLED;
     534                    break;
     535                }
     536            }
     537#endif
     538            if (   RT_SUCCESS(rc)
     539                || rc == VERR_TIMEOUT)
     540            {
     541                rc = pam_vbox_check_creds(pUserData->hPAM);
     542                if (RT_SUCCESS(rc))
     543                {
     544                    /* Credentials retrieved. */
     545                    break; /* Thread no longer is required, bail out. */
     546                }
     547                else if (rc == VERR_NOT_FOUND)
     548                {
     549                    /* No credentials found, but try next round (if there's
     550                     * time left for) ... */
     551#ifndef VBOX_WITH_GUEST_PROPS
     552                    RTThreadSleep(500); /* Wait 500 ms. */
     553#endif
     554                }
     555                else
     556                    break; /* Something bad happend ... */
     557            }
     558            else
     559                break;
     560
     561            /* Calculate timeout value left after process has been started.  */
     562            uint64_t u64Elapsed = RTTimeMilliTS() - u64StartMS;
     563            /* Is it time to bail out? */
     564            if (pUserData->uTimeoutMS < u64Elapsed)
     565            {
     566                pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: Waiting thread has reached timeout (%dms), exiting ...\n",
     567                             pUserData->uTimeoutMS);
     568                rc = VERR_TIMEOUT;
     569                break;
     570            }
     571        }
     572#ifdef VBOX_WITH_GUEST_PROPS
     573    }
     574    VbglR3GuestPropDisconnect(uClientID);
     575#endif
     576
     577    /* Save result. */
     578    pUserData->rc = rc; /** @todo Use ASMAtomicXXX? */
     579
     580    int rc2 = RTThreadUserSignal(RTThreadSelf());
     581    AssertRC(rc2);
     582
     583    pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: Waiting thread returned with rc=%Rrc\n", rc);
     584    return rc;
     585}
     586
     587
     588static int pam_vbox_wait_for_creds(pam_handle_t *hPAM, uint32_t uClientID, uint32_t uTimeoutMS)
     589{
     590    PAMVBOXTHREAD threadData;
     591    threadData.hPAM = hPAM;
     592    threadData.uTimeoutMS = uTimeoutMS;
     593
     594    RTTHREAD threadWait;
     595    int rc = RTThreadCreate(&threadWait, pam_vbox_wait_thread,
     596                            (void *)&threadData, 0,
     597                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "pam_vbox");
     598    if (RT_SUCCESS(rc))
     599    {
     600        pam_vbox_log(hPAM, "pam_vbox_wait_for_creds: Waiting for credentials (%dms) ...\n", uTimeoutMS);
     601        /* Wait for thread to initialize. */
     602        rc = RTThreadUserWait(threadWait, RT_INDEFINITE_WAIT);
     603        if (RT_SUCCESS(rc))
     604            rc = threadData.rc; /* Get back thread result to take further actions. */
     605    }
     606    else
     607        pam_vbox_error(hPAM, "pam_vbox_wait_for_creds: Creating thread failed with rc=%Rrc\n", rc);
     608
     609    pam_vbox_log(hPAM, "pam_vbox_wait_for_creds: Waiting for credentials returned with rc=%Rrc\n", rc);
     610    return rc;
     611}
    477612
    478613
     
    563698                    else if (rc == VERR_TIMEOUT)
    564699                    {
    565                         pam_vbox_log(hPAM, "pam_sm_authenticate: no credentials given within time\n", rc);
     700                        pam_vbox_log(hPAM, "pam_sm_authenticate: no credentials given within time\n");
    566701
    567702                        rc2 = pam_vbox_read_prop(hPAM, uClientId,
     
    570705                                                 szVal, sizeof(szVal));
    571706                        if (RT_SUCCESS(rc2))
     707                        {
    572708                            rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal);
     709                            AssertRC(rc2);
     710                        }
     711                    }
     712                    else if (rc == VERR_CANCELLED)
     713                    {
     714                        pam_vbox_log(hPAM, "pam_sm_authenticate: waiting aborted\n");
     715
     716                        rc2 = pam_vbox_read_prop(hPAM, uClientId,
     717                                                 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort",
     718                                                 true /* Read-only on guest */,
     719                                                 szVal, sizeof(szVal));
     720                        if (RT_SUCCESS(rc2))
     721                        {
     722                            rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal);
     723                            AssertRC(rc2);
     724                        }
    573725                    }
    574726                }
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