LCOV - code coverage report
Current view: top level - extensions/auth - nsAuthSambaNTLM.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 151 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* vim:set ts=4 sw=4 et cindent: */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsAuth.h"
       7             : #include "nsAuthSambaNTLM.h"
       8             : #include "prenv.h"
       9             : #include "plbase64.h"
      10             : #include "prerror.h"
      11             : #include "mozilla/Telemetry.h"
      12             : 
      13             : #include <stdlib.h>
      14             : 
      15           0 : nsAuthSambaNTLM::nsAuthSambaNTLM()
      16             :     : mInitialMessage(nullptr), mChildPID(nullptr), mFromChildFD(nullptr),
      17           0 :       mToChildFD(nullptr)
      18             : {
      19           0 : }
      20             : 
      21           0 : nsAuthSambaNTLM::~nsAuthSambaNTLM()
      22             : {
      23             :     // ntlm_auth reads from stdin regularly so closing our file handles
      24             :     // should cause it to exit.
      25           0 :     Shutdown();
      26           0 :     free(mInitialMessage);
      27           0 : }
      28             : 
      29             : void
      30           0 : nsAuthSambaNTLM::Shutdown()
      31             : {
      32           0 :     if (mFromChildFD) {
      33           0 :         PR_Close(mFromChildFD);
      34           0 :         mFromChildFD = nullptr;
      35             :     }
      36           0 :     if (mToChildFD) {
      37           0 :         PR_Close(mToChildFD);
      38           0 :         mToChildFD = nullptr;
      39             :     }
      40           0 :     if (mChildPID) {
      41             :         int32_t exitCode;
      42           0 :         PR_WaitProcess(mChildPID, &exitCode);
      43           0 :         mChildPID = nullptr;
      44             :     }
      45           0 : }
      46             : 
      47           0 : NS_IMPL_ISUPPORTS(nsAuthSambaNTLM, nsIAuthModule)
      48             : 
      49             : static bool
      50           0 : SpawnIOChild(char* const* aArgs, PRProcess** aPID,
      51             :              PRFileDesc** aFromChildFD, PRFileDesc** aToChildFD)
      52             : {
      53             :     PRFileDesc* toChildPipeRead;
      54             :     PRFileDesc* toChildPipeWrite;
      55           0 :     if (PR_CreatePipe(&toChildPipeRead, &toChildPipeWrite) != PR_SUCCESS)
      56           0 :         return false;
      57           0 :     PR_SetFDInheritable(toChildPipeRead, true);
      58           0 :     PR_SetFDInheritable(toChildPipeWrite, false);
      59             : 
      60             :     PRFileDesc* fromChildPipeRead;
      61             :     PRFileDesc* fromChildPipeWrite;
      62           0 :     if (PR_CreatePipe(&fromChildPipeRead, &fromChildPipeWrite) != PR_SUCCESS) {
      63           0 :         PR_Close(toChildPipeRead);
      64           0 :         PR_Close(toChildPipeWrite);
      65           0 :         return false;
      66             :     }
      67           0 :     PR_SetFDInheritable(fromChildPipeRead, false);
      68           0 :     PR_SetFDInheritable(fromChildPipeWrite, true);
      69             : 
      70           0 :     PRProcessAttr* attr = PR_NewProcessAttr();
      71           0 :     if (!attr) {
      72           0 :         PR_Close(fromChildPipeRead);
      73           0 :         PR_Close(fromChildPipeWrite);
      74           0 :         PR_Close(toChildPipeRead);
      75           0 :         PR_Close(toChildPipeWrite);
      76           0 :         return false;
      77             :     }
      78             : 
      79           0 :     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, toChildPipeRead);
      80           0 :     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, fromChildPipeWrite);
      81             : 
      82           0 :     PRProcess* process = PR_CreateProcess(aArgs[0], aArgs, nullptr, attr);
      83           0 :     PR_DestroyProcessAttr(attr);
      84           0 :     PR_Close(fromChildPipeWrite);
      85           0 :     PR_Close(toChildPipeRead);
      86           0 :     if (!process) {
      87           0 :         LOG(("ntlm_auth exec failure [%d]", PR_GetError()));
      88           0 :         PR_Close(fromChildPipeRead);
      89           0 :         PR_Close(toChildPipeWrite);
      90           0 :         return false;
      91             :     }
      92             : 
      93           0 :     *aPID = process;
      94           0 :     *aFromChildFD = fromChildPipeRead;
      95           0 :     *aToChildFD = toChildPipeWrite;
      96           0 :     return true;
      97             : }
      98             : 
      99           0 : static bool WriteString(PRFileDesc* aFD, const nsACString& aString)
     100             : {
     101           0 :     int32_t length = aString.Length();
     102           0 :     const char* s = aString.BeginReading();
     103           0 :     LOG(("Writing to ntlm_auth: %s", s));
     104             : 
     105           0 :     while (length > 0) {
     106           0 :         int result = PR_Write(aFD, s, length);
     107           0 :         if (result <= 0)
     108           0 :             return false;
     109           0 :         s += result;
     110           0 :         length -= result;
     111             :     }
     112           0 :     return true;
     113             : }
     114             : 
     115           0 : static bool ReadLine(PRFileDesc* aFD, nsACString& aString)
     116             : {
     117             :     // ntlm_auth is defined to only send one line in response to each of our
     118             :     // input lines. So this simple unbuffered strategy works as long as we
     119             :     // read the response immediately after sending one request.
     120           0 :     aString.Truncate();
     121             :     for (;;) {
     122             :         char buf[1024];
     123           0 :         int result = PR_Read(aFD, buf, sizeof(buf));
     124           0 :         if (result <= 0)
     125           0 :             return false;
     126           0 :         aString.Append(buf, result);
     127           0 :         if (buf[result - 1] == '\n') {
     128           0 :             LOG(("Read from ntlm_auth: %s", nsPromiseFlatCString(aString).get()));
     129           0 :             return true;
     130             :         }
     131           0 :     }
     132             : }
     133             : 
     134             : /**
     135             :  * Returns a heap-allocated array of PRUint8s, and stores the length in aLen.
     136             :  * Returns nullptr if there's an error of any kind.
     137             :  */
     138           0 : static uint8_t* ExtractMessage(const nsACString& aLine, uint32_t* aLen)
     139             : {
     140             :     // ntlm_auth sends blobs to us as base64-encoded strings after the "xx "
     141             :     // preamble on the response line.
     142           0 :     int32_t length = aLine.Length();
     143             :     // The caller should verify there is a valid "xx " prefix and the line
     144             :     // is terminated with a \n
     145           0 :     NS_ASSERTION(length >= 4, "Line too short...");
     146           0 :     const char* line = aLine.BeginReading();
     147           0 :     const char* s = line + 3;
     148           0 :     length -= 4; // lose first 3 chars plus trailing \n
     149           0 :     NS_ASSERTION(s[length] == '\n', "aLine not newline-terminated");
     150             : 
     151           0 :     if (length & 3) {
     152             :         // The base64 encoded block must be multiple of 4. If not, something
     153             :         // screwed up.
     154           0 :         NS_WARNING("Base64 encoded block should be a multiple of 4 chars");
     155           0 :         return nullptr;
     156             :     }
     157             : 
     158             :     // Calculate the exact length. I wonder why there isn't a function for this
     159             :     // in plbase64.
     160             :     int32_t numEquals;
     161           0 :     for (numEquals = 0; numEquals < length; ++numEquals) {
     162           0 :         if (s[length - 1 - numEquals] != '=')
     163           0 :             break;
     164             :     }
     165           0 :     *aLen = (length/4)*3 - numEquals;
     166           0 :     return reinterpret_cast<uint8_t*>(PL_Base64Decode(s, length, nullptr));
     167             : }
     168             : 
     169             : nsresult
     170           0 : nsAuthSambaNTLM::SpawnNTLMAuthHelper()
     171             : {
     172           0 :     const char* username = PR_GetEnv("USER");
     173           0 :     if (!username)
     174           0 :         return NS_ERROR_FAILURE;
     175             : 
     176             :     const char* const args[] = {
     177             :         "ntlm_auth",
     178             :         "--helper-protocol", "ntlmssp-client-1",
     179             :         "--use-cached-creds",
     180             :         "--username", username,
     181             :         nullptr
     182           0 :     };
     183             : 
     184           0 :     bool isOK = SpawnIOChild(const_cast<char* const*>(args), &mChildPID, &mFromChildFD, &mToChildFD);
     185           0 :     if (!isOK)
     186           0 :         return NS_ERROR_FAILURE;
     187             : 
     188           0 :     if (!WriteString(mToChildFD, NS_LITERAL_CSTRING("YR\n")))
     189           0 :         return NS_ERROR_FAILURE;
     190           0 :     nsCString line;
     191           0 :     if (!ReadLine(mFromChildFD, line))
     192           0 :         return NS_ERROR_FAILURE;
     193           0 :     if (!StringBeginsWith(line, NS_LITERAL_CSTRING("YR "))) {
     194             :         // Something went wrong. Perhaps no credentials are accessible.
     195           0 :         return NS_ERROR_FAILURE;
     196             :     }
     197             : 
     198             :     // It gave us an initial client-to-server request packet. Save that
     199             :     // because we'll need it later.
     200           0 :     mInitialMessage = ExtractMessage(line, &mInitialMessageLen);
     201           0 :     if (!mInitialMessage)
     202           0 :         return NS_ERROR_FAILURE;
     203           0 :     return NS_OK;
     204             : }
     205             : 
     206             : NS_IMETHODIMP
     207           0 : nsAuthSambaNTLM::Init(const char *serviceName,
     208             :                       uint32_t    serviceFlags,
     209             :                       const char16_t *domain,
     210             :                       const char16_t *username,
     211             :                       const char16_t *password)
     212             : {
     213           0 :     NS_ASSERTION(!username && !domain && !password, "unexpected credentials");
     214             : 
     215             :     static bool sTelemetrySent = false;
     216           0 :     if (!sTelemetrySent) {
     217           0 :         mozilla::Telemetry::Accumulate(
     218             :             mozilla::Telemetry::NTLM_MODULE_USED_2,
     219           0 :             serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
     220             :                 ? NTLM_MODULE_SAMBA_AUTH_PROXY
     221           0 :                 : NTLM_MODULE_SAMBA_AUTH_DIRECT);
     222           0 :         sTelemetrySent = true;
     223             :     }
     224             : 
     225           0 :     return NS_OK;
     226             : }
     227             : 
     228             : NS_IMETHODIMP
     229           0 : nsAuthSambaNTLM::GetNextToken(const void *inToken,
     230             :                               uint32_t    inTokenLen,
     231             :                               void      **outToken,
     232             :                               uint32_t   *outTokenLen)
     233             : {
     234           0 :     if (!inToken) {
     235             :         /* someone wants our initial message */
     236           0 :         *outToken = nsMemory::Clone(mInitialMessage, mInitialMessageLen);
     237           0 :         if (!*outToken)
     238           0 :             return NS_ERROR_OUT_OF_MEMORY;
     239           0 :         *outTokenLen = mInitialMessageLen;
     240           0 :         return NS_OK;
     241             :     }
     242             : 
     243             :     /* inToken must be a type 2 message. Get ntlm_auth to generate our response */
     244           0 :     char* encoded = PL_Base64Encode(static_cast<const char*>(inToken), inTokenLen, nullptr);
     245           0 :     if (!encoded)
     246           0 :         return NS_ERROR_OUT_OF_MEMORY;
     247             : 
     248           0 :     nsCString request;
     249           0 :     request.AssignLiteral("TT ");
     250           0 :     request.Append(encoded);
     251           0 :     free(encoded);
     252           0 :     request.Append('\n');
     253             : 
     254           0 :     if (!WriteString(mToChildFD, request))
     255           0 :         return NS_ERROR_FAILURE;
     256           0 :     nsCString line;
     257           0 :     if (!ReadLine(mFromChildFD, line))
     258           0 :         return NS_ERROR_FAILURE;
     259           0 :     if (!StringBeginsWith(line, NS_LITERAL_CSTRING("KK ")) &&
     260           0 :         !StringBeginsWith(line, NS_LITERAL_CSTRING("AF "))) {
     261             :         // Something went wrong. Perhaps no credentials are accessible.
     262           0 :         return NS_ERROR_FAILURE;
     263             :     }
     264           0 :     uint8_t* buf = ExtractMessage(line, outTokenLen);
     265           0 :     if (!buf)
     266           0 :         return NS_ERROR_FAILURE;
     267           0 :     *outToken = nsMemory::Clone(buf, *outTokenLen);
     268           0 :     free(buf);
     269           0 :     if (!*outToken) {
     270           0 :         return NS_ERROR_OUT_OF_MEMORY;
     271             :     }
     272             : 
     273             :     // We're done. Close our file descriptors now and reap the helper
     274             :     // process.
     275           0 :     Shutdown();
     276           0 :     return NS_SUCCESS_AUTH_FINISHED;
     277             : }
     278             : 
     279             : NS_IMETHODIMP
     280           0 : nsAuthSambaNTLM::Unwrap(const void *inToken,
     281             :                         uint32_t    inTokenLen,
     282             :                         void      **outToken,
     283             :                         uint32_t   *outTokenLen)
     284             : {
     285           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     286             : }
     287             : 
     288             : NS_IMETHODIMP
     289           0 : nsAuthSambaNTLM::Wrap(const void *inToken,
     290             :                       uint32_t    inTokenLen,
     291             :                       bool        confidential,
     292             :                       void      **outToken,
     293             :                       uint32_t   *outTokenLen)
     294             : {
     295           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     296             : }

Generated by: LCOV version 1.13