57f8adb6b8f688f9e6df720abae6e2e40128603b
[citadel.git] / webcit / auth.c
1 /*
2  * These functions handle authentication of users to a Citadel server.
3  *
4  * Copyright (c) 1996-2021 by the citadel.org team
5  *
6  * This program is open source software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include "webcit.h"
16 #include "webserver.h"
17 #include <ctype.h>
18
19
20 /*
21  * Access level definitions.  This is initialized from a function rather than a
22  * static array so that the strings may be localized.
23  */
24 char *axdefs[7]; 
25
26 void initialize_axdefs(void) {
27
28         /* an erased user */
29         axdefs[0] = _("Deleted");       
30
31         /* a new user */
32         axdefs[1] = _("New User");      
33
34         /* a trouble maker */
35         axdefs[2] = _("Problem User");  
36
37         /* user with normal privileges */
38         axdefs[3] = _("Local User");    
39
40         /* a user that may access network resources */
41         axdefs[4] = _("Network User");  
42
43         /* a moderator */
44         axdefs[5] = _("Preferred User");
45
46         /* chief */
47         axdefs[6] = _("Admin");          
48 }
49
50
51
52 /* 
53  * Display the login screen
54  * mesg = the error message if last attempt failed.
55  */
56 void display_login(void)
57 {
58         begin_burst();
59         output_headers(1, 0, 0, 0, 1, 0);
60         do_template("login");
61         end_burst();
62 }
63
64
65
66
67
68 /* Initialize the session
69  *
70  * This function needs to get called whenever the session changes from
71  * not-logged-in to logged-in, either by an explicit login by the user or
72  * by a timed-out session automatically re-establishing with a little help
73  * from the browser cookie.  Either way, we need to load access controls and
74  * preferences from the server.
75  *
76  * user                 the username
77  * pass                 his password
78  * serv_response        The parameters returned from a Citadel USER or NEWU command
79  */
80 void become_logged_in(const StrBuf *user, const StrBuf *pass, StrBuf *serv_response)
81 {
82         wcsession *WCC = WC;
83         StrBuf *Buf;
84         StrBuf *FloorDiv;
85
86         WCC->logged_in = 1;
87
88         if (WCC->wc_fullname == NULL)
89                 WCC->wc_fullname = NewStrBufPlain(NULL, StrLength(serv_response));
90         StrBufExtract_token(WCC->wc_fullname, serv_response, 0, '|');
91         StrBufCutLeft(WCC->wc_fullname, 4 );
92         
93         if (WCC->wc_username == NULL)
94                 WCC->wc_username = NewStrBufDup(user);
95         else {
96                 FlushStrBuf(WCC->wc_username);
97                 StrBufAppendBuf(WCC->wc_username, user, 0);
98         }
99
100         if (WCC->wc_password == NULL)
101                 WCC->wc_password = NewStrBufDup(pass);
102         else {
103                 FlushStrBuf(WCC->wc_password);
104                 StrBufAppendBuf(WCC->wc_password, pass, 0);
105         }
106
107         WCC->axlevel = StrBufExtract_int(serv_response, 1, '|');
108         if (WCC->axlevel >= 6) {
109                 WCC->is_aide = 1;
110         }
111
112         load_preferences();
113
114         Buf = NewStrBuf();
115         serv_puts("CHEK");
116         StrBuf_ServGetln(Buf);
117         if (GetServerStatus(Buf, NULL) == 2) {
118                 const char *pch;
119
120                 pch = ChrPtr(Buf) + 4;
121                 /*WCC->new_mail  =*/ StrBufExtractNext_long(Buf, &pch, '|');
122                 WCC->need_regi = StrBufExtractNext_long(Buf, &pch, '|');
123                 WCC->need_vali = StrBufExtractNext_long(Buf, &pch, '|');
124                 if (WCC->cs_inet_email == NULL)
125                         WCC->cs_inet_email  = NewStrBuf();
126                 StrBufExtract_NextToken(WCC->cs_inet_email, Buf, &pch, '|');
127         }
128         get_preference("floordiv_expanded", &FloorDiv);
129         WCC->floordiv_expanded = FloorDiv;
130         FreeStrBuf(&Buf);
131         FlushRoomlist();
132 }
133
134
135 /* 
136  * modal/ajax version of 'login' (username and password)
137  */
138 void ajax_login_username_password(void) {
139         StrBuf *Buf = NewStrBuf();
140
141         serv_printf("USER %s", bstr("name"));
142         StrBuf_ServGetln(Buf);
143         if (GetServerStatus(Buf, NULL) == 3) {
144                 serv_printf("PASS %s", bstr("pass"));
145                 StrBuf_ServGetln(Buf);
146                 if (GetServerStatus(Buf, NULL) == 2) {
147                         become_logged_in(sbstr("name"), sbstr("pass"), Buf);
148                 }
149         }
150
151         /* The client is expecting to read back a citadel protocol response */
152         wc_printf("%s", ChrPtr(Buf));
153         FreeStrBuf(&Buf);
154 }
155
156
157
158 /* 
159  * modal/ajax version of 'new user' (username and password)
160  */
161 void ajax_login_newuser(void) {
162         StrBuf *NBuf = NewStrBuf();
163         StrBuf *SBuf = NewStrBuf();
164
165         serv_printf("NEWU %s", bstr("name"));
166         StrBuf_ServGetln(NBuf);
167         if (GetServerStatus(NBuf, NULL) == 2) {
168                 become_logged_in(sbstr("name"), sbstr("pass"), NBuf);
169                 serv_printf("SETP %s", bstr("pass"));
170                 StrBuf_ServGetln(SBuf);
171         }
172
173         /* The client is expecting to read back a citadel protocol response */
174         wc_printf("%s", ChrPtr(NBuf));
175         FreeStrBuf(&NBuf);
176         FreeStrBuf(&SBuf);
177 }
178
179
180
181 /* 
182  * Try to create an account manually after an OpenID was verified
183  */
184 void openid_manual_create(void)
185 {
186         StrBuf *Buf;
187
188         /* Did the user change his mind?  Pack up and go home. */
189         if (havebstr("exit_action")) {
190                 begin_burst();
191                 output_headers(1, 0, 0, 0, 1, 0);
192                 do_template("authpopup_finished");
193                 end_burst();
194                 return;
195         }
196
197
198         /* Ok, let's give this a try.  Can we create the new user? */
199
200         Buf = NewStrBuf();
201         serv_printf("OIDC %s", bstr("name"));
202         StrBuf_ServGetln(Buf);
203         if (GetServerStatus(Buf, NULL) == 2) {
204                 StrBuf *gpass;
205
206                 gpass = NewStrBuf();
207                 serv_puts("SETP GENERATE_RANDOM_PASSWORD");
208                 StrBuf_ServGetln(gpass);
209                 StrBufCutLeft(gpass, 4);
210                 become_logged_in(sbstr("name"), gpass, Buf);
211                 FreeStrBuf(&gpass);
212         }
213         FreeStrBuf(&Buf);
214
215         /* Did we manage to log in?  If so, continue with the normal flow... */
216         if (WC->logged_in) {
217                 if (WC->logged_in) {
218                         begin_burst();
219                         output_headers(1, 0, 0, 0, 1, 0);
220                         do_template("authpopup_finished");
221                         end_burst();
222                 }
223         } else {
224                 /* Still no good!  Go back to teh dialog to select a username */
225                 const StrBuf *Buf;
226                 putbstr("__claimed_id", NewStrBufDup(sbstr("openid_url")));
227                 Buf = sbstr("name");
228                 if (StrLength(Buf) > 0)
229                         putbstr("__username", NewStrBufDup(Buf));
230                 begin_burst();
231                 output_headers(1, 0, 0, 0, 1, 0);
232                 wc_printf("<html><body>");
233                 do_template("openid_manual_create");
234                 wc_printf("</body></html>");
235                 end_burst();
236         }
237
238 }
239
240
241 /* 
242  * Perform authentication using OpenID
243  * assemble the checkid_setup request and then redirect to the user's identity provider
244  */
245 void do_openid_login(void)
246 {
247         char buf[4096];
248
249         snprintf(buf, sizeof buf,
250                 "OIDS %s|%s/finalize_openid_login|%s",
251                 bstr("openid_url"),
252                 ChrPtr(site_prefix),
253                 ChrPtr(site_prefix)
254         );
255
256         serv_puts(buf);
257         serv_getln(buf, sizeof buf);
258         if (buf[0] == '2') {
259                 syslog(LOG_DEBUG, "OpenID server contacted; redirecting to %s\n", &buf[4]);
260                 http_redirect(&buf[4]);
261                 return;
262         }
263
264         begin_burst();
265         output_headers(1, 0, 0, 0, 1, 0);
266         wc_printf("<html><body>");
267         escputs(&buf[4]);
268         wc_printf("</body></html>");
269         end_burst();
270 }
271
272
273 /* 
274  * Complete the authentication using OpenID
275  * This function handles the positive or negative assertion from the user's Identity Provider
276  */
277 void finalize_openid_login(void)
278 {
279         StrBuf *Buf;
280         wcsession *WCC = WC;
281         int linecount = 0;
282         StrBuf *result = NULL;
283         StrBuf *username = NULL;
284         StrBuf *password = NULL;
285         StrBuf *logged_in_response = NULL;
286         StrBuf *claimed_id = NULL;
287
288         if (havebstr("openid.mode")) {
289                 if (!strcasecmp(bstr("openid.mode"), "id_res")) {
290                         Buf = NewStrBuf();
291                         serv_puts("OIDF");
292                         StrBuf_ServGetln(Buf);
293                         if (GetServerStatus(Buf, NULL) == 8) {
294                                 urlcontent *u;
295                                 void *U;
296                                 long HKLen;
297                                 const char *HKey;
298                                 HashPos *Cursor;
299                                 int len;
300                                 
301                                 Cursor = GetNewHashPos (WCC->Hdr->urlstrings, 0);
302                                 while (GetNextHashPos(WCC->Hdr->urlstrings, Cursor, &HKLen, &HKey, &U)) {
303                                         u = (urlcontent*) U;
304                                         if (!strncasecmp(u->url_key, "openid.", 7)) {
305                                                 serv_printf("%s|%s", &u->url_key[7], ChrPtr(u->url_data));
306                                         }
307                                 }
308
309                                 serv_puts("000");
310
311                                 linecount = 0;
312                                 while (len = StrBuf_ServGetln(Buf), 
313                                        ((len >= 0) &&
314                                         ((len != 3) || strcmp(ChrPtr(Buf), "000") )))
315                                 {
316                                         if (linecount == 0) result = NewStrBufDup(Buf);
317                                         if (!strcasecmp(ChrPtr(result), "authenticate")) {
318                                                 if (linecount == 1) {
319                                                         username = NewStrBufDup(Buf);
320                                                 }
321                                                 else if (linecount == 2) {
322                                                         password = NewStrBufDup(Buf);
323                                                 }
324                                                 else if (linecount == 3) {
325                                                         logged_in_response = NewStrBufDup(Buf);
326                                                 }
327                                         }
328                                         else if (!strcasecmp(ChrPtr(result), "verify_only")) {
329                                                 if (linecount == 1) {
330                                                         claimed_id = NewStrBufDup(Buf);
331                                                 }
332                                                 if (linecount == 2) {
333                                                         username = NewStrBufDup(Buf);
334                                                 }
335                                         }
336                                         ++linecount;
337                                 }
338                         }
339                         FreeStrBuf(&Buf);
340                 }
341         }
342
343         /*
344          * Is this an attempt to associate a new OpenID with an account that is already logged in?
345          */
346         if ( (WCC->logged_in) && (havebstr("attach_existing")) ) {
347                 display_openids();
348         }
349
350         /* If this operation logged us in, either by connecting with an existing account or by
351          * auto-creating one using Simple Registration Extension, we're already on our way.
352          */
353         else if (!strcasecmp(ChrPtr(result), "authenticate")) {
354                 become_logged_in(username, password, logged_in_response);
355
356                 /* Did we manage to log in?  If so, continue with the normal flow... */
357                 if (WC->logged_in) {
358                         begin_burst();
359                         output_headers(1, 0, 0, 0, 1, 0);
360                         do_template("authpopup_finished");
361                         end_burst();
362                 } else {
363                         begin_burst();
364                         output_headers(1, 0, 0, 0, 1, 0);
365                         wc_printf("<html><body>");
366                         wc_printf(_("An error has occurred."));
367                         wc_printf("</body></html>");
368                         end_burst();
369                 }
370         }
371
372         /* The specified OpenID was verified but the desired user name was either not specified via SRE
373          * or conflicts with an existing user.  Either way the user will need to specify a new name.
374          */
375         else if (!strcasecmp(ChrPtr(result), "verify_only")) {
376                 putbstr("__claimed_id", claimed_id);
377                 claimed_id = NULL;
378                 if (StrLength(username) > 0) {
379                         putbstr("__username", username);
380                         username = NULL;
381                 }
382                 begin_burst();
383                 output_headers(1, 0, 0, 0, 1, 0);
384                 wc_printf("<html><body>");
385                 do_template("openid_manual_create");
386                 wc_printf("</body></html>");
387                 end_burst();
388         }
389
390         /* Something went VERY wrong if we get to this point */
391         else {
392                 syslog(LOG_DEBUG, "finalize_openid_login() failed to do anything.  This is a code problem.\n");
393                 begin_burst();
394                 output_headers(1, 0, 0, 0, 1, 0);
395                 wc_printf("<html><body>");
396                 wc_printf(_("An error has occurred."));
397                 wc_printf("</body></html>");
398                 end_burst();
399         }
400
401         FreeStrBuf(&result);
402         FreeStrBuf(&username);
403         FreeStrBuf(&password);
404         FreeStrBuf(&claimed_id);
405         FreeStrBuf(&logged_in_response);
406 }
407
408
409 /*
410  * Display a welcome screen to the user.
411  */
412 void do_welcome(void) {
413         StrBuf *Buf;
414         /*
415          * Go to the user's preferred start page
416          */
417         if (!get_preference("startpage", &Buf)) {
418                 Buf = NewStrBuf ();
419                 StrBufPrintf(Buf, "dotskip?room=_BASEROOM_");
420                 set_preference("startpage", Buf, 1);
421         }
422         if (ChrPtr(Buf)[0] == '/') {
423                 StrBufCutLeft(Buf, 1);
424         }
425         if (StrLength(Buf) == 0) {
426                 StrBufAppendBufPlain(Buf, "dotgoto?room=_BASEROOM_", -1, 0);
427         }
428         syslog(LOG_DEBUG, "Redirecting to user's start page: %s\n", ChrPtr(Buf));
429         http_redirect(ChrPtr(Buf));
430 }
431
432
433 /*
434  * Disconnect from the Citadel server, and end this WebCit session
435  */
436 void end_webcit_session(void) {
437         serv_puts("QUIT");
438         WC->killthis = 1;
439         /* close() of citadel socket will be done by do_housekeeping() */
440 }
441
442
443 /* 
444  * Log out the session with the Citadel server
445  */
446 void do_logout(void)
447 {
448         wcsession *WCC = WC;
449         char buf[SIZ];
450
451         FlushStrBuf(WCC->wc_username);
452         FlushStrBuf(WCC->wc_password);
453         FlushStrBuf(WCC->wc_fullname);
454         FlushRoomlist();
455
456         serv_puts("LOUT");
457         serv_getln(buf, sizeof buf);
458         WCC->logged_in = 0;
459
460         FlushStrBuf(WCC->CurRoom.name);
461
462         /* Calling output_headers() this way causes the cookies to be un-set */
463         output_headers(1, 1, 0, 1, 0, 0);
464         do_template("logout");
465         if ((WCC->serv_info != NULL) && WCC->serv_info->serv_supports_guest) {
466                 display_default_landing_page();
467                 return;
468         }
469
470         wDumpContent(2);
471         end_webcit_session();
472 }
473
474
475 /* 
476  * Special page for monitoring scripts etc
477  */
478 void monitor(void)
479 {
480         output_headers(0, 0, 0, 0, 0, 0);
481
482         hprintf("Content-type: text/plain\r\n"
483                 "Server: " PACKAGE_STRING "\r\n"
484                 "Connection: close\r\n"
485         );
486         begin_burst();
487
488         wc_printf("Connection to Citadel server in %s : %s\r\n", ctdl_dir,
489                 (WC->connected ? "SUCCESS" : "FAIL")
490         );
491
492         wDumpContent(0);
493 }
494
495
496 /*
497  * validate new users
498  */
499 void validate(void)
500 {
501         char cmd[SIZ];
502         char user[SIZ];
503         char buf[SIZ];
504         int a;
505
506         output_headers(1, 1, 1, 0, 0, 0);
507
508         do_template("box_begin_1");
509         StrBufAppendBufPlain(WC->WBuf, _("Validate new users"), -1, 0);
510         do_template("box_begin_2");
511
512         /* If the user just submitted a validation, process it... */
513         safestrncpy(buf, bstr("user"), sizeof buf);
514         if (!IsEmptyStr(buf)) {
515                 if (havebstr("axlevel")) {
516                         serv_printf("VALI %s|%s", buf, bstr("axlevel"));
517                         serv_getln(buf, sizeof buf);
518                         if (buf[0] != '2') {
519                                 wc_printf("<b>%s</b><br>\n", &buf[4]);
520                         }
521                 }
522         }
523
524         /* Now see if any more users require validation. */
525         serv_puts("GNUR");
526         serv_getln(buf, sizeof buf);
527         if (buf[0] == '2') {
528                 wc_printf("<b>");
529                 wc_printf(_("No users require validation at this time."));
530                 wc_printf("</b><br>\n");
531                 wDumpContent(1);
532                 return;
533         }
534         if (buf[0] != '3') {
535                 wc_printf("<b>%s</b><br>\n", &buf[4]);
536                 wDumpContent(1);
537                 return;
538         }
539
540         wc_printf("<table class=\"auth_validate\"><tr><td>\n");
541         wc_printf("<div id=\"validate\">");
542
543         safestrncpy(user, &buf[4], sizeof user);
544         serv_printf("GREG %s", user);
545         serv_getln(cmd, sizeof cmd);
546         if (cmd[0] == '1') {
547                 a = 0;
548                 do {
549                         serv_getln(buf, sizeof buf);
550                         ++a;
551                         if (a == 1)
552                                 wc_printf("#%s<br><H1>%s</H1>",
553                                         buf, &cmd[4]);
554                         if (a == 2) {
555                                 char *pch;
556                                 int haveChar = 0;
557                                 int haveNum = 0;
558                                 int haveOther = 0;
559                                 int haveLong = 0;
560                                 pch = buf;
561                                 while (!IsEmptyStr(pch))
562                                 {
563                                         if (isdigit(*pch))
564                                                 haveNum = 1;
565                                         else if (isalpha(*pch))
566                                                 haveChar = 1;
567                                         else
568                                                 haveOther = 1;
569                                         pch ++;
570                                 }
571                                 if (pch - buf > 7)
572                                         haveLong = 1;
573                                 switch (haveLong + 
574                                         haveChar + 
575                                         haveNum + 
576                                         haveOther)
577                                 {
578                                 case 0:
579                                         pch = _("very weak");
580                                         break;
581                                 case 1:
582                                         pch = _("weak");
583                                         break;
584                                 case 2:
585                                         pch = _("ok");
586                                         break;
587                                 case 3:
588                                 default:
589                                         pch = _("strong");
590                                 }
591
592                                 wc_printf("PW: %s<br>\n", pch);
593                         }
594                         if (a == 3)
595                                 wc_printf("%s<br>\n", buf);
596                         if (a == 4)
597                                 wc_printf("%s<br>\n", buf);
598                         if (a == 5)
599                                 wc_printf("%s, ", buf);
600                         if (a == 6)
601                                 wc_printf("%s ", buf);
602                         if (a == 7)
603                                 wc_printf("%s<br>\n", buf);
604                         if (a == 8)
605                                 wc_printf("%s<br>\n", buf);
606                         if (a == 9)
607                                 wc_printf(_("Current access level: %d (%s)\n"),
608                                         atoi(buf), axdefs[atoi(buf)]);
609                 } while (strcmp(buf, "000"));
610         } else {
611                 wc_printf("<H1>%s</H1>%s<br>\n", user, &cmd[4]);
612         }
613
614         wc_printf("<hr />");
615         wc_printf(_("Select access level for this user:"));
616         wc_printf("<br>\n");
617         for (a = 0; a <= 6; ++a) {
618                 wc_printf("<a href=\"validate?nonce=%d?user=", WC->nonce);
619                 urlescputs(user);
620                 wc_printf("&axlevel=%d\">%s</A>&nbsp;&nbsp;&nbsp;\n",
621                         a, axdefs[a]);
622         }
623         wc_printf("<br>\n");
624
625         wc_printf("</div>\n");
626         wc_printf("</td></tr></table>\n");
627         do_template("box_end");
628         wDumpContent(1);
629 }
630
631
632 /*
633  * Display form for registration.
634  *
635  * (Set during_login to 1 if this registration is being performed during
636  * new user login and will require chaining to the proper screen.)
637  */
638 void display_reg(int during_login)
639 {
640         folder Room;
641         StrBuf *Buf;
642         message_summary *VCMsg = NULL;
643         wc_mime_attachment *VCAtt = NULL;
644         long vcard_msgnum;
645
646         Buf = NewStrBuf();
647         memset(&Room, 0, sizeof(folder));
648         if (goto_config_room(Buf, &Room) != 0) {
649                 syslog(LOG_WARNING, "display_reg() exiting because goto_config_room() failed\n");
650                 if (during_login) {
651                         pop_destination();
652                 }
653                 else {
654                         display_main_menu();
655                 }
656                 FreeStrBuf(&Buf);
657                 FlushFolder(&Room);             
658                 return;
659         }
660         FlushFolder(&Room);
661
662         FreeStrBuf(&Buf);
663         vcard_msgnum = locate_user_vcard_in_this_room(&VCMsg, &VCAtt);
664         if (vcard_msgnum < 0L) {
665                 syslog(LOG_WARNING, "display_reg() exiting because locate_user_vcard_in_this_room() failed\n");
666                 if (during_login) {
667                         pop_destination();
668                 }
669                 else {
670                         display_main_menu();
671                 }
672                 return;
673         }
674
675         if (during_login) {
676                 do_edit_vcard(vcard_msgnum, "1", VCMsg, VCAtt, "pop", USERCONFIGROOM);
677         }
678         else {
679                 StrBuf *ReturnTo;
680                 ReturnTo = NewStrBufPlain(HKEY("display_main_menu?go="));
681                 StrBufAppendBuf(ReturnTo, WC->CurRoom.name, 0);
682                 do_edit_vcard(vcard_msgnum, "1", VCMsg, VCAtt, ChrPtr(ReturnTo), USERCONFIGROOM);
683                 FreeStrBuf(&ReturnTo);
684         }
685
686 }
687
688 /*
689  * change password
690  * if passwords match, propagate it to citserver.
691  */
692 void changepw(void)
693 {
694         StrBuf *Line;
695         char newpass1[32], newpass2[32];
696
697         if (!havebstr("change_action")) {
698                 AppendImportantMessage(_("Cancelled.  Password was not changed."), -1);
699                 display_main_menu();
700                 return;
701         }
702
703         safestrncpy(newpass1, bstr("newpass1"), sizeof newpass1);
704         safestrncpy(newpass2, bstr("newpass2"), sizeof newpass2);
705
706         if (strcasecmp(newpass1, newpass2)) {
707                 AppendImportantMessage(_("They don't match.  Password was not changed."), -1);
708                 do_template("menu_change_pw");
709                 return;
710         }
711
712         if (IsEmptyStr(newpass1)) {
713                 AppendImportantMessage(_("Blank passwords are not allowed."), -1);
714                 do_template("menu_change_pw");
715                 return;
716         }
717
718         Line = NewStrBuf();
719         serv_printf("SETP %s", newpass1);
720         StrBuf_ServGetln(Line);
721         if (GetServerStatusMsg(Line, NULL, 1, 0) == 2) {
722                 if (WC->wc_password == NULL)
723                         WC->wc_password = NewStrBufPlain(
724                                 ChrPtr(Line) + 4, 
725                                 StrLength(Line) - 4);
726                 else {
727                         FlushStrBuf(WC->wc_password);
728                         StrBufAppendBufPlain(WC->wc_password,  
729                                              ChrPtr(Line) + 4, 
730                                              StrLength(Line) - 4, 0);
731                 }
732                 display_main_menu();
733         }
734         else {
735                 do_template("menu_change_pw");
736         }
737         FreeStrBuf(&Line);
738 }
739
740
741 int ConditionalHaveAccessCreateRoom(StrBuf *Target, WCTemplputParams *TP)
742 {
743         StrBuf *Buf;    
744
745         Buf = NewStrBuf();
746         serv_puts("CRE8 0");
747         StrBuf_ServGetln(Buf);
748
749         if (GetServerStatus(Buf, NULL) == 2) {
750                 StrBufCutLeft(Buf, 4);
751                 AppendImportantMessage(SKEY(Buf));
752                 FreeStrBuf(&Buf);
753                 return 0;
754         }
755         FreeStrBuf(&Buf);
756         return 1;
757 }
758
759
760 int ConditionalAide(StrBuf *Target, WCTemplputParams *TP)
761 {
762         wcsession *WCC = WC;
763         return (WCC != NULL) ? ((WCC->logged_in == 0)||(WC->is_aide == 0)) : 0;
764 }
765
766
767 int ConditionalIsLoggedIn(StrBuf *Target, WCTemplputParams *TP) 
768 {
769         wcsession *WCC = WC;
770         return (WCC != NULL) ? (WCC->logged_in == 0) : 0;
771
772 }
773
774
775 /* 
776  * toggle the session over to a different language
777  */
778 void switch_language(void) {
779         set_selected_language(bstr("lang"));
780         pop_destination();
781 }
782
783
784 void _display_reg(void) {
785         display_reg(0);
786 }
787
788
789 void Header_HandleAuth(StrBuf *Line, ParsedHttpHdrs *hdr)
790 {
791         if (hdr->HR.got_auth == NO_AUTH) /* don't override cookie auth... */
792         {
793                 if (strncasecmp(ChrPtr(Line), "Basic", 5) == 0) {
794                         StrBufCutLeft(Line, 6);
795                         StrBufDecodeBase64(Line);
796                         hdr->HR.plainauth = Line;
797                         hdr->HR.got_auth = AUTH_BASIC;
798                 }
799                 else 
800                         syslog(LOG_WARNING, "Authentication scheme not supported! [%s]\n", ChrPtr(Line));
801         }
802 }
803
804
805 void CheckAuthBasic(ParsedHttpHdrs *hdr)
806 {
807 /*
808   todo: enable this if we can have other sessions than authenticated ones.
809         if (hdr->DontNeedAuth)
810                 return;
811 */
812         StrBufAppendBufPlain(hdr->HR.plainauth, HKEY(":"), 0);
813         StrBufAppendBuf(hdr->HR.plainauth, hdr->HR.user_agent, 0);
814 }
815
816
817 void GetAuthBasic(ParsedHttpHdrs *hdr)
818 {
819         const char *Pos = NULL;
820         if (hdr->c_username == NULL)
821                 hdr->c_username = NewStrBufPlain(HKEY(DEFAULT_HTTPAUTH_USER));
822         if (hdr->c_password == NULL)
823                 hdr->c_password = NewStrBufPlain(HKEY(DEFAULT_HTTPAUTH_PASS));
824         StrBufExtract_NextToken(hdr->c_username, hdr->HR.plainauth, &Pos, ':');
825         StrBufExtract_NextToken(hdr->c_password, hdr->HR.plainauth, &Pos, ':');
826 }
827
828
829 void Header_HandleCookie(StrBuf *Line, ParsedHttpHdrs *hdr)
830 {
831         const char *pch;
832 /*
833   todo: enable this if we can have other sessions than authenticated ones.
834         if (hdr->DontNeedAuth)
835                 return;
836 */
837         pch = strstr(ChrPtr(Line), "webcit=");
838         if (pch == NULL) {
839                 return;
840         }
841
842         hdr->HR.RawCookie = Line;
843         StrBufCutLeft(hdr->HR.RawCookie, (pch - ChrPtr(hdr->HR.RawCookie)) + 7);
844         StrBufDecodeHex(hdr->HR.RawCookie);
845
846         cookie_to_stuff(Line, &hdr->HR.desired_session,
847                         hdr->c_username,
848                         hdr->c_password,
849                         hdr->c_roomname,
850                         hdr->c_language
851         );
852         hdr->HR.got_auth = AUTH_COOKIE;
853 }
854
855
856 void 
857 HttpNewModule_AUTH
858 (ParsedHttpHdrs *httpreq)
859 {
860         httpreq->c_username = NewStrBufPlain(HKEY(DEFAULT_HTTPAUTH_USER));
861         httpreq->c_password = NewStrBufPlain(HKEY(DEFAULT_HTTPAUTH_PASS));
862         httpreq->c_roomname = NewStrBuf();
863         httpreq->c_language = NewStrBuf();
864 }
865
866
867 void 
868 HttpDetachModule_AUTH
869 (ParsedHttpHdrs *httpreq)
870 {
871         FLUSHStrBuf(httpreq->c_username);
872         FLUSHStrBuf(httpreq->c_password);
873         FLUSHStrBuf(httpreq->c_roomname);
874         FLUSHStrBuf(httpreq->c_language);
875 }
876
877
878 void 
879 HttpDestroyModule_AUTH
880 (ParsedHttpHdrs *httpreq)
881 {
882         FreeStrBuf(&httpreq->c_username);
883         FreeStrBuf(&httpreq->c_password);
884         FreeStrBuf(&httpreq->c_roomname);
885         FreeStrBuf(&httpreq->c_language);
886 }
887
888
889 void 
890 InitModule_AUTH
891 (void)
892 {
893         initialize_axdefs();
894         RegisterHeaderHandler(HKEY("COOKIE"), Header_HandleCookie);
895         RegisterHeaderHandler(HKEY("AUTHORIZATION"), Header_HandleAuth);
896
897         /* no url pattern at all? Show login. */
898         WebcitAddUrlHandler(HKEY(""), "", 0, do_welcome, ANONYMOUS|COOKIEUNNEEDED);
899
900         WebcitAddUrlHandler(HKEY("do_welcome"), "", 0, do_welcome, ANONYMOUS|COOKIEUNNEEDED);
901         WebcitAddUrlHandler(HKEY("openid_login"), "", 0, do_openid_login, ANONYMOUS);
902         WebcitAddUrlHandler(HKEY("finalize_openid_login"), "", 0, finalize_openid_login, ANONYMOUS);
903         WebcitAddUrlHandler(HKEY("openid_manual_create"), "", 0, openid_manual_create, ANONYMOUS);
904         WebcitAddUrlHandler(HKEY("validate"), "", 0, validate, 0);
905         WebcitAddUrlHandler(HKEY("do_welcome"), "", 0, do_welcome, 0);
906         WebcitAddUrlHandler(HKEY("display_reg"), "", 0, _display_reg, 0);
907         WebcitAddUrlHandler(HKEY("changepw"), "", 0, changepw, 0);
908         WebcitAddUrlHandler(HKEY("termquit"), "", 0, do_logout, 0);
909         WebcitAddUrlHandler(HKEY("do_logout"), "", 0, do_logout, ANONYMOUS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE);
910         WebcitAddUrlHandler(HKEY("monitor"), "", 0, monitor, ANONYMOUS|COOKIEUNNEEDED|FORCE_SESSIONCLOSE);
911         WebcitAddUrlHandler(HKEY("ajax_login_username_password"), "", 0, ajax_login_username_password, AJAX|ANONYMOUS);
912         WebcitAddUrlHandler(HKEY("ajax_login_newuser"), "", 0, ajax_login_newuser, AJAX|ANONYMOUS);
913         WebcitAddUrlHandler(HKEY("switch_language"), "", 0, switch_language, ANONYMOUS);
914         RegisterConditional("COND:AIDE", 2, ConditionalAide, CTX_NONE);
915         RegisterConditional("COND:LOGGEDIN", 2, ConditionalIsLoggedIn, CTX_NONE);
916         RegisterConditional("COND:MAY_CREATE_ROOM", 2,  ConditionalHaveAccessCreateRoom, CTX_NONE);
917         return;
918 }
919
920
921 void 
922 SessionDestroyModule_AUTH
923 (wcsession *sess)
924 {
925         FreeStrBuf(&sess->wc_username);
926         FreeStrBuf(&sess->wc_fullname);
927         FreeStrBuf(&sess->wc_password);
928         FreeStrBuf(&sess->httpauth_pass);
929         FreeStrBuf(&sess->cs_inet_email);
930 }