4 * This is an implementation of OpenID 1.1 Relying Party support, in stateless mode.
16 #include <sys/types.h>
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
23 # include <sys/time.h>
32 #include <curl/curl.h>
33 #include "ctdl_module.h"
35 #include "citserver.h"
39 char claimed_id
[1024];
49 /**************************************************************************/
51 /* Functions in this section handle Citadel internal OpenID mapping stuff */
53 /**************************************************************************/
57 * The structure of an openid record *key* is:
59 * |--------------claimed_id-------------|
60 * (actual length of claimed id)
63 * The structure of an openid record *value* is:
65 * |-----user_number----|------------claimed_id---------------|
66 * (sizeof long) (actual length of claimed id)
73 * Attach an OpenID to a Citadel account
75 int attach_openid(struct ctdluser
*who
, char *claimed_id
)
77 struct cdbdata
*cdboi
;
84 if (!claimed_id
) return(1);
85 if (IsEmptyStr(claimed_id
)) return(1);
87 /* Check to see if this OpenID is already in the database */
89 cdboi
= cdb_fetch(CDB_OPENID
, claimed_id
, strlen(claimed_id
));
91 memcpy(&fetched_usernum
, cdboi
->ptr
, sizeof(long));
94 if (fetched_usernum
== who
->usernum
) {
95 CtdlLogPrintf(CTDL_INFO
, "%s already associated; no action is taken\n", claimed_id
);
99 CtdlLogPrintf(CTDL_INFO
, "%s already belongs to another user\n", claimed_id
);
104 /* Not already in the database, so attach it now */
106 data_len
= sizeof(long) + strlen(claimed_id
) + 1;
107 data
= malloc(data_len
);
109 memcpy(data
, &who
->usernum
, sizeof(long));
110 memcpy(&data
[sizeof(long)], claimed_id
, strlen(claimed_id
) + 1);
112 cdb_store(CDB_OPENID
, claimed_id
, strlen(claimed_id
), data
, data_len
);
115 snprintf(buf
, sizeof buf
, "User <%s> (#%ld) has claimed the OpenID URL %s\n",
116 who
->fullname
, who
->usernum
, claimed_id
);
117 aide_message(buf
, "OpenID claim");
118 CtdlLogPrintf(CTDL_INFO
, "%s", buf
);
125 * When a user is being deleted, we have to delete any OpenID associations
127 void openid_purge(struct ctdluser
*usbuf
) {
128 struct cdbdata
*cdboi
;
129 HashList
*keys
= NULL
;
131 char *deleteme
= NULL
;
136 keys
= NewHash(1, NULL
);
140 cdb_rewind(CDB_OPENID
);
141 while (cdboi
= cdb_next_item(CDB_OPENID
), cdboi
!= NULL
) {
142 if (cdboi
->len
> sizeof(long)) {
143 if (((long)*(cdboi
->ptr
)) == usbuf
->usernum
) {
144 deleteme
= strdup(cdboi
->ptr
+ sizeof(long)),
145 Put(keys
, deleteme
, strlen(deleteme
), deleteme
, generic_free_handler
);
151 /* Go through the hash list, deleting keys we stored in it */
153 HashPos
= GetNewHashPos(keys
, 0);
154 while (GetNextHashPos(keys
, HashPos
, &len
, &Key
, &Value
)!=0)
156 CtdlLogPrintf(CTDL_DEBUG
, "Deleting associated OpenID <%s>\n", Value
);
157 cdb_delete(CDB_OPENID
, Value
, strlen(Value
));
158 /* note: don't free(Value) -- deleting the hash list will handle this for us */
160 DeleteHashPos(&HashPos
);
167 * List the OpenIDs associated with the currently logged in account
169 void cmd_oidl(char *argbuf
) {
170 struct cdbdata
*cdboi
;
172 if (CtdlAccessCheck(ac_logged_in
)) return;
173 cdb_rewind(CDB_OPENID
);
174 cprintf("%d Associated OpenIDs:\n", LISTING_FOLLOWS
);
176 while (cdboi
= cdb_next_item(CDB_OPENID
), cdboi
!= NULL
) {
177 if (cdboi
->len
> sizeof(long)) {
178 if (((long)*(cdboi
->ptr
)) == CC
->user
.usernum
) {
179 cprintf("%s\n", cdboi
->ptr
+ sizeof(long));
189 * Attempt to register (populate the vCard) the currently-logged-in user
190 * using the data from Simple Registration Extension, if present.
192 void populate_vcard_from_sreg(HashList
*sreg_keys
) {
195 int pop
= 0; /* number of fields populated */
197 char *postcode
= NULL
;
198 char *country
= NULL
;
200 if (!sreg_keys
) return;
204 if (GetHash(sreg_keys
, "identity", 8, (void *) &data
)) {
205 vcard_add_prop(v
, "url;type=openid", data
);
209 if (GetHash(sreg_keys
, "sreg.email", 10, (void *) &data
)) {
210 vcard_add_prop(v
, "email;internet", data
);
214 if (GetHash(sreg_keys
, "sreg.nickname", 13, (void *) &data
)) {
215 vcard_add_prop(v
, "nickname", data
);
219 if (GetHash(sreg_keys
, "sreg.fullname", 13, (void *) &data
)) {
221 vcard_add_prop(v
, "fn", data
);
222 vcard_fn_to_n(n
, data
, sizeof n
);
223 vcard_add_prop(v
, "n", n
);
227 if (!GetHash(sreg_keys
, "sreg.postcode", 13, (void *) &postcode
)) {
231 if (!GetHash(sreg_keys
, "sreg.country", 12, (void *) &country
)) {
235 if (postcode
|| country
) {
237 snprintf(adr
, sizeof adr
, ";;;;;%s;%s",
238 (postcode
? postcode
: ""),
239 (country
? country
: "")
241 vcard_add_prop(v
, "adr", adr
);
245 if (GetHash(sreg_keys
, "sreg.dob", 8, (void *) &data
)) {
246 vcard_add_prop(v
, "bday", data
);
250 if (GetHash(sreg_keys
, "sreg.gender", 11, (void *) &data
)) {
251 vcard_add_prop(v
, "x-funambol-gender", data
);
255 /* Only save the vCard if there is some useful data in it */
258 ser
= vcard_serialize(v
);
260 CtdlWriteObject(USERCONFIGROOM
, "text/x-vcard",
261 ser
, strlen(ser
)+1, &CC
->user
, 0, 0, 0
271 * Create a new user account, manually specifying the name, after successfully
272 * verifying an OpenID (which will of course be attached to the account)
274 void cmd_oidc(char *argbuf
) {
275 struct ctdl_openid
*oiddata
= (struct ctdl_openid
*) CC
->openid_data
;
277 if (!oiddata
->verified
) {
278 cprintf("%d You have not verified an OpenID yet.\n", ERROR
);
282 /* We can make the semantics of OIDC exactly the same as NEWU, simply
283 * by _calling_ cmd_newu() and letting it run. Very clever!
287 /* Now, if this logged us in, we have to attach the OpenID */
289 attach_openid(&CC
->user
, oiddata
->claimed_id
);
290 if (oiddata
->sreg_keys
!= NULL
) {
291 populate_vcard_from_sreg(oiddata
->sreg_keys
);
301 * Detach an OpenID from the currently logged in account
303 void cmd_oidd(char *argbuf
) {
304 struct cdbdata
*cdboi
;
305 char id_to_detach
[1024];
306 int this_is_mine
= 0;
308 if (CtdlAccessCheck(ac_logged_in
)) return;
309 extract_token(id_to_detach
, argbuf
, 0, '|', sizeof id_to_detach
);
310 if (IsEmptyStr(id_to_detach
)) {
311 cprintf("%d An empty OpenID URL is not allowed.\n", ERROR
+ ILLEGAL_VALUE
);
314 cdb_rewind(CDB_OPENID
);
315 while (cdboi
= cdb_next_item(CDB_OPENID
), cdboi
!= NULL
) {
316 if (cdboi
->len
> sizeof(long)) {
317 if (((long)*(cdboi
->ptr
)) == CC
->user
.usernum
) {
325 cprintf("%d That OpenID was not found or not associated with your account.\n",
326 ERROR
+ ILLEGAL_VALUE
);
330 cdb_delete(CDB_OPENID
, id_to_detach
, strlen(id_to_detach
));
331 cprintf("%d %s detached from your account.\n", CIT_OK
, id_to_detach
);
337 * Attempt to auto-create a new Citadel account using the nickname from Simple Registration Extension
339 int openid_create_user_via_sreg(char *claimed_id
, HashList
*sreg_keys
)
341 char *desired_name
= NULL
;
342 char new_password
[32];
344 if (config
.c_auth_mode
!= AUTHMODE_NATIVE
) return(1);
345 if (config
.c_disable_newu
) return(2);
346 if (CC
->logged_in
) return(3);
347 if (!GetHash(sreg_keys
, "sreg.nickname", 13, (void *) &desired_name
)) return(4);
349 CtdlLogPrintf(CTDL_DEBUG
, "The desired account name is <%s>\n", desired_name
);
351 if (!getuser(&CC
->user
, desired_name
)) {
352 CtdlLogPrintf(CTDL_DEBUG
, "<%s> is already taken by another user.\n", desired_name
);
353 memset(&CC
->user
, 0, sizeof(struct ctdluser
));
357 /* The desired account name is available. Create the account and log it in! */
358 if (create_user(desired_name
, 1)) return(6);
360 snprintf(new_password
, sizeof new_password
, "%08lx%08lx", random(), random());
361 CtdlSetPassword(new_password
);
362 attach_openid(&CC
->user
, claimed_id
);
363 populate_vcard_from_sreg(sreg_keys
);
369 * If a user account exists which is associated with the Claimed ID, log it in and return zero.
370 * Otherwise it returns nonzero.
372 int login_via_openid(char *claimed_id
)
374 struct cdbdata
*cdboi
;
377 cdboi
= cdb_fetch(CDB_OPENID
, claimed_id
, strlen(claimed_id
));
382 memcpy(&usernum
, cdboi
->ptr
, sizeof(long));
385 if (!getuserbynumber(&CC
->user
, usernum
)) {
386 /* Now become the user we just created */
387 safestrncpy(CC
->curr_user
, CC
->user
.fullname
, sizeof CC
->curr_user
);
392 memset(&CC
->user
, 0, sizeof(struct ctdluser
));
400 /**************************************************************************/
402 /* Functions in this section handle OpenID protocol */
404 /**************************************************************************/
408 * Locate a <link> tag and, given its 'rel=' parameter, return its 'href' parameter
410 void extract_link(char *target_buf
, int target_size
, char *rel
, char *source_buf
)
412 char *ptr
= source_buf
;
414 if (!target_buf
) return;
416 if (!source_buf
) return;
420 while (ptr
= bmstrcasestr(ptr
, "<link"), ptr
!= NULL
) {
422 char work_buffer
[2048];
423 char *link_tag_start
= NULL
;
424 char *link_tag_end
= NULL
;
429 link_tag_start
= ptr
;
430 link_tag_end
= strchr(ptr
, '>');
434 if ((link_tag_end
) && (link_tag_end
> link_tag_start
)) {
436 len
= link_tag_end
- link_tag_start
;
437 if (len
> sizeof work_buffer
) len
= sizeof work_buffer
;
438 memcpy(work_buffer
, link_tag_start
, len
);
440 char *rel_start
= NULL
;
441 char *rel_end
= NULL
;
442 rel_start
= bmstrcasestr(work_buffer
, "rel=");
444 rel_start
= strchr(rel_start
, '\"');
447 rel_end
= strchr(rel_start
, '\"');
448 if ((rel_end
) && (rel_end
> rel_start
)) {
449 safestrncpy(rel_tag
, rel_start
, rel_end
- rel_start
+ 1);
454 char *href_start
= NULL
;
455 char *href_end
= NULL
;
456 href_start
= bmstrcasestr(work_buffer
, "href=");
458 href_start
= strchr(href_start
, '\"');
461 href_end
= strchr(href_start
, '\"');
462 if ((href_end
) && (href_end
> href_start
)) {
463 safestrncpy(href_tag
, href_start
, href_end
- href_start
+ 1);
468 if (!strcasecmp(rel
, rel_tag
)) {
469 safestrncpy(target_buf
, href_tag
, target_size
);
485 int total_bytes_received
;
490 size_t fh_callback(void *ptr
, size_t size
, size_t nmemb
, void *stream
)
492 struct fh_data
*fh
= (struct fh_data
*) stream
;
493 int got_bytes
= (size
* nmemb
);
495 if (fh
->total_bytes_received
+ got_bytes
> fh
->maxbytes
) {
496 got_bytes
= fh
->maxbytes
- fh
->total_bytes_received
;
499 memcpy(&fh
->buf
[fh
->total_bytes_received
], ptr
, got_bytes
);
500 fh
->total_bytes_received
+= got_bytes
;
503 return (size
* nmemb
); /* always succeed; libcurl doesn't need to know if we truncated it */
509 * Begin an HTTP fetch (returns number of bytes actually fetched, or -1 for error) using libcurl.
511 * If 'normalize_len' is nonzero, the caller is specifying the buffer size of 'url', and is
512 * requesting that the effective (normalized) URL be copied back to it.
514 int fetch_http(char *url
, char *target_buf
, int maxbytes
, int normalize_len
)
518 char errmsg
[1024] = "";
519 struct fh_data fh
= {
524 char *effective_url
= NULL
;
526 if (!url
) return(-1);
527 if (!target_buf
) return(-1);
528 memset(target_buf
, 0, maxbytes
);
530 curl
= curl_easy_init();
532 CtdlLogPrintf(CTDL_ALERT
, "Unable to initialize libcurl.\n");
536 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
537 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, 0);
538 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYHOST
, 0);
539 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
, &fh
);
540 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fh_callback
);
541 curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, errmsg
);
542 curl_easy_setopt(curl
, CURLOPT_FOLLOWLOCATION
, 1);
543 curl_easy_setopt(curl
, CURLOPT_USERAGENT
, CITADEL
);
544 curl_easy_setopt(curl
, CURLOPT_TIMEOUT
, 180); /* die after 180 seconds */
545 if (!IsEmptyStr(config
.c_ip_addr
)) {
546 curl_easy_setopt(curl
, CURLOPT_INTERFACE
, config
.c_ip_addr
);
548 res
= curl_easy_perform(curl
);
550 CtdlLogPrintf(CTDL_DEBUG
, "fetch_http() libcurl error %d: %s\n", res
, errmsg
);
552 if (normalize_len
> 0) {
553 curl_easy_getinfo(curl
, CURLINFO_EFFECTIVE_URL
, &effective_url
);
554 safestrncpy(url
, effective_url
, normalize_len
);
556 curl_easy_cleanup(curl
);
557 return fh
.total_bytes_received
;
562 * Setup an OpenID authentication
564 void cmd_oids(char *argbuf
) {
565 char return_to
[1024];
566 char trust_root
[1024];
569 struct CitContext
*CCC
= CC
; /* CachedCitContext - performance boost */
570 struct ctdl_openid
*oiddata
;
572 oiddata
= (struct ctdl_openid
*) CCC
->openid_data
;
574 if (oiddata
!= NULL
) {
575 if (oiddata
->sreg_keys
!= NULL
) {
576 DeleteHash(&oiddata
->sreg_keys
);
577 oiddata
->sreg_keys
= NULL
;
579 free(CCC
->openid_data
);
581 oiddata
= malloc(sizeof(struct ctdl_openid
));
582 if (oiddata
== NULL
) {
583 cprintf("%d malloc failed\n", ERROR
+ INTERNAL_ERROR
);
586 memset(oiddata
, 0, sizeof(struct ctdl_openid
));
587 CCC
->openid_data
= (void *) oiddata
;
589 extract_token(oiddata
->claimed_id
, argbuf
, 0, '|', sizeof oiddata
->claimed_id
);
590 extract_token(return_to
, argbuf
, 1, '|', sizeof return_to
);
591 extract_token(trust_root
, argbuf
, 2, '|', sizeof trust_root
);
592 oiddata
->verified
= 0;
594 i
= fetch_http(oiddata
->claimed_id
, buf
, sizeof buf
- 1, sizeof oiddata
->claimed_id
);
595 CtdlLogPrintf(CTDL_DEBUG
, "Normalized URL and Claimed ID is: %s\n", oiddata
->claimed_id
);
596 buf
[sizeof buf
- 1] = 0;
598 char openid_delegate
[1024];
600 extract_link(oiddata
->server
, sizeof oiddata
->server
, "openid.server", buf
);
601 extract_link(openid_delegate
, sizeof openid_delegate
, "openid.delegate", buf
);
603 if (IsEmptyStr(oiddata
->server
)) {
604 cprintf("%d There is no OpenID identity provider at this URL.\n", ERROR
);
608 /* Empty delegate is legal; we just use the openid_url instead */
609 if (IsEmptyStr(openid_delegate
)) {
610 safestrncpy(openid_delegate
, oiddata
->claimed_id
, sizeof openid_delegate
);
613 /* Assemble a URL to which the user-agent will be redirected. */
614 char redirect_string
[4096];
615 char escaped_identity
[512];
616 char escaped_return_to
[2048];
617 char escaped_trust_root
[1024];
618 char escaped_sreg_optional
[256];
620 urlesc(escaped_identity
, sizeof escaped_identity
, openid_delegate
);
621 urlesc(escaped_return_to
, sizeof escaped_return_to
, return_to
);
622 urlesc(escaped_trust_root
, sizeof escaped_trust_root
, trust_root
);
623 urlesc(escaped_sreg_optional
, sizeof escaped_sreg_optional
,
624 "nickname,email,fullname,postcode,country,dob,gender");
626 snprintf(redirect_string
, sizeof redirect_string
,
628 "?openid.mode=checkid_setup"
629 "&openid.identity=%s"
630 "&openid.return_to=%s"
631 "&openid.trust_root=%s"
632 "&openid.sreg.optional=%s"
638 escaped_sreg_optional
640 cprintf("%d %s\n", CIT_OK
, redirect_string
);
644 cprintf("%d Unable to fetch OpenID URL\n", ERROR
);
652 * Finalize an OpenID authentication
654 void cmd_oidf(char *argbuf
) {
658 HashList
*keys
= NULL
;
659 struct ctdl_openid
*oiddata
= (struct ctdl_openid
*) CC
->openid_data
;
661 keys
= NewHash(1, NULL
);
663 cprintf("%d NewHash() failed\n", ERROR
+ INTERNAL_ERROR
);
667 cprintf("%d Transmit OpenID data now\n", START_CHAT_MODE
);
669 while (client_getln(buf
, sizeof buf
), strcmp(buf
, "000")) {
670 extract_token(thiskey
, buf
, 0, '|', sizeof thiskey
);
671 extract_token(thisdata
, buf
, 1, '|', sizeof thisdata
);
672 CtdlLogPrintf(CTDL_DEBUG
, "%s: [%d] %s\n", thiskey
, strlen(thisdata
), thisdata
);
673 Put(keys
, thiskey
, strlen(thiskey
), strdup(thisdata
), generic_free_handler
);
677 /* Now that we have all of the parameters, we have to validate the signature against the server */
678 CtdlLogPrintf(CTDL_DEBUG
, "About to validate the signature...\n");
682 struct curl_httppost
*formpost
= NULL
;
683 struct curl_httppost
*lastptr
= NULL
;
684 char errmsg
[1024] = "";
685 char *o_assoc_handle
= NULL
;
687 char *o_signed
= NULL
;
688 int num_signed_values
;
691 char k_o_keyname
[128];
692 char *k_value
= NULL
;
695 struct fh_data fh
= {
701 curl_formadd(&formpost
, &lastptr
,
702 CURLFORM_COPYNAME
, "openid.mode",
703 CURLFORM_COPYCONTENTS
, "check_authentication",
705 CtdlLogPrintf(CTDL_DEBUG
, "%25s : %s\n", "openid.mode", "check_authentication");
707 if (GetHash(keys
, "assoc_handle", 12, (void *) &o_assoc_handle
)) {
708 curl_formadd(&formpost
, &lastptr
,
709 CURLFORM_COPYNAME
, "openid.assoc_handle",
710 CURLFORM_COPYCONTENTS
, o_assoc_handle
,
712 CtdlLogPrintf(CTDL_DEBUG
, "%25s : %s\n", "openid.assoc_handle", o_assoc_handle
);
715 if (GetHash(keys
, "sig", 3, (void *) &o_sig
)) {
716 curl_formadd(&formpost
, &lastptr
,
717 CURLFORM_COPYNAME
, "openid.sig",
718 CURLFORM_COPYCONTENTS
, o_sig
,
720 CtdlLogPrintf(CTDL_DEBUG
, "%25s : %s\n", "openid.sig", o_sig
);
723 if (GetHash(keys
, "signed", 6, (void *) &o_signed
)) {
724 curl_formadd(&formpost
, &lastptr
,
725 CURLFORM_COPYNAME
, "openid.signed",
726 CURLFORM_COPYCONTENTS
, o_signed
,
728 CtdlLogPrintf(CTDL_DEBUG
, "%25s : %s\n", "openid.signed", o_signed
);
730 num_signed_values
= num_tokens(o_signed
, ',');
731 for (i
=0; i
<num_signed_values
; ++i
) {
732 extract_token(k_keyname
, o_signed
, i
, ',', sizeof k_keyname
);
733 if (strcasecmp(k_keyname
, "mode")) { // work around phpMyID bug
734 if (GetHash(keys
, k_keyname
, strlen(k_keyname
), (void *) &k_value
)) {
735 snprintf(k_o_keyname
, sizeof k_o_keyname
, "openid.%s", k_keyname
);
736 curl_formadd(&formpost
, &lastptr
,
737 CURLFORM_COPYNAME
, k_o_keyname
,
738 CURLFORM_COPYCONTENTS
, k_value
,
740 CtdlLogPrintf(CTDL_DEBUG
, "%25s : %s\n", k_o_keyname
, k_value
);
743 CtdlLogPrintf(CTDL_INFO
, "OpenID: signed field '%s' is missing\n",
750 curl
= curl_easy_init();
751 curl_easy_setopt(curl
, CURLOPT_URL
, oiddata
->server
);
752 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, 0);
753 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYHOST
, 0);
754 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
, &fh
);
755 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fh_callback
);
756 curl_easy_setopt(curl
, CURLOPT_HTTPPOST
, formpost
);
757 curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, errmsg
);
758 curl_easy_setopt(curl
, CURLOPT_FOLLOWLOCATION
, 1);
759 curl_easy_setopt(curl
, CURLOPT_USERAGENT
, CITADEL
);
760 curl_easy_setopt(curl
, CURLOPT_TIMEOUT
, 180); /* die after 180 seconds */
761 if (!IsEmptyStr(config
.c_ip_addr
)) {
762 curl_easy_setopt(curl
, CURLOPT_INTERFACE
, config
.c_ip_addr
);
765 res
= curl_easy_perform(curl
);
767 CtdlLogPrintf(CTDL_DEBUG
, "cmd_oidf() libcurl error %d: %s\n", res
, errmsg
);
769 curl_easy_cleanup(curl
);
770 curl_formfree(formpost
);
772 valbuf
[fh
.total_bytes_received
] = 0;
774 if (bmstrcasestr(valbuf
, "is_valid:true")) {
775 oiddata
->verified
= 1;
778 CtdlLogPrintf(CTDL_DEBUG
, "Authentication %s.\n", (oiddata
->verified
? "succeeded" : "failed") );
780 /* Respond to the client */
782 if (oiddata
->verified
) {
784 /* If we were already logged in, attach the OpenID to the user's account */
786 if (attach_openid(&CC
->user
, oiddata
->claimed_id
) == 0) {
794 /* Otherwise, a user is attempting to log in using the verified OpenID */
797 * Existing user who has claimed this OpenID?
799 * Note: if you think that sending the password back over the wire is insecure,
800 * check your assumptions. If someone has successfully asserted an OpenID that
801 * is associated with the account, they already have password equivalency and can
802 * login, so they could just as easily change the password, etc.
804 if (login_via_openid(oiddata
->claimed_id
) == 0) {
805 cprintf("authenticate\n%s\n%s\n", CC
->user
.fullname
, CC
->user
.password
);
806 logged_in_response();
810 * If this system does not allow self-service new user registration, the
811 * remaining modes do not apply, so fail here and now.
813 else if (config
.c_disable_newu
) {
818 * New user whose OpenID is verified and Simple Registration Extension is in use?
820 else if (openid_create_user_via_sreg(oiddata
->claimed_id
, keys
) == 0) {
821 cprintf("authenticate\n%s\n%s\n", CC
->user
.fullname
, CC
->user
.password
);
822 logged_in_response();
826 * OpenID is verified, but the desired username either was not specified or
827 * conflicts with an existing user. Manual account creation is required.
830 char *desired_name
= NULL
;
831 cprintf("verify_only\n");
832 cprintf("%s\n", oiddata
->claimed_id
);
833 if (GetHash(keys
, "sreg.nickname", 13, (void *) &desired_name
)) {
834 cprintf("%s\n", desired_name
);
847 if (oiddata
->sreg_keys
!= NULL
) {
848 DeleteHash(&oiddata
->sreg_keys
);
849 oiddata
->sreg_keys
= NULL
;
851 oiddata
->sreg_keys
= keys
;
856 /**************************************************************************/
858 /* Functions in this section handle module initialization and shutdown */
860 /**************************************************************************/
864 * This cleanup function blows away the temporary memory used by this module.
866 void openid_cleanup_function(void) {
867 struct ctdl_openid
*oiddata
= (struct ctdl_openid
*) CC
->openid_data
;
869 if (oiddata
!= NULL
) {
870 CtdlLogPrintf(CTDL_DEBUG
, "Clearing OpenID session state\n");
871 if (oiddata
->sreg_keys
!= NULL
) {
872 DeleteHash(&oiddata
->sreg_keys
);
873 oiddata
->sreg_keys
= NULL
;
880 CTDL_MODULE_INIT(openid_rp
)
883 curl_global_init(CURL_GLOBAL_ALL
);
885 /* Only enable the OpenID command set when native mode authentication is in use. */
886 if (config
.c_auth_mode
== AUTHMODE_NATIVE
) {
887 CtdlRegisterProtoHook(cmd_oids
, "OIDS", "Setup OpenID authentication");
888 CtdlRegisterProtoHook(cmd_oidf
, "OIDF", "Finalize OpenID authentication");
889 CtdlRegisterProtoHook(cmd_oidl
, "OIDL", "List OpenIDs associated with an account");
890 CtdlRegisterProtoHook(cmd_oidd
, "OIDD", "Detach an OpenID from an account");
891 CtdlRegisterProtoHook(cmd_oidc
, "OIDC", "Create new user after validating OpenID");
893 CtdlRegisterSessionHook(openid_cleanup_function
, EVT_LOGOUT
);
894 CtdlRegisterUserHook(openid_purge
, EVT_PURGEUSER
);
897 /* return our Subversion id for the Log */