📄 cookies.c
字号:
/* * File: cookies.c * Cookies server. * * Copyright 2001 Lars Clausen <lrclause@cs.uiuc.edu> * J鰎gen Viksell <jorgen.viksell@telia.com> * Copyright 2002-2005 Jorge Arellano Cid <jcid@dillo.org> * * 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 *//* Todo: this server is not assembling the received packets. * This means it currently expects dillo to send full dpi tags * within the socket; if that fails, everything stops. * This is not hard to fix, mainly is a matter of expecting the * final '>' of a tag. */#ifdef DISABLE_COOKIESint main(void){ return 0; /* never called */}#else#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/un.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <stddef.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <time.h> /* for time() and time_t */#include <ctype.h>#include <netdb.h>#include <signal.h>#include "dpiutil.h"#include "../dpip/dpip.h"#include <glib.h>/* This one is tricky, some sources state it should include the byte * for the terminating NULL, and others say it shouldn't. */# define D_SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + strlen ((ptr)->sun_path))/* Debugging macros */#define _MSG(fmt...)#define MSG(fmt...) g_print("[cookies dpi]: " fmt)/* * a_List_add() * * Make sure there's space for 'num_items' items within the list * (First, allocate an 'alloc_step' sized chunk, after that, double the * list size --to make it faster) */#define a_List_add(list,num_items,alloc_step) \ if ( !list ) { \ list = g_malloc(alloc_step * sizeof((*list))); \ } \ if ( num_items >= alloc_step ){ \ while ( num_items >= alloc_step ) \ alloc_step <<= 1; \ list = g_realloc(list, alloc_step * sizeof((*list))); \ }/* The maximum length of a line in the cookie file */#define LINE_MAXLEN 4096typedef enum { COOKIE_ACCEPT, COOKIE_ACCEPT_SESSION, COOKIE_DENY} CookieControlAction;typedef struct { CookieControlAction action; char *domain;} CookieControl;typedef struct { char *name; char *value; char *domain; char *path; time_t expires_at; guint version; char *comment; char *comment_url; gboolean secure; gboolean session_only; GList *ports;} CookieData_t;/* * Local data *//* Hashtable indexed by domain, each value is a set of cookies for * that domain. */static GHashTable *cookies;/* 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 *file_stream;static char *cookies_txt_header_str ="# HTTP Cookie File\n""# http://www.netscape.com/newsref/std/cookie_spec.html\n""# This is a generated file! Do not edit.\n\n";/* * Forward declarations */static gchar *d_strsep(char **orig, const char *delim);static FILE *Cookies_fopen(const char *file, gchar *init_str);static CookieControlAction Cookies_control_check_domain(const char *domain);static int Cookie_control_init(void);static void Cookies_parse_ports(gint url_port, CookieData_t *cookie, const char *port_str);static char *Cookies_build_ports_str(CookieData_t *cookie);static char *Cookies_strip_path(const char *path);static void Cookies_add_cookie(CookieData_t *cookie);static void Cookies_remove_cookie(CookieData_t *cookie);static gint Cookies_equals(gconstpointer a, gconstpointer b);/* * strsep implementation */gchar *d_strsep(char **orig, const char *delim){ gchar *str, *p; if (!(str = *orig)) return NULL; p = strpbrk(str, delim); if (p) { *p++ = 0; *orig = p; } else { *orig = NULL; } return str;}/* * 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); MSG("Created file: %s\n", filename); F_in = Cookies_fopen(filename, NULL); } else { MSG("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;}static void Cookies_free_cookie(CookieData_t *cookie){ g_free(cookie->name); g_free(cookie->value); g_free(cookie->domain); g_free(cookie->path); g_free(cookie->comment); g_free(cookie->comment_url); g_list_free(cookie->ports); g_free(cookie);}/* * Initialize the cookies module * (The 'disabled' variable is writable only within Cookies_init) */void Cookies_init(){ CookieData_t *cookie; char *filename; char line[LINE_MAXLEN];#ifndef HAVE_LOCKF struct flock lck;#endif FILE *old_cookies_file_stream; /* Default setting */ disabled = TRUE; /* Read and parse the cookie control file (cookiesrc) */ if (Cookie_control_init() != 0) { MSG("Disabling cookies.\n"); return; } /* Get a stream for the cookies file */ filename = g_strconcat(g_get_home_dir(), "/.dillo/cookies.txt", NULL); file_stream = Cookies_fopen(filename, cookies_txt_header_str); g_free(filename); if (!file_stream) { MSG("ERROR: Can't open ~/.dillo/cookies.txt, disabling cookies\n"); return; } /* Try to get a lock from the file descriptor */#ifdef HAVE_LOCKF disabled = (lockf(fileno(file_stream), F_TLOCK, 0) == -1);#else /* POSIX lock */ lck.l_start = 0; /* start at beginning of file */ lck.l_len = 0; /* lock entire file */ lck.l_type = F_WRLCK; lck.l_whence = SEEK_SET; /* absolute offset */ disabled = (fcntl(fileno(file_stream), F_SETLK, &lck) == -1);#endif if (disabled) { MSG("The cookies file has a file lock: disabling cookies!\n"); fclose(file_stream); return; } MSG("Enabling cookies as from cookiesrc...\n"); cookies = g_hash_table_new(g_str_hash, g_str_equal); /* Get all lines in the file */ while (!feof(file_stream)) { line[0] = '\0'; fgets(line, LINE_MAXLEN, file_stream); /* Remove leading and trailing whitespaces */ g_strstrip(line); if ((line[0] != '\0') && (line[0] != '#')) { /* Would use g_strsplit, but it doesn't give empty trailing pieces. */ /* Split the row into pieces using a tab as the delimiter. * pieces[0] The domain name * pieces[1] TRUE/FALSE: is the domain a suffix, or a full domain? * pieces[2] The path * pieces[3] Is the cookie unsecure or secure (TRUE/FALSE) * pieces[4] Timestamp of expire date * pieces[5] Name of the cookie * pieces[6] Value of the cookie */ CookieControlAction action; char *piece; char *line_marker = line; cookie = g_new0(CookieData_t, 1); cookie->session_only = FALSE; cookie->version = 0; cookie->domain = g_strdup(d_strsep(&line_marker, "\t")); d_strsep(&line_marker, "\t"); /* we use domain always as sufix */ cookie->path = g_strdup(d_strsep(&line_marker, "\t")); piece = d_strsep(&line_marker, "\t"); if (piece != NULL && piece[0] == 'T') cookie->secure = TRUE; piece = d_strsep(&line_marker, "\t"); if (piece != NULL) cookie->expires_at = (time_t) strtol(piece, NULL, 10); cookie->name = g_strdup(d_strsep(&line_marker, "\t")); cookie->value = g_strdup(d_strsep(&line_marker, "\t")); if (!cookie->domain || cookie->domain[0] == '\0' || !cookie->path || cookie->path[0] != '/' || !cookie->name || cookie->name[0] == '\0' || !cookie->value) { MSG("Malformed line in cookies.txt file!\n"); Cookies_free_cookie(cookie); continue; } action = Cookies_control_check_domain(cookie->domain); if (action == COOKIE_DENY) { Cookies_free_cookie(cookie); continue; } else if (action == COOKIE_ACCEPT_SESSION) { cookie->session_only = TRUE; } /* Save cookie in memory */ Cookies_add_cookie(cookie); } } filename = g_strconcat(g_get_home_dir(), "/.dillo/cookies", NULL); if ((old_cookies_file_stream = fopen(filename, "r")) != NULL) { g_free(filename); MSG("WARNING: Reading old cookies file ~/.dillo/cookies too\n"); /* Get all lines in the file */ while (!feof(old_cookies_file_stream)) { line[0] = '\0'; fgets(line, LINE_MAXLEN, old_cookies_file_stream); /* Remove leading and trailing whitespaces */ g_strstrip(line); if (line[0] != '\0') { /* Would use g_strsplit, but it doesn't give empty trailing pieces. */ /* Split the row into pieces using a tab as the delimiter. * pieces[0] The version this cookie was set as (0 / 1) * pieces[1] The domain name * pieces[2] A comma separated list of accepted ports * pieces[3] The path * pieces[4] Is the cookie unsecure or secure (0 / 1) * pieces[5] Timestamp of expire date * pieces[6] Name of the cookie * pieces[7] Value of the cookie * pieces[8] Comment * pieces[9] Comment url */ CookieControlAction action; char *piece; char *line_marker = line; cookie = g_new0(CookieData_t, 1); cookie->session_only = FALSE; piece = d_strsep(&line_marker, "\t"); if (piece != NULL) cookie->version = strtol(piece, NULL, 10); cookie->domain = g_strdup(d_strsep(&line_marker, "\t")); Cookies_parse_ports(0, cookie, d_strsep(&line_marker, "\t")); cookie->path = g_strdup(d_strsep(&line_marker, "\t")); piece = d_strsep(&line_marker, "\t"); if (piece != NULL && piece[0] == '1') cookie->secure = TRUE; piece = d_strsep(&line_marker, "\t"); if (piece != NULL) cookie->expires_at = (time_t) strtol(piece, NULL, 10); cookie->name = g_strdup(d_strsep(&line_marker, "\t")); cookie->value = g_strdup(d_strsep(&line_marker, "\t")); cookie->comment = g_strdup(d_strsep(&line_marker, "\t")); cookie->comment_url = g_strdup(d_strsep(&line_marker, "\t")); if (!cookie->domain || cookie->domain[0] == '\0' || !cookie->path || cookie->path[0] != '/' || !cookie->name || cookie->name[0] == '\0' || !cookie->value) { MSG("Malformed line in cookies file!\n"); Cookies_free_cookie(cookie); continue; } action = Cookies_control_check_domain(cookie->domain); if (action == COOKIE_DENY) { Cookies_free_cookie(cookie); continue; } else if (action == COOKIE_ACCEPT_SESSION) { cookie->session_only = TRUE; } /* Save cookie in memory */ Cookies_add_cookie(cookie); } } fclose(old_cookies_file_stream); } else { g_free(filename); }}/* * Save the cookies and remove them from the hash table */static gboolean Cookies_freeall_cb(gpointer key, gpointer value, gpointer data){ CookieData_t *cookie; GList *domain_cookies = value;/* char *ports_str; */ for (; domain_cookies; domain_cookies = g_list_next(domain_cookies)) { cookie = domain_cookies->data; if (!cookie->session_only) {/* ports_str = Cookies_build_ports_str(cookie); */ fprintf(file_stream, "%s\tTRUE\t%s\t%s\t%ld\t%s\t%s\n", cookie->domain, cookie->path, cookie->secure ? "TRUE" : "FALSE", (long)cookie->expires_at, cookie->name, cookie->value);/* g_free(ports_str); */ } Cookies_free_cookie(cookie); } g_list_free(value); g_free(key); /* Return TRUE to tell GLIB to free this key from the hash table */ return TRUE;}/* * Flush cookies to disk and free all the memory allocated. */void Cookies_freeall(){ int fd;#ifndef HAVE_LOCKF struct flock lck;#endif if (disabled) return; rewind(file_stream); fd = fileno(file_stream); ftruncate(fd, 0); fprintf(file_stream, cookies_txt_header_str); g_hash_table_foreach_remove(cookies, Cookies_freeall_cb, NULL);#ifdef HAVE_LOCKF lockf(fd, F_ULOCK, 0);#else /* POSIX file lock */ lck.l_start = 0; /* start at beginning of file */ lck.l_len = 0; /* lock entire file */ lck.l_type = F_UNLCK; lck.l_whence = SEEK_SET; /* absolute offset */ fcntl(fileno(file_stream), F_SETLKW, &lck);#endif fclose(file_stream);}static char *months[] ={ "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};/* * Take a months name and return a number between 1-12. * E.g. 'April' -> 4 */static int Cookies_get_month(const char *month_name)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -