INT64_T http_fetch_to_file(const char *url, const char *filename, time_t stoptime) { FILE *file; INT64_T size; INT64_T actual; struct link *link; file = fopen(filename, "w"); if(file) { link = http_query_size(url, "GET", &size, stoptime, 1); if(link) { actual = link_stream_to_file(link, file, size, stoptime); link_close(link); fclose(file); if(actual == size) { return actual; } else { unlink(filename); return -1; } } else { fclose(file); return -1; } } else { return -1; } }
INT64_T chirp_client_getfile(struct chirp_client * c, const char *path, FILE * stream, time_t stoptime) { INT64_T length; char safepath[CHIRP_LINE_MAX]; url_encode(path, safepath, sizeof(safepath)); length = simple_command(c, stoptime, "getfile %s\n", safepath); if(length >= 0) { if(link_stream_to_file(c->link, stream, length, stoptime) == length) { return length; } else { c->broken = 1; errno = ECONNRESET; } } return -1; }
static int auth_ticket_assert(struct link *link, time_t stoptime) { /* FIXME need to save errno ? */ char line[AUTH_LINE_MAX]; char **tickets = client_tickets; if(tickets) { char *ticket; char digest[DIGEST_LENGTH]; for (ticket = *tickets; ticket; ticket = *(++tickets)) { if (access(ticket, R_OK) == -1) { debug(D_AUTH, "could not access ticket %s: %s", ticket, strerror(errno)); continue; } /* load the digest */ /* WARNING: openssl is *very* bad at giving sensible output. Use the last * 32 non-space characters as the MD5 sum. */ char command[PATH_MAX * 2 + 4096]; sprintf(command, "openssl rsa -in '%s' -pubout 2> /dev/null | openssl md5 2> /dev/null | tr -d '[:space:]' | tail -c 32", ticket); FILE *digestf = popen(command, "r"); if(full_fread(digestf, digest, DIGEST_LENGTH) < DIGEST_LENGTH) { pclose(digestf); return 0; } pclose(digestf); debug(D_AUTH, "trying ticket %.*s", DIGEST_LENGTH, digest); if(link_putlstring(link, digest, DIGEST_LENGTH, stoptime) <= 0) return 0; if(link_putliteral(link, "\n", stoptime) <= 0) return 0; if(link_readline(link, line, sizeof(line), stoptime) <= 0) return 0; if(strcmp(line, "declined") == 0) continue; unsigned long length = strtoul(line, NULL, 10); if(errno == ERANGE || errno == EINVAL) return 0; /* not a number? */ debug(D_AUTH, "receiving challenge of %d bytes", length); FILE *in, *out; static const char command_template[] = "T1=`mktemp`\n" /* signed challenge */ "T2=`mktemp`\n" /* private key without comments */ "sed '/^\\s*#/d' < '%s' > \"$T2\"\n" "openssl rsautl -inkey \"$T2\" -sign > \"$T1\" 2> /dev/null\n" "R=\"$?\"\n" "if [ \"$R\" -ne 0 ]; then\n" " rm -f \"$T1\" \"$T2\"\n" " exit \"$R\"\n" "fi\n" "ls -l \"$T1\" | awk '{ print $5 }'\n" "cat \"$T1\"\n" "rm -f \"$T1\" \"$T2\"\n"; sprintf(command, command_template, ticket); pid_t pid = dpopen(command, &in, &out); if(pid == 0) return 0; if(link_stream_to_file(link, in, length, stoptime) <= 0) { dpclose(in, out, pid); debug(D_AUTH, "openssl failed, your keysize may be too small"); debug(D_AUTH, "please debug using \"dd if=/dev/urandom count=64 bs=1 | openssl rsautl -inkey <ticket file> -sign\""); return 0; } fclose(in); in = NULL; if(link_stream_from_file(link, out, 1 << 20, stoptime) <= 0) { dpclose(in, out, pid); debug(D_AUTH, "openssl failed, your keysize may be too small"); debug(D_AUTH, "please debug using \"dd if=/dev/urandom count=64 bs=1 | openssl rsautl -inkey <ticket file> -sign\""); return 0; } dpclose(in, out, pid); if(link_readline(link, line, sizeof(line), stoptime) <= 0) return 0; if(strcmp(line, "success") == 0) { debug(D_AUTH, "succeeded challenge for %.*s\n", DIGEST_LENGTH, digest); return 1; } else if(strcmp(line, "failure") == 0) { debug(D_AUTH, "failed challenge for %.*s\n", DIGEST_LENGTH, digest); errno = EINVAL; return 0; } else { debug(D_AUTH, "received bad response: '%s'", line); errno = EINVAL; return 0; } } } link_putliteral(link, "==\n", stoptime); return 0; }
static int auth_ticket_accept(struct link *link, char **subject, time_t stoptime) { int serrno = errno; int status = 0; char line[AUTH_LINE_MAX]; char ticket_subject[AUTH_LINE_MAX]; char *ticket = NULL; errno = 0; debug(D_AUTH, "ticket: waiting for tickets"); while(1) { if(link_readline(link, line, sizeof(line), stoptime) > 0) { if(strcmp(line, "==") == 0) { debug(D_AUTH, "ticket: exhausted all ticket challenges"); break; } else if(strlen(line) == DIGEST_LENGTH) { char ticket_digest[DIGEST_LENGTH + 1]; strcpy(ticket_digest, line); strcpy(ticket_subject, line); debug(D_AUTH, "ticket: read ticket digest: %s", ticket_digest); if(server_callback) { free(ticket); /* free previously allocated ticket string or NULL (noop) */ ticket = server_callback(ticket_digest); if(ticket) { static const char command_template[] = "T1=`mktemp`\n" /* The RSA Public Key */ "T2=`mktemp`\n" /* The Challenge */ "T3=`mktemp`\n" /* The Signed Challenge */ "T4=`mktemp`\n" /* The Decrypted (verified) Signed Challenge */ "echo -n '%s' > \"$T1\"\n" "dd if=/dev/urandom of=\"$T2\" bs=%u count=1 > /dev/null 2> /dev/null\n" "cat \"$T2\"\n" /* to stdout */ "cat > \"$T3\"\n" /* from stdin */ "openssl rsautl -inkey \"$T1\" -pubin -verify < \"$T3\" > \"$T4\" 2> /dev/null\n" "cmp \"$T2\" \"$T4\" > /dev/null 2> /dev/null\n" "R=\"$?\"\n" "rm -f \"$T1\" \"$T2\" \"$T3\" \"$T4\" > /dev/null 2> /dev/null\n" "exit \"$R\"\n"; char *command = xxmalloc(sizeof(command_template) + strlen(ticket) + 64); sprintf(command, command_template, ticket, CHALLENGE_LENGTH); FILE *in, *out; pid_t pid = dpopen(command, &in, &out); free(command); if(pid == 0) break; if(!link_putfstring(link, "%zu\n", stoptime, CHALLENGE_LENGTH)) break; if(!link_stream_from_file(link, out, CHALLENGE_LENGTH, stoptime)) break; if(link_readline(link, line, sizeof(line), stoptime) <= 0) break; unsigned long length = strtoul(line, NULL, 10); if(errno == ERANGE || errno == EINVAL) break; /* not a number? */ if(!link_stream_to_file(link, in, length, stoptime)) break; int result = dpclose(in, out, pid); if(result == 0) { debug(D_AUTH, "succeeded challenge for %s\n", ticket_digest); link_putliteral(link, "success\n", stoptime); status = 1; break; } else { debug(D_AUTH, "failed challenge for %s\n", ticket_digest); link_putliteral(link, "failure\n", stoptime); break; } } else { debug(D_AUTH, "declining key %s", ticket_digest); link_putliteral(link, "declined\n", stoptime); } } else { debug(D_AUTH, "declining key %s", ticket_digest); link_putliteral(link, "declined\n", stoptime); } } else { debug(D_AUTH, "ticket: bad response"); break; } } else { break; } } if(status) { *subject = xxmalloc(AUTH_LINE_MAX); strcpy(*subject, ticket_subject); } free(ticket); /* free previously allocated ticket string or NULL (noop) */ errno = serrno; return status; }