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