Codebase list dillo / upstream/0.8.6 src / cookies.c
upstream/0.8.6

Tree @upstream/0.8.6 (Download .tar.gz)

cookies.c @upstream/0.8.6raw · history · blame

/*
 * File: cookies.c
 *
 * Copyright 2001 Lars Clausen   <lrclause@cs.uiuc.edu>
 *                Jörgen Viksell <jorgen.viksell@telia.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

/* Handling of cookies takes place here.
 * This implementation aims to follow RFC 2965:
 * http://www.cis.ohio-state.edu/cs/Services/rfc/rfc-text/rfc2965.txt
 */

#define DEBUG_LEVEL 10
#include "debug.h"


#ifdef DISABLE_COOKIES

/*
 * Initialize the cookies module
 */
void a_Cookies_init(void)
{
   DEBUG_MSG(10, "Cookies: absolutely disabled at compilation time.\n");
}

#else

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>       /* for time() and time_t */
#include <ctype.h>

#include "msg.h"
#include "IO/Url.h"
#include "misc.h"
#include "list.h"
#include "cookies.h"
#include "capi.h"
#include "dpiapi.h"
#include "../dpip/dpip.h"


/* The maximum length of a line in the cookie file */
#define LINE_MAXLEN 4096

typedef enum {
   COOKIE_ACCEPT,
   COOKIE_ACCEPT_SESSION,
   COOKIE_DENY
} CookieControlAction;

typedef struct {
   CookieControlAction action;
   char *domain;
} CookieControl;

/* Variables for access control */
static CookieControl *ccontrol = NULL;
static int num_ccontrol = 0;
static int num_ccontrol_max = 1;
static CookieControlAction default_action = COOKIE_DENY;

static gboolean disabled;

static FILE *Cookies_fopen(const char *file, gchar *init_str);
static CookieControlAction Cookies_control_check(const DilloUrl *url);
static CookieControlAction Cookies_control_check_domain(const char *domain);
static int Cookie_control_init(void);

/*
 * Return a file pointer. If the file doesn't exist, try to create it,
 * with the optional 'init_str' as its content.
 */
static FILE *Cookies_fopen(const char *filename, gchar *init_str)
{
   FILE *F_in;
   int fd;

   if ((F_in = fopen(filename, "r")) == NULL) {
      /* Create the file */
      fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
      if (fd != -1) {
         if (init_str)
            write(fd, init_str, strlen(init_str));
         close(fd);

         DEBUG_MSG(10, "Cookies: Created file: %s\n", filename);
         F_in = Cookies_fopen(filename, NULL);
      } else {
         DEBUG_MSG(10, "Cookies: Could not create file: %s!\n", filename);
      }
   }

   /* set close on exec */
   fcntl(fileno(F_in), F_SETFD, FD_CLOEXEC | fcntl(fileno(F_in), F_GETFD));

   return F_in;
}

/*
 * Initialize the cookies module
 * (The 'disabled' variable is writable only within a_Cookies_init)
 */
void a_Cookies_init(void)
{
   /* Default setting */
   disabled = TRUE;

   /* Read and parse the cookie control file (cookiesrc) */
   if (Cookie_control_init() != 0) {
      DEBUG_MSG(10, "Disabling cookies.\n");
      return;
   }

   DEBUG_MSG(10, "Enabling cookies as from cookiesrc...\n");
   disabled = FALSE;
}

/*
 * Flush cookies to disk and free all the memory allocated.
 */
void a_Cookies_freeall()
{
}

/*
 * Set the value corresponding to the cookie string
 */
void a_Cookies_set(GList *cookie_strings, const DilloUrl *set_url)
{
   CookieControlAction action;
   char *cmd, *path, numstr[16];

   if (disabled)
      return;

   action = Cookies_control_check(set_url);
   if (action == COOKIE_DENY) {
      DEBUG_MSG(5, "Cookies: denied SET for %s\n", URL_HOST_(set_url));
      return;
   }

   while (cookie_strings != NULL ) {
      char *cookie_string = cookie_strings->data;
      path = (char *) URL_PATH_(set_url);

      g_snprintf(numstr, 16, "%d", URL_PORT(set_url));
      cmd = a_Dpip_build_cmd("cmd=%s cookie=%s host=%s path=%s port=%s",
                             "set_cookie", cookie_string, URL_HOST_(set_url),
                            path ? path : "/", numstr);

      DEBUG_MSG(5, "Cookies.c: a_Cookies_set \n\t \"%s\" \n",cmd );
      a_Capi_dpi_send_cmd(NULL, NULL, cmd, "cookies", 1);
      g_free(cmd);

      cookie_strings = g_list_next(cookie_strings);
   }

}

/*
 * Return a string that contains all relevant cookies as headers.
 */
char *a_Cookies_get(const DilloUrl *request_url)
{
   char *cmd, *path, *dpip_tag, *cookie, numstr[16];
   CookieControlAction action;

   cookie = g_strdup("");

   if (disabled)
      return cookie;

   action = Cookies_control_check(request_url);
   if (action == COOKIE_DENY) {
      DEBUG_MSG(5, "Cookies: denied GET for %s\n", URL_HOST_(request_url));
      return cookie;
   }
   path = (char *) URL_PATH_(request_url);

   g_snprintf(numstr, 16, "%d", URL_PORT(request_url));
   cmd = a_Dpip_build_cmd("cmd=%s scheme=%s host=%s path=%s port=%s",
                          "get_cookie", URL_SCHEME(request_url),
                         URL_HOST(request_url), path ? path : "/", numstr);

   /* Get the answer from cookies.dpi */
   dpip_tag = a_Dpi_send_blocking_cmd("cookies", cmd);
   g_free(cmd);

   if (dpip_tag != NULL) {
      cookie = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "cookie");
      g_free(dpip_tag);
   }
   return cookie;
}

/* -------------------------------------------------------------
 *                    Access control routines
 * ------------------------------------------------------------- */


/*
 * Get the cookie control rules (from cookiesrc).
 * Return value:
 *   0 = Parsed OK, with cookies enabled
 *   1 = Parsed OK, with cookies disabled
 *   2 = Can't open the control file
 */
static int Cookie_control_init(void)
{
   CookieControl cc;
   FILE *stream;
   char *filename;
   char line[LINE_MAXLEN];
   char domain[LINE_MAXLEN];
   char rule[LINE_MAXLEN];
   int i, j;
   gboolean enabled = FALSE;

   /* Get a file pointer */
   filename = a_Misc_prepend_user_home(".dillo/cookiesrc");
   stream = Cookies_fopen(filename, "DEFAULT DENY\n");
   g_free(filename);

   if (!stream)
      return 2;

   /* Get all lines in the file */
   while (!feof(stream)) {
      line[0] = '\0';
      fgets(line, LINE_MAXLEN, stream);

      /* Remove leading and trailing whitespaces */
      g_strstrip(line);

      if (line[0] != '\0' && line[0] != '#') {
         i = 0;
         j = 0;

         /* Get the domain */
         while (!isspace(line[i]))
            domain[j++] = line[i++];
         domain[j] = '\0';

         /* Skip past whitespaces */
         i++;
         while (isspace(line[i]))
            i++;

         /* Get the rule */
         j = 0;
         while (line[i] != '\0' && !isspace(line[i]))
            rule[j++] = line[i++];
         rule[j] = '\0';

         if (g_strcasecmp(rule, "ACCEPT") == 0)
            cc.action = COOKIE_ACCEPT;
         else if (g_strcasecmp(rule, "ACCEPT_SESSION") == 0)
            cc.action = COOKIE_ACCEPT_SESSION;
         else if (g_strcasecmp(rule, "DENY") == 0)
            cc.action = COOKIE_DENY;
         else {
            MSG("Cookies: rule '%s' for domain '%s' is not recognised.\n",
                rule, domain);
            continue;
         }

         cc.domain = g_strdup(domain);
         if (g_strcasecmp(cc.domain, "DEFAULT") == 0) {
            /* Set the default action */
            default_action = cc.action;
            g_free(cc.domain);
         } else {
            a_List_add(ccontrol, num_ccontrol, num_ccontrol_max);
            ccontrol[num_ccontrol++] = cc;
         }

         if (cc.action != COOKIE_DENY)
            enabled = TRUE;
      }
   }

   fclose(stream);

   return (enabled ? 0 : 1);
}

/*
 * Check the rules for an appropriate action for this domain
 */
static CookieControlAction Cookies_control_check_domain(const char *domain)
{
   int i, diff;

   for (i = 0; i < num_ccontrol; i++) {
      if (ccontrol[i].domain[0] == '.') {
         diff = strlen(domain) - strlen(ccontrol[i].domain);
         if (diff >= 0) {
            if (g_strcasecmp(domain + diff, ccontrol[i].domain) != 0)
               continue;
         } else {
            continue;
         }
      } else {
         if (g_strcasecmp(domain, ccontrol[i].domain) != 0)
            continue;
      }

      /* If we got here we have a match */
      return( ccontrol[i].action );
   }

   return default_action;
}

/*
 * Same as the above except it takes an URL
 */
static CookieControlAction Cookies_control_check(const DilloUrl *url)
{
   return Cookies_control_check_domain(URL_HOST(url));
}

#endif /* !DISABLE_COOKIES */