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)
264 if (havebstr("exit_action")) {
270 if (havebstr("newuser_action")) {
271 serv_printf("OIDC %s", bstr("name"));
272 serv_getln(buf, sizeof buf);
274 char gpass[1024] = "";
275 serv_puts("SETP GENERATE_RANDOM_PASSWORD");
276 serv_getln(gpass, sizeof gpass);
277 become_logged_in(bstr("name"), &gpass[4], buf);
284 } else if (WC->need_vali) {
290 display_openid_name_request(bstr("openid_url"), bstr("name"));
297 * Perform authentication using OpenID
298 * assemble the checkid_setup request and then redirect to the user's identity provider
300 void do_openid_login(void)
304 if (havebstr("language")) {
305 set_selected_language(bstr("language"));
306 go_selected_language();
309 if (havebstr("exit_action")) {
313 if (havebstr("login_action")) {
314 snprintf(buf, sizeof buf,
315 "OIDS %s|%s://%s/finalize_openid_login|%s://%s",
317 (is_https ? "https" : "http"), WC->http_host,
318 (is_https ? "https" : "http"), WC->http_host
322 serv_getln(buf, sizeof buf);
324 lprintf(CTDL_DEBUG, "OpenID server contacted; redirecting to %s\n", &buf[4]);
325 http_redirect(&buf[4]);
329 display_openid_login(&buf[4]);
334 /* If we get to this point then something failed. */
335 display_openid_login(_("Your password was not accepted."));
339 * Complete the authentication using OpenID
340 * This function handles the positive or negative assertion from the user's Identity Provider
342 void finalize_openid_login(void)
346 int already_logged_in = (WCC->logged_in) ;
348 char result[128] = "";
349 char username[128] = "";
350 char password[128] = "";
351 char logged_in_response[1024] = "";
352 char claimed_id[1024] = "";
354 if (havebstr("openid.mode")) {
355 if (!strcasecmp(bstr("openid.mode"), "id_res")) {
358 serv_getln(buf, sizeof buf);
367 Cursor = GetNewHashPos (WCC->urlstrings, 0);
368 while (GetNextHashPos(WCC->urlstrings, Cursor, &HKLen, &HKey, &U)) {
370 if (!strncasecmp(u->url_key, "openid.", 7)) {
371 serv_printf("%s|%s", &u->url_key[7], ChrPtr(u->url_data));
378 while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
379 if (linecount == 0) safestrncpy(result, buf, sizeof result);
380 if (!strcasecmp(result, "authenticate")) {
381 if (linecount == 1) {
382 safestrncpy(username, buf, sizeof username);
384 else if (linecount == 2) {
385 safestrncpy(password, buf, sizeof password);
387 else if (linecount == 3) {
388 safestrncpy(logged_in_response, buf,
389 sizeof logged_in_response);
392 else if (!strcasecmp(result, "verify_only")) {
393 if (linecount == 1) {
394 safestrncpy(claimed_id, buf, sizeof claimed_id);
396 if (linecount == 2) {
397 safestrncpy(username, buf, sizeof username);
406 /* If we were already logged in, this was an attempt to associate an OpenID account */
407 if (already_logged_in) {
412 /* If this operation logged us in, either by connecting with an existing account or by
413 * auto-creating one using Simple Registration Extension, we're already on our way.
415 if (!strcasecmp(result, "authenticate")) {
416 become_logged_in(username, password, logged_in_response);
419 /* The specified OpenID was verified but the desired user name was either not specified via SRI
420 * or conflicts with an existing user. Either way the user will need to specify a new name.
423 else if (!strcasecmp(result, "verify_only")) {
424 display_openid_name_request(claimed_id, username);
427 /* Did we manage to log in? If so, continue with the normal flow... */
435 display_openid_login(_("Your password was not accepted."));
442 * Display a welcome screen to the user.
444 * If this is the first time login, and the web based setup is enabled,
445 * lead the user through the setup routines
447 void do_welcome(void)
450 #ifdef XXX_NOT_FINISHED_YET_XXX
455 * See if we have to run the first-time setup wizard
460 sprintf(wizard_filename, "setupwiz.%s.%s",
462 len = strlen(wizard_filename);
463 for (i=0; i<len; ++i) {
464 if ( (wizard_filename[i]==' ')
465 || (wizard_filename[i] == '/')
467 wizard_filename[i] = '_';
471 fp = fopen(wizard_filename, "r");
473 fgets(buf, sizeof buf, fp);
474 buf[strlen(buf)-1] = 0;
476 if (atoi(buf) == serv_info.serv_rev_level) {
477 setup_wizard = 1; /**< already run */
483 http_redirect("setup_wizard");
489 * Go to the user's preferred start page
491 if (!get_preference("startpage", &Buf)) {
493 StrBufPrintf(Buf, "dotskip&room=_BASEROOM_");
494 set_preference("startpage", Buf, 1);
496 if (ChrPtr(Buf)[0] == '/') {
497 StrBufCutLeft(Buf, 1);
499 if (StrLength(Buf) == 0)
500 StrBufAppendBufPlain(Buf, "dotgoto?room=_BASEROOM_", -1, 0);
501 http_redirect(ChrPtr(Buf));
506 * Disconnect from the Citadel server, and end this WebCit session
508 void end_webcit_session(void) {
511 set_pref_long("current_iconbar", WC->current_iconbar, 0);
516 /* close() of citadel socket will be done by do_housekeeping() */
526 safestrncpy(WC->wc_username, "", sizeof WC->wc_username);
527 safestrncpy(WC->wc_password, "", sizeof WC->wc_password);
528 safestrncpy(WC->wc_roomname, "", sizeof WC->wc_roomname);
529 safestrncpy(WC->wc_fullname, "", sizeof WC->wc_fullname);
531 /** Calling output_headers() this way causes the cookies to be un-set */
532 output_headers(1, 1, 0, 1, 0, 0);
534 wprintf("<div id=\"logout_screen\">");
535 wprintf("<div class=\"box\">");
536 wprintf("<div class=\"boxlabel\">");
537 wprintf(_("Log off"));
538 wprintf("</div><div class=\"boxcontent\">");
539 serv_puts("MESG goodbye");
540 serv_getln(buf, sizeof buf);
542 if (WC->serv_sock >= 0) {
546 wprintf("Goodbye\n");
550 wprintf(_("This program was unable to connect or stay "
551 "connected to the Citadel server. Please report "
552 "this problem to your system administrator.")
554 wprintf("<a href=\"http://www.citadel.org/doku.php/"
555 "faq:mastering_your_os:net#netstat\">%s</a>",
559 wprintf("<hr /><div class=\"buttons\"> "
560 "<span class=\"button_link\"><a href=\".\">");
561 wprintf(_("Log in again"));
562 wprintf("</a></span> <span class=\"button_link\">"
563 "<a href=\"javascript:window.close();\">");
564 wprintf(_("Close window"));
565 wprintf("</a></span></div></div></div></div>\n");
567 end_webcit_session();
581 output_headers(1, 1, 2, 0, 0, 0);
582 wprintf("<div id=\"banner\">\n");
584 wprintf(_("Validate new users"));
588 wprintf("<div id=\"content\" class=\"service\">\n");
590 /* If the user just submitted a validation, process it... */
591 safestrncpy(buf, bstr("user"), sizeof buf);
592 if (!IsEmptyStr(buf)) {
593 if (havebstr("axlevel")) {
594 serv_printf("VALI %s|%s", buf, bstr("axlevel"));
595 serv_getln(buf, sizeof buf);
597 wprintf("<b>%s</b><br />\n", &buf[4]);
602 /* Now see if any more users require validation. */
604 serv_getln(buf, sizeof buf);
607 wprintf(_("No users require validation at this time."));
608 wprintf("</b><br />\n");
613 wprintf("<b>%s</b><br />\n", &buf[4]);
618 wprintf("<div class=\"fix_scrollbar_bug\">"
619 "<table class=\"auth_validate\"><tr><td>\n");
622 safestrncpy(user, &buf[4], sizeof user);
623 serv_printf("GREG %s", user);
624 serv_getln(cmd, sizeof cmd);
628 serv_getln(buf, sizeof buf);
631 wprintf("#%s<br /><H1>%s</H1>",
640 while (!IsEmptyStr(pch))
644 else if (isalpha(*pch))
655 pch = _("very weak");
668 wprintf("PW: %s<br />\n", pch);
671 wprintf("%s<br />\n", buf);
673 wprintf("%s<br />\n", buf);
675 wprintf("%s, ", buf);
679 wprintf("%s<br />\n", buf);
681 wprintf("%s<br />\n", buf);
683 wprintf(_("Current access level: %d (%s)\n"),
684 atoi(buf), axdefs[atoi(buf)]);
685 } while (strcmp(buf, "000"));
687 wprintf("<H1>%s</H1>%s<br />\n", user, &cmd[4]);
691 wprintf(_("Select access level for this user:"));
693 for (a = 0; a <= 6; ++a) {
694 wprintf("<a href=\"validate?nonce=%d?user=", WC->nonce);
696 wprintf("&axlevel=%d\">%s</A> \n",
701 wprintf("</CENTER>\n");
702 wprintf("</td></tr></table></div>\n");
709 * Display form for registration.
711 * (Set during_login to 1 if this registration is being performed during
712 * new user login and will require chaining to the proper screen.)
714 void display_reg(int during_login)
718 if (goto_config_room() != 0) {
719 if (during_login) do_welcome();
720 else display_main_menu();
724 vcard_msgnum = locate_user_vcard(WC->wc_fullname, -1);
725 if (vcard_msgnum < 0L) {
726 if (during_login) do_welcome();
727 else display_main_menu();
732 do_edit_vcard(vcard_msgnum, "1", "do_welcome", USERCONFIGROOM);
735 do_edit_vcard(vcard_msgnum, "1", "display_main_menu", USERCONFIGROOM);
744 * display form for changing your password
746 void display_changepw(void)
750 output_headers(1, 1, 1, 0, 0, 0);
752 Buf = NewStrBufPlain(_("Change your password"), -1);
753 DoTemplate(HKEY("beginbox"), NULL, Buf, CTX_STRBUF);
757 if (!IsEmptyStr(WC->ImportantMessage)) {
758 wprintf("<span class=\"errormsg\">"
759 "%s</span><br />\n", WC->ImportantMessage);
760 safestrncpy(WC->ImportantMessage, "", sizeof WC->ImportantMessage);
763 serv_puts("MESG changepw");
764 serv_getln(buf, sizeof buf);
769 wprintf("<form name=\"changepwform\" action=\"changepw\" method=\"post\">\n");
770 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
771 wprintf("<table class=\"altern\" ");
772 wprintf("<tr class=\"even\"><td>");
773 wprintf(_("Enter new password:"));
774 wprintf("</td><td>");
775 wprintf("<input type=\"password\" name=\"newpass1\" value=\"\" maxlength=\"20\"></td></tr>\n");
776 wprintf("<tr class=\"odd\"><td>");
777 wprintf(_("Enter it again to confirm:"));
778 wprintf("</td><td>");
779 wprintf("<input type=\"password\" name=\"newpass2\" value=\"\" maxlength=\"20\"></td></tr>\n");
780 wprintf("</table>\n");
782 wprintf("<div class=\"buttons\">\n");
783 wprintf("<input type=\"submit\" name=\"change_action\" value=\"%s\">", _("Change password"));
785 wprintf("<input type=\"submit\" name=\"cancel_action\" value=\"%s\">\n", _("Cancel"));
787 wprintf("</form>\n");
789 do_template("endbox", NULL);
795 * if passwords match, propagate it to citserver.
800 char newpass1[32], newpass2[32];
802 if (!havebstr("change_action")) {
803 safestrncpy(WC->ImportantMessage,
804 _("Cancelled. Password was not changed."),
805 sizeof WC->ImportantMessage);
810 safestrncpy(newpass1, bstr("newpass1"), sizeof newpass1);
811 safestrncpy(newpass2, bstr("newpass2"), sizeof newpass2);
813 if (strcasecmp(newpass1, newpass2)) {
814 safestrncpy(WC->ImportantMessage,
815 _("They don't match. Password was not changed."),
816 sizeof WC->ImportantMessage);
821 if (IsEmptyStr(newpass1)) {
822 safestrncpy(WC->ImportantMessage,
823 _("Blank passwords are not allowed."),
824 sizeof WC->ImportantMessage);
829 serv_printf("SETP %s", newpass1);
830 serv_getln(buf, sizeof buf);
831 sprintf(WC->ImportantMessage, "%s", &buf[4]);
833 safestrncpy(WC->wc_password, buf, sizeof WC->wc_password);
841 int ConditionalAide(WCTemplateToken *Tokens, void *Context, int ContextType)
843 return (WC->is_aide == 0);
846 int ConditionalRoomAide(WCTemplateToken *Tokens, void *Context, int ContextType)
848 return (WC->is_room_aide == 0);
851 int ConditionalRoomAcessDelete(WCTemplateToken *Tokens, void *Context, int ContextType)
854 return ( (WCC->is_room_aide) || (WCC->is_mailbox) || (WCC->room_flags2 & QR2_COLLABDEL) );
859 void _display_openid_login(void) {display_openid_login(NULL);}
860 void _display_reg(void) {display_reg(0);}
867 WebcitAddUrlHandler(HKEY("do_welcome"), do_welcome, ANONYMOUS);
868 WebcitAddUrlHandler(HKEY("login"), do_login, ANONYMOUS);
869 WebcitAddUrlHandler(HKEY("display_openid_login"), _display_openid_login, ANONYMOUS);
870 WebcitAddUrlHandler(HKEY("openid_login"), do_openid_login, ANONYMOUS);
871 WebcitAddUrlHandler(HKEY("finalize_openid_login"), finalize_openid_login, ANONYMOUS);
872 WebcitAddUrlHandler(HKEY("openid_manual_create"), openid_manual_create, ANONYMOUS);
873 WebcitAddUrlHandler(HKEY("do_logout"), do_logout, 0);
874 WebcitAddUrlHandler(HKEY("validate"), validate, 0);
875 WebcitAddUrlHandler(HKEY("display_reg"), _display_reg, 0);
876 WebcitAddUrlHandler(HKEY("display_changepw"), display_changepw, 0);
877 WebcitAddUrlHandler(HKEY("changepw"), changepw, 0);
878 WebcitAddUrlHandler(HKEY("termquit"), do_logout, 0);
880 RegisterConditional(HKEY("COND:AIDE"), 2, ConditionalAide, CTX_NONE);
881 RegisterConditional(HKEY("COND:ROOMAIDE"), 2, ConditionalRoomAide, CTX_NONE);
882 RegisterConditional(HKEY("COND:ACCESS:DELETE"), 2, ConditionalRoomAcessDelete, CTX_NONE);