diff --git a/ChangeLog b/ChangeLog index 763b718..f76c742 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-08-19 Markus Gutschke + + * Added a ${url} parameter that can be used in the service description. + 2009-08-11 Markus Gutschke * Added support for user selectable style sheets. Included example diff --git a/config.h b/config.h index 895a918..16c487b 100644 --- a/config.h +++ b/config.h @@ -138,7 +138,7 @@ #define STDC_HEADERS 1 /* Most recent revision number in the version control system */ -#define VCS_REVISION "172" +#define VCS_REVISION "174" /* Version number of package */ #define VERSION "2.9" diff --git a/configure b/configure index b399573..ae4769f 100755 --- a/configure +++ b/configure @@ -2317,7 +2317,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -VCS_REVISION=172 +VCS_REVISION=174 cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index b803160..1cbaa0f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.57) dnl This is the one location where the authoritative version number is stored AC_INIT(shellinabox, 2.9, markus@shellinabox.com) -VCS_REVISION=172 +VCS_REVISION=174 AC_SUBST(VCS_REVISION) AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", [Most recent revision number in the version control system]) diff --git a/demo/vt100.js b/demo/vt100.js index 9f8cc89..f4bd7d0 100644 --- a/demo/vt100.js +++ b/demo/vt100.js @@ -1892,7 +1892,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.9 (revision 172)" + + alert("VT100 Terminal Emulator " + "2.9 (revision 174)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); }; diff --git a/shellinabox/launcher.c b/shellinabox/launcher.c index 26976fb..3bf3933 100644 --- a/shellinabox/launcher.c +++ b/shellinabox/launcher.c @@ -401,21 +401,27 @@ static int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, } #endif -int launchChild(int service, struct Session *session) { +int launchChild(int service, struct Session *session, const char *url) { if (launcher < 0) { errno = EINVAL; return -1; } - struct LaunchRequest request = { - .service = service, - .width = session->width, - .height = session->height }; - strncat(request.peerName, httpGetPeerName(session->http), - sizeof(request.peerName) - 1); - if (NOINTR(write(launcher, &request, sizeof(request))) != sizeof(request)) { + struct LaunchRequest *request; + size_t len = sizeof(struct LaunchRequest) + strlen(url) + 1; + check(request = calloc(len, 1)); + request->service = service; + request->width = session->width; + request->height = session->height; + strncat(request->peerName, httpGetPeerName(session->http), + sizeof(request->peerName) - 1); + request->urlLength = strlen(url); + memcpy(&request->url, url, request->urlLength); + if (NOINTR(write(launcher, request, len)) != len) { + free(request); return -1; } + free(request); pid_t pid; char cmsg_buf[CMSG_SPACE(sizeof(int))]; struct iovec iov = { 0 }; @@ -1023,7 +1029,8 @@ static void destroyVariableHashEntry(void *arg, char *key, char *value) { } static void execService(int width, int height, struct Service *service, - const char *peerName, char **environment) { + const char *peerName, char **environment, + const char *url) { // Create a hash table with all the variables that we can expand. This // includes all environment variables being passed to the child. HashMap *vars; @@ -1059,6 +1066,8 @@ static void execService(int width, int height, struct Service *service, addToHashMap(vars, key, value); check(key = strdup("uid")); addToHashMap(vars, key, stringPrintf(NULL, "%d", service->uid)); + check(key = strdup("url")); + addToHashMap(vars, key, strdup(url)); enum { ENV, ARGS } state = ENV; enum { NONE, SINGLE, DOUBLE @@ -1110,11 +1119,26 @@ static void execService(int width, int height, struct Service *service, if (ch) { end++; } + int incr = replLen - (end - ptr); + if (incr > 0) { + char *oldCmdline = cmdline; + check(cmdline = realloc(cmdline, + (end - cmdline) + strlen(end) + + incr + 1)); + ptr += cmdline - oldCmdline; + end += cmdline - oldCmdline; + if (key) { + key += cmdline - oldCmdline; + } + if (value) { + value += cmdline - oldCmdline; + } + } memmove(ptr + replLen, end, strlen(end) + 1); if (repl) { memcpy(ptr, repl, replLen); } - ptr += replLen; + ptr += replLen - 1; } break; case '\\': @@ -1168,7 +1192,7 @@ static void execService(int width, int height, struct Service *service, } else { // Add entry to argv. state = ARGS; - argv[argc++] = key; + argv[argc++] = strdup(key); check(argv = realloc(argv, (argc + 1)*sizeof(char *))); } } @@ -1183,6 +1207,7 @@ static void execService(int width, int height, struct Service *service, } } done: + free(cmdline); argv[argc] = NULL; deleteHashMap(vars); check(argc); @@ -1217,7 +1242,8 @@ void setWindowSize(int pty, int width, int height) { } static void childProcess(struct Service *service, int width, int height, - struct Utmp *utmp, const char *peerName) { + struct Utmp *utmp, const char *peerName, + const char *url) { // Set initial window size setWindowSize(0, width, height); @@ -1343,7 +1369,7 @@ static void childProcess(struct Service *service, int width, int height, execle("/usr/bin/login", "login", "-p", "-h", peerName, (void *)0, environment); } else { - execService(width, height, service, peerName, environment); + execService(width, height, service, peerName, environment, url); } _exit(1); } @@ -1363,6 +1389,9 @@ static void launcherDaemon(int fd) { errno = 0; int len = read(fd, &request, sizeof(request)); if (len != sizeof(request) && errno != EINTR) { + if (len) { + debug("Failed to read launch request"); + } break; } @@ -1381,6 +1410,26 @@ static void launcherDaemon(int fd) { continue; } + char *url; + check(url = calloc(request.urlLength + 1, 1)); + readURL: + len = read(fd, url, request.urlLength + 1); + if (len != request.urlLength + 1 && errno != EINTR) { + debug("Failed to read URL"); + free(url); + break; + } + while (NOINTR(pid = waitpid(-1, &status, WNOHANG)) > 0) { + if (WIFEXITED(pid) || WIFSIGNALED(pid)) { + char key[32]; + snprintf(&key[0], sizeof(key), "%d", pid); + deleteFromHashMap(childProcesses, key); + } + } + if (len != request.urlLength + 1) { + goto readURL; + } + check(request.service >= 0); check(request.service < numServices); @@ -1403,11 +1452,13 @@ static void launcherDaemon(int fd) { services[request.service]->useLogin, &utmp, request.peerName)) == 0) { childProcess(services[request.service], request.width, request.height, - utmp, request.peerName); + utmp, request.peerName, url); + free(url); _exit(1); } else { // Remember the utmp entry so that we can clean up when the child // terminates. + free(url); if (pid > 0) { if (!childProcesses) { childProcesses = newHashMap(destroyUtmpHashEntry, NULL); diff --git a/shellinabox/launcher.h b/shellinabox/launcher.h index fc5fc44..945bccc 100644 --- a/shellinabox/launcher.h +++ b/shellinabox/launcher.h @@ -55,10 +55,12 @@ struct LaunchRequest { int service; int width, height; char peerName[128]; + int urlLength; + char url[0]; }; int supportsPAM(void); -int launchChild(int service, struct Session *session); +int launchChild(int service, struct Session *session, const char *url); void setWindowSize(int pty, int width, int height); int forkLauncher(void); void terminateLauncher(void); diff --git a/shellinabox/shell_in_a_box.js b/shellinabox/shell_in_a_box.js index ab52210..f66323f 100644 --- a/shellinabox/shell_in_a_box.js +++ b/shellinabox/shell_in_a_box.js @@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) { }; ShellInABox.prototype.about = function() { - alert("Shell In A Box version " + "2.9 (revision 172)" + + alert("Shell In A Box version " + "2.9 (revision 174)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com" + (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ? diff --git a/shellinabox/shellinaboxd.c b/shellinabox/shellinaboxd.c index 350e313..027f03c 100644 --- a/shellinabox/shellinaboxd.c +++ b/shellinabox/shellinaboxd.c @@ -341,6 +341,7 @@ static int dataHandler(HttpConnection *http, struct Service *service, const char *width = getFromHashMap(args, "width"); const char *height = getFromHashMap(args, "height"); const char *keys = getFromHashMap(args, "keys"); + const char *rootURL = getFromHashMap(args, "rooturl"); // Adjust window dimensions if provided by client if (width && height) { @@ -362,7 +363,8 @@ static int dataHandler(HttpConnection *http, struct Service *service, goto bad_new_session; } session->http = http; - if (launchChild(service->id, session) < 0) { + if (launchChild(service->id, session, + rootURL && *rootURL ? rootURL : urlGetURL(url)) < 0) { abandonSession(session); httpSendReply(http, 500, "Internal Error", NO_MSG); return HTTP_DONE; @@ -809,7 +811,7 @@ static void parseArgs(int argc, char * const argv[]) { HashMap *serviceTable = newHashMap(destroyServiceHashEntry, NULL); extern char stylesStart[]; extern char stylesEnd[]; - check(cssStyleSheet = malloc(stylesEnd - stylesStart)); + check(cssStyleSheet = malloc(stylesEnd - stylesStart + 1)); memcpy(cssStyleSheet, stylesStart, stylesEnd - stylesStart); cssStyleSheet[stylesEnd - stylesStart] = '\000'; diff --git a/shellinabox/shellinaboxd.man.in b/shellinabox/shellinaboxd.man.in index 4dd43a8..7403447 100644 --- a/shellinabox/shellinaboxd.man.in +++ b/shellinabox/shellinaboxd.man.in @@ -403,6 +403,9 @@ name of remote peer. .B ${uid} numeric user id. .TP +.B ${url} +the URL that serves the terminal session. +.TP .B ${user} user name. .P diff --git a/shellinabox/vt100.js b/shellinabox/vt100.js index 9f8cc89..f4bd7d0 100644 --- a/shellinabox/vt100.js +++ b/shellinabox/vt100.js @@ -1892,7 +1892,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.9 (revision 172)" + + alert("VT100 Terminal Emulator " + "2.9 (revision 174)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); };