LCOV - code coverage report
Current view: directory - extensions/auth - nsAuthSambaNTLM.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 145 0 0.0 %
Date: 2012-06-02 Functions: 15 0 0.0 %

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

Generated by: LCOV version 1.7