/* simple.c --- Test the simple SASL mechanisms. * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Simon Josefsson * * This file is part of GNU SASL. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "utils.h" #define MAX_LINE_LENGTH BUFSIZ #define MAXSTEP 50 #define CLIENT 1 #define SERVER 0 #define UTF8_a "\xC2\xAA" struct sasltv { int clientp; char *mech; char *step[MAXSTEP]; char *password; char *authzid; char *authid; char *service; char *hostname; char *servicename; char *anonymous; char *passcode; char *suggestpin; char *pin; int securidrc; }; static struct sasltv sasltv[] = { {CLIENT, "EXTERNAL", {"", NULL}}, {SERVER, "EXTERNAL", {"", NULL}}, {CLIENT, "ANONYMOUS", {"", "Zm9vQGJhci5jb20=", NULL, NULL}, NULL, NULL, NULL, NULL, NULL, NULL, "foo@bar.com"}, {SERVER, "ANONYMOUS", {"Zm9vQGJhci5jb20=", NULL, NULL}, NULL, NULL, NULL, NULL, NULL, NULL, "foo@bar.com"}, {CLIENT, "NTLM", {"Kw==", "TlRMTVNTUAABAAAAB7IAAAYABgAgAAAAAAAAACYAAABhdXRoaWQ=", "TlRMTVNTUAAAAAAAAAAAAAAAAAAAAGFiY2RlZmdoMDEyMzQ1Njc4ODY2NDQwMTIz", "TlRMTVNTUAADAAAAGAAYAFgAAAAYABgAcAAAAAAAAABAAAAADAAMAEAAAAAMAAwATAAAA" "AAAAACIAAAAAABhYmEAdQB0AGgAaQBkAGEAdQB0AGgAaQBkABeBBp9xJad9eYo3oh1k55" "GNFDIui8H8Qz4CfWYVVToBhVzFFbzyzqAZN5Wl59K/Fg==", NULL, NULL}, "password", "authzid", "authid"}, {CLIENT, "PLAIN", {"", "YXV0aHppZABhdXRoaWQAcGFzc3dvcmQ=", NULL, NULL}, "password", "authzid", "authid"}, {CLIENT, "PLAIN", {"", "YQBhAGE=", NULL, NULL}, "a", "a", "a"}, {CLIENT, "PLAIN", {"", "wqoAwqoAwqo=", NULL, NULL}, UTF8_a, UTF8_a, UTF8_a}, {SERVER, "PLAIN", {"YXV0aHppZABhdXRoaWQAcGFzc3dvcmQ=", NULL, NULL}, "password", "authzid", "authid"}, {SERVER, "PLAIN", {"", "", "YXV0aHppZABhdXRoaWQAcGFzc3dvcmQ=", NULL, NULL}, "password", "authzid", "authid"}, {CLIENT, "LOGIN", {"VXNlciBOYW1l", "YXV0aGlk", "UGFzc3dvcmQ=", "cGFzc3dvcmQ=", NULL, NULL}, "password", NULL, "authid"}, {CLIENT, "LOGIN", {"VXNlciBOYW1l", "YXV0aGlk", "UGFzc3dvcmQ=", "YQ==", NULL, NULL}, "a", NULL, "authid"}, {CLIENT, "LOGIN", {"VXNlciBOYW1l", "YXV0aGlk", "UGFzc3dvcmQ=", "wqo=", NULL, NULL}, UTF8_a, NULL, "authid"}, {SERVER, "LOGIN", {"", "VXNlciBOYW1l", "YXV0aGlk", "UGFzc3dvcmQ=", "cGFzc3dvcmQ=", NULL, NULL}, "password", NULL, "authid"}, {CLIENT, "CRAM-MD5", {"PGNiNmQ5YTQ5ZDA3ZjEwY2MubGliZ3Nhc2xAbG9jYWxob3N0Pg==", "YXV0aGlkIGZkNjRmMjYxZWYxYjBjYjg0ZmZjNGVmYzgwZDk3NjFj", NULL, NULL}, "password", "authzid", "authid"}, {CLIENT, "SECURID", {"", "YXV0aHppZABhdXRoaWQANDcxMQA=", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711"}, {CLIENT, "SECURID", {"", "YXV0aHppZABhdXRoaWQANDcxMQA=", "cGFzc2NvZGU=", "YXV0aHppZABhdXRoaWQANDcxMQA=", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711"}, {CLIENT, "SECURID", {"", "YXV0aHppZABhdXRoaWQANDcxMQA=", "cGlu", "YXV0aHppZABhdXRoaWQANDcxMQA0MgA=", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711", NULL, "42"}, {CLIENT, "SECURID", {"", "YXV0aHppZABhdXRoaWQANDcxMQA=", "cGluMjM=", "YXV0aHppZABhdXRoaWQANDcxMQA0MgA=", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711", "23", "42"}, {CLIENT, "SECURID", {"", "YXV0aHppZABhdXRoaWQANDcxMQA=", "cGluMjM=", "YXV0aHppZABhdXRoaWQANDcxMQA0MgA=", "cGFzc2NvZGU=", "YXV0aHppZABhdXRoaWQANDcxMQA=", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711", "23", "42"}, {SERVER, "SECURID", {"YXV0aHppZABhdXRoaWQANDcxMQA=", "", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711"}, {SERVER, "SECURID", {"YXV0aHppZABhdXRoaWQANDcxMQA=", "", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711"}, {SERVER, "SECURID", {"YXV0aHppZABhdXRoaWQANDcxMQA=", "cGlu", "YXV0aHppZABhdXRoaWQANDcxMQA0MgA=", "", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711", NULL, "42", GSASL_SECURID_SERVER_NEED_NEW_PIN}, {SERVER, "SECURID", {"YXV0aHppZABhdXRoaWQANDcxMQA=", "cGluMTc=", "YXV0aHppZABhdXRoaWQANDcxMQAyMwA=", "", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711", "17", "23", GSASL_SECURID_SERVER_NEED_NEW_PIN}, {SERVER, "SECURID", {"YXV0aHppZABhdXRoaWQANDcxMQA=", "cGFzc2NvZGU=", "YXV0aHppZABhdXRoaWQANDcxMQA=", NULL, NULL}, NULL, "authzid", "authid", NULL, NULL, NULL, NULL, "4711", NULL, NULL, GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE} }; static int client_callback_authorization_id (Gsasl_session_ctx * xctx, char *out, size_t * outlen) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = sasltv[i].authzid ? strlen (sasltv[i].authzid) : 0; if (*outlen < needlen) return GSASL_TOO_SMALL_BUFFER; *outlen = needlen; if (out && sasltv[i].authzid) memcpy (out, sasltv[i].authzid, needlen); return GSASL_OK; } static int client_callback_authentication_id (Gsasl_session_ctx * xctx, char *out, size_t * outlen) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = strlen (sasltv[i].authid); if (*outlen < needlen) return GSASL_TOO_SMALL_BUFFER; *outlen = needlen; if (out) memcpy (out, sasltv[i].authid, needlen); return GSASL_OK; } static int client_callback_password (Gsasl_session_ctx * xctx, char *out, size_t * outlen) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = strlen (sasltv[i].password); if (*outlen < needlen) return GSASL_TOO_SMALL_BUFFER; *outlen = needlen; if (out) memcpy (out, sasltv[i].password, needlen); return GSASL_OK; } static int server_callback_validate (Gsasl_session_ctx * xctx, const char *authorization_id, const char *authentication_id, const char *password) { Gsasl_ctx *ctx = gsasl_server_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); if (authorization_id && sasltv[i].authzid && strcmp (authorization_id, sasltv[i].authzid) != 0) return GSASL_AUTHENTICATION_ERROR; if ((authorization_id == NULL && sasltv[i].authzid != NULL) || (authorization_id != NULL && sasltv[i].authzid == NULL)) return GSASL_AUTHENTICATION_ERROR; if (authentication_id && sasltv[i].authid && strcmp (authentication_id, sasltv[i].authid) != 0) return GSASL_AUTHENTICATION_ERROR; if (strcmp (password, sasltv[i].password) != 0) return GSASL_AUTHENTICATION_ERROR; return GSASL_OK; } static int server_callback_retrieve (Gsasl_session_ctx * xctx, const char *authentication_id, const char *authorization_id, const char *realm, char *key, size_t * keylen) { Gsasl_ctx *ctx = gsasl_server_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = strlen (sasltv[i].password); if (*keylen < needlen) return GSASL_TOO_SMALL_BUFFER; *keylen = strlen (sasltv[i].password); if (key) memcpy (key, sasltv[i].password, needlen); return GSASL_OK; } static int client_callback_service (Gsasl_session_ctx * ctx, char *srv, size_t * srvlen, char *host, size_t * hostlen, char *srvname, size_t * srvnamelen) { if (srvlen) *srvlen = 0; if (hostlen) *hostlen = 0; if (srvnamelen) *srvnamelen = 0; return GSASL_OK; } static int client_callback_anonymous (Gsasl_session_ctx * xctx, char *out, size_t * outlen) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = strlen (sasltv[i].anonymous); if (*outlen < needlen) return GSASL_TOO_SMALL_BUFFER; *outlen = needlen; if (out) memcpy (out, sasltv[i].anonymous, strlen (sasltv[i].anonymous)); return GSASL_OK; } static int server_callback_anonymous (Gsasl_session_ctx * xctx, const char *token) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); return strcmp (sasltv[i].anonymous, token) == 0 ? GSASL_OK : GSASL_AUTHENTICATION_ERROR; } static int server_callback_external (Gsasl_session_ctx * xctx) { return GSASL_OK; } static int client_callback_passcode (Gsasl_session_ctx * xctx, char *out, size_t * outlen) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = strlen (sasltv[i].passcode); if (*outlen < needlen) return GSASL_TOO_SMALL_BUFFER; *outlen = needlen; if (out) memcpy (out, sasltv[i].passcode, needlen); return GSASL_OK; } static int client_callback_pin (Gsasl_session_ctx * xctx, char *suggestion, char *out, size_t * outlen) { Gsasl_ctx *ctx = gsasl_client_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); size_t needlen = strlen (sasltv[i].pin); if (suggestion && sasltv[i].suggestpin && strcmp (suggestion, sasltv[i].suggestpin) != 0) return GSASL_AUTHENTICATION_ERROR; if ((suggestion == NULL && sasltv[i].suggestpin != NULL) || (suggestion != NULL && sasltv[i].suggestpin == NULL)) return GSASL_AUTHENTICATION_ERROR; if (*outlen < needlen) return GSASL_TOO_SMALL_BUFFER; *outlen = needlen; if (out) memcpy (out, sasltv[i].pin, needlen); return GSASL_OK; } static int server_callback_securid (Gsasl_session_ctx * xctx, const char *authentication_id, const char *authorization_id, const char *passcode, char *pin, char *suggestpin, size_t * suggestpinlen) { Gsasl_ctx *ctx = gsasl_server_ctx_get (xctx); int i = *(int *) gsasl_application_data_get (ctx); int res; if (strcmp (passcode, sasltv[i].passcode) != 0) return GSASL_AUTHENTICATION_ERROR; if (sasltv[i].securidrc == GSASL_SECURID_SERVER_NEED_NEW_PIN) { res = sasltv[i].securidrc; sasltv[i].securidrc = GSASL_OK; if (sasltv[i].suggestpin) { if (*suggestpinlen) *suggestpinlen = strlen (sasltv[i].suggestpin); if (suggestpin) memcpy (suggestpin, sasltv[i].suggestpin, strlen (sasltv[i].suggestpin)); } else if (*suggestpinlen) *suggestpinlen = 0; } else if (sasltv[i].securidrc == GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE) { res = sasltv[i].securidrc; sasltv[i].securidrc = GSASL_OK; } else { res = sasltv[i].securidrc; if (pin && sasltv[i].pin && strcmp (pin, sasltv[i].pin) != 0) return GSASL_AUTHENTICATION_ERROR; if ((pin == NULL && sasltv[i].pin != NULL) || (pin != NULL && sasltv[i].pin == NULL)) return GSASL_AUTHENTICATION_ERROR; if (*suggestpinlen) *suggestpinlen = 0; } return res; } void doit (void) { Gsasl_ctx *ctx = NULL; Gsasl_session_ctx *xctx = NULL; char output[MAX_LINE_LENGTH]; size_t outputlen; size_t i, j; int res; if (!gsasl_check_version (GSASL_VERSION)) fail ("gsasl_check_version failure"); success ("Header version %s library version %s\n", GSASL_VERSION, gsasl_check_version (NULL)); res = gsasl_init (&ctx); if (res != GSASL_OK) { fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res)); return; } gsasl_client_callback_authentication_id_set (ctx, client_callback_authentication_id); gsasl_client_callback_authorization_id_set (ctx, client_callback_authorization_id); gsasl_client_callback_password_set (ctx, client_callback_password); gsasl_server_callback_validate_set (ctx, server_callback_validate); gsasl_server_callback_retrieve_set (ctx, server_callback_retrieve); gsasl_client_callback_service_set (ctx, client_callback_service); gsasl_client_callback_anonymous_set (ctx, client_callback_anonymous); gsasl_server_callback_anonymous_set (ctx, server_callback_anonymous); gsasl_server_callback_external_set (ctx, server_callback_external); gsasl_client_callback_passcode_set (ctx, client_callback_passcode); gsasl_client_callback_pin_set (ctx, client_callback_pin); gsasl_server_callback_securid_set (ctx, server_callback_securid); outputlen = sizeof (output); res = gsasl_client_listmech (ctx, output, &outputlen); if (res != GSASL_OK) fail ("gsasl_client_listmech() failed (%d):\n%s\n", res, gsasl_strerror (res)); outputlen = sizeof (output); res = gsasl_server_listmech (ctx, output, &outputlen); if (res != GSASL_OK) fail ("gsasl_server_listmech() failed (%d):\n%s\n", res, gsasl_strerror (res)); for (i = 0; i < sizeof (sasltv) / sizeof (sasltv[0]); i++) { gsasl_application_data_set (ctx, &i); if (debug) printf ("Entry %d %s mechanism %s:\n", i, sasltv[i].clientp ? "client" : "server", sasltv[i].mech); if (sasltv[i].clientp) res = gsasl_client_support_p (ctx, sasltv[i].mech); else res = gsasl_server_support_p (ctx, sasltv[i].mech); if (!res) continue; if (sasltv[i].clientp) res = gsasl_client_start (ctx, sasltv[i].mech, &xctx); else res = gsasl_server_start (ctx, sasltv[i].mech, &xctx); if (res != GSASL_OK) { fail ("SASL %s start for mechanism %s failed (%d):\n%s\n", sasltv[i].clientp ? "client" : "server", sasltv[i].mech, res, gsasl_strerror (res)); continue; } for (j = 0; sasltv[i].step[j]; j += 2) { if (sasltv[i].clientp) gsasl_client_application_data_set (xctx, &j); else gsasl_server_application_data_set (xctx, &j); if (debug) printf ("Input : %s\n", sasltv[i].step[j] ? sasltv[i].step[j] : ""); output[0] = '\0'; outputlen = sizeof (output); if (sasltv[i].clientp) res = gsasl_client_step_base64 (xctx, sasltv[i].step[j], output, outputlen); else res = gsasl_server_step_base64 (xctx, sasltv[i].step[j], output, outputlen); if (debug) printf ("Output: %s\n", output); if (res != GSASL_OK && res != GSASL_NEEDS_MORE) break; if (strlen (output) != strlen (sasltv[i].step[j + 1] ? sasltv[i].step[j + 1] : "")) { printf ("Expected: %s\n", sasltv[i].step[j + 1] ? sasltv[i].step[j + 1] : ""); fail ("SASL entry %d mechanism %s client step %d length error\n", i, sasltv[i].mech, j); j = -1; break; } if (strcmp (output, sasltv[i].step[j + 1] ? sasltv[i].step[j + 1] : "") != 0) { printf ("Expected: %s\n", sasltv[i].step[j + 1] ? sasltv[i].step[j + 1] : ""); fail ("SASL entry %d mechanism %s client step %d data error\n", i, sasltv[i].mech, j); j = -1; break; } if (strcmp (sasltv[i].mech, "SECURID") != 0 && res == GSASL_OK) break; } if ((int) j != -1 && res == GSASL_OK && sasltv[i].step[j + 2]) fail ("SASL entry %d mechanism %s step %d code ended prematurely\n", i, sasltv[i].mech, j); else if ((int) j != -1 && res == GSASL_NEEDS_MORE) fail ("SASL entry %d mechanism %s step %d table ended prematurely\n", i, sasltv[i].mech, j, res, gsasl_strerror (res)); else if ((int) j != -1 && res != GSASL_OK) fail ("SASL entry %d mechanism %s step %d failed (%d):\n%s\n", i, sasltv[i].mech, j, res, gsasl_strerror (res)); else printf ("PASS: simple %s %s %d\n", sasltv[i].mech, sasltv[i].clientp ? "client" : "server", i); if (sasltv[i].clientp) gsasl_client_finish (xctx); else gsasl_server_finish (xctx); if (debug) printf ("\n"); } gsasl_done (ctx); }