static int callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { int rc = GSASL_NO_CALLBACK; switch (prop) { case GSASL_AUTHZID: if (*AUTHZID[i]) { gsasl_property_set (sctx, GSASL_AUTHZID, AUTHZID[i]); rc = GSASL_OK; } break; case GSASL_SERVICE: gsasl_property_set (sctx, prop, SERVICE); rc = GSASL_OK; break; case GSASL_HOSTNAME: gsasl_property_set (sctx, prop, HOST); rc = GSASL_OK; break; case GSASL_VALIDATE_GSSAPI: { const char *client_name = gsasl_property_fast (sctx, GSASL_GSSAPI_DISPLAY_NAME); const char *authzid = gsasl_property_fast (sctx, GSASL_AUTHZID); if (client_name) printf ("GSSAPI user: %s\n", client_name); else fail ("no client name\n"); if (authzid) printf ("Authorization ID: %s\n", authzid); if (client_name && strcmp (client_name, GSSAPI_USER) == 0 && ((authzid == NULL && *AUTHZID[i] == '\0') || strcmp (authzid, AUTHZID[i]) == 0)) rc = GSASL_OK; else rc = GSASL_AUTHENTICATION_ERROR; } break; default: fail ("Unknown callback property %d\n", prop); break; } return rc; }
static void server_auth (FILE * fh, Gsasl_session * session) { char *line = NULL; size_t n = 0; char *p; int rc; /* The ordering and the type of checks in the following loop has to be adapted for each protocol depending on its SASL properties. SMTP is a "server-first" SASL protocol. This implementation do not support piggy-backing of the initial client challenge nor piggy-backing of the terminating server response. See RFC 2554 and RFC 4422 for terminology. That profile results in the following loop structure. Ask on the help-gsasl list if you are uncertain. */ do { rc = gsasl_step64 (session, line, &p); if (rc == GSASL_NEEDS_MORE || (rc == GSASL_OK && p && *p)) { print (fh, "334 %s\n", p); gsasl_free (p); if (gettrimline (&line, &n, fh) < 0) { print (fh, "221 localhost getline failure\n"); goto done; } } } while (rc == GSASL_NEEDS_MORE); if (rc != GSASL_OK) { print (fh, "535 gsasl_step64 (%d): %s\n", rc, gsasl_strerror (rc)); goto done; } { const char *authid = gsasl_property_fast (session, GSASL_AUTHID); const char *authzid = gsasl_property_fast (session, GSASL_AUTHZID); print (fh, "235 OK [authid: %s authzid: %s]\n", authid ? authid : "N/A", authzid ? authzid : "N/A"); } done: free (line); }
/** * gsasl_property_get: * @sctx: session handle. * @prop: enumerated value of Gsasl_property type, indicating the * type of data in @data. * * Retrieve the data stored in the session handle for given property * @prop, possibly invoking the application callback to get the value. * * The pointer is to live data, and must not be deallocated or * modified in any way. * * This function will invoke the application callback, using * gsasl_callback(), when a property value is not known. * * If no value is known, and no callback is specified or if the * callback fail to return data, and if any obsolete callback * functions has been set by the application, this function will try * to call these obsolete callbacks, and store the returned data as * the corresponding property. This behaviour of this function will * be removed when the obsolete callback interfaces are removed. * * Return value: Return data for property, or NULL if no value known. * * Since: 0.2.0 **/ const char * gsasl_property_get (Gsasl_session * sctx, Gsasl_property prop) { const char *p = gsasl_property_fast (sctx, prop); if (!p) { gsasl_callback (NULL, sctx, prop); p = gsasl_property_fast (sctx, prop); } #ifndef GSASL_NO_OBSOLETE if (!p) p = _gsasl_obsolete_property_map (sctx, prop); #endif return p; }
/** move the stream to the auth state */ void _sx_sasl_open(sx_t s, Gsasl_session *sd) { char *method, *authzid; const char *realm = NULL; struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; _sx_sasl_t ctx = gsasl_session_hook_get(sd); const char *mechname = gsasl_mechanism_name (sd); /* get the method */ method = (char *) malloc(sizeof(char) * (strlen(mechname) + 6)); sprintf(method, "SASL/%s", mechname); /* and the authorization identifier */ creds.authzid = gsasl_property_fast(sd, GSASL_AUTHZID); creds.authnid = gsasl_property_fast(sd, GSASL_AUTHID); creds.realm = gsasl_property_fast(sd, GSASL_REALM); if(0 && ctx && ctx->cb) { /* not supported yet */ if((ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, &creds, NULL, s, ctx->cbarg)!=sx_sasl_ret_OK) { _sx_debug(ZONE, "stream authzid: %s verification failed, not advancing to auth state", creds.authzid); free(method); return; } } else if (NULL != gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)) { creds.authzid = strdup(gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)); authzid = NULL; } else { /* override unchecked arbitrary authzid */ if(creds.realm && creds.realm[0] != '\0') { realm = creds.realm; } else { realm = s->req_to; } authzid = (char *) malloc(sizeof(char) * (strlen(creds.authnid) + strlen(realm) + 2)); sprintf(authzid, "%s@%s", creds.authnid, realm); creds.authzid = authzid; } /* proceed stream to authenticated state */ sx_auth(s, method, creds.authzid); free(method); if(authzid) free(authzid); }
/** make the stream authenticated second time round */ static void _sx_sasl_stream(sx_t s, sx_plugin_t p) { Gsasl_session *sd = (Gsasl_session *) s->plugin_data[p->index]; /* do nothing the first time */ if(sd == NULL) return; /* are we auth'd? */ if(NULL == gsasl_property_fast(sd, GSASL_AUTHID)) { _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet"); return; } /* otherwise, its auth time */ _sx_sasl_open(s, sd); }
int callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { int rc = GSASL_NO_CALLBACK; switch (prop) { case GSASL_ANONYMOUS_TOKEN: if (args_info.anonymous_token_arg == NULL) args_info.anonymous_token_arg = readutf8line ("Enter anonymous token (e.g., email address): "); gsasl_property_set (sctx, GSASL_ANONYMOUS_TOKEN, args_info.anonymous_token_arg); rc = GSASL_OK; break; case GSASL_CB_TLS_UNIQUE: if (!args_info.no_cb_flag && b64cbtlsunique == NULL && args_info.hostname_arg == NULL) b64cbtlsunique = readutf8line ("Enter base64 encoded tls-unique channel binding: "); if (!args_info.no_cb_flag && b64cbtlsunique && *b64cbtlsunique) gsasl_property_set (sctx, prop, b64cbtlsunique); rc = GSASL_OK; break; case GSASL_PASSWORD: if (args_info.password_arg == NULL) args_info.password_arg = readutf8pass ("Enter password: "******"Enter passcode: "); gsasl_property_set (sctx, GSASL_PASSCODE, args_info.passcode_arg); rc = GSASL_OK; break; case GSASL_AUTHID: if (args_info.authentication_id_arg == NULL) { #if HAVE_GETPWUID uid_t uid; struct passwd *pw; uid = getuid (); pw = getpwuid (uid); if (pw && pw->pw_name) { printf ("Using system username `%s' as " "authentication identity.\n", pw->pw_name); args_info.authentication_id_arg = xstrdup (pw->pw_name); } else #endif args_info.authentication_id_arg = readutf8line ("Enter authentication ID: "); } gsasl_property_set (sctx, GSASL_AUTHID, args_info.authentication_id_arg); rc = GSASL_OK; break; case GSASL_AUTHZID: gsasl_property_set (sctx, GSASL_AUTHZID, args_info.authorization_id_arg); rc = GSASL_OK; break; case GSASL_SERVICE: if (args_info.service_arg == NULL) args_info.service_arg = readutf8line ("Enter GSSAPI service name (e.g. \"imap\"): "); gsasl_property_set (sctx, GSASL_SERVICE, args_info.service_arg); rc = GSASL_OK; break; case GSASL_HOSTNAME: if (args_info.hostname_arg == NULL) args_info.hostname_arg = readutf8line ("Enter hostname of server: "); gsasl_property_set (sctx, GSASL_HOSTNAME, args_info.hostname_arg); rc = GSASL_OK; break; case GSASL_REALM: if (args_info.realm_arg == NULL) args_info.realm_arg = readutf8line ("Enter realm of server (optional): "); if (args_info.realm_arg && *args_info.realm_arg) gsasl_property_set (sctx, GSASL_REALM, args_info.realm_arg); rc = GSASL_OK; break; case GSASL_QOP: if (args_info.quality_of_protection_arg == NULL) args_info.quality_of_protection_arg = readutf8line ("Enter quality of protection (optional, e.g. 'qop-int'): "); if (args_info.quality_of_protection_arg && *args_info.quality_of_protection_arg) gsasl_property_set (sctx, GSASL_QOP, args_info.quality_of_protection_arg); rc = GSASL_OK; break; case GSASL_VALIDATE_GSSAPI: { char *str; printf ("Authzid: %s\nDisplay Name: %s\n", gsasl_property_fast (sctx, GSASL_AUTHZID), gsasl_property_fast (sctx, GSASL_GSSAPI_DISPLAY_NAME)); str = readutf8line ("Validate GSS-API user? (y/n) "); if (strcmp (str, "y") == 0 || strcmp (str, "Y") == 0) rc = GSASL_OK; else rc = GSASL_AUTHENTICATION_ERROR; free (str); } break; case GSASL_SCRAM_SALTED_PASSWORD: case GSASL_SCRAM_ITER: case GSASL_SCRAM_SALT: break; case GSASL_SAML20_IDP_IDENTIFIER: { char *str = readutf8line ("Enter SAML authentication identifier " "(e.g. \"http://example.org/\"): "); gsasl_property_set (sctx, GSASL_SAML20_IDP_IDENTIFIER, str); rc = GSASL_OK; } break; case GSASL_SAML20_AUTHENTICATE_IN_BROWSER: { const char *url = gsasl_property_get (sctx, GSASL_SAML20_REDIRECT_URL); printf ("Proceed to this URL to authenticate using SAML 2.0:\n%s\n", url); rc = GSASL_OK; } break; case GSASL_OPENID20_AUTHENTICATE_IN_BROWSER: { const char *url = gsasl_property_get (sctx, GSASL_OPENID20_REDIRECT_URL); printf ("Proceed to this URL to authenticate using OpenID 2.0:\n%s\n", url); rc = GSASL_OK; } break; default: fprintf (stderr, "warning: mechanism requested unsupported property `%d'\n", prop); break; } return rc; }
static int cb (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { int rc = GSASL_NO_CALLBACK; int i = 0, j = 0; if (gsasl_callback_hook_get (ctx)) i = *(int *) gsasl_callback_hook_get (ctx); if (gsasl_session_hook_get (sctx)) j = *(int *) gsasl_session_hook_get (sctx); if (j < 0 || j > 5) fail ("j out of bounds: %d\n", j); switch (prop) { case GSASL_AUTHID: gsasl_property_set (sctx, prop, sasltv[i].authid); rc = GSASL_OK; break; case GSASL_AUTHZID: gsasl_property_set (sctx, prop, sasltv[i].authzid); rc = GSASL_OK; break; case GSASL_PASSWORD: gsasl_property_set (sctx, prop, sasltv[i].password); rc = GSASL_OK; break; case GSASL_ANONYMOUS_TOKEN: gsasl_property_set (sctx, prop, sasltv[i].anonymous); rc = GSASL_OK; break; case GSASL_SERVICE: rc = GSASL_OK; break; case GSASL_PASSCODE: gsasl_property_set (sctx, prop, sasltv[i].passcode); rc = GSASL_OK; break; case GSASL_SUGGESTED_PIN: case GSASL_PIN: { const char *suggestion = gsasl_property_fast (sctx, GSASL_SUGGESTED_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; gsasl_property_set (sctx, prop, sasltv[i].pin); rc = GSASL_OK; } case GSASL_REALM: break; case GSASL_VALIDATE_EXTERNAL: rc = GSASL_OK; break; case GSASL_VALIDATE_ANONYMOUS: if (strcmp (sasltv[i].anonymous, gsasl_property_fast (sctx, GSASL_ANONYMOUS_TOKEN)) == 0) rc = GSASL_OK; else rc = GSASL_AUTHENTICATION_ERROR; break; case GSASL_VALIDATE_SECURID: { const char *passcode = gsasl_property_fast (sctx, GSASL_PASSCODE); const char *pin = gsasl_property_fast (sctx, GSASL_PIN); if (strcmp (passcode, sasltv[i].passcode) != 0) return GSASL_AUTHENTICATION_ERROR; if (sasltv[i].securidrc == GSASL_SECURID_SERVER_NEED_NEW_PIN) { rc = sasltv[i].securidrc; sasltv[i].securidrc = GSASL_OK; if (sasltv[i].suggestpin) { gsasl_property_set (sctx, GSASL_SUGGESTED_PIN, sasltv[i].suggestpin); } } else if (sasltv[i].securidrc == GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE) { rc = sasltv[i].securidrc; sasltv[i].securidrc = GSASL_OK; } else { rc = 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; } } break; default: printf ("Unknown property %d\n", prop); break; } return rc; }