static void client (Gsasl * ctx) { Gsasl_session *session; const char *mech = "PLAIN"; int rc; /* Create new authentication session. */ if ((rc = gsasl_client_start (ctx, mech, &session)) != GSASL_OK) { printf ("Cannot initialize client (%d): %s\n", rc, gsasl_strerror (rc)); return; } /* Set username and password in session handle. This info will be lost when this session is deallocated below. */ gsasl_property_set (session, GSASL_AUTHID, "jas"); gsasl_property_set (session, GSASL_PASSWORD, "secret"); /* Do it. */ client_authenticate (session); /* Cleanup. */ gsasl_finish (session); }
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 int callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { char buf[BUFSIZ] = ""; int rc = GSASL_NO_CALLBACK; char *p; /* Get user info from user. */ printf ("Callback invoked, for property %d.\n", prop); switch (prop) { case GSASL_PASSCODE: printf ("Enter passcode:\n"); p = fgets (buf, sizeof (buf) - 1, stdin); if (p == NULL) { perror ("fgets"); break; } buf[strlen (buf) - 1] = '\0'; gsasl_property_set (sctx, GSASL_PASSCODE, buf); rc = GSASL_OK; break; case GSASL_AUTHID: printf ("Enter username:\n"); p = fgets (buf, sizeof (buf) - 1, stdin); if (p == NULL) { perror ("fgets"); break; } buf[strlen (buf) - 1] = '\0'; gsasl_property_set (sctx, GSASL_AUTHID, buf); rc = GSASL_OK; break; default: printf ("Unknown property! Don't worry.\n"); break; } return rc; }
// static int SASLSession::gsaslCallback (Gsasl* ctx, Gsasl_session* sctx, Gsasl_property prop) { SASLSession* sess = reinterpret_cast <SASLSession*>(gsasl_callback_hook_get(ctx)); if (!sess) return GSASL_AUTHENTICATION_ERROR; shared_ptr <authenticator> auth = sess->getAuthenticator(); try { string res; switch (prop) { case GSASL_AUTHID: res = auth->getUsername(); break; case GSASL_PASSWORD: res = auth->getPassword(); break; case GSASL_ANONYMOUS_TOKEN: res = auth->getAnonymousToken(); break; case GSASL_HOSTNAME: res = auth->getHostname(); break; case GSASL_SERVICE: res = auth->getServiceName(); break; case GSASL_AUTHZID: case GSASL_GSSAPI_DISPLAY_NAME: case GSASL_PASSCODE: case GSASL_SUGGESTED_PIN: case GSASL_PIN: case GSASL_REALM: default: return GSASL_NO_CALLBACK; } gsasl_property_set(sctx, prop, res.c_str()); return GSASL_OK; } catch (...) { return GSASL_NO_CALLBACK; } }
static int callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { int rc = GSASL_NO_CALLBACK; /* Get user info from user. */ switch (prop) { case GSASL_SAML20_IDP_IDENTIFIER: gsasl_property_set (sctx, prop, "https://saml.example.org/"); rc = GSASL_OK; break; case GSASL_SAML20_AUTHENTICATE_IN_BROWSER: printf ("client got redirect URL: %s\n", gsasl_property_get (sctx, GSASL_SAML20_REDIRECT_URL)); rc = GSASL_OK; break; default: printf ("Unknown property %d! Don't worry.\n", prop); break; } return rc; }
static char * sasl_auth_plain( char *user, char *pass) { Gsasl *ctx = NULL; Gsasl_session *session; char *p = NULL; const char *mech = "PLAIN"; if (gsasl_init(&ctx) != GSASL_OK) /* TODO: do this only once at startup */ return p; if (gsasl_client_start(ctx, mech, &session) != GSASL_OK) { gsasl_done(ctx); return p; } gsasl_property_set(session, GSASL_AUTHID, user); gsasl_property_set(session, GSASL_PASSWORD, pass); if (gsasl_step64(session, NULL, &p) != GSASL_OK) FreeAndNull(p); gsasl_finish(session); gsasl_done(ctx); return p; }
/** * gsasl_callback: * @ctx: handle received from gsasl_init(), may be NULL to derive it * from @sctx. * @sctx: session handle. * @prop: enumerated value of Gsasl_property type. * * Invoke the application callback. The @prop value indicate what the * callback is expected to do. For example, for * GSASL_ANONYMOUS_TOKEN, the function is expected to invoke * gsasl_property_set(SCTX, GSASL_ANONYMOUS_TOKEN, "token") where * "token" is the anonymous token the application wishes the SASL * mechanism to use. See the manual for the meaning of all * parameters. * * Note that if no callback has been set by the application, but the * obsolete callback interface has been used, this function will * translate the old callback interface into the new. This interface * should be sufficient to invoke all callbacks, both new and old. * * Return value: Returns whatever the application callback return, or * GSASL_NO_CALLBACK if no application was known. * * Since: 0.2.0 **/ int gsasl_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { if (ctx == NULL && sctx == NULL) return GSASL_NO_CALLBACK; if (ctx == NULL) ctx = sctx->ctx; if (ctx->cb) return ctx->cb (ctx, sctx, prop); #ifndef GSASL_NO_OBSOLETE { /* Call obsolete callbacks. Remove this when the obsolete * callbacks are no longer supported. */ Gsasl_server_callback_anonymous cb_anonymous; Gsasl_server_callback_external cb_external; Gsasl_server_callback_securid cb_securid; Gsasl_server_callback_gssapi cb_gssapi; Gsasl_server_callback_validate cb_validate; Gsasl_server_callback_retrieve cb_retrieve; char buf[BUFSIZ]; size_t buflen = BUFSIZ - 1; int res; switch (prop) { case GSASL_VALIDATE_ANONYMOUS: if (!sctx->anonymous_token) break; cb_anonymous = gsasl_server_callback_anonymous_get (sctx->ctx); if (!cb_anonymous) break; res = cb_anonymous (sctx, sctx->anonymous_token); return res; break; case GSASL_VALIDATE_EXTERNAL: cb_external = gsasl_server_callback_external_get (sctx->ctx); if (!cb_external) break; res = cb_external (sctx); return res; break; case GSASL_VALIDATE_SECURID: cb_securid = gsasl_server_callback_securid_get (sctx->ctx); if (!cb_securid) break; res = cb_securid (sctx, sctx->authid, sctx->authzid, sctx->passcode, sctx->pin, buf, &buflen); if (buflen > 0 && buflen < BUFSIZ - 1) { buf[buflen] = '\0'; gsasl_property_set (sctx, GSASL_SUGGESTED_PIN, buf); } return res; break; case GSASL_VALIDATE_GSSAPI: cb_gssapi = gsasl_server_callback_gssapi_get (sctx->ctx); if (!cb_gssapi) break; res = cb_gssapi (sctx, sctx->gssapi_display_name, sctx->authzid); return res; break; case GSASL_VALIDATE_SIMPLE: cb_validate = gsasl_server_callback_validate_get (sctx->ctx); if (!cb_validate) break; res = cb_validate (sctx, sctx->authzid, sctx->authid, sctx->password); return res; break; case GSASL_PASSWORD: cb_retrieve = gsasl_server_callback_retrieve_get (sctx->ctx); if (!cb_retrieve) break; res = cb_retrieve (sctx, sctx->authid, sctx->authzid, sctx->hostname, &buf, &buflen); if (res == GSASL_OK) gsasl_property_set_raw (sctx, GSASL_PASSWORD, buf, buflen); /* FIXME else if (res == GSASL_TOO_SMALL_BUFFER)... */ return res; break; default: break; } } #endif return GSASL_NO_CALLBACK; }
static int callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop) { int rc = GSASL_OK; struct sasl_data *pdata; const char *user; char *string; switch (prop) { case GSASL_PASSWORD: pdata = gsasl_callback_hook_get(ctx); user = pdata->username; if (!user) { user = gsasl_property_get(sctx, GSASL_AUTHID); if (!user) { dico_log(L_ERR, 0, _("user name not supplied")); return GSASL_NO_AUTHID; } pdata->username = user; } if (dico_udb_get_password(user_db, user, &string)) { dico_log(L_ERR, 0, _("failed to get password for `%s' from the database"), user); return GSASL_NO_PASSWORD; } gsasl_property_set(sctx, prop, string); free(string); break; case GSASL_SERVICE: gsasl_property_set(sctx, prop, sasl_service); break; case GSASL_REALM: gsasl_property_set(sctx, prop, sasl_realm ? sasl_realm : hostname); break; case GSASL_HOSTNAME: gsasl_property_set(sctx, prop, hostname); break; case GSASL_VALIDATE_SIMPLE: rc = cb_validate(ctx, sctx); break; #if 0 FIXME: case GSASL_VALIDATE_EXTERNAL: case GSASL_VALIDATE_SECURID: #endif case GSASL_VALIDATE_ANONYMOUS: pdata = gsasl_callback_hook_get(ctx); user = gsasl_property_get(sctx, GSASL_ANONYMOUS_TOKEN); pdata->username = user; pdata->anon = 1; break; case GSASL_VALIDATE_GSSAPI: pdata = gsasl_callback_hook_get(ctx); user = gsasl_property_get(sctx, GSASL_AUTHZID); pdata->username = user; break; default: rc = GSASL_NO_CALLBACK; /*dico_log(L_NOTICE, 0, _("Unsupported callback property %d"), prop);*/ break; } return rc; }
static void sasl_authenticate( SV *client, mongo_link *link ) { Gsasl *ctx = NULL; Gsasl_session *session; SV *username, *mechanism, *conv_id; HV *result; /* response document from mongod */ char *p, *buf; /* I/O buffers for gsasl */ int rc; char out_buf[8192]; mechanism = perl_mongo_call_method( client, "sasl_mechanism", 0, 0 ); if ( !SvOK( mechanism ) ) { croak( "MongoDB: Could not retrieve SASL mechanism from client object\n" ); } if ( strncmp( "PLAIN", SvPV_nolen( mechanism ), 5 ) == 0 ) { /* SASL PLAIN does not require a libgsasl conversation loop, so we can handle it elsewhere */ return perl_mongo_call_method( client, "_sasl_plain_authenticate", 0, 0 ); } if ( ( rc = gsasl_init( &ctx ) ) != GSASL_OK ) { croak( "MongoDB: Cannot initialize libgsasl (%d): %s\n", rc, gsasl_strerror(rc) ); } if ( ( rc = gsasl_client_start( ctx, SvPV_nolen( mechanism ), &session ) ) != GSASL_OK ) { croak( "MongoDB: Cannot initialize SASL client (%d): %s\n", rc, gsasl_strerror(rc) ); } username = perl_mongo_call_method( client, "username", 0, 0 ); if ( !SvOK( username ) ) { croak( "MongoDB: Cannot start SASL session without username. Specify username in constructor\n" ); } gsasl_property_set( session, GSASL_SERVICE, "mongodb" ); gsasl_property_set( session, GSASL_HOSTNAME, link->master->host ); gsasl_property_set( session, GSASL_AUTHID, SvPV_nolen( username ) ); rc = gsasl_step64( session, "", &p ); if ( ( rc != GSASL_OK ) && ( rc != GSASL_NEEDS_MORE ) ) { croak( "MongoDB: No data from GSSAPI. Did you run kinit?\n" ); } if ( ! strncpy( out_buf, p, 8192 ) ) { croak( "MongoDB: Unable to copy SASL output buffer\n" ); } gsasl_free( p ); result = (HV *)SvRV( perl_mongo_call_method( client, "_sasl_start", 0, 2, newSVpv( out_buf, 0 ), mechanism ) ); #if 0 fprintf( stderr, "result conv id = [%s]\n", SvPV_nolen( *hv_fetch( result, "conversationId", 14, FALSE ) ) ); fprintf( stderr, "result payload = [%s]\n", SvPV_nolen( *hv_fetch( result, "payload", 7, FALSE ) ) ); #endif buf = SvPV_nolen( *hv_fetch( result, "payload", 7, FALSE ) ); conv_id = *hv_fetch( result, "conversationId", 14, FALSE ); do { rc = gsasl_step64( session, buf, &p ); if ( ( rc != GSASL_OK ) && ( rc != GSASL_NEEDS_MORE ) ) { croak( "MongoDB: SASL step error (%d): %s\n", rc, gsasl_strerror(rc) ); } if ( ! strncpy( out_buf, p, 8192 ) ) { croak( "MongoDB: Unable to copy SASL output buffer\n" ); } gsasl_free( p ); result = (HV *)SvRV( perl_mongo_call_method( client, "_sasl_continue", 0, 2, newSVpv( out_buf, 0 ), conv_id ) ); #if 0 fprintf( stderr, "result conv id = [%s]\n", SvPV_nolen( *hv_fetch( result, "conversationId", 14, FALSE ) ) ); fprintf( stderr, "result payload = [%s]\n", SvPV_nolen( *hv_fetch( result, "payload", 7, FALSE ) ) ); #endif buf = SvPV_nolen( *hv_fetch( result, "payload", 7, FALSE ) ); } while( rc == GSASL_NEEDS_MORE ); if ( rc != GSASL_OK ) { croak( "MongoDB: SASL Authentication error (%d): %s\n", rc, gsasl_strerror(rc) ); } gsasl_finish( session ); gsasl_done( ctx ); }
static int callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop) { int rc = GSASL_NO_CALLBACK; struct cfg *cfg = gsasl_callback_hook_get (ctx); switch (prop) { case GSASL_SAML20_REDIRECT_URL: { FILE *fh; char *reqid, *redirect_url, *tmp; size_t n = 0; const char *idp = gsasl_property_get (sctx, GSASL_SAML20_IDP_IDENTIFIER); /* User did not provide a SAML IdP identifier. */ if (!idp) return GSASL_AUTHENTICATION_ERROR; /* Sanitize input. */ if (strcmp (idp, ".") == 0 || strcmp (idp, "..") == 0) return GSASL_AUTHENTICATION_ERROR; for (n = 0; idp[n]; n++) if (!((idp[n] >= 'a' && idp[n] <= 'z') || (idp[n] >= 'A' && idp[n] <= 'Z') || (idp[n] >= '0' && idp[n] <= '9') || idp[n] == '.')) { printf ("Cannot handle identifier (%ld): %s\n", (unsigned long) n, idp); return GSASL_AUTHENTICATION_ERROR; } /* Run helper to generate SAML AuthnRequest. Read out request ID. */ rc = asprintf (&tmp, "gsasl-saml20-request %s %s %s %s " "%s/%s/idp-metadata.xml", cfg->state_path, cfg->sp_metadata, cfg->sp_key, cfg->sp_cert, cfg->cfg_path, idp); if (rc <= 0) return GSASL_AUTHENTICATION_ERROR; fh = popen (tmp, "r"); free (tmp); if (!fh) { perror ("popen"); return GSASL_AUTHENTICATION_ERROR; } reqid = NULL; n = 0; if (getline (&reqid, &n, fh) <= 0) { perror ("getline"); return GSASL_AUTHENTICATION_ERROR; } if (reqid[strlen (reqid) - 1] == '\n') reqid[strlen (reqid) - 1] = '\0'; if (reqid[strlen (reqid) - 1] == '\r') reqid[strlen (reqid) - 1] = '\0'; rc = pclose (fh); if (rc != 0) { perror ("pclose"); return GSASL_AUTHENTICATION_ERROR; } /* Read URL to redirect to. Written by gsasl-saml20-request. */ rc = asprintf (&tmp, "%s/%s/redirect_url", cfg->state_path, reqid); if (rc <= 0) return GSASL_AUTHENTICATION_ERROR; fh = fopen (tmp, "r"); free (tmp); if (!fh) { perror ("fopen"); return GSASL_AUTHENTICATION_ERROR; } redirect_url = NULL; n = 0; if (getline (&redirect_url, &n, fh) <= 0) { perror ("getline"); return GSASL_AUTHENTICATION_ERROR; } rc = fclose (fh); if (rc != 0) { perror ("fclose"); return GSASL_AUTHENTICATION_ERROR; } /* We are done */ gsasl_session_hook_set (sctx, reqid); gsasl_property_set (sctx, prop, redirect_url); printf ("read id: %s\n", reqid); printf ("url: %s\n", redirect_url); free (redirect_url); return GSASL_OK; } break; case GSASL_VALIDATE_SAML20: { time_t start = time (NULL); char *id = (char *) gsasl_session_hook_get (sctx); char *tmp, *line; size_t n; FILE *fh; if (!id) return GSASL_AUTHENTICATION_ERROR; do { sleep (1); rc = asprintf (&tmp, "%s/%s/success", cfg->state_path, id); if (rc <= 0) return GSASL_AUTHENTICATION_ERROR; fh = fopen (tmp, "r"); free (tmp); if (!fh) { rc = asprintf (&tmp, "%s/%s/fail", cfg->state_path, id); if (rc <= 0) return GSASL_AUTHENTICATION_ERROR; fh = fopen (tmp, "r"); free (tmp); if (!fh) { puts ("waiting"); continue; } rc = fclose (fh); if (rc != 0) { perror ("fclose"); return GSASL_AUTHENTICATION_ERROR; } return GSASL_AUTHENTICATION_ERROR; } rc = fclose (fh); if (rc != 0) { perror ("fclose"); return GSASL_AUTHENTICATION_ERROR; } rc = asprintf (&tmp, "%s/%s/subject", cfg->state_path, id); if (rc <= 0) return GSASL_AUTHENTICATION_ERROR; fh = fopen (tmp, "r"); free (tmp); if (!fh) { perror ("fopen"); return GSASL_AUTHENTICATION_ERROR; } line = NULL; n = 0; if (getline (&line, &n, fh) <= 0) { perror ("getline"); return GSASL_AUTHENTICATION_ERROR; } printf ("subject: %s\n", line); gsasl_property_set (sctx, GSASL_AUTHID, line); free (line); rc = fclose (fh); if (rc != 0) { perror ("fclose"); return GSASL_AUTHENTICATION_ERROR; } free (id); return GSASL_OK; } while (time (NULL) - start < 30); printf ("timeout\n"); return GSASL_AUTHENTICATION_ERROR; } break; case GSASL_PASSWORD: gsasl_property_set (sctx, prop, "sesam"); rc = GSASL_OK; break; default: /* You may want to log (at debug verbosity level) that an unknown property was requested here, possibly after filtering known rejected property requests. */ 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; }
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; }
int _gsasl_securid_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { const char *authorization_id = NULL; const char *authentication_id = NULL; const char *passcode = NULL; const char *suggestedpin; char *pin = NULL; int res; size_t len; if (input_len == 0) { *output_len = 0; *output = NULL; return GSASL_NEEDS_MORE; } authorization_id = input; authentication_id = memchr (input, '\0', input_len - 1); if (authentication_id) { authentication_id++; passcode = memchr (authentication_id, '\0', input_len - strlen (authorization_id) - 1 - 1); if (passcode) { passcode++; pin = memchr (passcode, '\0', input_len - strlen (authorization_id) - 1 - strlen (authentication_id) - 1 - 1); if (pin) { pin++; if (pin && !*pin) pin = NULL; } } } if (passcode == NULL) return GSASL_MECHANISM_PARSE_ERROR; gsasl_property_set (sctx, GSASL_AUTHID, authentication_id); gsasl_property_set (sctx, GSASL_AUTHZID, authorization_id); gsasl_property_set (sctx, GSASL_PASSCODE, passcode); if (pin) gsasl_property_set (sctx, GSASL_PIN, pin); else gsasl_property_set (sctx, GSASL_PIN, NULL); res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SECURID); switch (res) { case GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE: *output = strdup (PASSCODE); if (!*output) return GSASL_MALLOC_ERROR; *output_len = strlen (PASSCODE); res = GSASL_NEEDS_MORE; break; case GSASL_SECURID_SERVER_NEED_NEW_PIN: suggestedpin = gsasl_property_get (sctx, GSASL_SUGGESTED_PIN); if (suggestedpin) len = strlen (suggestedpin); else len = 0; *output_len = strlen (PIN) + len; *output = malloc (*output_len); if (!*output) return GSASL_MALLOC_ERROR; memcpy (*output, PIN, strlen (PIN)); if (suggestedpin) memcpy (*output + strlen (PIN), suggestedpin, len); res = GSASL_NEEDS_MORE; break; default: *output_len = 0; *output = NULL; break; } return res; }
int _gsasl_login_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { struct _Gsasl_login_server_state *state = mech_data; int res; switch (state->step) { case 0: *output = strdup (CHALLENGE_USERNAME); if (!*output) return GSASL_MALLOC_ERROR; *output_len = strlen (CHALLENGE_USERNAME); state->step++; res = GSASL_NEEDS_MORE; break; case 1: if (input_len == 0) return GSASL_MECHANISM_PARSE_ERROR; state->username = malloc (input_len + 1); if (state->username == NULL) return GSASL_MALLOC_ERROR; memcpy (state->username, input, input_len); state->username[input_len] = '\0'; *output = strdup (CHALLENGE_PASSWORD); if (!*output) return GSASL_MALLOC_ERROR; *output_len = strlen (CHALLENGE_PASSWORD); state->step++; res = GSASL_NEEDS_MORE; break; case 2: if (input_len == 0) return GSASL_MECHANISM_PARSE_ERROR; state->password = malloc (input_len + 1); if (state->password == NULL) return GSASL_MALLOC_ERROR; memcpy (state->password, input, input_len); state->password[input_len] = '\0'; if (input_len != strlen (state->password)) return GSASL_MECHANISM_PARSE_ERROR; gsasl_property_set (sctx, GSASL_AUTHID, state->username); gsasl_property_set (sctx, GSASL_PASSWORD, state->password); res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SIMPLE); if (res == GSASL_NO_CALLBACK) { const char *key; gsasl_property_set (sctx, GSASL_AUTHZID, NULL); gsasl_property_set (sctx, GSASL_PASSWORD, NULL); key = gsasl_property_get (sctx, GSASL_PASSWORD); if (key && strlen (state->password) == strlen (key) && strcmp (state->password, key) == 0) res = GSASL_OK; else res = GSASL_AUTHENTICATION_ERROR; } *output_len = 0; *output = NULL; state->step++; break; default: res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; break; } return res; }
int _gsasl_scram_sha1_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { struct scram_server_state *state = mech_data; int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; int rc; *output = NULL; *output_len = 0; switch (state->step) { case 0: { if (input_len == 0) return GSASL_NEEDS_MORE; if (scram_parse_client_first (input, input_len, &state->cf) < 0) return GSASL_MECHANISM_PARSE_ERROR; /* In PLUS server mode, we require use of channel bindings. */ if (state->plus && state->cf.cbflag != 'p') return GSASL_AUTHENTICATION_ERROR; /* In non-PLUS mode, but where have channel bindings data (and thus advertised PLUS) we reject a client 'y' cbflag. */ if (!state->plus && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y') return GSASL_AUTHENTICATION_ERROR; /* Check that username doesn't fail SASLprep. */ { char *tmp; rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED, &tmp, NULL); if (rc != GSASL_OK || *tmp == '\0') return GSASL_AUTHENTICATION_ERROR; gsasl_free (tmp); } { const char *p; /* Save "gs2-header" and "message-bare" for next step. */ p = memchr (input, ',', input_len); if (!p) return GSASL_AUTHENTICATION_ERROR; p++; p = memchr (p, ',', input_len - (p - input)); if (!p) return GSASL_AUTHENTICATION_ERROR; p++; state->gs2header = malloc (p - input + 1); if (!state->gs2header) return GSASL_MALLOC_ERROR; memcpy (state->gs2header, input, p - input); state->gs2header[p - input] = '\0'; state->cfmb_str = malloc (input_len - (p - input) + 1); if (!state->cfmb_str) return GSASL_MALLOC_ERROR; memcpy (state->cfmb_str, p, input_len - (p - input)); state->cfmb_str[input_len - (p - input)] = '\0'; } /* Create new nonce. */ { size_t cnlen = strlen (state->cf.client_nonce); state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1); if (!state->sf.nonce) return GSASL_MALLOC_ERROR; memcpy (state->sf.nonce, state->cf.client_nonce, cnlen); memcpy (state->sf.nonce + cnlen, state->snonce, SNONCE_ENTROPY_BYTES); state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0'; } gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username); gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid); { const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER); if (p) state->sf.iter = strtoul (p, NULL, 10); if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX) state->sf.iter = 4096; } { const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT); if (p) { free (state->sf.salt); state->sf.salt = strdup (p); } } rc = scram_print_server_first (&state->sf, &state->sf_str); if (rc != 0) return GSASL_MALLOC_ERROR; *output = strdup (state->sf_str); if (!*output) return GSASL_MALLOC_ERROR; *output_len = strlen (*output); state->step++; return GSASL_NEEDS_MORE; break; } case 1: { if (scram_parse_client_final (input, input_len, &state->cl) < 0) return GSASL_MECHANISM_PARSE_ERROR; if (strcmp (state->cl.nonce, state->sf.nonce) != 0) return GSASL_AUTHENTICATION_ERROR; /* Base64 decode the c= field and check that it matches client-first. Also check channel binding data. */ { size_t len; rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind), &state->cbind, &len); if (rc != 0) return rc; if (state->cf.cbflag == 'p') { if (len < strlen (state->gs2header)) return GSASL_AUTHENTICATION_ERROR; if (memcmp (state->cbind, state->gs2header, strlen (state->gs2header)) != 0) return GSASL_AUTHENTICATION_ERROR; if (len - strlen (state->gs2header) != state->cbtlsuniquelen) return GSASL_AUTHENTICATION_ERROR; if (memcmp (state->cbind + strlen (state->gs2header), state->cbtlsunique, state->cbtlsuniquelen) != 0) return GSASL_AUTHENTICATION_ERROR; } else { if (len != strlen (state->gs2header)) return GSASL_AUTHENTICATION_ERROR; if (memcmp (state->cbind, state->gs2header, len) != 0) return GSASL_AUTHENTICATION_ERROR; } } /* Base64 decode client proof and check that length matches SHA-1 size. */ { size_t len; rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof), &state->clientproof, &len); if (rc != 0) return rc; if (len != 20) return GSASL_MECHANISM_PARSE_ERROR; } { const char *p; /* Get StoredKey and ServerKey */ if ((p = gsasl_property_get (sctx, GSASL_PASSWORD))) { Gc_rc err; char *salt; size_t saltlen; char saltedpassword[20]; char *clientkey; char *preppasswd; rc = gsasl_saslprep (p, 0, &preppasswd, NULL); if (rc != GSASL_OK) return rc; rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt), &salt, &saltlen); if (rc != 0) { gsasl_free (preppasswd); return rc; } /* SaltedPassword := Hi(password, salt) */ err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd), salt, saltlen, state->sf.iter, saltedpassword, 20); gsasl_free (preppasswd); gsasl_free (salt); if (err != GC_OK) return GSASL_MALLOC_ERROR; /* ClientKey := HMAC(SaltedPassword, "Client Key") */ #define CLIENT_KEY "Client Key" rc = gsasl_hmac_sha1 (saltedpassword, 20, CLIENT_KEY, strlen (CLIENT_KEY), &clientkey); if (rc != 0) return rc; /* StoredKey := H(ClientKey) */ rc = gsasl_sha1 (clientkey, 20, &state->storedkey); free (clientkey); if (rc != 0) return rc; /* ServerKey := HMAC(SaltedPassword, "Server Key") */ #define SERVER_KEY "Server Key" rc = gsasl_hmac_sha1 (saltedpassword, 20, SERVER_KEY, strlen (SERVER_KEY), &state->serverkey); if (rc != 0) return rc; } else return GSASL_NO_PASSWORD; /* Compute AuthMessage */ { size_t len; int n; /* Get client-final-message-without-proof. */ p = memmem (input, input_len, ",p=", 3); if (!p) return GSASL_MECHANISM_PARSE_ERROR; len = p - input; n = asprintf (&state->authmessage, "%s,%.*s,%.*s", state->cfmb_str, (int) strlen (state->sf_str), state->sf_str, (int) len, input); if (n <= 0 || !state->authmessage) return GSASL_MALLOC_ERROR; } /* Check client proof. */ { char *clientsignature; char *maybe_storedkey; /* ClientSignature := HMAC(StoredKey, AuthMessage) */ rc = gsasl_hmac_sha1 (state->storedkey, 20, state->authmessage, strlen (state->authmessage), &clientsignature); if (rc != 0) return rc; /* ClientKey := ClientProof XOR ClientSignature */ memxor (clientsignature, state->clientproof, 20); rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey); free (clientsignature); if (rc != 0) return rc; rc = memcmp (state->storedkey, maybe_storedkey, 20); free (maybe_storedkey); if (rc != 0) return GSASL_AUTHENTICATION_ERROR; } /* Generate server verifier. */ { char *serversignature; /* ServerSignature := HMAC(ServerKey, AuthMessage) */ rc = gsasl_hmac_sha1 (state->serverkey, 20, state->authmessage, strlen (state->authmessage), &serversignature); if (rc != 0) return rc; rc = gsasl_base64_to (serversignature, 20, &state->sl.verifier, NULL); free (serversignature); if (rc != 0) return rc; } } rc = scram_print_server_final (&state->sl, output); if (rc != 0) return GSASL_MALLOC_ERROR; *output_len = strlen (*output); state->step++; return GSASL_OK; break; } default: break; } return res; }
int _gsasl_digest_md5_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { _Gsasl_digest_md5_server_state *state = mech_data; int rc, res; *output = NULL; *output_len = 0; switch (state->step) { case 0: /* Set realm. */ { const char *c; c = gsasl_property_get (sctx, GSASL_REALM); if (c) { state->challenge.nrealms = 1; state->challenge.realms = malloc (sizeof (*state->challenge.realms)); if (!state->challenge.realms) return GSASL_MALLOC_ERROR; state->challenge.realms[0] = strdup (c); if (!state->challenge.realms[0]) return GSASL_MALLOC_ERROR; } } /* Set QOP */ { const char *qopstr = gsasl_property_get (sctx, GSASL_QOPS); if (qopstr) { int qops = digest_md5_qopstr2qops (qopstr); if (qops == -1) return GSASL_MALLOC_ERROR; /* We don't support confidentiality right now. */ if (qops & DIGEST_MD5_QOP_AUTH_CONF) return GSASL_AUTHENTICATION_ERROR; if (qops) state->challenge.qops = qops; } } /* FIXME: cipher, maxbuf, more realms. */ /* Create challenge. */ *output = digest_md5_print_challenge (&state->challenge); if (!*output) return GSASL_AUTHENTICATION_ERROR; *output_len = strlen (*output); state->step++; res = GSASL_NEEDS_MORE; break; case 1: if (digest_md5_parse_response (input, input_len, &state->response) < 0) return GSASL_MECHANISM_PARSE_ERROR; /* Make sure response is consistent with challenge. */ if (digest_md5_validate (&state->challenge, &state->response) < 0) return GSASL_MECHANISM_PARSE_ERROR; /* Store properties, from the client response. */ if (state->response.utf8) { gsasl_property_set (sctx, GSASL_AUTHID, state->response.username); gsasl_property_set (sctx, GSASL_REALM, state->response.realm); } else { /* Client provided username/realm in ISO-8859-1 form, convert it to UTF-8 since the library is all-UTF-8. */ char *tmp; tmp = latin1toutf8 (state->response.username); if (!tmp) return GSASL_MALLOC_ERROR; gsasl_property_set (sctx, GSASL_AUTHID, tmp); free (tmp); tmp = latin1toutf8 (state->response.realm); if (!tmp) return GSASL_MALLOC_ERROR; gsasl_property_set (sctx, GSASL_REALM, tmp); free (tmp); } gsasl_property_set (sctx, GSASL_AUTHZID, state->response.authzid); /* FIXME: cipher, maxbuf. */ /* Compute secret. */ { const char *passwd; const char *hashed_passwd; hashed_passwd = gsasl_property_get (sctx, GSASL_DIGEST_MD5_HASHED_PASSWORD); if (hashed_passwd) { if (strlen (hashed_passwd) != (DIGEST_MD5_LENGTH * 2)) return GSASL_AUTHENTICATION_ERROR; rc = _gsasl_digest_md5_set_hashed_secret (state->secret, hashed_passwd); if (rc != GSASL_OK) return rc; } else if ((passwd = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL) { char *tmp, *tmp2; tmp2 = utf8tolatin1ifpossible (passwd); rc = asprintf (&tmp, "%s:%s:%s", state->response.username, state->response.realm ? state->response.realm : "", tmp2); free (tmp2); if (rc < 0) return GSASL_MALLOC_ERROR; rc = gsasl_md5 (tmp, strlen (tmp), &tmp2); free (tmp); if (rc != GSASL_OK) return rc; memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH); free (tmp2); } else { return GSASL_NO_PASSWORD; } } /* Check client response. */ { char check[DIGEST_MD5_RESPONSE_LENGTH + 1]; rc = digest_md5_hmac (check, state->secret, state->response.nonce, state->response.nc, state->response.cnonce, state->response.qop, state->response.authzid, state->response.digesturi, 0, state->response.cipher, state->kic, state->kis, state->kcc, state->kcs); if (rc) return GSASL_AUTHENTICATION_ERROR; if (strcmp (state->response.response, check) != 0) return GSASL_AUTHENTICATION_ERROR; } /* Create finish token. */ rc = digest_md5_hmac (state->finish.rspauth, state->secret, state->response.nonce, state->response.nc, state->response.cnonce, state->response.qop, state->response.authzid, state->response.digesturi, 1, state->response.cipher, NULL, NULL, NULL, NULL); if (rc) return GSASL_AUTHENTICATION_ERROR; *output = digest_md5_print_finish (&state->finish); if (!*output) return GSASL_MALLOC_ERROR; *output_len = strlen (*output); state->step++; res = GSASL_OK; break; default: res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; break; } return res; }
END_TEST START_TEST (test_saslplugin_request_scram_sha_1) { g_print("Starting test_saslplugin_request_scram_sha_1\n"); gpointer plugin; Gsasl *gsasl_context; Gsasl_session *gsasl_session; plugin = g_object_new(GSIGNOND_TYPE_SASL_PLUGIN, NULL); fail_if(plugin == NULL); fail_if (gsasl_init (&gsasl_context) != GSASL_OK); fail_if (gsasl_server_start (gsasl_context, "SCRAM-SHA-1", &gsasl_session) != GSASL_OK); GSignondSessionData* result = NULL; GSignondSessionData* result_final = NULL; GError* error = NULL; g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result_final); g_signal_connect(plugin, "response", G_CALLBACK(response_callback), &result); g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error); GSignondSessionData* data = gsignond_dictionary_new(); char* server_challenge; fail_if(gsasl_step64(gsasl_session, "", &server_challenge) != GSASL_NEEDS_MORE); gsignond_dictionary_set_string(data, "ChallengeBase64", server_challenge); free(server_challenge); gsignond_session_data_set_username(data, "*****@*****.**"); gsignond_session_data_set_secret(data, "megapassword"); gsignond_plugin_request_initial(plugin, data, NULL, "SCRAM-SHA-1"); fail_if(result == NULL); fail_if(result_final != NULL); fail_if(error != NULL); gsasl_property_set(gsasl_session, GSASL_PASSWORD, "megapassword"); fail_if (gsasl_step64(gsasl_session, gsignond_dictionary_get_string(result, "ResponseBase64"), &server_challenge) != GSASL_NEEDS_MORE); gsignond_dictionary_unref(result); result = NULL; gsignond_dictionary_set_string(data, "ChallengeBase64", server_challenge); free(server_challenge); gsignond_plugin_request(plugin, data); fail_if(result == NULL); fail_if(result_final != NULL); fail_if(error != NULL); fail_if (gsasl_step64(gsasl_session, gsignond_dictionary_get_string(result, "ResponseBase64"), &server_challenge) != GSASL_OK); gsignond_dictionary_unref(result); result = NULL; gsignond_dictionary_set_string(data, "ChallengeBase64", server_challenge); free(server_challenge); gsignond_plugin_request(plugin, data); fail_if(result != NULL); fail_if(result_final == NULL); fail_if(error != NULL); fail_if(strlen(gsignond_dictionary_get_string(result_final, "ResponseBase64")) > 0); gsignond_dictionary_unref(result_final); result_final = NULL; gsasl_finish(gsasl_session); gsasl_done(gsasl_context); gsignond_dictionary_unref(data); g_object_unref(plugin); }