Added IsSupportingRTP function to simplify detecting when STUN supports RTP
[pwlib.git] / src / ptclib / psasl.cxx
blob6a1340684befac63ac1796c48e2ec97398cd89ce
1 /*
2 * sasl.cxx
4 * Simple Authentication Security Layer interface classes
6 * Portable Windows Library
8 * Copyright (c) 2004 Reitek S.p.A.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Post Increment
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.5 2004/05/09 07:23:50 rjongbloed
28 * More work on XMPP, thanks Federico Pinna and Reitek S.p.A.
30 * Revision 1.4 2004/04/28 11:26:43 csoutheren
31 * Hopefully fixed SASL and SASL2 problems
33 * Revision 1.3 2004/04/24 06:27:56 rjongbloed
34 * Fixed GCC 3.4.0 warnings about PAssertNULL and improved recoverability on
35 * NULL pointer usage in various bits of code.
37 * Revision 1.2 2004/04/18 12:34:22 csoutheren
38 * Modified to compile under Unix
40 * Revision 1.1 2004/04/18 12:02:31 csoutheren
41 * Added classes for SASL authentication
42 * Thanks to Federico Pinna and Reitek S.p.A.
47 #ifdef __GNUC__
48 #pragma implementation "psasl.h"
49 #endif
51 #include <ptlib.h>
53 #include <ptclib/psasl.h>
54 #include <ptclib/cypher.h>
56 #if P_SASL2
58 extern "C" {
60 #if P_HAS_SASL_SASL_H
61 #include <sasl/sasl.h>
62 #else
63 #include <sasl.h>
64 #endif
69 #ifdef _MSC_VER
71 #pragma comment(lib, P_SASL_LIBRARY)
73 #endif
75 ///////////////////////////////////////////////////////
77 static int PSASL_ClientRealm(void *, int id, const char **, const char **result)
79 if (id != SASL_CB_GETREALM)
80 return SASL_FAIL;
82 *result = (const char *)PSASLClient::GetRealm();
83 return SASL_OK;
86 static int PSASL_ClientAuthID(void *context, int id, const char **result, unsigned *len)
88 if (id != SASL_CB_AUTHNAME)
89 return SASL_FAIL;
91 if (PAssertNULL(context) == NULL)
92 return SASL_FAIL;
94 const PSASLClient * c = (const PSASLClient *)context;
95 *result = (const char *)c->GetAuthID();
97 if (len)
98 *len = *result ? strlen(*result) : 0;
100 return SASL_OK;
103 static int PSASL_ClientUserID(void *context, int id, const char **result, unsigned *len)
105 if (id != SASL_CB_USER)
106 return SASL_FAIL;
108 if (PAssertNULL(context) == NULL)
109 return SASL_FAIL;
111 const PSASLClient * c = (const PSASLClient *)context;
112 *result = (const char *)c->GetUserID();
114 if (len)
115 *len = *result ? strlen(*result) : 0;
117 return SASL_OK;
120 static int PSASL_ClientPassword(sasl_conn_t *, void *context, int id, sasl_secret_t **psecret)
122 if (id != SASL_CB_PASS)
123 return SASL_FAIL;
125 if (PAssertNULL(context) == NULL)
126 return SASL_FAIL;
128 const PSASLClient * c = (const PSASLClient *)context;
129 const char * pwd = c->GetPassword();
131 if (!pwd)
132 return SASL_FAIL;
134 size_t len = strlen(pwd);
136 *psecret = (sasl_secret_t *)malloc(sizeof(sasl_secret_t) + len);
137 (*psecret)->len = len;
138 strcpy((char *)(*psecret)->data, pwd);
140 return SASL_OK;
143 static int PSASL_ClientGetPath(void *, const char ** path)
145 *path = (const char *)PSASLClient::GetPath();
146 return SASL_OK;
149 static int PSASL_ClientLog(void *, int priority, const char *message)
151 #if PTRACING
152 static const char * labels[7] = { "Error", "Fail", "Warning", "Note", "Debug", "Trace", "Pass" };
153 #endif
155 if (!message || priority > SASL_LOG_PASS)
156 return SASL_BADPARAM;
158 if (priority < SASL_LOG_ERR)
159 return SASL_OK;
161 PTRACE(priority, "SASL\t" << labels[priority - 1] << ": " << message);
163 return SASL_OK;
167 static void psasl_Initialise()
169 PINDEX max = PSASLClient::GetPath().IsEmpty() ? 3 : 4;
171 sasl_callback_t * cbs = new sasl_callback_t[max];
173 cbs[0].id = SASL_CB_GETREALM;
174 cbs[0].proc = (int (*)())&PSASL_ClientRealm;
175 cbs[0].context = 0;
177 cbs[1].id = SASL_CB_LOG;
178 cbs[1].proc = (int (*)())&PSASL_ClientLog;
179 cbs[1].context = 0;
181 if (max == 4) {
182 cbs[2].id = SASL_CB_GETPATH;
183 cbs[2].proc = (int (*)())&PSASL_ClientGetPath;
184 cbs[2].context = 0;
187 cbs[max - 1].id = SASL_CB_LIST_END;
188 cbs[max - 1].proc = 0;
189 cbs[max - 1].context = 0;
191 sasl_client_init(cbs);
194 static PAtomicInteger psasl_UsageCount(0);
195 PString PSASLClient::s_Realm;
196 PString PSASLClient::s_Path;
198 PSASLClient::PSASLClient(const PString& service, const PString& uid, const PString& auth, const PString& pwd) :
199 m_CallBacks(NULL),
200 m_ConnState(NULL),
201 m_Service(service),
202 m_UserID(uid.IsEmpty() ? auth : uid),
203 m_AuthID(auth.IsEmpty() ? uid : auth),
204 m_Password(pwd)
206 if (++psasl_UsageCount == 1)
207 psasl_Initialise();
211 PSASLClient::~PSASLClient()
213 if (m_ConnState)
214 End();
216 delete (sasl_callback_t *)m_CallBacks;
220 BOOL PSASLClient::Init(const PString& fqdn, PStringSet& supportedMechanisms)
222 if (!m_CallBacks)
224 sasl_callback_t * cbs = new sasl_callback_t[4];
226 cbs[0].id = SASL_CB_AUTHNAME;
227 cbs[0].proc = (int (*)())&PSASL_ClientAuthID;
228 cbs[0].context = this;
230 cbs[1].id = SASL_CB_USER;
231 cbs[1].proc = (int (*)())&PSASL_ClientUserID;
232 cbs[1].context = this;
234 cbs[2].id = SASL_CB_PASS;
235 cbs[2].proc = (int (*)())&PSASL_ClientPassword;
236 cbs[2].context = this;
238 cbs[3].id = SASL_CB_LIST_END;
239 cbs[3].proc = 0;
240 cbs[3].context = 0;
242 m_CallBacks = cbs;
245 if (m_ConnState)
246 End();
248 int result = sasl_client_new(m_Service, fqdn, 0, 0, (const sasl_callback_t *)m_CallBacks, 0, (sasl_conn_t **)&m_ConnState);
250 if (result != SASL_OK)
251 return FALSE;
253 const char * list;
254 unsigned plen;
255 int pcount;
257 sasl_listmech((sasl_conn_t *)m_ConnState, 0, 0, " ", 0, &list, &plen, &pcount);
259 PStringArray a = PString(list).Tokenise(" ");
261 for (PINDEX i = 0, max = a.GetSize() ; i < max ; i++)
262 supportedMechanisms.Include(a[i]);
264 return TRUE;
268 BOOL PSASLClient::Start(const PString& mechanism, PString& output)
270 const char * _output = 0;
271 unsigned _len = 0;
273 if (Start(mechanism, &_output, _len))
275 if (_output)
277 PBase64 b64;
278 b64.StartEncoding();
279 b64.ProcessEncoding(_output, _len);
280 output = b64.CompleteEncoding();
281 output.Replace("\r\n", PString::Empty(), TRUE);
284 return TRUE;
287 return FALSE;
291 BOOL PSASLClient::Start(const PString& mechanism, const char ** output, unsigned& len)
293 if (!m_ConnState)
294 return FALSE;
296 int result = sasl_client_start((sasl_conn_t *)m_ConnState, mechanism, 0, output, &len, 0);
298 if (result == SASL_OK || result == SASL_CONTINUE)
299 return TRUE;
301 return FALSE;
305 PSASLClient::PSASLResult PSASLClient::Negotiate(const PString& input, PString& output)
307 PBase64 b64;
309 b64.StartDecoding();
310 b64.ProcessDecoding(input);
312 PBYTEArray _bin_input = b64.GetDecodedData();
313 PString _input((const char *)(const BYTE *)_bin_input, _bin_input.GetSize());
315 const char * _output;
317 PSASLClient::PSASLResult result = Negotiate(_input, &_output);
319 if (_output)
321 b64.StartEncoding();
322 b64.ProcessEncoding(_output);
323 output = b64.CompleteEncoding();
324 output.Replace("\r\n", PString::Empty(), TRUE);
327 return result;
331 PSASLClient::PSASLResult PSASLClient::Negotiate(const char * input, const char ** output)
333 unsigned len;
335 int result = sasl_client_step((sasl_conn_t *)m_ConnState, input, strlen(input), 0, output, &len);
337 if (result != SASL_OK && result != SASL_CONTINUE)
338 return PSASLClient::Fail;
340 if (result == SASL_OK)
341 return PSASLClient::OK;
342 else
343 return PSASLClient::Continue;
347 BOOL PSASLClient::End()
349 if (m_ConnState)
351 sasl_dispose((sasl_conn_t **)&m_ConnState);
352 m_ConnState = 0;
353 return TRUE;
356 return FALSE;
359 #endif // P_SASL2
361 // End of File ///////////////////////////////////////////////////////////////