4 * WebcitAuth; Handles authentication of users to a Citadel server.
12 void display_reg(int during_login);
15 * Access level definitions. This is initialized from a function rather than a
16 * static array so that the strings may be localized.
20 void initialize_axdefs(void) {
21 axdefs[0] = _("Deleted"); /* an erased user */
22 axdefs[1] = _("New User"); /* a new user */
23 axdefs[2] = _("Problem User"); /* a trouble maker */
24 axdefs[3] = _("Local User"); /* user with normal privileges */
25 axdefs[4] = _("Network User"); /* a user that may access network resources */
26 axdefs[5] = _("Preferred User");/* a moderator */
27 axdefs[6] = _("Aide"); /* chief */
34 * Display the login screen
35 * mesg = the error message if last attempt failed.
37 void display_login(void)
40 output_headers(1, 0, 0, 0, 1, 0);
41 do_template("login", NULL);
49 * Display the openid-enabled login screen
50 * mesg = the error message if last attempt failed.
52 void display_openid_login(char *mesg)
56 output_headers(1, 1, 2, 0, 0, 0);
57 wprintf("<div id=\"login_screen\">\n");
59 if ((mesg != NULL) && (!IsEmptyStr(mesg))) {
60 stresc(buf, SIZ, mesg, 0, 0);
61 svprintf(HKEY("MESG"), WCS_STRING, "%s", buf);
64 svprintf(HKEY("LOGIN_INSTRUCTIONS"), WCS_STRING,
66 "<li>Enter your OpenID URL and click "Login"."
67 "<li><a href=\"http://www.citadel.org/doku.php/documentation:openid\">"
68 "Click here to learn what OpenID is and how Citadel is using it.</a>"
69 "<li>Please log off properly when finished. "
70 "<li>You must use a browser that supports <i>frames</i> and "
72 "<li>Also keep in mind that if your browser is "
73 "configured to block pop-up windows, you will not be able "
74 "to receive any instant messages.<br />"
78 svput("HELLO", WCS_SERVCMD, "MESG hello");
80 svprintf(HKEY("OFFER_CONVENTIONAL_LOGIN"), WCS_STRING,
82 "<a href=\"display_login\">"
86 "Log in using a user name and password"
89 do_template("openid_login", NULL);
94 void display_openid_name_request(char *claimed_id, char *username) {
97 output_headers(1, 1, 2, 0, 0, 0);
98 wprintf("<div id=\"login_screen\">\n");
100 stresc(buf, sizeof buf, claimed_id, 0, 0);
101 svprintf(HKEY("VERIFIED"), WCS_STRING, _("Your OpenID <tt>%s</tt> was successfully verified."),
103 svput("CLAIMED_ID", WCS_STRING, claimed_id);
106 if (!IsEmptyStr(username)) {
107 stresc(buf, sizeof buf, username, 0, 0);
108 svprintf(HKEY("REASON"), WCS_STRING,
109 _("However, the user name '%s' conflicts with an existing user."), username);
112 svput("REASON", WCS_STRING, "");
115 svput("ACTION_REQUESTED", WCS_STRING, _("Please specify the user name you would like to use."));
117 svput("USERNAME_BOX", WCS_STRING, _("User name:"));
118 svput("NEWUSER_BUTTON", WCS_STRING, _("New User"));
119 svput("EXIT_BUTTON", WCS_STRING, _("Exit"));
121 svprintf(HKEY("BOXTITLE"), WCS_STRING, _("%s - powered by <a href=\"http://www.citadel.org\">Citadel</a>"),
122 serv_info.serv_humannode);
124 do_template("openid_manual_create", NULL);
130 /* Initialize the session
132 * This function needs to get called whenever the session changes from
133 * not-logged-in to logged-in, either by an explicit login by the user or
134 * by a timed-out session automatically re-establishing with a little help
135 * from the browser cookie. Either way, we need to load access controls and
136 * preferences from the server.
140 * serv_response The parameters returned from a Citadel USER or NEWU command
142 void become_logged_in(char *user, char *pass, char *serv_response)
148 extract_token(WC->wc_fullname, &serv_response[4], 0, '|', sizeof WC->wc_fullname);
149 safestrncpy(WC->wc_username, user, sizeof WC->wc_username);
150 safestrncpy(WC->wc_password, pass, sizeof WC->wc_password);
151 WC->axlevel = extract_int(&serv_response[4], 1);
152 if (WC->axlevel >= 6) {
159 serv_getln(buf, sizeof buf);
161 WC->new_mail = extract_int(&buf[4], 0);
162 WC->need_regi = extract_int(&buf[4], 1);
163 WC->need_vali = extract_int(&buf[4], 2);
164 extract_token(WC->cs_inet_email, &buf[4], 3, '|', sizeof WC->cs_inet_email);
167 get_pref_long("current_iconbar", &WC->current_iconbar, current_iconbar_menu);
169 get_preference("floordiv_expanded", &FloorDiv);
170 WC->floordiv_expanded = FloorDiv;
175 * Perform authentication using a user name and password
182 if (havebstr("language")) {
183 set_selected_language(bstr("language"));
184 go_selected_language();
187 if (havebstr("exit_action")) {
191 if (havebstr("login_action")) {
192 serv_printf("USER %s", bstr("name"));
193 serv_getln(buf, sizeof buf);
195 serv_printf("PASS %s", bstr("pass"));
196 serv_getln(buf, sizeof buf);
198 become_logged_in(bstr("name"), bstr("pass"), buf);
200 snprintf(WCC->ImportantMessage,
201 sizeof (WCC->ImportantMessage),
208 snprintf(WCC->ImportantMessage,
209 sizeof (WCC->ImportantMessage),
216 if (havebstr("newuser_action")) {
217 if (!havebstr("pass")) {
218 snprintf(WCC->ImportantMessage,
219 sizeof (WCC->ImportantMessage),
221 _("Blank passwords are not allowed."));
225 serv_printf("NEWU %s", bstr("name"));
226 serv_getln(buf, sizeof buf);
228 become_logged_in(bstr("name"), bstr("pass"), buf);
229 serv_printf("SETP %s", bstr("pass"));
230 serv_getln(buf, sizeof buf);
232 snprintf(WCC->ImportantMessage,
233 sizeof (WCC->ImportantMessage),
240 if (WCC->logged_in) {
241 set_preference("language", NewStrBufPlain(bstr("language"), -1), 1);
242 if (WCC->need_regi) {
244 } else if (WCC->need_vali) {
250 snprintf(WCC->ImportantMessage,
251 sizeof (WCC->ImportantMessage),
253 _("Your password was not accepted."));
260 * Try to create an account manually after an OpenID was verified
262 void openid_manual_create(void)
266 if (havebstr("exit_action")) {
271 if (havebstr("newuser_action")) {
272 serv_printf("OIDC %s", bstr("name"));
273 serv_getln(buf, sizeof buf);
275 char gpass[1024] = "";
276 serv_puts("SETP GENERATE_RANDOM_PASSWORD");
277 serv_getln(gpass, sizeof gpass);
278 become_logged_in(bstr("name"), &gpass[4], buf);
285 } else if (WC->need_vali) {
291 display_openid_name_request(bstr("openid_url"), bstr("name"));
298 * Perform authentication using OpenID
299 * assemble the checkid_setup request and then redirect to the user's identity provider
301 void do_openid_login(void)
305 if (havebstr("language")) {
306 set_selected_language(bstr("language"));
307 go_selected_language();
310 if (havebstr("exit_action")) {
314 if (havebstr("login_action")) {
315 snprintf(buf, sizeof buf,
316 "OIDS %s|%s://%s/finalize_openid_login|%s://%s",
318 (is_https ? "https" : "http"), WC->http_host,
319 (is_https ? "https" : "http"), WC->http_host
323 serv_getln(buf, sizeof buf);
325 lprintf(CTDL_DEBUG, "OpenID server contacted; redirecting to %s\n", &buf[4]);
326 http_redirect(&buf[4]);
330 display_openid_login(&buf[4]);
335 /* If we get to this point then something failed. */
336 display_openid_login(_("Your password was not accepted."));
340 * Complete the authentication using OpenID
341 * This function handles the positive or negative assertion from the user's Identity Provider
343 void finalize_openid_login(void)
347 int already_logged_in = (WCC->logged_in) ;
349 char result[128] = "";
350 char username[128] = "";
351 char password[128] = "";
352 char logged_in_response[1024] = "";
353 char claimed_id[1024] = "";
355 if (havebstr("openid.mode")) {
356 if (!strcasecmp(bstr("openid.mode"), "id_res")) {
359 serv_getln(buf, sizeof buf);
368 Cursor = GetNewHashPos (WCC->urlstrings, 0);
369 while (GetNextHashPos(WCC->urlstrings, Cursor, &HKLen, &HKey, &U)) {
371 if (!strncasecmp(u->url_key, "openid.", 7)) {
372 serv_printf("%s|%s", &u->url_key[7], ChrPtr(u->url_data));
379 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
380 if (linecount == 0) safestrncpy(result, buf, sizeof result);
381 if (!strcasecmp(result, "authenticate")) {
382 if (linecount == 1) {
383 safestrncpy(username, buf, sizeof username);
385 else if (linecount == 2) {
386 safestrncpy(password, buf, sizeof password);
388 else if (linecount == 3) {
389 safestrncpy(logged_in_response, buf,
390 sizeof logged_in_response);
393 else if (!strcasecmp(result, "verify_only")) {
394 if (linecount == 1) {
395 safestrncpy(claimed_id, buf, sizeof claimed_id);
397 if (linecount == 2) {
398 safestrncpy(username, buf, sizeof username);
407 /* If we were already logged in, this was an attempt to associate an OpenID account */
408 if (already_logged_in) {
413 /* If this operation logged us in, either by connecting with an existing account or by
414 * auto-creating one using Simple Registration Extension, we're already on our way.
416 if (!strcasecmp(result, "authenticate")) {
417 become_logged_in(username, password, logged_in_response);
420 /* The specified OpenID was verified but the desired user name was either not specified via SRI
421 * or conflicts with an existing user. Either way the user will need to specify a new name.
424 else if (!strcasecmp(result, "verify_only")) {
425 display_openid_name_request(claimed_id, username);
428 /* Did we manage to log in? If so, continue with the normal flow... */
436 display_openid_login(_("Your password was not accepted."));
443 * Display a welcome screen to the user.
445 * If this is the first time login, and the web based setup is enabled,
446 * lead the user through the setup routines
448 void do_welcome(void)
451 #ifdef XXX_NOT_FINISHED_YET_XXX
456 * See if we have to run the first-time setup wizard
461 sprintf(wizard_filename, "setupwiz.%s.%s",
463 len = strlen(wizard_filename);
464 for (i=0; i<len; ++i) {
465 if ( (wizard_filename[i]==' ')
466 || (wizard_filename[i] == '/')
468 wizard_filename[i] = '_';
472 fp = fopen(wizard_filename, "r");
474 fgets(buf, sizeof buf, fp);
475 buf[strlen(buf)-1] = 0;
477 if (atoi(buf) == serv_info.serv_rev_level) {
478 setup_wizard = 1; /**< already run */
484 http_redirect("setup_wizard");
490 * Go to the user's preferred start page
492 if (!get_preference("startpage", &Buf)) {
494 StrBufPrintf(Buf, "dotskip&room=_BASEROOM_");
495 set_preference("startpage", Buf, 1);
497 if (ChrPtr(Buf)[0] == '/') {
498 StrBufCutLeft(Buf, 1);
500 if (StrLength(Buf) == 0)
501 StrBufAppendBufPlain(Buf, "dotgoto?room=_BASEROOM_", -1, 0);
502 http_redirect(ChrPtr(Buf));
507 * Disconnect from the Citadel server, and end this WebCit session
509 void end_webcit_session(void) {
512 set_pref_long("current_iconbar", WC->current_iconbar, 0);
517 /* close() of citadel socket will be done by do_housekeeping() */
527 safestrncpy(WC->wc_username, "", sizeof WC->wc_username);
528 safestrncpy(WC->wc_password, "", sizeof WC->wc_password);
529 safestrncpy(WC->wc_roomname, "", sizeof WC->wc_roomname);
530 safestrncpy(WC->wc_fullname, "", sizeof WC->wc_fullname);
532 /** Calling output_headers() this way causes the cookies to be un-set */
533 output_headers(1, 1, 0, 1, 0, 0);
535 wprintf("<div id=\"logout_screen\">");
536 wprintf("<div class=\"box\">");
537 wprintf("<div class=\"boxlabel\">");
538 wprintf(_("Log off"));
539 wprintf("</div><div class=\"boxcontent\">");
540 serv_puts("MESG goodbye");
541 serv_getln(buf, sizeof buf);
543 if (WC->serv_sock >= 0) {
547 wprintf("Goodbye\n");
551 wprintf(_("This program was unable to connect or stay "
552 "connected to the Citadel server. Please report "
553 "this problem to your system administrator.")
555 wprintf("<a href=\"http://www.citadel.org/doku.php/"
556 "faq:mastering_your_os:net#netstat\">%s</a>",
560 wprintf("<hr /><div class=\"buttons\"> "
561 "<span class=\"button_link\"><a href=\".\">");
562 wprintf(_("Log in again"));
563 wprintf("</a></span> <span class=\"button_link\">"
564 "<a href=\"javascript:window.close();\">");
565 wprintf(_("Close window"));
566 wprintf("</a></span></div></div></div></div>\n");
568 end_webcit_session();
582 output_headers(1, 1, 2, 0, 0, 0);
583 wprintf("<div id=\"banner\">\n");
585 wprintf(_("Validate new users"));
589 wprintf("<div id=\"content\" class=\"service\">\n");
591 /* If the user just submitted a validation, process it... */
592 safestrncpy(buf, bstr("user"), sizeof buf);
593 if (!IsEmptyStr(buf)) {
594 if (havebstr("axlevel")) {
595 serv_printf("VALI %s|%s", buf, bstr("axlevel"));
596 serv_getln(buf, sizeof buf);
598 wprintf("<b>%s</b><br />\n", &buf[4]);
603 /* Now see if any more users require validation. */
605 serv_getln(buf, sizeof buf);
608 wprintf(_("No users require validation at this time."));
609 wprintf("</b><br />\n");
614 wprintf("<b>%s</b><br />\n", &buf[4]);
619 wprintf("<div class=\"fix_scrollbar_bug\">"
620 "<table class=\"auth_validate\"><tr><td>\n");
623 safestrncpy(user, &buf[4], sizeof user);
624 serv_printf("GREG %s", user);
625 serv_getln(cmd, sizeof cmd);
629 serv_getln(buf, sizeof buf);
632 wprintf("#%s<br /><H1>%s</H1>",
641 while (!IsEmptyStr(pch))
645 else if (isalpha(*pch))
656 pch = _("very weak");
669 wprintf("PW: %s<br />\n", pch);
672 wprintf("%s<br />\n", buf);
674 wprintf("%s<br />\n", buf);
676 wprintf("%s, ", buf);
680 wprintf("%s<br />\n", buf);
682 wprintf("%s<br />\n", buf);
684 wprintf(_("Current access level: %d (%s)\n"),
685 atoi(buf), axdefs[atoi(buf)]);
686 } while (strcmp(buf, "000"));
688 wprintf("<H1>%s</H1>%s<br />\n", user, &cmd[4]);
692 wprintf(_("Select access level for this user:"));
694 for (a = 0; a <= 6; ++a) {
695 wprintf("<a href=\"validate?nonce=%d?user=", WC->nonce);
697 wprintf("&axlevel=%d\">%s</A> \n",
702 wprintf("</CENTER>\n");
703 wprintf("</td></tr></table></div>\n");
710 * Display form for registration.
712 * (Set during_login to 1 if this registration is being performed during
713 * new user login and will require chaining to the proper screen.)
715 void display_reg(int during_login)
719 if (goto_config_room() != 0) {
720 if (during_login) do_welcome();
721 else display_main_menu();
725 vcard_msgnum = locate_user_vcard(WC->wc_fullname, -1);
726 if (vcard_msgnum < 0L) {
727 if (during_login) do_welcome();
728 else display_main_menu();
733 do_edit_vcard(vcard_msgnum, "1", "do_welcome", USERCONFIGROOM);
736 do_edit_vcard(vcard_msgnum, "1", "display_main_menu", USERCONFIGROOM);
745 * display form for changing your password
747 void display_changepw(void)
751 output_headers(1, 1, 1, 0, 0, 0);
753 Buf = NewStrBufPlain(_("Change your password"), -1);
754 DoTemplate(HKEY("beginbox"), NULL, Buf, CTX_STRBUF);
758 if (!IsEmptyStr(WC->ImportantMessage)) {
759 wprintf("<span class=\"errormsg\">"
760 "%s</span><br />\n", WC->ImportantMessage);
761 safestrncpy(WC->ImportantMessage, "", sizeof WC->ImportantMessage);
764 serv_puts("MESG changepw");
765 serv_getln(buf, sizeof buf);
770 wprintf("<form name=\"changepwform\" action=\"changepw\" method=\"post\">\n");
771 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
772 wprintf("<table class=\"altern\" ");
773 wprintf("<tr class=\"even\"><td>");
774 wprintf(_("Enter new password:"));
775 wprintf("</td><td>");
776 wprintf("<input type=\"password\" name=\"newpass1\" value=\"\" maxlength=\"20\"></td></tr>\n");
777 wprintf("<tr class=\"odd\"><td>");
778 wprintf(_("Enter it again to confirm:"));
779 wprintf("</td><td>");
780 wprintf("<input type=\"password\" name=\"newpass2\" value=\"\" maxlength=\"20\"></td></tr>\n");
781 wprintf("</table>\n");
783 wprintf("<div class=\"buttons\">\n");
784 wprintf("<input type=\"submit\" name=\"change_action\" value=\"%s\">", _("Change password"));
786 wprintf("<input type=\"submit\" name=\"cancel_action\" value=\"%s\">\n", _("Cancel"));
788 wprintf("</form>\n");
790 do_template("endbox", NULL);
796 * if passwords match, propagate it to citserver.
801 char newpass1[32], newpass2[32];
803 if (!havebstr("change_action")) {
804 safestrncpy(WC->ImportantMessage,
805 _("Cancelled. Password was not changed."),
806 sizeof WC->ImportantMessage);
811 safestrncpy(newpass1, bstr("newpass1"), sizeof newpass1);
812 safestrncpy(newpass2, bstr("newpass2"), sizeof newpass2);
814 if (strcasecmp(newpass1, newpass2)) {
815 safestrncpy(WC->ImportantMessage,
816 _("They don't match. Password was not changed."),
817 sizeof WC->ImportantMessage);
822 if (IsEmptyStr(newpass1)) {
823 safestrncpy(WC->ImportantMessage,
824 _("Blank passwords are not allowed."),
825 sizeof WC->ImportantMessage);
830 serv_printf("SETP %s", newpass1);
831 serv_getln(buf, sizeof buf);
832 sprintf(WC->ImportantMessage, "%s", &buf[4]);
834 safestrncpy(WC->wc_password, buf, sizeof WC->wc_password);
842 int ConditionalAide(WCTemplateToken *Tokens, void *Context, int ContextType)
844 return (WC->is_aide == 0);
847 int ConditionalRoomAide(WCTemplateToken *Tokens, void *Context, int ContextType)
849 return (WC->is_room_aide == 0);
852 int ConditionalRoomAcessDelete(WCTemplateToken *Tokens, void *Context, int ContextType)
855 return ( (WCC->is_room_aide) || (WCC->is_mailbox) || (WCC->room_flags2 & QR2_COLLABDEL) );
860 void _display_openid_login(void) {display_openid_login(NULL);}
861 void _display_reg(void) {display_reg(0);}
868 WebcitAddUrlHandler(HKEY("do_welcome"), do_welcome, ANONYMOUS);
869 WebcitAddUrlHandler(HKEY("login"), do_login, ANONYMOUS);
870 WebcitAddUrlHandler(HKEY("display_openid_login"), _display_openid_login, ANONYMOUS);
871 WebcitAddUrlHandler(HKEY("openid_login"), do_openid_login, ANONYMOUS);
872 WebcitAddUrlHandler(HKEY("finalize_openid_login"), finalize_openid_login, ANONYMOUS);
873 WebcitAddUrlHandler(HKEY("openid_manual_create"), openid_manual_create, ANONYMOUS);
874 WebcitAddUrlHandler(HKEY("do_logout"), do_logout, 0);
875 WebcitAddUrlHandler(HKEY("validate"), validate, 0);
876 WebcitAddUrlHandler(HKEY("display_reg"), _display_reg, 0);
877 WebcitAddUrlHandler(HKEY("display_changepw"), display_changepw, 0);
878 WebcitAddUrlHandler(HKEY("changepw"), changepw, 0);
879 WebcitAddUrlHandler(HKEY("termquit"), do_logout, 0);
881 RegisterConditional(HKEY("COND:AIDE"), 2, ConditionalAide, CTX_NONE);
882 RegisterConditional(HKEY("COND:ROOMAIDE"), 2, ConditionalRoomAide, CTX_NONE);
883 RegisterConditional(HKEY("COND:ACCESS:DELETE"), 2, ConditionalRoomAcessDelete, CTX_NONE);