diff options
Diffstat (limited to 'src/pwgui')
-rw-r--r-- | src/pwgui/main.cpp | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/src/pwgui/main.cpp b/src/pwgui/main.cpp index 5dc2060..dc14006 100644 --- a/src/pwgui/main.cpp +++ b/src/pwgui/main.cpp @@ -14,6 +14,7 @@ #include <limits.h> #include <pwd.h> #include <grp.h> +#include <errno.h> #define NAMELEN 400 #define BUFLEN 1000 @@ -33,6 +34,7 @@ static bool helper_getpiduid(char *user, char *title); static bool helper_loadlpuser(); static void helper_dropprivs(); static void helper_copyenv(); +static char *helper_urlencode(char *s, char *enc); int main(int argc, char *argv[]) { @@ -182,11 +184,31 @@ int main(int argc, char *argv[]) static int run_backend(char *backend, char *uri, char *jobid, char *user, char *title, char *copies, char *options, char *file, char *password) { + int pipefd[2]; + pipe(pipefd); pid_t pid = fork(); if (pid == 0) { // Child + close(pipefd[0]); // close reading end + dup2(pipefd[1], 2); // send stderr to pipe + close(pipefd[1]); // no longer needed after dup + // Newer backend can read credentials from environment if (user != NULL) setenv("AUTH_USERNAME", user, 1); if (password != NULL) setenv("AUTH_PASSWORD", password, 1); + // For ipp14 (at least) we need to build a new URI with ://username:password@.... + if (user != NULL && password != NULL && strncmp(uri, "ipp14", 5) == 0) { + char *newstr = (char*)malloc(strlen(uri) + strlen(user) * 3 + strlen(password) * 3 + 20); + char *ptr = newstr; + ptr += sprintf(ptr, "ipp14://"); + ptr = helper_urlencode(user, ptr); + *ptr++ = ':'; + ptr = helper_urlencode(password, ptr); + *ptr++ = '@'; + ptr += sprintf(ptr, "%s", uri + 8); // TODO: If uri already contains credentials, skip over them (check if there's a @ before the first /, starting at index 8) + uri = newstr; + setenv("DEVICE_URI", uri, 1); + // Since we've already forked and execv anyways there's no need to clean up anything... + } char *args[8]; args[0] = uri; args[1] = jobid; @@ -206,12 +228,39 @@ static int run_backend(char *backend, char *uri, char *jobid, char *user, char * } // Main - wait for it... + close(pipefd[1]); // close writing end + char buffer[BUFLEN]; + bool needAuth = false; + int readlen = 0; + while ((readlen = read(pipefd[0], buffer, BUFLEN-1)) > 0) { + buffer[readlen] = '\0'; + if (strstr(buffer, "Unable to get printer status (Unauthorized)!") != NULL) { + needAuth = true; + if (kill(pid, SIGTERM) < 0) { + fprintf(stderr, "ERROR: Sending kill1 to backend %d failed: %d\n", (int)pid, errno); + } + break; + } + } + close(pipefd[0]); int status; - waitpid(pid, &status, 0); + if (waitpid(pid, &status, WNOHANG) == 0) { + if (kill(pid, SIGKILL) == 0) { + // Try to reap zombie + sleep(1); + waitpid(pid, &status, WNOHANG); + } + } + if (needAuth) { + fprintf(stderr, "ERROR: Killed backend because of 'unauthorized' message (iprint crap?), trying with auth\n"); + return CUPS_BACKEND_AUTH_REQUIRED; + } if (!WIFEXITED(status)) { fprintf(stderr, "ERROR: Running backend %s failed!\n", backend); return CUPS_BACKEND_FAILED; } + status = WEXITSTATUS(status); + if (status != CUPS_BACKEND_OK) fprintf(stderr, "ERROR: Backend returned %d\n", status); return WEXITSTATUS(status); } @@ -314,3 +363,29 @@ static void helper_copyenv() } } +/** + * Make sure enc is 3 times as large as s + */ +static char *helper_urlencode(char *source, char *enc) +{ + static char table[256] = {3}; + int len; + + if (table[0] == 3) { + int i; + for (i = 0; i < 256; i++) { + table[i] = (isalnum(i) || i == '~' || i == '-' || i == '.' || i == '_') ? i : 0; + } + } + + unsigned char *s = (unsigned char*)source; + for (; *s != '\0'; s++) { + if (table[*s] != '\0') len = sprintf(enc, "%c", table[*s]); + else len = sprintf(enc, "%%%02X", *s); + enc += len; + } + *enc = '\0'; + + return enc; +} + |