From 9bea9618424093c6d2cc93954f4cbdd0be4b7637 Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Fri, 29 Oct 2010 21:49:38 -0600 Subject: add uzbl-cookie-manager --- examples/uzbl-cookie-manager.c | 211 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 examples/uzbl-cookie-manager.c (limited to 'examples') diff --git a/examples/uzbl-cookie-manager.c b/examples/uzbl-cookie-manager.c new file mode 100644 index 0000000..b873aeb --- /dev/null +++ b/examples/uzbl-cookie-manager.c @@ -0,0 +1,211 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../src/util.h" + +extern const XDG_Var XDG[]; + +int verbose = 0; + +#define SOCK_BACKLOG 10 +#define MAX_COOKIE_LENGTH 4096 + +char cookie_buffer[MAX_COOKIE_LENGTH]; + +int setup_socket(const char *cookied_socket_path) { + int socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + + if(socket_fd < 0) { + fprintf(stderr, "socket failed (%s)\n", strerror(errno)); + return -1; + } + + struct sockaddr_un sa; + sa.sun_family = AF_UNIX; + strcpy(sa.sun_path, cookied_socket_path); + + if(bind(socket_fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) { + fprintf(stderr, "bind failed (%s)\n", strerror(errno)); + return -1; + } + + if(listen(socket_fd, SOCK_BACKLOG) < 0) { + fprintf(stderr, "listen failed (%s)\n", strerror(errno)); + return -1; + } + + return socket_fd; +} + +void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) { + const char *command = buff; + + const char *scheme = command + strlen(command) + 1; + if((scheme - buff) > len) { + fprintf(stderr, "got malformed or partial request\n"); + return; + } + + const char *host = scheme + strlen(scheme) + 1; + if((host - buff) > len) { + fprintf(stderr, "got malformed or partial request\n"); + return; + } + + const char *path = host + strlen(host) + 1; + if((path - buff) > len) { + fprintf(stderr, "got malformed or partial request\n"); + return; + } + + /* glue the parts back together into a SoupURI */ + char *u = g_strconcat(scheme, "://", host, path, NULL); + if(verbose) printf("%s %s\n", command, u); + SoupURI *uri = soup_uri_new(u); + g_free(u); + + if(!strcmp(command, "GET")) { + char *result = soup_cookie_jar_get_cookies(j, uri, TRUE); + if(result) { + if(verbose) puts(result); + if(write(fd, result, strlen(result)+1) < 0) + fprintf(stderr, "write failed (%s)", strerror(errno)); + + g_free(result); + } else { + if(verbose) puts("-"); + if(write(fd, "", 1) < 0) + fprintf(stderr, "write failed (%s)", strerror(errno)); + } + } else if(!strcmp(command, "PUT")) { + const char *name_and_val = path + strlen(path) + 1; + if((name_and_val - buff) > len) { + fprintf(stderr, "got malformed or partial request\n"); + return; + } + + if(verbose) puts(name_and_val); + + char *eql = strchr(name_and_val, '='); + eql[0] = 0; + + const char *name = name_and_val; + const char *value = eql + 1; + + SoupCookie *cookie = soup_cookie_new(name, value, host, path, SOUP_COOKIE_MAX_AGE_ONE_YEAR); + + soup_cookie_jar_add_cookie(j, cookie); + + if(write(fd, "", 1) < 0) + fprintf(stderr, "write failed (%s)", strerror(errno)); + } + + soup_uri_free(uri); +} + +void usage(const char *progname) { + printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-v]\n", progname); +} + +int main(int argc, char *argv[]) { + int i; + + const char *cookies_txt_path = NULL; + const char *cookied_socket_path = NULL; + + for(i = 1; i < argc && argv[i][0] == '-'; i++) { + switch(argv[i][1]) { + case 's': + cookied_socket_path = argv[++i]; + break; + case 'f': + cookies_txt_path = argv[++i]; + break; + case 'v': + verbose = 1; + break; + default: + usage(argv[0]); + return 1; + } + } + + if(!cookies_txt_path) + cookies_txt_path = find_xdg_file(1, "/uzbl/cookies.txt"); + + if(!cookied_socket_path) + cookied_socket_path = g_strconcat(get_xdg_var(XDG[2]), "/uzbl/cookie_daemon_socket", NULL); + + g_type_init(); + + SoupCookieJar *j = soup_cookie_jar_text_new(cookies_txt_path, FALSE); + + int cookie_socket = setup_socket(cookied_socket_path); + if(cookie_socket < 0) { + return 1; + } + + GArray *connections = g_array_new (FALSE, FALSE, sizeof (int)); + + while(1) { + unsigned int i; + int r; + fd_set fs; + + int maxfd = cookie_socket; + FD_ZERO(&fs); + FD_SET(maxfd, &fs); + + for(i = 0; i < connections->len; i++) { + int fd = g_array_index(connections, int, i); + if(fd > maxfd) maxfd = fd; + FD_SET(fd, &fs); + } + + r = select(maxfd+1, &fs, NULL, NULL, NULL); + if(r < 0) { + fprintf(stderr, "select failed (%s)\n", strerror(errno)); + continue; + } + + if(FD_ISSET(cookie_socket, &fs)) { + /* handle new connection */ + int fd = accept(cookie_socket, NULL, NULL); + g_array_append_val(connections, fd); + if(verbose) puts("got connection."); + } + + for(i = 0; i < connections->len; i++) { + /* handle activity on a connection */ + int fd = g_array_index(connections, int, i); + if(FD_ISSET(fd, &fs)) { + r = read(fd, cookie_buffer, MAX_COOKIE_LENGTH); + if(r < 0) { + fprintf(stderr, "read failed (%s)\n", strerror(errno)); + continue; + } else if(r == 0) { + if(verbose) puts("client hung up."); + g_array_remove_index(connections, i); + i--; /* other elements in the array are moved down to fill the gap */ + continue; + } + cookie_buffer[r] = 0; + + handle_request(j, cookie_buffer, r, fd); + } + } + } + + return 0; +} -- cgit v1.2.3 From b19783544927c6f27a9224f1287c6faaf4993c5d Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Fri, 5 Nov 2010 10:29:46 -0600 Subject: add optional whitelist --- examples/uzbl-cookie-manager.c | 140 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 9 deletions(-) (limited to 'examples') diff --git a/examples/uzbl-cookie-manager.c b/examples/uzbl-cookie-manager.c index b873aeb..7684fb3 100644 --- a/examples/uzbl-cookie-manager.c +++ b/examples/uzbl-cookie-manager.c @@ -1,6 +1,10 @@ +#define _POSIX_SOURCE + #include #include #include +#include +#include #include #include @@ -8,6 +12,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -48,6 +56,82 @@ int setup_socket(const char *cookied_socket_path) { return socket_fd; } +const char *whitelist_path = NULL; +GPtrArray *whitelisted_hosts = NULL; +time_t whitelist_update_time = 0; + +void whitelist_line_cb(const gchar* line, void *user_data) { + (void) user_data; + + gchar *norm_host; + + const gchar *p = line; + while(isspace(*p)) + p++; + + if(p[0] == '#' || !p[0]) /* ignore comments and blank lines */ + return; + + if(p[0] == '.') + norm_host = g_strdup(p); + else + norm_host = g_strconcat(".", p, NULL); + + g_ptr_array_add(whitelisted_hosts, g_strchomp(norm_host)); +} + +gboolean load_whitelist(const char *whitelist_path) { + if(!file_exists(whitelist_path)) + return FALSE; + + /* check if the whitelist file was updated */ + struct stat f; + if(stat(whitelist_path, &f) < 0) + return FALSE; + + if(whitelisted_hosts == NULL) + whitelisted_hosts = g_ptr_array_new(); + + if(f.st_mtime > whitelist_update_time) { + /* the file was updated, reload the whitelist */ + if(verbose) puts("reloading whitelist"); + while(whitelisted_hosts->len > 0) { + g_free(g_ptr_array_index(whitelisted_hosts, 0)); + g_ptr_array_remove_index_fast(whitelisted_hosts, 0); + } + for_each_line_in_file(whitelist_path, whitelist_line_cb, NULL); + whitelist_update_time = f.st_mtime; + } + + return TRUE; +} + +gboolean should_save_cookie(const char *host) { + if(!load_whitelist(whitelist_path)) + return TRUE; /* some error with the file, assume no whitelist */ + + /* we normalize the hostname so it has a . in front like the whitelist entries */ + gchar *test_host = (host[0] == '.') ? g_strdup(host) : g_strconcat(".", host, NULL); + int hl = strlen(test_host); + + /* test against each entry in the whitelist */ + gboolean result = FALSE; + guint i; + for(i = 0; i < whitelisted_hosts->len; i++) { + /* a match means the host ends with (or is equal to) the whitelist entry */ + const gchar *entry = g_ptr_array_index(whitelisted_hosts, i); + int el = strlen(entry); + result = (el <= hl) && !strcmp(test_host + (hl - el), entry); + + if(result) + break; + } + + g_free(test_host); + + return result; +} + void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) { const char *command = buff; @@ -97,15 +181,18 @@ void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) { if(verbose) puts(name_and_val); - char *eql = strchr(name_and_val, '='); - eql[0] = 0; + if(should_save_cookie(host)) { + char *eql = strchr(name_and_val, '='); + eql[0] = 0; - const char *name = name_and_val; - const char *value = eql + 1; + const char *name = name_and_val; + const char *value = eql + 1; - SoupCookie *cookie = soup_cookie_new(name, value, host, path, SOUP_COOKIE_MAX_AGE_ONE_YEAR); + SoupCookie *cookie = soup_cookie_new(name, value, host, path, SOUP_COOKIE_MAX_AGE_ONE_YEAR); - soup_cookie_jar_add_cookie(j, cookie); + soup_cookie_jar_add_cookie(j, cookie); + } else if(verbose) + puts("no, blacklisted."); if(write(fd, "", 1) < 0) fprintf(stderr, "write failed (%s)", strerror(errno)); @@ -118,11 +205,20 @@ void usage(const char *progname) { printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-v]\n", progname); } +const char *pid_file_path = NULL; +const char *cookied_socket_path = NULL; + +void cleanup_after_signal(int signal) { + (void) signal; + unlink(pid_file_path); + unlink(cookied_socket_path); + exit(0); +} + int main(int argc, char *argv[]) { int i; const char *cookies_txt_path = NULL; - const char *cookied_socket_path = NULL; for(i = 1; i < argc && argv[i][0] == '-'; i++) { switch(argv[i][1]) { @@ -132,6 +228,9 @@ int main(int argc, char *argv[]) { case 'f': cookies_txt_path = argv[++i]; break; + case 'w': + whitelist_path = argv[++i]; + break; case 'v': verbose = 1; break; @@ -142,17 +241,40 @@ int main(int argc, char *argv[]) { } if(!cookies_txt_path) - cookies_txt_path = find_xdg_file(1, "/uzbl/cookies.txt"); + cookies_txt_path = g_strconcat(get_xdg_var(XDG[1]), "/uzbl/cookies.txt", NULL); if(!cookied_socket_path) cookied_socket_path = g_strconcat(get_xdg_var(XDG[2]), "/uzbl/cookie_daemon_socket", NULL); + if(!whitelist_path) + whitelist_path = g_strconcat(get_xdg_var(XDG[0]), "/uzbl/cookie_whitelist", NULL); + + pid_file_path = g_strconcat(cookied_socket_path, ".pid", NULL); + int fd = open(pid_file_path, O_WRONLY|O_CREAT|O_EXCL, 0600); + if(fd < 0) { + if(errno == EEXIST) + fprintf(stderr, "pid file %s exists, exiting\n", pid_file_path); + else + fprintf(stderr, "couldn't open pid file %s (%s)\n", pid_file_path, strerror(errno)); + return 1; + } + + //grar grar grar + //fprintf(fd, "%d\n", getpid()); + close(fd); + g_type_init(); SoupCookieJar *j = soup_cookie_jar_text_new(cookies_txt_path, FALSE); int cookie_socket = setup_socket(cookied_socket_path); - if(cookie_socket < 0) { + if(cookie_socket < 0) + return 1; + + struct sigaction sa; + sa.sa_handler = cleanup_after_signal; + if(sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)) { + fprintf(stderr, "sigaction failed (%s)\n", strerror(errno)); return 1; } -- cgit v1.2.3 From 4c745b7b4f7020a32a08760dad2fab0b9249094e Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Sat, 13 Nov 2010 09:44:05 -0700 Subject: daemonise. --- examples/uzbl-cookie-manager.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/uzbl-cookie-manager.c b/examples/uzbl-cookie-manager.c index 7684fb3..16ca196 100644 --- a/examples/uzbl-cookie-manager.c +++ b/examples/uzbl-cookie-manager.c @@ -202,7 +202,26 @@ void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) { } void usage(const char *progname) { - printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-v]\n", progname); + printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-n] [-v]\n", progname); + puts("\t-n\tdon't daemonise the process"); + puts("\t-v\tbe verbose"); +} + +void daemonise() { + int r = fork(); + + if(r < 0) { + fprintf(stderr, "fork failed (%s)", strerror(errno)); + exit(1); + } else if (r > 0) { + /* this is the parent, which has done its job */ + exit(0); + } + + if(setsid() < 0) { + fprintf(stderr, "setsid failed (%s)", strerror(errno)); + exit(1); + } } const char *pid_file_path = NULL; @@ -219,6 +238,7 @@ int main(int argc, char *argv[]) { int i; const char *cookies_txt_path = NULL; + gboolean foreground = FALSE; for(i = 1; i < argc && argv[i][0] == '-'; i++) { switch(argv[i][1]) { @@ -231,6 +251,9 @@ int main(int argc, char *argv[]) { case 'w': whitelist_path = argv[++i]; break; + case 'n': + foreground = TRUE; + break; case 'v': verbose = 1; break; @@ -240,6 +263,12 @@ int main(int argc, char *argv[]) { } } + if(verbose) + foreground = TRUE; + + if(!foreground) + daemonise(); + if(!cookies_txt_path) cookies_txt_path = g_strconcat(get_xdg_var(XDG[1]), "/uzbl/cookies.txt", NULL); @@ -278,6 +307,13 @@ int main(int argc, char *argv[]) { return 1; } + if(!foreground) { + /* close STDIO */ + close(0); + close(1); + close(2); + } + GArray *connections = g_array_new (FALSE, FALSE, sizeof (int)); while(1) { -- cgit v1.2.3 From 94a7ef21e4036407fa800567766e20957e8d55ae Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Sat, 13 Nov 2010 10:23:37 -0700 Subject: lock the pid file to prevent multiple instances of uzbl-cookie-manager --- examples/uzbl-cookie-manager.c | 141 +++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 63 deletions(-) (limited to 'examples') diff --git a/examples/uzbl-cookie-manager.c b/examples/uzbl-cookie-manager.c index 16ca196..133a857 100644 --- a/examples/uzbl-cookie-manager.c +++ b/examples/uzbl-cookie-manager.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -32,6 +33,9 @@ int verbose = 0; char cookie_buffer[MAX_COOKIE_LENGTH]; int setup_socket(const char *cookied_socket_path) { + /* delete the cookie socket if it was left behind on a previous run */ + unlink(cookied_socket_path); + int socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); if(socket_fd < 0) { @@ -201,6 +205,60 @@ void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) { soup_uri_free(uri); } +void +wait_for_things_to_happen_and_then_do_things(SoupCookieJar* j, int cookie_socket) { + GArray *connections = g_array_new (FALSE, FALSE, sizeof (int)); + + while(1) { + unsigned int i; + int r; + fd_set fs; + + int maxfd = cookie_socket; + FD_ZERO(&fs); + FD_SET(maxfd, &fs); + + for(i = 0; i < connections->len; i++) { + int fd = g_array_index(connections, int, i); + if(fd > maxfd) maxfd = fd; + FD_SET(fd, &fs); + } + + r = select(maxfd+1, &fs, NULL, NULL, NULL); + if(r < 0) { + fprintf(stderr, "select failed (%s)\n", strerror(errno)); + continue; + } + + if(FD_ISSET(cookie_socket, &fs)) { + /* handle new connection */ + int fd = accept(cookie_socket, NULL, NULL); + g_array_append_val(connections, fd); + if(verbose) puts("got connection."); + } + + for(i = 0; i < connections->len; i++) { + /* handle activity on a connection */ + int fd = g_array_index(connections, int, i); + if(FD_ISSET(fd, &fs)) { + r = read(fd, cookie_buffer, MAX_COOKIE_LENGTH); + if(r < 0) { + fprintf(stderr, "read failed (%s)\n", strerror(errno)); + continue; + } else if(r == 0) { + if(verbose) puts("client hung up."); + g_array_remove_index(connections, i); + i--; /* other elements in the array are moved down to fill the gap */ + continue; + } + cookie_buffer[r] = 0; + + handle_request(j, cookie_buffer, r, fd); + } + } + } +} + void usage(const char *progname) { printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-n] [-v]\n", progname); puts("\t-n\tdon't daemonise the process"); @@ -278,27 +336,25 @@ int main(int argc, char *argv[]) { if(!whitelist_path) whitelist_path = g_strconcat(get_xdg_var(XDG[0]), "/uzbl/cookie_whitelist", NULL); + /* write out and lock the pid file. + * this ensures that only one uzbl-cookie-manager is running per-socket. + * (we should probably also lock the cookies.txt to prevent accidents...) */ pid_file_path = g_strconcat(cookied_socket_path, ".pid", NULL); - int fd = open(pid_file_path, O_WRONLY|O_CREAT|O_EXCL, 0600); - if(fd < 0) { - if(errno == EEXIST) - fprintf(stderr, "pid file %s exists, exiting\n", pid_file_path); - else - fprintf(stderr, "couldn't open pid file %s (%s)\n", pid_file_path, strerror(errno)); + int lockfd = open(pid_file_path, O_RDWR|O_CREAT, 0600); + if(lockfd < 0) { + fprintf(stderr, "couldn't open pid file %s (%s)\n", pid_file_path, strerror(errno)); return 1; } - //grar grar grar - //fprintf(fd, "%d\n", getpid()); - close(fd); - - g_type_init(); - - SoupCookieJar *j = soup_cookie_jar_text_new(cookies_txt_path, FALSE); - - int cookie_socket = setup_socket(cookied_socket_path); - if(cookie_socket < 0) + if(flock(lockfd, LOCK_EX|LOCK_NB) < 0) { + fprintf(stderr, "couldn't lock pid file %s (%s)\n", pid_file_path, strerror(errno)); + fprintf(stderr, "uzbl-cookie-manager is probably already running\n"); return 1; + } + + gchar* pids = g_strdup_printf("%d\n", getpid()); + write(lockfd, pids, strlen(pids)); + g_free(pids); struct sigaction sa; sa.sa_handler = cleanup_after_signal; @@ -314,56 +370,15 @@ int main(int argc, char *argv[]) { close(2); } - GArray *connections = g_array_new (FALSE, FALSE, sizeof (int)); - - while(1) { - unsigned int i; - int r; - fd_set fs; - - int maxfd = cookie_socket; - FD_ZERO(&fs); - FD_SET(maxfd, &fs); - - for(i = 0; i < connections->len; i++) { - int fd = g_array_index(connections, int, i); - if(fd > maxfd) maxfd = fd; - FD_SET(fd, &fs); - } - - r = select(maxfd+1, &fs, NULL, NULL, NULL); - if(r < 0) { - fprintf(stderr, "select failed (%s)\n", strerror(errno)); - continue; - } + g_type_init(); - if(FD_ISSET(cookie_socket, &fs)) { - /* handle new connection */ - int fd = accept(cookie_socket, NULL, NULL); - g_array_append_val(connections, fd); - if(verbose) puts("got connection."); - } + SoupCookieJar *j = soup_cookie_jar_text_new(cookies_txt_path, FALSE); - for(i = 0; i < connections->len; i++) { - /* handle activity on a connection */ - int fd = g_array_index(connections, int, i); - if(FD_ISSET(fd, &fs)) { - r = read(fd, cookie_buffer, MAX_COOKIE_LENGTH); - if(r < 0) { - fprintf(stderr, "read failed (%s)\n", strerror(errno)); - continue; - } else if(r == 0) { - if(verbose) puts("client hung up."); - g_array_remove_index(connections, i); - i--; /* other elements in the array are moved down to fill the gap */ - continue; - } - cookie_buffer[r] = 0; + int cookie_socket = setup_socket(cookied_socket_path); + if(cookie_socket < 0) + return 1; - handle_request(j, cookie_buffer, r, fd); - } - } - } + wait_for_things_to_happen_and_then_do_things(j, cookie_socket); return 0; } -- cgit v1.2.3