summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/pwgui/main.cpp77
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;
+}
+