/** 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); }
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; }