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