/**
 * $Id$
 *
 * fnord-auth // .http-auth - for fnord httpd 
 *    (see http://www.fefe.de/fnord/)
 *
 * see also RFC2617 
 * 
 * Arguments: (passed by with -DAUTH compiled fnord-httpd)
 *   1. hostname
 *   2. path
 *   3. type user:pass (base64 encoded) [see RFC2617]
 *
 * ths@so36.net -- 2004/02/10 
 *
 * TODO: support SHA/MD5 hashes of passwords
 *
 * This software is published under "THE BEER-WARE LICENSE" (Revision 42):
 * <ths@so36.net> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you
 * think this stuff is worth it, you can buy me a beer in return.
 *
 **/

#include "fnord-auth.h"


int main(int argc, char** argv)
{
   int      auth_type;
   int      require_auth = 0;
   int      fd    = 0;
   int      i     = 0;
   char     *s    = NULL;
   char     *cpw  = NULL;
   char     *tmp  = NULL;
   char     *line = NULL;
   char     *credentials = NULL;
   char     *basic_creds = NULL;
   unsigned char *auth   = NULL;
   
   if( (fd = open(AUTH_DIRS, O_RDONLY)) < 0 )
      _err("fopen auth-dirs", __LINE__);

   while( (line = readln(fd, MAXLINE)) != NULL ) {
      
      if( (s = strnstr(argv[2], line, strlen(line))) != NULL ) {
         require_auth = 1;
         free(line);
         break;
      }
      free(line);
   }
   if( close(fd) == -1 )
      _err("close AUTH_DIRS failed.", __LINE__);
   
   if(require_auth == 0)
      exit(0);

   if(argv[3] != NULL) {
      
      int len = strlen(argv[3]);

      if( (credentials = (char *)malloc(len + 1)) == NULL )
         _err("malloc auth failed.", __LINE__);

      memset(credentials, 0, (len + 1));
      memcpy(credentials, argv[3], len);
      printf("1 creds: %s\n", credentials);

   } else /* no creds */
      exit(1); 
   
   if( (tmp=strnstr(credentials, "Basic ", 6)) != NULL  ) {
      basic_creds = credentials+6;
      auth_type   = AUTH_BASIC;

      if( (strlen(basic_creds) % 4) != 0)
         exit(1);

   } /* TODO: else if strnstr ... Digest .. */

   if( (auth = (unsigned char *)malloc(strlen(basic_creds + 1))) == NULL ) {
      free(credentials);
      _err("malloc auth failed.", __LINE__);
   }

   memset(auth, 0, strlen(basic_creds + 1));

   raw_base64_decode((unsigned char*)basic_creds, auth);

   if( (cpw = (char *)strchr((char *)auth, ':')) == NULL) {
      free(auth);
      free(credentials);
      exit(1);
   }
   
   cpw++;   /* skip ':' */
   auth[(long)cpw-(long)auth-1] = 0;

   if( (fd = open(AUTH_PASSWD, O_RDONLY)) < 0 )
      _err("open AUTH_PASSWD", __LINE__);

   i = strlen((char *)auth);

   while( (line = readln(fd, MAXLINE)) != NULL ) {
      char *sl = NULL;

      sl = line;
      
      s = strnstr(line, (char *)auth, i);
      
      line+=i+1;

      if(s != NULL) {
         /* TODO: implement md5/sha */
         if( strncmp(crypt(cpw, (char *)line), line, strlen(line)) == 0 ) {
            memset(line, 0x23, strlen(line));
            free(sl);
            if( close(fd) == -1 )
               _err("close AUTH_PASSWD failed.", __LINE__);
            exit(0);
         }
         memset(line, 0x23, strlen(line));
         free(sl);
         break;
      } else {
         memset(line, 0x23, strlen(line));
         free(sl);
      }
   }
   if( close(fd) == -1 )
      _err("close AUTH_PASSWD failed.", __LINE__);

   exit(1);
}

char * readln(int fd, size_t max)
{
   int i = 1;
   int j = 0;
   char *c;
   
   if((c = (char *)malloc(max+1)) == NULL)
      _err("malloc error...\n", __LINE__);

   memset(c, 0, max+1);
   
   while( ( (c[j-1] != 0xA) || (c[j-1] = 0) ) && (j < max) ) {

      if( (i = read(fd, c+j ,1)) <= 0 )
         return(NULL);

      j++;
   }
   return(c);
}

void _err(char *s, int l)
{
   fprintf(stderr, "HTTPD-AUTH ERROR at line %d: %s\n", l, s);
   exit(-1);
}

