diff options
author | Marco Peereboom <marco@conformal.com> | 2010-12-28 18:53:06 +0000 |
---|---|---|
committer | Marco Peereboom <marco@conformal.com> | 2010-12-28 18:53:06 +0000 |
commit | 7c76d9a0ff916196752b07d8a0b66d0b561a6f0b (patch) | |
tree | d67dbd8804713c4f23e247e1ffe3f84ef0ecc061 | |
parent | f2af3adf713f7b6007b14439d492b4fc46e1faae (diff) | |
download | xombrero-7c76d9a0ff916196752b07d8a0b66d0b561a6f0b.tar.gz |
Add local socket option to open new tabs from the command line.
Mostly from Stevan Andjelkovic <stevan@student.chalmers.se> Debugging and some extra stuff by me.
-rw-r--r-- | xxxterm.1 | 14 | ||||
-rw-r--r-- | xxxterm.c | 153 | ||||
-rw-r--r-- | xxxterm.conf | 1 |
3 files changed, 164 insertions, 4 deletions
diff --git a/xxxterm.1 b/xxxterm.1 index c5351ea..9d71d65 100644 --- a/xxxterm.1 +++ b/xxxterm.1 @@ -25,6 +25,7 @@ .Bk -words .Op Fl STtV .Op Fl f Ar file +.Op Fl n Ar url .Op Ar uri ... .Ek .Sh DESCRIPTION @@ -74,6 +75,10 @@ Disable the toolbar. Disable visualization of tabs. .It Fl t Disable tabs. +.It Fl n Ar url +Open a new tab in a running +.Nm . +This option requires enable_socket to be enabled. .It Fl V Display version and exit. .El @@ -173,6 +178,15 @@ If ssl_ca_file is not set then the URL bar will color all https connections red. .It Cm ssl_strict_certs If this value is set connections to untrusted sites will be aborted. This value is only used if ssl_ca_file is set. +.It Cm enable_socket +When enabled the first instance of +.Nm +will create a socket in the ~/.xxxterm directory. +Using the -n url option on subsequent +.Nm +invocations will cause the specified url to be loaded in a new tab. +.Pp +Only a user with identical UID and GID can use this option. .El .Pp .Nm diff --git a/xxxterm.c b/xxxterm.c index 4fed443..fbf3f67 100644 --- a/xxxterm.c +++ b/xxxterm.c @@ -47,6 +47,8 @@ #include <sys/queue.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> @@ -212,6 +214,7 @@ struct karg { #define XT_CONF_FILE ("xxxterm.conf") #define XT_FAVS_FILE ("favorites") #define XT_SAVED_TABS_FILE ("saved_tabs") +#define XT_SOCKET_FILE ("socket") #define XT_CB_HANDLED (TRUE) #define XT_CB_PASSTHROUGH (FALSE) #define XT_DOCTYPE "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>" @@ -222,6 +225,8 @@ struct karg { "th {background-color: #cccccc}" \ "table {width: 90%%; border: 1px black" \ " solid; table-layout: fixed}\n</style>\n\n" +#define XT_MAX_URL_LENGTH (4096) /* 1 page is atomic, don't make bigger */ + /* file sizes */ #define SZ_KB ((uint64_t) 1024) #define SZ_MB (SZ_KB * SZ_KB) @@ -365,6 +370,7 @@ time_t session_timeout = 3600; /* cookie session timeout */ int cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY; char *ssl_ca_file = NULL; gboolean ssl_strict_certs = FALSE; +int enable_socket = 1; int append_next = 1; /* append tab after current tab */ /* @@ -853,7 +859,9 @@ config_parse(char *filename) "%s/%s", pwd->pw_dir, &val[1]); else strlcpy(download_dir, val, sizeof download_dir); - } else + } else if (!strcmp(var, "enable_socket")) + enable_socket = atoi(val); + else errx(1, "invalid conf file entry: %s=%s", var, val); free(line); @@ -4041,11 +4049,141 @@ setup_proxy(char *uri) } } +int +send_url_to_socket(char *url) +{ + int s, len, rv = -1; + struct sockaddr_un sa; + + pwd = getpwuid(getuid()); + if (pwd == NULL) + errx(1, "invalid user %d", getuid()); + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + warnx("send_url_to_socket: socket"); + return (-1); + } + + sa.sun_family = AF_UNIX; + + snprintf(sa.sun_path, sizeof(sa.sun_path), "%s/%s/%s", + pwd->pw_dir, XT_DIR, XT_SOCKET_FILE); + + len = SUN_LEN(&sa); + + if (connect(s, (struct sockaddr *)&sa, len) == -1) { + warnx("send_url_to_socket: connect"); + goto done; + } + + if (send(s, url, strlen(url) + 1, 0) == -1) { + warnx("send_url_to_socket: send"); + goto done; + } +done: + close(s); + return (rv); +} + +void +socket_watcher(gpointer data, gint fd, GdkInputCondition cond) +{ + int s, n; + char str[XT_MAX_URL_LENGTH]; + socklen_t t = sizeof(struct sockaddr_un); + struct sockaddr_un sa; + struct passwd *p; +#ifdef __linux__ + struct ucred cr; + size_t len; +#else + uid_t uid; + gid_t gid; +#endif + if ((s = accept(fd, (struct sockaddr *)&sa, &t)) == -1) { + warn("socket_watcher: accept"); + return; + } + +#ifdef __linux__ + len = sizeof(struct ucred); + if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &len) < 0) { + warnx("socket_watcher: getsockopt"); + return; + } + + if (cr.uid != getuid() || cr.gid != getgid()) { + warnx("socket_watcher: cr check"); + return; + } +#else + if (getpeereid(s, &uid, &gid) == -1) { + warn("socket_watcher: getpeereid"); + return; + } + if (uid != getuid() || gid != getgid()) { + warnx("socket_watcher: unauthorized user"); + return; + } +#endif + + p = getpwuid(uid); + if (p == NULL) { + warnx("socket_watcher: not a valid user"); + return; + } + + n = recv(s, str, sizeof(str), 0); + if (n <= 0) + return; + + create_new_tab(str, 1); +} + +int +build_socket(void) +{ + int s, len; + struct sockaddr_un sa; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + warn("build_socket: socket"); + return (-1); + } + + sa.sun_family = AF_UNIX; + snprintf(sa.sun_path, sizeof(sa.sun_path), "%s/%s/%s", + pwd->pw_dir, XT_DIR, XT_SOCKET_FILE); + len = SUN_LEN(&sa); + + /* connect to see if there is a listener */ + if (connect(s, (struct sockaddr *)&sa, len) == -1) { + /* no listener so we will */ + unlink(sa.sun_path); + + if (bind(s, (struct sockaddr *)&sa, len) == -1) { + warn("build_socket: bind"); + goto done; + } + + if (listen(s, 1) == -1) { + warn("build_socket: listen"); + goto done; + } + + return (s); + } + +done: + close(s); + return (-1); +} + void usage(void) { fprintf(stderr, - "%s [-STVt][-f file] url ...\n", __progname); + "%s [-STVt][-f file][-n url] url ...\n", __progname); exit(0); } @@ -4053,13 +4191,13 @@ int main(int argc, char *argv[]) { struct stat sb; - int c, focus = 1; + int c, focus = 1, s; char conf[PATH_MAX] = { '\0' }; char file[PATH_MAX]; char *env_proxy = NULL; FILE *f = NULL; - while ((c = getopt(argc, argv, "STVf:t")) != -1) { + while ((c = getopt(argc, argv, "STVf:tn:")) != -1) { switch (c) { case 'S': showurl = 0; @@ -4076,6 +4214,9 @@ main(int argc, char *argv[]) case 't': tabless = 1; break; + case 'n': + send_url_to_socket(optarg); + exit(0); default: usage(); /* NOTREACHED */ @@ -4190,6 +4331,10 @@ main(int argc, char *argv[]) if (focus == 1) create_new_tab(home, 1); + if (enable_socket) + if ((s = build_socket()) != -1) + gdk_input_add(s, GDK_INPUT_READ, socket_watcher, NULL); + gtk_main(); return (0); diff --git a/xxxterm.conf b/xxxterm.conf index c5631fb..c8c62d9 100644 --- a/xxxterm.conf +++ b/xxxterm.conf @@ -15,6 +15,7 @@ session_timeout = 3600 enable_cookie_whitelist = 1 # ssl_ca_file = /etc/ssl/cert.pem ssl_strict_certs = 0 +enable_socket = 0 # only useful if enable_scripts = 0 enable_js_whitelist = 1 |