1 #include "config.h"
2 /*
3 ** Copyright 2003 Double Precision, Inc. See COPYING for
4 ** distribution information.
5 **
6 ** Original author: Jesse D. Guardiani, wingnet.net
7 */
8
9 /*
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "logindomainlist.h"
17
18 /* LINELEN is the maximum length of a line in the file we are reading. */
19 #define LINELEN 500
20 #define NUM_WC_EN_MODS 2
21
22 /* constants */
23 static const int g_delim=':';
24 static const int g_wildcard_char='*';
25
26 /* array of wildcard enabled modifiers */
27 static const char g_wc_en_mods[NUM_WC_EN_MODS][2] = { "@", "-" };
28
29 /* --------------------------------------------------------------
30 * Function : mystrsep()
31 * Created : 03/03/03
32 * Author : JDG
33 * Purpose : Emulate the BSD strsep() function.
34 * Notes :
35 * This function is designed to emulate the BSD strsep function
36 * without introducing any doubts that it is a custom
37 * implementation. It's probably quite a bit slower than the
38 * original BSD strsep(), but it'll do for most purposes.
39 * mystrsep's functionality should be nearly identical to the
40 * BSD strsep, except that it takes an int as argument for the
41 * delimiter.
42 * -------------------------------------------------------------- */
mystrsep(char ** stringp,int delim)43 static char *mystrsep( char **stringp, int delim )
44 {
45 char *orig_stringp=*stringp;
46
47 /* Make sure we return NULL if we are given NULL */
48 if (*stringp == NULL) return orig_stringp;
49
50 /* Locate first occurance of delim in stringp */
51 *stringp=strchr(*stringp, delim);
52
53 /* If no more delimiters were found, return the last substring */
54 if (*stringp == NULL) return orig_stringp;
55
56 /* Set that first occurance to NUL */
57 **stringp='\0';
58
59 /* move pointer in front of NUL character */
60 ++(*stringp);
61
62 /* Return original value of *stringp */
63 return orig_stringp;
64
65 }
66
67
68 /* --------------------------------------------------------------
69 * Function : ldl_haswildcard()
70 * Created : 04/08/03
71 * Author : JDG
72 * Purpose : Determine if the NUL terminated stringp contains
73 * the wildcard character specified in wildcard.
74 * Notes : Returns 0 if wildcard doesn't exist in stringp.
75 * Returns 1 if stringp does contain wildcard.
76 * -------------------------------------------------------------- */
ldl_haswildcard(char * stringp,int wildcard)77 static int ldl_haswildcard( char *stringp, int wildcard)
78 {
79 char *wildcardp;
80
81 /* get pointer to wildcard within stringp */
82 wildcardp = strchr(stringp, wildcard);
83
84 if (wildcardp == NULL) return 0;
85
86 return 1;
87 }
88
89
90 /* --------------------------------------------------------------
91 * Function : ldl_getfields()
92 * Created : 03/04/03
93 * Modified : 04/07/03 by JDG
94 * Author : JDG
95 * Purpose : Retrieve fields from a logindomainlist statement.
96 * Notes : This function is designed to provide a standard
97 * interface to retrieve fields from a logindomainlist
98 * statement line.
99 *
100 * This function should never generate a NULL pointer,
101 * even if a field is empty.
102 * -------------------------------------------------------------- */
ldl_getfields(char * statementp,char * firstfieldp,char * secondfieldp,char * thirdfieldp)103 static void ldl_getfields( char *statementp, char *firstfieldp, char *secondfieldp, char *thirdfieldp )
104 {
105 int delim=g_delim;
106 char *tempfirst;
107 char *tempsecond;
108 char *tempthird;
109 char *bufp=statementp;
110
111
112 /* get pointers to individual fields from file */
113 tempfirst=mystrsep(&bufp, delim);
114 tempsecond=mystrsep(&bufp, delim);
115 tempthird=mystrsep(&bufp, delim);
116
117 /* fix NULL pointers */
118 if (tempfirst == NULL) tempfirst="";
119 if (tempsecond == NULL) tempsecond="";
120 if (tempthird == NULL) tempthird="";
121
122 /* copy strings */
123 strcpy(firstfieldp, tempfirst);
124 strcpy(secondfieldp, tempsecond);
125 strcpy(thirdfieldp, tempthird);
126 }
127
128
129 /* --------------------------------------------------------------
130 * Function : ldl_invalidstatement()
131 * Created : 03/04/03
132 * Modified : 04/07/03
133 * Author : JDG
134 * Purpose : Examine line and determine if it is a valid state-
135 * ment.
136 * Notes : This function can be used to filter out comments,
137 * empty lines, and anything else that shouldn't be in
138 * a valid statement line. Returns 1 (one) if
139 * statementp is a comment or other invalid statement.
140 *
141 * Returns zero otherwise.
142 * -------------------------------------------------------------- */
ldl_invalidstatement(char * statementp)143 static int ldl_invalidstatement( char *statementp )
144 {
145 const int TRUE = 1;
146 const int FALSE = 0;
147
148 /* comments aren't valid statements */
149 if (statementp[0] == '#') return TRUE;
150
151 /* empty lines aren't valid statements */
152 if (statementp[0] == ' ' ||
153 statementp[0] == '\t' ||
154 statementp[0] == '\n') return TRUE;
155
156 /* extra long lines aren't valid statements either... */
157 if (strlen(statementp) > LINELEN) return TRUE;
158
159 /* might be a valid statement line */
160 return FALSE;
161 }
162
163
164 /* --------------------------------------------------------------
165 * Function : extract_wildcardvalue()
166 * Created : 04/07/03
167 * Author : JDG
168 * Purpose : compare wildcardedstringp and realstringp. If the
169 * two match, then replace the contents of realstringp
170 * with the contents of the wildcard character in
171 * wildcardedstringp.
172 * Notes : If the substring beforewildcardp appears at the
173 * absolute beginning of realstringp, then
174 * beforewildcardp is deleted from realstring.
175 * If the substring afterwildcardp appears at the
176 * absolute end of realstringp, then afterwildcardp
177 * is deleted from realstringp.
178 *
179 * The string remaining in realstringp represents the
180 * contents of our wildcard character in
181 * wildcardedstringp.
182 *
183 * For example, if:
184 *
185 * wildcardedstringp = my*domain.com
186 * realstringp = myexampledomain.com
187 *
188 * Then extract_wildcardvalue() will replace the
189 * contents of realstringp with the following string:
190 *
191 * example
192 *
193 * If no wildcard character exists in
194 * wildcardedstringp or if wildcardedstringp and
195 * realstringp don't match, extract_wildcardvalue()
196 * will return zero.
197 *
198 * Otherwise, extract_wildcardvalue() returns non
199 * zero.
200 * -------------------------------------------------------------- */
extract_wildcardvalue(char * wildcardedstringp,char * realstringp,int wildcard)201 static int extract_wildcardvalue( char *wildcardedstringp, char *realstringp, int wildcard) {
202 char wildcardedstring[LINELEN]="";
203 char *beforewildcardp;
204 char *afterwildcardp;
205 char *wildcardedstringpp=NULL;
206
207
208 /* Continue only if there is actually a wildcard character in wildcardedstring */
209 if (ldl_haswildcard(wildcardedstringp, wildcard)) {
210 /* Copy argument to buffer so as not to modify the original. */
211 strcpy(wildcardedstring, wildcardedstringp);
212
213 /* create a pointer to a pointer of a copy*/
214 wildcardedstringpp = wildcardedstring;
215
216
217 /* tokenize wildcardstring with '\0's */
218 beforewildcardp=mystrsep(&wildcardedstringpp, wildcard);
219 afterwildcardp=mystrsep(&wildcardedstringpp, wildcard);
220
221
222 if (beforewildcardp != NULL && strcmp(beforewildcardp, "") != 0)
223 {
224 /* If beforewildcardp string exists at the absolute
225 * beginning of realstring */
226 if (strstr(realstringp, beforewildcardp) == realstringp)
227 {
228 char *tmpp=realstringp;
229 char *p;
230
231 /* move pointer to the end of beforewildcardp in
232 * realstring. */
233 tmpp=tmpp + strlen(beforewildcardp);
234
235 /* Now, "delete" beforewildcardp from the very
236 * beginning of realstring. Note that we're not
237 * actually deleting it. We're just copying the
238 * remaining string in realstring from the
239 * location that tmpp points to in realstring.
240 * However, this has the same effect as if we
241 * had somehow "deleted" beforewildcardp from
242 * the beginning of realstring. */
243
244 p=realstringp;
245
246 while ((*p++= *tmpp++) != 0)
247 ;
248 }
249 else
250 {
251 /* if beforewildcardp does not exist at the
252 * beginning of realstringp, return non zero. */
253 return 0;
254 }
255 }
256
257
258 if (afterwildcardp != NULL && strcmp(afterwildcardp, "") != 0)
259 {
260 /* If afterwildcardp exists at the very end of realstring */
261 size_t n=strlen(realstringp);
262 size_t o=strlen(afterwildcardp);
263
264 if (n >= o &&
265 strcmp(realstringp+n-o, afterwildcardp) == 0)
266 {
267 char *tmpp=realstringp;
268
269 /* move temp pointer to the end of the NUL
270 * terminated string in realstringp, then
271 * backspace the length of afterwildcardp
272 * and write a NUL character.
273 *
274 * This effectively "deletes"
275 * afterwildcardp from realstringp as far
276 * as any string manipulation functions
277 * that rely on a terminating NUL character
278 * are concerned. */
279 tmpp=tmpp + n - o;
280 *tmpp='\0';
281 }
282 else
283 {
284 /* if afterwildcardp does not exist at the
285 * end of realstringp, return non zero. */
286 return 0;
287 }
288 }
289
290
291 /* if we made it here, then we must have
292 * successfully removed everything but
293 * the value of the wildcard in
294 * wildcardedstringp from realstringp.
295 *
296 * Return zero. */
297 return 1;
298 } else {
299 /* no wildcard in wildcardedstringp */
300 return 0;
301 }
302 }
303
304
305 /* --------------------------------------------------------------
306 * Function : replace_wildcard()
307 * Created : 04/07/03
308 * Author : JDG
309 * Purpose : replace wildcard character in wildcardedstringp
310 * with contents of wildcardvalue.
311 * Notes : return non zero on success. return zero otherwise.
312 * -------------------------------------------------------------- */
replace_wildcard(char * wildcardedstringp,char * wildcardvaluep,int wildcard)313 static int replace_wildcard( char *wildcardedstringp, char *wildcardvaluep, int wildcard) {
314 char wildcardedstring[LINELEN]="";
315 char *beforewildcardp;
316 char *afterwildcardp;
317 char *wildcardedstringpp=NULL;
318
319
320 /* Continue only if there is actually a wildcard in wildcardedstringp */
321 if (ldl_haswildcard(wildcardedstringp, wildcard)) {
322 /* Copy wildcardedstringp so as not to modify the original. */
323 strcpy(wildcardedstring, wildcardedstringp);
324
325 /* create a pointer to a pointer of a copy */
326 wildcardedstringpp = wildcardedstring;
327
328
329 /* tokenize first field */
330 beforewildcardp=mystrsep(&wildcardedstringpp, wildcard);
331 afterwildcardp=mystrsep(&wildcardedstringpp, wildcard);
332
333 /* start with a clean slate */
334 strcpy(wildcardedstringp, "");
335
336 if (beforewildcardp != NULL &&
337 strcmp(beforewildcardp, "") != 0)
338 {
339 /* Place string contents of beforewildcardp in wildcardedstringp */
340 strcpy(wildcardedstringp, beforewildcardp);
341 }
342
343 /* Add wildcardvaluep string to end of wildcardedstringp */
344 strncat(wildcardedstringp, wildcardvaluep,
345 LINELEN-1-strlen(wildcardedstringp));
346
347 if (afterwildcardp != NULL &&
348 strcmp(afterwildcardp, "") != 0)
349 {
350 /* Add afterwildcardp string to end of wildcardedstringp */
351 strncat(wildcardedstringp, afterwildcardp,
352 LINELEN-1-strlen(wildcardedstringp));
353 }
354
355 /* all is well */
356 return 1;
357
358 } else {
359 /* no wildcard in wildcardedstringp */
360 return 0;
361 }
362 }
363
364
365 /* --------------------------------------------------------------
366 * Function : get_defaultdomainfields()
367 * Created : 02/25/03
368 * Modified : 04/07/03 by JDG
369 * Author : JDG
370 * Purpose : Retrieve default domain from 'LOGINDOMAINLIST' file
371 * using either 'SERVER_ADDR' or 'HTTP_HOST' CGI
372 * variables.
373 * Notes :
374 *
375 * LOGINDOMAINLIST file can have the following format:
376 *
377 * DOMAIN1:IP1:MODIFIER
378 * DOMAIN2:DOMAIN3:MODIFIER
379 * DOMAIN4:DOMAIN5:MODIFIER
380 * etc...
381 *
382 * The first field contains the mail domain, and it is this field
383 * that appears in the drop down list if a drop down is specified
384 * by the modifier field.
385 *
386 * The second field can contain either an IP address or a domain
387 * name. This field is campared against the contents of the
388 * HTTP_HOST and/or SERVER_ADDR CGI environment variables. If a
389 * match is found, then the first and third (last) fields are
390 * written to domainp and modifyp, respectively.
391 *
392 * The third field, or modifier, can be an "*", an "@", or an
393 * rbitrary group identifier string. See README.logindomainlist
394 * in the main distribution directory for more details regarding
395 * LOGINDOMAINLIST file syntax.
396 * -------------------------------------------------------------- */
get_defaultdomainfields(FILE * fp,char * domainp,char * modifyp)397 static void get_defaultdomainfields( FILE *fp, char *domainp, char *modifyp)
398 {
399 char buf[LINELEN]="";
400 char *serveraddr=getenv("SERVER_ADDR");
401 char *httphost=getenv("HTTP_HOST");
402
403 if (!serveraddr) serveraddr="";
404 if (!httphost) httphost="";
405
406 /* rewind the file pointer */
407 rewind(fp);
408
409 /* Read one line at a time from fp */
410 while (fgets(buf, sizeof(buf), fp))
411 {
412 int count = 0;
413 char firstfield[LINELEN]="";
414 char secondfield[LINELEN]="";
415 char thirdfield[LINELEN]="";
416 /* get the position of the newline (if it exists) */
417 char *p=strchr(buf, '\n');
418
419 /* replace the newline with NUL */
420 if (*p) *p='\0';
421
422 /* ignore comments, empty lines, etc... */
423 if (ldl_invalidstatement(buf)) continue;
424
425
426 /* get individual fields from line */
427 ldl_getfields(buf, firstfield, secondfield, thirdfield);
428
429 /* process any wildcard enabled modifiers */
430 for (count = 0; count < NUM_WC_EN_MODS; count++)
431 {
432 const char *current_modifier = &g_wc_en_mods[count][0];
433
434 /* If this record is using wildcard domain mapping... */
435 if (strcmp(thirdfield, current_modifier) == 0)
436 {
437 int wildcard = g_wildcard_char;
438
439 /* If either the first or second field contains a wildcard char */
440 if (ldl_haswildcard(firstfield, wildcard) ||
441 ldl_haswildcard(secondfield, wildcard))
442 {
443 char finaldomain[LINELEN] = "";
444 char wildcardvalue[LINELEN] = "";
445 char tempbuf[LINELEN] = "";
446
447 /* extract the string that the wildcard in
448 * secondfield represents when compared
449 * with currentdomain */
450
451 /* seed wildcardvalue with contents of
452 * httphost. Sorry - no IP wildcarding. */
453 strcpy( wildcardvalue, httphost);
454
455 /* if secondfield and wildcardvalue match,
456 * extract_wildcardvalue will "chop off"
457 * the text before and after the wildcard
458 * character in secondfield from
459 * wildcardvalue */
460 if (extract_wildcardvalue(secondfield, wildcardvalue, wildcard))
461 {
462 /* wildcardvalue may now contain the final
463 * domain name to use as default domain if
464 * firstfield does NOT contain a wildcard.
465 *
466 * That is why we save the contents of
467 * wildcardvalue in finaldomain here. */
468 strcpy(finaldomain, wildcardvalue);
469 }
470 else
471 {
472 /* Make sure this wildcardless record
473 * actually matches httphost before doing
474 * anything else */
475 if (strcmp(secondfield, httphost) != 0) continue;
476
477 /* we don't have a wildcard in the second
478 * field, so just do a straight copy */
479 strcpy(finaldomain, secondfield);
480 }
481
482
483 /* seed tempbuf with contents of firstfield */
484 strcpy(tempbuf, firstfield);
485
486 /* Replace wildcard character in tempbuf
487 * with contents of wildcardvalue */
488 if (replace_wildcard(tempbuf, wildcardvalue, wildcard))
489 {
490
491 /* The above replace_wildcard() must have
492 * been seccessful if we're still here,
493 * so save the contents of tempbuf in
494 * finaldomain. */
495 strcpy(finaldomain, tempbuf);
496 }
497 else
498 {
499 /* we don't have a wildcard in the first
500 * field, so just do a straight copy */
501 strcpy(finaldomain, firstfield);
502 }
503
504 /* return default domain */
505 strcpy(domainp, finaldomain);
506 strcpy(modifyp, thirdfield);
507 return;
508 }
509 else
510 {
511 /* Fall through to matching against serveraddr
512 * and httphost if no wildcards exist in either
513 * firstfield or secondfield */
514 }
515 }
516 }
517
518
519 /* This is reached if the third field (modifier) is NOT a wildcard */
520 /* compare second field against CGI variables */
521 if (strcmp(secondfield, serveraddr) == 0 ||
522 strcmp(secondfield, httphost) == 0)
523 {
524 strcpy(domainp, firstfield);
525 strcpy(modifyp, thirdfield);
526 return;
527 }
528
529 }
530 }
531
532
533 /* --------------------------------------------------------------
534 * Function : ldl_displayhidden()
535 * Created : 04/05/03
536 * Author : JDG
537 * Purpose : display an HTML hidden input field with
538 * value="defaultdomain"
539 * Notes : none
540 * -------------------------------------------------------------- */
ldl_displayhiddenfield(char * defaultdomainp)541 static void ldl_displayhiddenfield( char *defaultdomainp) {
542
543 if (strlen(defaultdomainp) > 0)
544 {
545 /* This is displayed only if defaultdomain is NOT
546 * empty */
547 printf("<input type=\"hidden\" name=\"logindomain\" value=\"%s\" />@%s",
548 defaultdomainp, defaultdomainp);
549 }
550 else
551 {
552 /* Do nothing. This is here so that nothing will
553 * be displayed if defaultdomain is empty. */
554 }
555 }
556
557
558 /* --------------------------------------------------------------
559 * Function : ldl_displaytextfield()
560 * Created : 04/07/03
561 * Author : JDG
562 * Purpose : display an HTML text input field with
563 * value="defaultdomain"
564 * Notes : none
565 * -------------------------------------------------------------- */
ldl_displaytextfield(char * defaultdomainp)566 static void ldl_displaytextfield( char *defaultdomainp) {
567
568 if (strlen(defaultdomainp) > 0)
569 {
570 /* This is displayed only if defaultdomain is NOT
571 * empty */
572 printf("@<input type=\"text\" name=\"logindomain\" value=\"%s\" size=\"%d\" />",
573 defaultdomainp, (int)strlen(defaultdomainp)+2);
574 }
575 else
576 {
577 /* Do nothing. This is here so that nothing will
578 * be displayed if defaultdomain is empty. */
579 }
580 }
581
582 /* --------------------------------------------------------------
583 * Function : ldl_displaydropdown()
584 * Created : 04/05/03
585 * Modified : 04/07/03
586 * Author : JDG
587 * Purpose : Display an HTML drop down menu containing only
588 * records from fp with a third field identical to
589 * defaultgroupp.
590 * Set the record with a first field matching
591 * defaultdomainp as 'selected'.
592 * Notes : none
593 * -------------------------------------------------------------- */
ldl_displaydropdown(FILE * fp,char * defaultdomainp,char * defaultgroupp)594 static void ldl_displaydropdown( FILE *fp, char *defaultdomainp, char *defaultgroupp) {
595
596 char buf[LINELEN];
597
598 /* This is a flag that is toggled once the first match has been
599 * made. */
600 int firstmatch=0;
601
602
603 /* rewind file pointer */
604 rewind(fp);
605
606
607 /* Read one line at a time from fp */
608 while (fgets(buf, sizeof(buf), fp))
609 {
610 char firstfield[LINELEN]="";
611 char secondfield[LINELEN]="";
612 char thirdfield[LINELEN]="";
613 /* get the position of the newline (if it exists) */
614 char *p=strchr(buf, '\n');
615
616 /* replace the newline with NUL */
617 if (*p) *p='\0';
618
619 /* ignore comments, empty lines, etc... */
620 if (ldl_invalidstatement(buf)) continue;
621
622 /* get individual fields from file */
623 ldl_getfields(buf, firstfield, secondfield, thirdfield);
624
625 /* only display this option if it's group field (thirdfield)
626 * is identical to defaultgroupp. */
627 if (strcmp(thirdfield, defaultgroupp) == 0)
628 {
629 /* Only display the select tag the first time we
630 * find a match. */
631 if (firstmatch == 0)
632 {
633 printf("@<select name=\"logindomain\"><option value=\"\"> </option>\n");
634 firstmatch=1;
635 }
636
637 /* Do not display options with empty first fields. */
638 if (strlen(firstfield) > 0)
639 {
640 /* If 'defaultdomainp' is identical to firstfield
641 * then set this option as 'selected'. */
642 if (strcmp(defaultdomainp, firstfield) == 0)
643 {
644 printf("<option value=\"%s\" selected=\"selected\">%s</option>\n",
645 firstfield, firstfield);
646 }
647 else
648 {
649 printf("<option value=\"%s\">%s</option>\n",
650 firstfield, firstfield);
651 }
652 }
653 }
654 }
655
656 /* Display a closing select tag only if we displayed
657 * a starting select tag */
658 if (firstmatch > 0) printf("</select>");
659 }
660
661
662 /* --------------------------------------------------------------
663 * Function : print_logindomainlist()
664 * Created : 03/04/03
665 * Modified : 04/07/03 - JDG
666 * Author : JDG
667 * Purpose : parse fp and print proper output.
668 * Notes : none
669 * -------------------------------------------------------------- */
print_logindomainlist(FILE * fp)670 void print_logindomainlist( FILE *fp )
671 {
672 char defaultdomain[LINELEN]="";
673 char modifierfield[LINELEN]="";
674
675 /* get default domain field and the corresponding default
676 * group field (if applicable) from fp. */
677 get_defaultdomainfields(fp, defaultdomain, modifierfield);
678
679
680 /* There are basically two ways to graphically display the
681 * default domain.
682 *
683 * 1.) As a hidden field with descriptive text.
684 * 2.) As a drop down menu with a defaulted option.
685 *
686 * The modifiers '@' and '*' display a hidden field.
687 *
688 * If the modifier field contains anything else, then we
689 * consider it's contents a 'group' identifier and we
690 * display a drop down. */
691 if (strcmp(modifierfield, "@") == 0)
692 {
693 /* ----------------------
694 * DISPLAY HIDDEN FIELD
695 * ---------------------- */
696
697 ldl_displayhiddenfield(defaultdomain);
698 }
699 else if (strcmp(modifierfield, "-") == 0)
700 {
701 /* ----------------------
702 * DISPLAY TEXT FIELD
703 * ---------------------- */
704
705 ldl_displaytextfield(defaultdomain);
706 }
707 else
708 {
709 /* ----------------------
710 * DISPLAY DROP DOWN MENU
711 * ---------------------- */
712
713 ldl_displaydropdown(fp, defaultdomain, modifierfield);
714 }
715 }
716