Back to index

lightning-sunbird  0.9+nobinonly
nsAuthSASL.cpp
Go to the documentation of this file.
00001 /* vim:set ts=4 sw=4 et cindent: */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is saslgssapi
00016  *
00017  * The Initial Developer of the Original Code is Simon Wilkinson
00018  * Portions created by the Initial Developer are Copyright (C) 2005
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Simon Wilkinson <simon@sxw.org.uk>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsComponentManagerUtils.h"
00039 #include "nsNativeCharsetUtils.h"
00040 #include "nsIServiceManager.h"
00041 #include "nsIPrefService.h"
00042 
00043 #include "nsAuthSASL.h"
00044 
00045 static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
00046 
00047 nsAuthSASL::nsAuthSASL()
00048 {
00049     mSASLReady = false;
00050 }
00051 
00052 void nsAuthSASL::Reset() 
00053 {
00054     mSASLReady = false;
00055 }
00056 
00057 NS_IMPL_ISUPPORTS1(nsAuthSASL, nsIAuthModule)
00058 
00059 NS_IMETHODIMP
00060 nsAuthSASL::Init(const char *serviceName,
00061                  PRUint32    serviceFlags,
00062                  const PRUnichar *domain,
00063                  const PRUnichar *username,
00064                  const PRUnichar *password)
00065 {
00066     nsresult rv;
00067     
00068     NS_ASSERTION(username, "SASL requires a username");
00069     NS_ASSERTION(!domain && !password, "unexpected credentials");
00070 
00071     mUsername = username;
00072     
00073     // If we're doing SASL, we should do mutual auth
00074     serviceFlags |= REQ_MUTUAL_AUTH;
00075    
00076     // Find out whether we should be trying SSPI or not
00077     const char *contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss";
00078     
00079     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
00080     if (prefs) {
00081         PRBool val;
00082         rv = prefs->GetBoolPref(kNegotiateAuthSSPI, &val);
00083         if (NS_SUCCEEDED(rv) && val)
00084             contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi";
00085     }
00086     
00087     mInnerModule = do_CreateInstance(contractID, &rv);
00088     // if we can't create the GSSAPI module, then bail
00089     NS_ENSURE_SUCCESS(rv, rv);
00090 
00091     mInnerModule->Init(serviceName, serviceFlags, nsnull, nsnull, nsnull);
00092 
00093     return NS_OK;
00094 }
00095 
00096 NS_IMETHODIMP
00097 nsAuthSASL::GetNextToken(const void *inToken,
00098                          PRUint32    inTokenLen,
00099                          void      **outToken,
00100                          PRUint32   *outTokenLen)
00101 {
00102     nsresult rv;
00103     void *unwrappedToken;
00104     char *message;
00105     PRUint32 unwrappedTokenLen, messageLen;
00106     nsCAutoString userbuf;
00107     
00108     if (!mInnerModule) 
00109         return NS_ERROR_NOT_INITIALIZED;
00110 
00111     if (mSASLReady) {
00112         // If the server COMPLETEs with an empty token, Cyrus sends us that token.
00113         // I don't think this is correct, but we need to handle that behaviour.
00114         // Cyrus ignores the contents of our reply token.
00115         if (inTokenLen == 0) {
00116             *outToken = NULL;
00117             *outTokenLen = 0;
00118             return NS_OK;
00119         }
00120         // We've completed the GSSAPI portion of the handshake, and are
00121         // now ready to do the SASL security layer and authzid negotiation
00122 
00123         // Input packet from the server needs to be unwrapped.
00124         rv = mInnerModule->Unwrap(inToken, inTokenLen, &unwrappedToken, 
00125                                   &unwrappedTokenLen);
00126         if (NS_FAILED(rv)) {
00127             Reset();
00128             return rv;
00129         }
00130         
00131         // If we were doing security layers then we'd care what the
00132         // server had sent us. We're not, so all we had to do was make
00133         // sure that the signature was correct with the above unwrap()
00134         nsMemory::Free(unwrappedToken);
00135         
00136         NS_CopyUnicodeToNative(mUsername, userbuf);
00137         messageLen = userbuf.Length() + 4 + 1;
00138         message = (char *)nsMemory::Alloc(messageLen);
00139         if (!message) {
00140           Reset();
00141           return NS_ERROR_OUT_OF_MEMORY;
00142         }
00143         message[0] = 0x01; // No security layer
00144         message[1] = 0x00;
00145         message[2] = 0x00;
00146         message[3] = 0x00; // Maxbuf must be zero if we've got no sec layer
00147         strcpy(message+4, userbuf.get());
00148         // Userbuf should not be NULL terminated, so trim the trailing NULL
00149         // when wrapping the message
00150         rv = mInnerModule->Wrap((void *) message, messageLen-1, PR_FALSE, 
00151                                 outToken, outTokenLen);
00152         nsMemory::Free(message);
00153         Reset(); // All done
00154         return NS_SUCCEEDED(rv) ? NS_SUCCESS_AUTH_FINISHED : rv;
00155     }
00156     rv = mInnerModule->GetNextToken(inToken, inTokenLen, outToken, 
00157                                     outTokenLen);
00158     if (rv == NS_SUCCESS_AUTH_FINISHED) {
00159         mSASLReady = true;
00160         rv = NS_OK;
00161     }
00162     return rv;
00163 }
00164 
00165 NS_IMETHODIMP
00166 nsAuthSASL::Unwrap(const void *inToken,
00167                    PRUint32    inTokenLen,
00168                    void      **outToken,
00169                    PRUint32   *outTokenLen)
00170 {
00171     return NS_ERROR_NOT_IMPLEMENTED;
00172 }
00173 
00174 NS_IMETHODIMP
00175 nsAuthSASL::Wrap(const void *inToken,
00176                  PRUint32    inTokenLen,
00177                  PRBool      confidential,
00178                  void      **outToken,
00179                  PRUint32   *outTokenLen)
00180 {
00181     return NS_ERROR_NOT_IMPLEMENTED;
00182 }