00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <libsyncml/syncml.h>
00023 #include "sml_auth.h"
00024
00025 #include <libsyncml/syncml_internals.h>
00026 #include "sml_auth_internals.h"
00027 #include <libsyncml/sml_session_internals.h>
00028 #include <libsyncml/sml_elements_internals.h>
00029 #include <libsyncml/sml_command_internals.h>
00030 #include "libsyncml/sml_error_internals.h"
00031
00032 static SmlStatus *_smlAuthHeaderReply(
00033 SmlSession *session,
00034 SmlErrorType code,
00035 SmlAuthType auth,
00036 SmlError **error);
00037
00038 void _status_callback(SmlSession *session, SmlStatus *status, void *userdata)
00039 {
00040 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
00041
00042 smlTrace(TRACE_EXIT, "%s", __func__);
00043 }
00044
00045 void _header_callback(SmlSession *session, SmlHeader *header, SmlCred *cred, void *userdata)
00046 {
00047 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, session, header, cred, userdata);
00048 smlAssert(session);
00049 smlAssert(userdata);
00050 SmlStatus *reply = NULL;
00051 SmlAuthenticator *auth = userdata;
00052 SmlError *error = NULL;
00053
00054 if (session->sessionType == SML_SESSION_TYPE_CLIENT) {
00055
00056
00057
00058
00059 g_warning("This is an OMA DS client. An OMA DS client should not use this authentication callback.");
00060 smlTrace(TRACE_INTERNAL, "%s: This is an OMA DS client and so auth is not supported.", __func__);
00061 auth->state = SML_NO_ERROR;
00062 if (auth->enabled)
00063 smlTrace(TRACE_ERROR,
00064 "%s: authentication is enabled but this is an OMA DS client.");
00065 }
00066 else if (!cred)
00067 {
00068 if (!auth->enabled)
00069 {
00070 smlTrace(TRACE_INTERNAL, "%s: Auth is disabled and no cred given", __func__);
00071 auth->state = SML_NO_ERROR;
00072 } else {
00073
00074 if (auth->state != SML_AUTH_ACCEPTED)
00075 {
00076
00077
00078
00079
00080
00081
00082 smlTrace(TRACE_INTERNAL, "%s: Auth is required", __func__);
00083 auth->state = SML_ERROR_AUTH_REQUIRED;
00084 session->authenticate = TRUE;
00085 }
00086 else
00087 {
00088
00089 smlTrace(TRACE_INTERNAL, "%s: Auth is already accepted.", __func__);
00090 auth->state = SML_AUTH_ACCEPTED;
00091 }
00092 }
00093 } else {
00094
00095 smlTrace(TRACE_INTERNAL, "%s: Cred is \"%s\"", __func__, VA_STRING(cred->data));
00096 if (!auth->enabled)
00097 {
00098 smlTrace(TRACE_INTERNAL, "%s: Cred received but unwanted", __func__);
00099 auth->state = SML_AUTH_ACCEPTED;
00100 } else {
00101
00102 if (auth->verifyCallback)
00103 {
00104
00105
00106
00107
00108
00109 if (auth->verifyCallback(session->chal, cred,
00110 smlLocationGetName(session->source),
00111 auth->verifyCallbackUserdata, &error))
00112 {
00113 auth->state = SML_AUTH_ACCEPTED;
00114 } else {
00115 smlErrorSet(&error, SML_ERROR_AUTH_REJECTED,
00116 "Auth rejected for username %s",
00117 smlLocationGetName(session->source));
00118 smlSessionDispatchEvent(session, SML_SESSION_EVENT_ERROR, NULL, NULL, NULL, error);
00119 smlErrorDeref(&error);
00120 auth->state = SML_ERROR_AUTH_REJECTED;
00121 }
00122 } else {
00123 smlTrace(TRACE_INTERNAL, "%s: No verify callback set", __func__);
00124 auth->state = SML_ERROR_AUTH_REJECTED;
00125 }
00126 }
00127 }
00128
00129 if (auth->state == SML_ERROR_AUTH_REJECTED) {
00130 smlTrace(TRACE_INTERNAL, "%s: Ending session due to wrong / missing creds", __func__);
00131 session->end = TRUE;
00132 }
00133
00134 reply = _smlAuthHeaderReply(session, auth->state, auth->type, &error);
00135 if (!reply)
00136 goto error;
00137
00138 if (!smlSessionSendReply(session, reply, &error)) {
00139 smlStatusUnref(reply);
00140 goto error;
00141 }
00142
00143 smlStatusUnref(reply);
00144
00145 if (!session->established && !session->end &&
00146 !session->authenticate &&
00147 session->sessionType == SML_SESSION_TYPE_SERVER)
00148 {
00149 session->established = TRUE;
00150 smlSessionDispatchEvent(
00151 session, SML_SESSION_EVENT_ESTABLISHED,
00152 NULL, NULL, NULL, NULL);
00153 }
00154
00155 smlTrace(TRACE_EXIT, "%s", __func__);
00156 return;
00157 error:
00158 smlSessionDispatchEvent(session, SML_SESSION_EVENT_ERROR, NULL, NULL, NULL, error);
00159 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
00160 smlErrorDeref(&error);
00161 return;
00162 }
00163
00164 char *smlAuthGetCredString(
00165 SmlAuthType type,
00166 const char *username,
00167 const char *password,
00168 const char *b64_nonce,
00169 SmlError **error)
00170 {
00171 smlTrace(TRACE_ENTRY, "%s", __func__);
00172 CHECK_ERROR_REF
00173 char *cred = NULL;
00174
00175 switch (type) {
00176 case SML_AUTH_TYPE_BASIC:
00177
00178 smlTrace(TRACE_INTERNAL, "%s - SML_AUTH_TYPE_BASIC", __func__);
00179 char *plain = g_strjoin(":", username, password, NULL);
00180 cred = g_base64_encode((unsigned char *) plain, strlen(plain));
00181 if (!cred) {
00182 smlErrorSet(error, SML_ERROR_GENERIC,
00183 "The syncml:auth-basic credential cannot be base64 encoded.");
00184 smlSafeCFree(&plain);
00185 goto error;
00186 }
00187 smlSafeCFree(&plain);
00188
00189 break;
00190 case SML_AUTH_TYPE_MD5:
00191
00192 smlTrace(TRACE_INTERNAL, "%s - SML_AUTH_TYPE_MD5", __func__);
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 ;
00209 char *auth = g_strjoin (":", username, password, NULL);
00210 unsigned char digest[16];
00211 smlMD5GetDigest (auth, strlen(auth), digest);
00212 smlSafeCFree(&auth);
00213 cred = g_base64_encode(digest, 16);
00214 if (!cred) {
00215 smlErrorSet(error, SML_ERROR_GENERIC,
00216 "The username:password part of the syncml:auth-md5 "\
00217 "credential cannot be base64 encoded.");
00218 goto error;
00219 }
00220 auth = g_strjoin (":", cred, b64_nonce, NULL);
00221 smlSafeCFree(&cred);
00222 smlMD5GetDigest (auth, strlen(auth), digest);
00223 smlSafeCFree(&auth);
00224 cred = g_base64_encode(digest, 16);
00225 if (!cred) {
00226 smlErrorSet(error, SML_ERROR_GENERIC,
00227 "The complete syncml:auth-md5 credential cannot be base64 encoded.");
00228 goto error;
00229 }
00230
00231 break;
00232 default:
00233 smlTrace(TRACE_ERROR, "%s - unknown authentication type", __func__);
00234 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown auth format");
00235 goto error;
00236 }
00237
00238 smlTrace(TRACE_EXIT, "%s", __func__);
00239 return cred;
00240 error:
00241 smlTrace(TRACE_EXIT_ERROR, "%s - cannot create credential string");
00242 if (*error == NULL)
00243 smlErrorSet(error, SML_ERROR_GENERIC, "Cannot create credential string for user %s.",
00244 username);
00245 return NULL;
00246 }
00247
00248 SmlBool smlAuthVerify(SmlChal *chal, SmlCred *cred, const char *username, const char *password, SmlError **error)
00249 {
00250 smlTrace(TRACE_ENTRY, "%s", __func__);
00251 CHECK_ERROR_REF
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 if (chal && chal->type != cred->type)
00265 {
00266 if (chal->type == SML_AUTH_TYPE_BASIC &&
00267 cred->type == SML_AUTH_TYPE_MD5)
00268 {
00269
00270
00271
00272 smlTrace(TRACE_INTERNAL, "%s - replace syncml:auth-basic by syncml:auth-md5", __func__);
00273 } else {
00274
00275 smlErrorSet(error, SML_ERROR_AUTH_REJECTED,
00276 "The type of the authentication was changed to a lower security level.");
00277 goto error;
00278 }
00279 }
00280 smlTrace(TRACE_INTERNAL, "%s - authentication security policy ok", __func__);
00281
00282 char *wanted = NULL;
00283 switch (cred->type) {
00284 case SML_AUTH_TYPE_BASIC:
00285 smlTrace(TRACE_INTERNAL, "%s - SML_AUTH_TYPE_BASIC", __func__);
00286 wanted = smlAuthGetCredString(SML_AUTH_TYPE_BASIC, username, password, NULL, error);
00287 break;
00288 case SML_AUTH_TYPE_MD5:
00289 smlTrace(TRACE_INTERNAL, "%s - SML_AUTH_TYPE_MD5", __func__);
00290 if (chal)
00291 wanted = smlAuthGetCredString(
00292 SML_AUTH_TYPE_MD5,
00293 username, password,
00294 chal->nonce_b64, error);
00295 else
00296 wanted = smlAuthGetCredString(
00297 SML_AUTH_TYPE_MD5,
00298 username, password,
00299 "", error);
00300 break;
00301 default:
00302 smlTrace(TRACE_ERROR, "%s - unknown authentication type", __func__);
00303 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown auth format");
00304 goto error;
00305 }
00306 smlTrace(TRACE_INTERNAL, "%s - credential string calculated", __func__);
00307
00308
00309 if (strcmp(wanted, cred->data))
00310 {
00311 smlTrace(TRACE_INTERNAL, "%s - credentials mismatch", __func__);
00312 smlSafeCFree(&wanted);
00313 goto error;
00314 }
00315 smlSafeCFree(&wanted);
00316
00317 smlTrace(TRACE_EXIT, "%s", __func__);
00318 return TRUE;
00319 error:
00320 smlTrace(TRACE_EXIT_ERROR, "%s - auth rejected");
00321 if (*error == NULL)
00322 smlErrorSet(error, SML_ERROR_AUTH_REJECTED, "Authentication rejected for username %s.",
00323 username);
00324 return FALSE;
00325 }
00326
00327 SmlAuthenticator *smlAuthNew(SmlError **error)
00328 {
00329 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, error);
00330 CHECK_ERROR_REF
00331 SmlAuthenticator *auth = smlTryMalloc0(sizeof(SmlAuthenticator), error);
00332 if (!auth)
00333 goto error;
00334
00335 auth->enabled = TRUE;
00336 auth->state = SML_ERROR_AUTH_REQUIRED;
00337
00338 smlTrace(TRACE_EXIT, "%s: %p", __func__, auth);
00339 return auth;
00340
00341 error:
00342 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00343 return NULL;
00344 }
00345
00346
00347 void smlAuthFree(SmlAuthenticator *auth)
00348 {
00349 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, auth);
00350 smlAssert(auth);
00351
00352 smlSafeFree((gpointer *)&auth);
00353
00354 smlTrace(TRACE_EXIT, "%s", __func__);
00355 }
00356
00357 SmlBool smlAuthRegister(SmlAuthenticator *auth, SmlManager *manager, SmlError **error)
00358 {
00359 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, auth, manager, error);
00360 CHECK_ERROR_REF
00361 smlAssert(auth);
00362 smlAssert(manager);
00363
00364 smlManagerRegisterHeaderHandler(manager, _header_callback, _status_callback, auth);
00365
00366 smlTrace(TRACE_EXIT, "%s", __func__);
00367 return TRUE;
00368 }
00369
00370 void smlAuthSetState(SmlAuthenticator *auth, SmlErrorType type)
00371 {
00372 smlTrace(TRACE_ENTRY, "%s(%p, %i)", __func__, auth, type);
00373 smlAssert(auth);
00374
00375 auth->state = type;
00376
00377 smlTrace(TRACE_EXIT, "%s", __func__);
00378 }
00379
00380
00381 SmlStatus *smlAuthHeaderReply(
00382 SmlSession *session,
00383 SmlAuthType code,
00384 SmlError **error) {
00385 CHECK_ERROR_REF
00386 g_warning("SmlAuthType of smlAuthHeaderReply is used as SmlErrorType.");
00387 return _smlAuthHeaderReply(session, (SmlErrorType) code, SML_AUTH_TYPE_BASIC, error);
00388 }
00389
00390 static SmlStatus *_smlAuthHeaderReply(
00391 SmlSession *session,
00392 SmlErrorType code,
00393 SmlAuthType auth,
00394 SmlError **error)
00395 {
00396 smlTrace(TRACE_ENTRY, "%s(%p, %i, %i, %p)", __func__, session, code, auth, error);
00397 CHECK_ERROR_REF
00398
00399
00400
00401
00402
00403 smlTrace(TRACE_INTERNAL, "%s: SourceRef: %s --> TargetRef: %s",
00404 __func__, VA_STRING(session->target->locURI), VA_STRING(session->source->locURI));
00405 SmlStatus *reply = smlStatusNew(code, 0, session->lastReceivedMessageID, session->target, session->source, SML_COMMAND_TYPE_HEADER, error);
00406 if (!reply)
00407 goto error;
00408
00409 if (code == SML_ERROR_AUTH_REJECTED ||
00410 code == SML_ERROR_AUTH_REQUIRED) {
00411 reply->chal = smlChalNew(auth, error);
00412 if (!reply->chal)
00413 goto error_free_reply;
00414 session->chal = reply->chal;
00415 smlChalRef(session->chal);
00416 }
00417
00418 smlTrace(TRACE_EXIT, "%s: %p", __func__, reply);
00419 return reply;
00420
00421 error_free_reply:
00422 smlStatusUnref(reply);
00423 error:
00424 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00425 return NULL;
00426 }
00427
00428 void smlAuthSetVerifyCallback(SmlAuthenticator *auth, SmlAuthVerifyCb callback, void *userdata)
00429 {
00430 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, auth, callback, userdata);
00431 smlAssert(auth);
00432 auth->verifyCallback = callback;
00433 auth->verifyCallbackUserdata = userdata;
00434 smlTrace(TRACE_EXIT, "%s", __func__);
00435 }
00436
00437 void smlAuthSetEnable(SmlAuthenticator *auth, SmlBool enabled)
00438 {
00439 smlTrace(TRACE_ENTRY, "%s(%p, %i)", __func__, auth, enabled);
00440 smlAssert(auth);
00441
00442 auth->enabled = enabled;
00443
00444 smlTrace(TRACE_EXIT, "%s", __func__);
00445 }
00446
00447 SmlBool smlAuthIsEnabled(SmlAuthenticator *auth)
00448 {
00449 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, auth);
00450 smlAssert(auth);
00451
00452 smlTrace(TRACE_EXIT, "%s - %u", __func__, auth->enabled);
00453 return auth->enabled;
00454 }
00455
00456 void smlAuthSetType(SmlAuthenticator *auth, SmlAuthType type)
00457 {
00458 smlTrace(TRACE_ENTRY, "%s(%p, %i)", __func__, auth, type);
00459 smlAssert(auth);
00460 smlAssert(type != SML_AUTH_TYPE_UNKNOWN);
00461
00462 auth->type = type;
00463
00464 smlTrace(TRACE_EXIT, "%s", __func__);
00465 }
00466