+/*
+ * Finalize an OpenID authentication
+ */
+void cmd_oidf(char *argbuf) {
+ long len;
+ char buf[2048];
+ char thiskey[1024];
+ char thisdata[1024];
+ HashList *keys = NULL;
+ ctdl_openid *oiddata = (ctdl_openid *) CC->openid_data;
+
+ if (oiddata == NULL) {
+ cprintf("%d run OIDS first.\n", ERROR + INTERNAL_ERROR);
+ return;
+ }
+ if (StrLength(oiddata->server) == 0){
+ cprintf("%d need a remote server to authenticate against\n", ERROR + ILLEGAL_VALUE);
+ return;
+ }
+ keys = NewHash(1, NULL);
+ if (!keys) {
+ cprintf("%d NewHash() failed\n", ERROR + INTERNAL_ERROR);
+ return;
+ }
+ cprintf("%d Transmit OpenID data now\n", START_CHAT_MODE);
+
+ while (client_getln(buf, sizeof buf), strcmp(buf, "000")) {
+ len = extract_token(thiskey, buf, 0, '|', sizeof thiskey);
+ if (len < 0)
+ len = sizeof(thiskey) - 1;
+ extract_token(thisdata, buf, 1, '|', sizeof thisdata);
+ syslog(LOG_DEBUG, "%s: ["SIZE_T_FMT"] %s", thiskey, strlen(thisdata), thisdata);
+ Put(keys, thiskey, len, strdup(thisdata), NULL);
+ }
+
+
+ /* Now that we have all of the parameters, we have to validate the signature against the server */
+ syslog(LOG_DEBUG, "About to validate the signature...");
+
+ CURL *curl;
+ CURLcode res;
+ struct curl_httppost *formpost = NULL;
+ struct curl_httppost *lastptr = NULL;
+ char errmsg[1024] = "";
+ char *o_assoc_handle = NULL;
+ char *o_sig = NULL;
+ char *o_signed = NULL;
+ int num_signed_values;
+ int i;
+ char k_keyname[128];
+ char k_o_keyname[128];
+ char *k_value = NULL;
+ StrBuf *ReplyBuf;
+
+ curl_formadd(&formpost, &lastptr,
+ CURLFORM_COPYNAME, "openid.mode",
+ CURLFORM_COPYCONTENTS, "check_authentication",
+ CURLFORM_END);
+ syslog(LOG_DEBUG, "%25s : %s", "openid.mode", "check_authentication");
+
+ if (GetHash(keys, "assoc_handle", 12, (void *) &o_assoc_handle)) {
+ curl_formadd(&formpost, &lastptr,
+ CURLFORM_COPYNAME, "openid.assoc_handle",
+ CURLFORM_COPYCONTENTS, o_assoc_handle,
+ CURLFORM_END);
+ syslog(LOG_DEBUG, "%25s : %s", "openid.assoc_handle", o_assoc_handle);
+ }
+
+ if (GetHash(keys, "sig", 3, (void *) &o_sig)) {
+ curl_formadd(&formpost, &lastptr,
+ CURLFORM_COPYNAME, "openid.sig",
+ CURLFORM_COPYCONTENTS, o_sig,
+ CURLFORM_END);
+ syslog(LOG_DEBUG, "%25s : %s", "openid.sig", o_sig);
+ }
+
+ if (GetHash(keys, "signed", 6, (void *) &o_signed)) {
+ curl_formadd(&formpost, &lastptr,
+ CURLFORM_COPYNAME, "openid.signed",
+ CURLFORM_COPYCONTENTS, o_signed,
+ CURLFORM_END);
+ syslog(LOG_DEBUG, "%25s : %s", "openid.signed", o_signed);
+
+ num_signed_values = num_tokens(o_signed, ',');
+ for (i=0; i<num_signed_values; ++i) {
+ extract_token(k_keyname, o_signed, i, ',', sizeof k_keyname);
+ if (strcasecmp(k_keyname, "mode")) { // work around phpMyID bug
+ if (GetHash(keys, k_keyname, strlen(k_keyname), (void *) &k_value)) {
+ snprintf(k_o_keyname, sizeof k_o_keyname, "openid.%s", k_keyname);
+ curl_formadd(&formpost, &lastptr,
+ CURLFORM_COPYNAME, k_o_keyname,
+ CURLFORM_COPYCONTENTS, k_value,
+ CURLFORM_END);
+ syslog(LOG_DEBUG, "%25s : %s", k_o_keyname, k_value);
+ }
+ else {
+ syslog(LOG_INFO, "OpenID: signed field '%s' is missing",
+ k_keyname);
+ }
+ }
+ }
+ }
+
+ ReplyBuf = NewStrBuf();
+
+ curl = ctdl_openid_curl_easy_init(errmsg);
+ curl_easy_setopt(curl, CURLOPT_URL, ChrPtr(oiddata->server));
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, ReplyBuf);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlFillStrBuf_callback);
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
+
+ res = curl_easy_perform(curl);
+ if (res) {
+ syslog(LOG_DEBUG, "cmd_oidf() libcurl error %d: %s", res, errmsg);
+ }
+ curl_easy_cleanup(curl);
+ curl_formfree(formpost);
+
+ if (cbmstrcasestr(ChrPtr(ReplyBuf), "is_valid:true")) {
+ oiddata->verified = 1;
+ }
+ FreeStrBuf(&ReplyBuf);
+
+ syslog(LOG_DEBUG, "Authentication %s.", (oiddata->verified ? "succeeded" : "failed") );
+
+ /* Respond to the client */
+
+ if (oiddata->verified) {
+
+ /* If we were already logged in, attach the OpenID to the user's account */
+ if (CC->logged_in) {
+ if (attach_openid(&CC->user, oiddata->claimed_id) == 0) {
+ cprintf("attach\n");
+ syslog(LOG_DEBUG, "OpenID attach succeeded");
+ }
+ else {
+ cprintf("fail\n");
+ syslog(LOG_DEBUG, "OpenID attach failed");
+ }
+ }
+
+ /* Otherwise, a user is attempting to log in using the verified OpenID */
+ else {
+ /*
+ * Existing user who has claimed this OpenID?
+ *
+ * Note: if you think that sending the password back over the wire is insecure,
+ * check your assumptions. If someone has successfully asserted an OpenID that
+ * is associated with the account, they already have password equivalency and can
+ * login, so they could just as easily change the password, etc.
+ */
+ if (login_via_openid(oiddata->claimed_id) == 0) {
+ cprintf("authenticate\n%s\n%s\n", CC->user.fullname, CC->user.password);
+ logged_in_response();
+ syslog(LOG_DEBUG, "Logged in using previously claimed OpenID");
+ }
+
+ /*
+ * If this system does not allow self-service new user registration, the
+ * remaining modes do not apply, so fail here and now.
+ */
+ else if (config.c_disable_newu) {
+ cprintf("fail\n");
+ syslog(LOG_DEBUG, "Creating user failed due to local policy");
+ }
+
+ /*
+ * New user whose OpenID is verified and Simple Registration Extension is in use?
+ */
+ else if (openid_create_user_via_sreg(oiddata->claimed_id, keys) == 0) {
+ cprintf("authenticate\n%s\n%s\n", CC->user.fullname, CC->user.password);
+ logged_in_response();
+ syslog(LOG_DEBUG, "Successfully auto-created new user");
+ }
+
+ /*
+ * OpenID is verified, but the desired username either was not specified or
+ * conflicts with an existing user. Manual account creation is required.
+ */
+ else {
+ char *desired_name = NULL;
+ cprintf("verify_only\n");
+ cprintf("%s\n", ChrPtr(oiddata->claimed_id));
+ if (GetHash(keys, "sreg.nickname", 13, (void *) &desired_name)) {
+ cprintf("%s\n", desired_name);
+ }
+ else {
+ cprintf("\n");
+ }
+ syslog(LOG_DEBUG, "The desired Simple Registration name is already taken.");
+ }
+ }
+ }
+ else {
+ cprintf("fail\n");
+ }
+ cprintf("000\n");
+
+ if (oiddata->sreg_keys != NULL) {
+ DeleteHash(&oiddata->sreg_keys);
+ oiddata->sreg_keys = NULL;
+ }
+ oiddata->sreg_keys = keys;
+}
+
+
+
+/**************************************************************************/
+/* */
+/* Functions in this section handle module initialization and shutdown */
+/* */
+/**************************************************************************/
+
+
+
+