//Default passphrase max size
#define DEFAULT_PASSPHRASE_SIZE_MAX 512
//Default keyfile max size
//XXX: file should be maximum 8192*1024-1 character long
#define DEFAULT_KEYFILE_SIZE_MAX (8192 * 1024)
//Default crypttab
#define CRYPTTAB "/etc/crypttab"
//Default cryptsetup
#define CRYPTSETUP "/sbin/cryptsetup"
//Default pid file
#define IHTTPDPID "/run/ihttpd/ihttpd.pid"
//Default systemd ask-password dir
#define ASKPASSWORDDIR "/run/systemd/ask-password"
//Define child log
#define ASKPASSWORDLOG "/run/ihttpd/log/child.askpassword.log"
#define IHTTPDLOG "/run/ihttpd/log/child.ihttpd.log"
//Create struct for http error status
struct httpStatusStruct {
int value;
char *description;
};
//Declare http error status array
const struct httpStatusStruct httpStatuses[] = {
{200, "OK"},
{400, "Bad Request"},
{405, "Method Not Allowed"},
{411, "Length Required"},
{500, "Internal Server Error"}
};
/**
* Prototype
*/
void die(const int, const char*);
void header(const int, const char*);
void showForm(const char*, const int, const int);
int extractValue(char**, int*, char*, int);
int extractLuksDevice(char**, char**);
int extractIHttpdPid(pid_t *);
int extractAskPasswordPid(pid_t *);
/**
* Die with error
*/
void die(const int code, const char *err) {
//TODO: see if we add a nice text/html template ?
//Send content as text
header(code, "text/plain");
//Print error line if available
if (err != NULL)
printf("%s", err);
//Flush all
if (fflush(NULL) == -1) {
perror("fflush");
}
//Exit with failure code
exit(EXIT_FAILURE);
}
/**
* Send header
*/
void header(const int code, const char *ctype) {
int k;
switch(code) {
case 400:
k = 1;
break;
case 405:
k = 2;
break;
case 411:
k = 3;
break;
case 500:
k = 4;
break;
default:
k = 0;
}
//Send http status
printf("Status: %d %s\r\n", httpStatuses[k].value, httpStatuses[k].description);
//Make sure no cache
printf("Cache-Control: no-cache, no-store, must-revalidate\r\n");
printf("Pragma: no-cache\r\n");
printf("Expires: 0\r\n");
printf("X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noodp\r\n");
printf("Content-type: %s\r\n\r\n", ctype);
}
/**
* Show form
*/
void showForm(const char *requestUri, const int keyfileSizeMax, const int passphraseSizeMax) {
header(200, "text/html");
printf("\r\n");
printf("\r\n");
printf("Key upload form\r\n");
printf("\r\n");
printf("\r\n");
printf("\r\n", requestUri, keyfileSizeMax);
printf("\r\n", requestUri, passphraseSizeMax);
printf("
\r\n");
printf("\r\n");
printf("\r\n");
}
/**
* Extract value
*/
int extractValue(char **value, int *valueLength, char *contentType, int contentLength) {
//Handle application/x-www-form-urlencoded request
if (contentType != NULL && !strncmp(contentType, "application/x-www-form-urlencoded", 33)) {
//Indexes and return
int i, k, v, r;
//Declare key and buf
char *key, *buf;
//Allocate key
if ((key = malloc(4*sizeof(char))) == NULL) {
//Unable to allocate key
return -1;
}
//Allocate buf to maximum possible value size + 1 for trailing \0
if ((buf = calloc(1, (DEFAULT_PASSPHRASE_SIZE_MAX+1)*sizeof(char))) == NULL) {
//Unable to allocate value
free(key);
return -2;
}
//Char buffer
char d = '\0';
//Char delimiter
//XXX: initialised as & for new key, becomes = when fetching value
char delim = '&';
for (i = 0, k = 0, v = 0; i < contentLength; i++) {
//Safeguard against a value greater than DEFAULT_PASSPHRASE_SIZE_MAX
//XXX: this should never happen because we should be protected by contentLength already
if (v == DEFAULT_PASSPHRASE_SIZE_MAX+1) {
//Invalid value
free(key);
free(buf);
return -3;
}
//Read one character from stdin
r = read(STDIN_FILENO, &d, 1);
//Handle errors
if (r < 0) {
//Error while parsing post data
free(key);
free(buf);
return -4;
} else if (r == 0) {
//Partial receive
free(key);
free(buf);
return -5;
}
//Handle case where key has an other name
if (i == 3) {
//Check key is "key" and we get '=' as new char and assign delim to =
if (strncmp(key, "key", 3) || (delim = d) != '=') {
//Invalid key
free(key);
free(buf);
return -6;
}
//Handle key or value separator in query string
} else if (d == '&' || d == '=') {
//Invalid query string
free(key);
free(buf);
return -7;
//Handle a value
} else {
//Save key char
if (delim == '&') {
key[k] = d;
k++;
//Save buf char
} else {
buf[v] = d;
v++;
}
}
}
//Free key
free(key);
//Unescape and reduce value if not empty
if (v > 0) {
//Declare iterators
int l,m, s = v;
//Loop on value and reduce length on the fly
for(l=0,m=0; m < v; l++,m++) {
//Replace + with space
if (buf[m] == '+') {
buf[l] = ' ';
//Skip partial present %XX
} else if (
//Assign char
(buf[l] = buf[m]) == '%' &&
//Check we didn't reach valueStrLength
(m+2 < v) &&
//Check next two digits are valid
((buf[m+1] >= 'A' && buf[m+1] <= 'F') || (buf[m+1] >= 'a' && buf[m+1] <= 'f') || (buf[m+1] >= '0' && buf[m+1] <= '9')) &&
((buf[m+2] >= 'A' && buf[m+2] <= 'F') || (buf[m+2] >= 'a' && buf[m+2] <= 'f') || (buf[m+2] >= '0' && buf[m+2] <= '9'))
) {
buf[l] = (buf[m+1] >= 'A' ? (buf[m+1] & 0xdf) - 'A' + 10 : buf[m+1] - '0') * 16 + (buf[m+2] >= 'A' ? (buf[m+2] & 0xdf) - 'A' + 10 : buf[m+2] - '0');
m += 2;
s -= 2;
}
}
//Set value length
*valueLength = s;
//Alloc value
if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) {
//Unable to alloc value
free(key);
free(buf);
return -8;
}
//Copy value
memcpy(*value, buf, *valueLength);
}
//Free buf
free(buf);
//Handle multipart/form-data request
} else if (contentType != NULL && !strncmp(contentType, "multipart/form-data", 19)) {
//Indexes and return
int b, s, r;
//Boundary length
int boundaryLength = strlen(contentType) - 30 + 1;
//Client send LF ending without CR
int lfstyle = 0;
//Declare boundary
char *boundary;
//Allocate boundary
if ((boundary = calloc(1, boundaryLength*sizeof(char))) == NULL) {
//Unable to allocate boundary
return -9;
}
//Extract boundary
memcpy(boundary, contentType + 30, boundaryLength - 1);
//Declare buffers
char *start, *buf;
//Allocate buffer
if ((buf = malloc(contentLength*sizeof(char))) == NULL) {
//Unable to allocate buffer
free(boundary);
return -10;
}
//Char buffer
char d = '\0';
//Loop
for (b = 0, s = 0; b < contentLength; b++) {
//Detect possible boundary
//XXX: b is boundaryLength-1 + 2 after s
//XXX: d will be a CR(CRLF line ending) or LF(LF line ending) or -(of final --)
if (b == s + 2 + boundaryLength - 1 && !strncmp(boundary, buf + b - boundaryLength + 1, boundaryLength - 1)) {
//Only after first boundary match
if (s > 0) {
//Trim line jump
if (start[0] == '\r' && start[1] == '\n') {
start += 2;
lfstyle = 1;
} else if (start[0] == '\n') {
start++;
}
//Found flag
bool found = false;
//Allocate pointers
char *new = start, *prev = start, *name = NULL;
//Search for a new line
while ((new = memchr(new, '\n', b - (new - buf)))) {
//Jump to first character after new line
new++;
//Init line length
int lineLength = new - prev - 1;
//Remove chariage return if necessary
if (prev[lineLength] == '\r') {
lineLength--;
lfstyle = 1;
}
//Break loop after headers end
if (lineLength == 1) {
break;
}
//Allocate a name buf of maximum line length
//XXX: need to be filled with zero as we don't know what will comes with sscanf call and we rely on strlen
if ((name = calloc(1, lineLength*sizeof(char))) == NULL) {
//Unable to allocate name
free(boundary);
free(buf);
return -11;
}
//Search for name
if (sscanf(prev, "Content-Disposition: form-data; name=\"%[^\"]\"", name)) {
//Realloc name
if ((name = realloc(name, (strlen(name)+1)*sizeof(char))) == NULL) {
//Unable to reduce name
free(boundary);
free(buf);
free(name);
return -12;
}
if (!strncmp(name, "key", 3)) {
found = true;
}
}
//Free name
free(name);
//Jump to next one
prev = new;
}
//Init value if found
if (found) {
//Declare end
char *end = buf + b - boundaryLength - 3;
//Remove CR at end if provided
//XXX: only remove CR at end if we encountered one before
if (lfstyle) {
end++;
}
//On too big keyfile
if (end - new - 1 >= DEFAULT_KEYFILE_SIZE_MAX) {
//Keyfile too large
free(boundary);
free(buf);
return -13;
}
//On non empty value
if (end - new > 1) {
//Set value length
*valueLength = end - new - 1;
//Allocate value
if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) {
//Unable to allocate value
free(boundary);
free(buf);
return -14;
}
//Copy value
memcpy(*value, new, *valueLength);
}
}
}
//Set start to matched boundary
start = buf + b;
}
//Read one character from stdin
r = read(STDIN_FILENO, &d, 1);
//Handle errors
if (r < 0) {
//Error while parsing post data
free(boundary);
free(buf);
return -15;
} else if (r == 0) {
//Partial receive
free(boundary);
free(buf);
return -16;
}
//New line case
if (d == '\n') {
//Store new possible boundary start
s = b + 1;
}
buf[b] = d;
}
//Free buffers
free(boundary);
free(buf);
//Unhandled request
} else {
return -17;
}
//Send value
return 0;
}
/**
* Extract luks and device
*/
int extractLuksDevice(char **luks, char **device) {
//Declare file descriptor
int fd, bufLength;
//Declare buf, device and luks pointer
char *buf, *d, *l;
//Declare stat struct
struct stat *stats;
//Open file
if ((fd = open(CRYPTTAB, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) {
//Can't open crypttab file
return -1;
}
//Allocate stats
if ((stats = calloc(1, sizeof(struct stat))) == NULL) {
//Unable to allocate stats
return -2;
}
//Stat file
if (fstat(fd, stats) == -1) {
//Can't stat crypttab
return -3;
}
//Check file size
if ((bufLength = stats->st_size) > SSIZE_MAX) {
//Crypttab too big
return -4;
}
//Allocate buf
if ((buf = malloc(bufLength*sizeof(char))) == NULL) {
//Unable to allocate buf
return -5;
}
//Read file
if ((read(fd, buf, bufLength)) < bufLength) {
//Fail to read crypttab file
return -6;
}
//Close file
close(fd);
//Free stats buffer
free(stats);
//Search first separator (\s|\t) after luks
if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL) {
return -7;
}
//Jump to next char
l++;
//Search first separator (\s|\t) after device
if ((d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, '\n', bufLength - (l - buf))) == NULL) {
return -8;
}
//Jump to next char
d++;
//Alloc luks
if ((*luks = malloc((l - buf - 1)*sizeof(char))) == NULL) {
return -9;
}
//Allocate device
if ((*device = malloc((d - l - 1)*sizeof(char))) == NULL) {
//Free and reset luks
free(luks);
luks=NULL;
return -10;
}
//Copy luks
memcpy(*luks, buf, l - buf - 1);
//Terminate luks
(*luks)[l - buf - 1] = '\0';
//Copy device
memcpy(*device, l, d - l - 1);
//Terminate device
(*device)[d - l - 1] = '\0';
//Free buffer
free(buf);
//Success
return 0;
}
/**
* Extract ask-password pid
*/
int extractAskPasswordPid(pid_t *pid) {
//Declare stuct dirent
struct dirent *entry;
//Declare askdir
DIR *askdir;
//Declare found
int found = 0;
//Allocate dirent struct
if ((entry = calloc(1, sizeof(struct dirent))) == NULL) {
//Unable to allocate entry
return -1;
}
//Open systemd ask-password dir
if ((askdir = opendir(ASKPASSWORDDIR)) == NULL) {
//Can't open ask dir
return -2;
}
//Change dir
if (chdir(ASKPASSWORDDIR) == -1) {
//Can't change to ask dir
return -3;
}
//Loop on dir content
while((entry = readdir(askdir))) {
//Handle each ask.XXXXXX file
if (!strncmp(entry->d_name, "ask.", 4) && strlen(entry->d_name) == 10) {
//Declare file descriptor
int fd, bufLength;
//Declare buf
char *buf;
//Declare stat struct
struct stat *stats;
//Open file
if ((fd = open(entry->d_name, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) {
//Can't open ask file
return -4;
}
//Allocate stats
if ((stats = calloc(1, sizeof(struct stat))) == NULL) {
//Unable to allocate stats
return -5;
}
//Stat file
if (fstat(fd, stats) == -1) {
//Can't stat ask file
return -6;
}
//Check file size
if ((bufLength = stats->st_size) > SSIZE_MAX) {
//Ask file too big
return -7;
}
//Allocate buf
if ((buf = malloc(bufLength*sizeof(char))) == NULL) {
//Unable to allocate buf
return -8;
}
//Read file
if ((read(fd, buf, bufLength)) < bufLength) {
//Fail to read ask file
return -9;
}
//Close file
close(fd);
//Free stats buffer
free(stats);
//Allocate pointers
char *nl = buf, *pl = buf, *e;
//Allocate pid
*pid = 0;
//Search for a new line
while ((nl = memmem(nl, bufLength - (nl - buf), "\n", strlen("\n")))) {
//Jump to next char
nl++;
//Check if we have a = in line but not empty value ("=\n")
if ((e = memmem(pl, bufLength - (pl - buf), "=", strlen("="))) && e < nl - 2) {
//Jump to next char
e++;
//Look for PID
if (!strncmp(pl, "PID", 3)) {
//Declade pid string
char *pidStr;
//Allocate pid string
if ((pidStr = malloc((nl - e)*sizeof(char))) == NULL) {
//Unable to allocate pid string
return -10;
}
//Copy pid
memcpy(pidStr, e, nl - e - 1);
//Terminate pid string
pidStr[nl - e] = '\0';
//Check pid value
if ((*pid = atoi(pidStr)) <= 1) {
//Invalid pid
return -11;
}
//Free pid string
free(pidStr);
//Found a valid process
found++;
}
}
//Jump prev line to new line
pl = nl;
}
//Free buffers
free(buf);
}
}
//Close systemd ask-password dir
if (closedir(askdir) == -1) {
//Can't close ask dir
return -13;
}
//Free entry
free(entry);
//Found no valid pid
if (found == 0) {
//No pid found
return -14;
//Found more than one pid
} else if (found > 1) {
//No pid found
return -15;
}
//Success
return 0;
}
/**
* Extract ihttpd pid
*/
int extractIHttpdPid(pid_t *pid) {
//Declare file descriptor
int fd, bufLength;
//Declare buf, device and luks pointer
char *buf, *l, *pidStr;
//Declare stat struct
struct stat *stats;
//Open file
if ((fd = open(IHTTPDPID, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) {
//Can't open crypttab file
return -1;
}
//Allocate stats
if ((stats = calloc(1, sizeof(struct stat))) == NULL) {
//Unable to allocate stats
return -2;
}
//Stat file
if (fstat(fd, stats) == -1) {
//Can't stat crypttab
return -3;
}
//Check file size
if ((bufLength = stats->st_size) > SSIZE_MAX) {
//Crypttab too big
return -4;
}
//Allocate buf
if ((buf = malloc(bufLength*sizeof(char))) == NULL) {
//Unable to allocate buf
return -5;
}
//Read file
if ((read(fd, buf, bufLength)) < bufLength) {
//Fail to read crypttab file
return -6;
}
//Close file
close(fd);
//Free stats buffer
free(stats);
//Search first separator (\s|\t|\n) after pid
if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, '\n', bufLength)) == NULL) {
return -7;
}
//Jump to next char
l++;
//Alloc pid string
if ((pidStr = malloc((l - buf - 1)*sizeof(char))) == NULL) {
return -9;
}
//Copy luks
memcpy(pidStr, buf, l - buf - 1);
//Terminate luks
pidStr[l - buf - 1] = '\0';
//Free buffer
free(buf);
//Store pid
if ((*pid = atoi(pidStr)) <= 1) {
//Invalid pid
return -10;
}
//Free pid string
free(pidStr);
//Success
return 0;
}
/**
* Main function
*/
int main(int argc, char **argv) {
//Get request method
char *requestMethod = getenv("REQUEST_METHOD");
//Handle unknown requests
if (requestMethod == NULL || (strncmp(requestMethod, "GET", 3) && strncmp(requestMethod, "HEAD", 4) && strncmp(requestMethod, "POST", 4))) {
//Send method not allowed
die(405, "Unsupported request method");
//Handle get and head
} else if (!strncmp(requestMethod, "GET", 3) || !strncmp(requestMethod, "HEAD", 4)) {
//Send form
showForm(getenv("REQUEST_URI")?getenv("REQUEST_URI"):"/", DEFAULT_KEYFILE_SIZE_MAX, DEFAULT_PASSPHRASE_SIZE_MAX);
//Handle post
} else /*if (!strncmp(requestMethod, "POST", 4))*/ {
//Return value
int ret;
//Child pid
pid_t pid;
//Value length
//XXX: will contain number of char in value without trailing \0
int valueLength;
//Value string
//XXX: will contain value without a tailing \0
char *value = NULL;
//Content length
int contentLength;
//Content length string from env
char *contentLengthStr = getenv("CONTENT_LENGTH");
//Content type
char *contentType = getenv("CONTENT_TYPE");
//Declare luks and device
char *luks = NULL, *device = NULL;
//Pairs of pipe for stdin, stdout and stderr
int inPipe[2], errPipe[2];
//Handle unknown content type
if (contentType == NULL || (strncmp(contentType, "application/x-www-form-urlencoded", 33) && strncmp(contentType, "multipart/form-data", 19))) {
die(400, "Unknown content type");
}
//Handle invalid multipart/form-data content type
//XXX: max boundary length is 70 as per rfc1521 & rfc2046
if (!strncmp(contentType, "multipart/form-data", 19) && (strncmp(contentType, "multipart/form-data; boundary=", 30) || strlen(contentType) <= 30 || strlen(contentType) > 100)) {
die(400, "Malformed boundary in multipart/form-data request");
}
//Handle invalid content length
//XXX: deny empty contentLength as chrome send a contentLength even for a device
if (contentLengthStr == NULL || (contentLength = atoi(contentLengthStr)) <= 0) {
die(411, "Invalid content length");
}
//Handle application/x-www-form-urlencoded request length
//XXX: limit to key=xyz where xyz can be all encoded in %XX
if (!strncmp(contentType, "application/x-www-form-urlencoded", 33) && contentLength > (DEFAULT_PASSPHRASE_SIZE_MAX * 3 + 4)) {
die(400, "Invalid application/x-www-form-urlencoded request length");
}
//Handle multipart/form-data request length
//XXX: limit to arbitrary 3 times the keyfile max size
if (!strncmp(contentType, "multipart/form-data", 19) && contentLength > (DEFAULT_KEYFILE_SIZE_MAX * 3)) {
die(400, "Invalid multipart/form-data request length");
}
//Extract value
if ((ret = extractValue(&value, &valueLength, contentType, contentLength)) < 0) {
die(500, "Failed to extract value");
}
//Extract luks and device
if ((ret = extractLuksDevice(&luks, &device)) < 0) {
die(500, "Failed to extract luks and device");
}
//Create stdin pipe
if (pipe(inPipe) == -1) {
die(500, "Failed to create in pipe");
}
//Create stderr pipe
if (pipe(errPipe) == -1) {
die(500, "Failed to create err pipe");
}
//Fork process
if ((pid = fork()) == -1) {
die(500, "Failed to fork");
}
//Child process
if (pid == 0) {
//Child argv
char *cargv[] = { CRYPTSETUP, "-d", "-", "luksOpen", device, luks, NULL };
char *carge[] = { NULL };
//Free value
free(value);
//Redirect stdin to pipe
if (dup2(inPipe[0], STDIN_FILENO) == -1) {
die(500, "Failed to redirect in pipe");
}
//Close inPipe
close(inPipe[0]);
close(inPipe[1]);
//Redirect stderr to pipe
if (dup2(errPipe[1], STDERR_FILENO) == -1) {
die(500, "Failed to redirect err pipe");
}
//Close errPipe
close(errPipe[0]);
close(errPipe[1]);
//Call cryptsetup
if (execve(CRYPTSETUP, cargv, carge) == -1) {
die(500, "Failed to call cryptsetup");
}
//Parent process
} else {
//Free luks
free(luks);
//Free device
free(device);
//Close unused inPipe end
close(inPipe[0]);
//Close unused errPipe end
close(errPipe[1]);
//Send password on stdin anyway
//XXX: this fail if device is already unlocked for example
write(inPipe[1], value, valueLength);
//Free value
free(value);
//Close stdin with EOF
close(inPipe[1]);
//Wait child
if (waitpid(pid, &ret, 0) == -1) {
die(500, "Failed to wait child");
}
//Handle already unlocked device
if (ret == 1280) {
die(200, "Device already unlocked");
//Handle already in use device
} else if (ret == 5) {
die(500, "Device already in use");
//Handle invalid luks device
} else if (ret == 256) {
die(500, "Device is now a valid device");
//Handle no key available with this passphrase
} else if (ret == 512) {
die(500, "No slot for this value");
//Handle unexisting device or permission denied
} else if (ret == 1014) {
die(500, "Device doesn't exist or access denied");
//Unknown error
} else if (ret != 0) {
//Err length and counter
int errLength = 2048, e = 0;
//Declare err buffer
char *err;
//Buffer char
char c;
//Alloc err buffer
if ((err = malloc(errLength*sizeof(char))) == NULL) {
die(500, "Couldn't alloc err buffer");
}
//Advance after ret code
e = sprintf(err, "%d:", ret);
//Fetch stderr and store in err buffer
while(read(errPipe[0], &c, 1) > 0) {
//Grow buffer if we reach end
if (e == errLength) {
if ((err = realloc(err, (errLength+2048)*sizeof(char))) == NULL) {
die(500, "Couldn't grow err buffer");
}
errLength += 2048;
}
//Store character
err[e] = c;
//Pass to next
e++;
}
//Terminate err buffer
err[e] = '\0';
//Realloc err buffer
if ((err = realloc(err, (e+1)*sizeof(char))) == NULL) {
die(500, "Couldn't ungrow err buffer");
}
//Die with luks error
die(500, err);
}
//Close errPipe
close(errPipe[0]);
}
//Fork process
if ((pid = fork()) == -1) {
die(500, "Failed to fork");
}
//IHttpd killing child process
if (pid == 0) {
//File descriptor
int fd;
//Declare ihttpd pid
pid_t ihttpdPid;
//Close stdin
close(STDIN_FILENO);
//Disable line buffering on stdout and stderr
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
//Redirect output to log
if ((fd = open(IHTTPDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) {
fprintf(stderr, "Open ihttpd child log failed\n");
} else {
//Close stdout
close(STDOUT_FILENO);
//Redirect stdout on childlog
if (dup2(fd, STDOUT_FILENO) == -1) {
fprintf(stderr, "Redirect stdout to ihttpd child log failed\n");
}
//Close stderr
close(STDERR_FILENO);
//Redirect stderr on childlog
if (dup2(fd, STDERR_FILENO) == -1) {
fprintf(stderr, "Redirect stderr to ihttpd child log failed\n");
}
//Close childlog fd
close(fd);
}
//Extract ihttpd pid
if (extractIHttpdPid(&ihttpdPid) < 0) {
fprintf(stderr, "Failed to extract ihttpd pid");
exit(EXIT_FAILURE);
}
//Close stdout and stderr without childlog
if (fd == -1) {
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
//Wait until get rattached to init(getppid()==1)
//XXX: we are really blind here
while(getppid() != 1) {
//Sleep half a second
if (usleep(500000) == -1 && fd != -1) {
printf("Usleep failed\n");
}
}
//Termiate ihttpd
if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGTERM) == -1 && fd != -1) {
printf("Termiate ihttpd failed\n");
}
//Sleep half a second
if (usleep(500000) == -1 && fd != -1) {
printf("Usleep failed\n");
}
//Kill ihttpd
if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGKILL) == -1) {
printf("Kill ihttpd failed\n");
}
//Parent process
} else {
//Fork process
if ((pid = fork()) == -1) {
die(500, "Failed to fork");
}
//Ask password killing child process
//XXX: we are blind here
if (pid == 0) {
//File descriptor
int fd;
//Declare ask password pid
pid_t askPasswordPid;
//Close stdin
close(STDIN_FILENO);
//Disable line buffering on stdout and stderr
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
//Redirect output to log
if ((fd = open(ASKPASSWORDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) {
fprintf(stderr, "Open ask password child log failed\n");
} else {
//Close stdout
close(STDOUT_FILENO);
//Redirect stdout on childlog
if (dup2(fd, STDOUT_FILENO) == -1) {
fprintf(stderr, "Redirect stdout to ask password child log failed\n");
}
//Close stderr
close(STDERR_FILENO);
//Redirect stderr on childlog
if (dup2(fd, STDERR_FILENO) == -1) {
fprintf(stderr, "Redirect stderr to ask password child log failed\n");
}
//Close childlog fd
close(fd);
}
//Extract ask password pid
if (extractAskPasswordPid(&askPasswordPid) < 0) {
fprintf(stderr, "Failed to extract ask password pid");
exit(EXIT_FAILURE);
}
//Close stdout and stderr without childlog
if (fd == -1) {
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
//Wait until get rattached to init(getppid()==1)
//XXX: we are really blind here
while(getppid() != 1) {
//Sleep half a second
if (usleep(500000) == -1 && fd != -1) {
printf("Usleep failed\n");
}
}
//Termitate ask password
if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGTERM) == -1 && fd != -1) {
printf("Termiate ask password failed\n");
}
//Sleep half a second
if (usleep(500000) == -1 && fd != -1) {
printf("Usleep failed\n");
}
//Kill ask password
if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGKILL) == -1) {
printf("Kill ask password failed\n");
}
//Parent process
} else {
//Process success
header(200, "text/plain");
printf("Sent value, boot should resume now");
fflush(NULL);
}
}
}
exit(EXIT_SUCCESS);
}