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
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Post Increment
24 * Contributor(s): ______________________________________.
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.
48 #pragma implementation "psasl.h"
53 #include <ptclib/psasl.h>
54 #include <ptclib/cypher.h>
61 #include <sasl/sasl.h>
71 #pragma comment(lib, P_SASL_LIBRARY)
75 ///////////////////////////////////////////////////////
77 static int PSASL_ClientRealm(void *, int id
, const char **, const char **result
)
79 if (id
!= SASL_CB_GETREALM
)
82 *result
= (const char *)PSASLClient::GetRealm();
86 static int PSASL_ClientAuthID(void *context
, int id
, const char **result
, unsigned *len
)
88 if (id
!= SASL_CB_AUTHNAME
)
91 if (PAssertNULL(context
) == NULL
)
94 const PSASLClient
* c
= (const PSASLClient
*)context
;
95 *result
= (const char *)c
->GetAuthID();
98 *len
= *result
? strlen(*result
) : 0;
103 static int PSASL_ClientUserID(void *context
, int id
, const char **result
, unsigned *len
)
105 if (id
!= SASL_CB_USER
)
108 if (PAssertNULL(context
) == NULL
)
111 const PSASLClient
* c
= (const PSASLClient
*)context
;
112 *result
= (const char *)c
->GetUserID();
115 *len
= *result
? strlen(*result
) : 0;
120 static int PSASL_ClientPassword(sasl_conn_t
*, void *context
, int id
, sasl_secret_t
**psecret
)
122 if (id
!= SASL_CB_PASS
)
125 if (PAssertNULL(context
) == NULL
)
128 const PSASLClient
* c
= (const PSASLClient
*)context
;
129 const char * pwd
= c
->GetPassword();
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
);
143 static int PSASL_ClientGetPath(void *, const char ** path
)
145 *path
= (const char *)PSASLClient::GetPath();
149 static int PSASL_ClientLog(void *, int priority
, const char *message
)
152 static const char * labels
[7] = { "Error", "Fail", "Warning", "Note", "Debug", "Trace", "Pass" };
155 if (!message
|| priority
> SASL_LOG_PASS
)
156 return SASL_BADPARAM
;
158 if (priority
< SASL_LOG_ERR
)
161 PTRACE(priority
, "SASL\t" << labels
[priority
- 1] << ": " << message
);
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
;
177 cbs
[1].id
= SASL_CB_LOG
;
178 cbs
[1].proc
= (int (*)())&PSASL_ClientLog
;
182 cbs
[2].id
= SASL_CB_GETPATH
;
183 cbs
[2].proc
= (int (*)())&PSASL_ClientGetPath
;
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
) :
202 m_UserID(uid
.IsEmpty() ? auth
: uid
),
203 m_AuthID(auth
.IsEmpty() ? uid
: auth
),
206 if (++psasl_UsageCount
== 1)
211 PSASLClient::~PSASLClient()
216 delete (sasl_callback_t
*)m_CallBacks
;
220 BOOL
PSASLClient::Init(const PString
& fqdn
, PStringSet
& supportedMechanisms
)
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
;
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
)
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
]);
268 BOOL
PSASLClient::Start(const PString
& mechanism
, PString
& output
)
270 const char * _output
= 0;
273 if (Start(mechanism
, &_output
, _len
))
279 b64
.ProcessEncoding(_output
, _len
);
280 output
= b64
.CompleteEncoding();
281 output
.Replace("\r\n", PString::Empty(), TRUE
);
291 BOOL
PSASLClient::Start(const PString
& mechanism
, const char ** output
, unsigned& len
)
296 int result
= sasl_client_start((sasl_conn_t
*)m_ConnState
, mechanism
, 0, output
, &len
, 0);
298 if (result
== SASL_OK
|| result
== SASL_CONTINUE
)
305 PSASLClient::PSASLResult
PSASLClient::Negotiate(const PString
& input
, PString
& output
)
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
);
322 b64
.ProcessEncoding(_output
);
323 output
= b64
.CompleteEncoding();
324 output
.Replace("\r\n", PString::Empty(), TRUE
);
331 PSASLClient::PSASLResult
PSASLClient::Negotiate(const char * input
, const char ** output
)
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
;
343 return PSASLClient::Continue
;
347 BOOL
PSASLClient::End()
351 sasl_dispose((sasl_conn_t
**)&m_ConnState
);
361 // End of File ///////////////////////////////////////////////////////////////