1 #include "uwsgi.h"
2 
3 extern struct uwsgi_server uwsgi;
4 
5 /*
6 
7 	poll based fd waiter.
8 	Use it for blocking areas (like startup functions)
9 	DO NOT USE IN REQUEST PLUGINS !!!
10 
11 */
uwsgi_waitfd_event(int fd,int timeout,int event)12 int uwsgi_waitfd_event(int fd, int timeout, int event) {
13 
14 	int ret;
15 	struct pollfd upoll;
16 
17 	if (!timeout)
18 		timeout = uwsgi.socket_timeout;
19 
20 	timeout = timeout * 1000;
21 	if (timeout < 0)
22 		timeout = -1;
23 
24 	upoll.fd = fd;
25 	upoll.events = event;
26 	upoll.revents = 0;
27 	ret = poll(&upoll, 1, timeout);
28 
29 	if (ret < 0) {
30 		uwsgi_error("uwsgi_waitfd_event()/poll()");
31 	}
32 	else if (ret > 0) {
33 		if (upoll.revents & event) {
34 			return ret;
35 		}
36 		return -1;
37 	}
38 
39 	return ret;
40 }
41 
42 /*
43 	consume data from an fd (blocking)
44 */
uwsgi_read_fd(int fd,size_t * size,int add_zero)45 char *uwsgi_read_fd(int fd, size_t *size, int add_zero) {
46 
47 	char stack_buf[4096];
48 	ssize_t len;
49 	char *buffer = NULL;
50 
51 	len = 1;
52 	while (len > 0) {
53 		len = read(fd, stack_buf, 4096);
54 		if (len > 0) {
55 			*size += len;
56 			char *tmp = realloc(buffer, *size);
57 			if (!tmp) {
58 				uwsgi_error("uwsgi_read_fd()/realloc()");
59 				exit(1);
60 			}
61 			buffer = tmp;
62 			memcpy(buffer + (*size - len), stack_buf, len);
63 		}
64 	}
65 
66 	if (add_zero) {
67 		*size = *size + 1;
68 		buffer = realloc(buffer, *size);
69 		if (!buffer) {
70 			uwsgi_error("uwsgi_read_fd()/realloc()");
71 			exit(1);
72 		}
73 		buffer[*size - 1] = 0;
74 	}
75 
76 	return buffer;
77 
78 }
79 
80 // simply read the whole content of a file
uwsgi_simple_file_read(char * filename)81 char *uwsgi_simple_file_read(char *filename) {
82 
83 	struct stat sb;
84 	char *buffer;
85 	ssize_t len;
86 	int fd = open(filename, O_RDONLY);
87 	if (fd < 0) {
88 		uwsgi_error_open(filename);
89 		goto end;
90 	}
91 
92 	if (fstat(fd, &sb)) {
93 		uwsgi_error("fstat()");
94 		close(fd);
95 		goto end;
96 	}
97 
98 	buffer = uwsgi_malloc(sb.st_size + 1);
99 
100 	len = read(fd, buffer, sb.st_size);
101 	if (len != sb.st_size) {
102 		uwsgi_error("read()");
103 		free(buffer);
104 		close(fd);
105 		goto end;
106 	}
107 
108 	close(fd);
109 	if (buffer[sb.st_size - 1] == '\n' || buffer[sb.st_size - 1] == '\r') {
110 		buffer[sb.st_size - 1] = 0;
111 	}
112 	buffer[sb.st_size] = 0;
113 	return buffer;
114 end:
115 	return (char *) "";
116 
117 }
118 
uwsgi_scheme_fd(char * url,size_t * size,int add_zero)119 static char *uwsgi_scheme_fd(char *url, size_t *size, int add_zero) {
120 	int fd = atoi(url);
121 	return uwsgi_read_fd(fd, size, add_zero);
122 }
123 
uwsgi_scheme_exec(char * url,size_t * size,int add_zero)124 static char *uwsgi_scheme_exec(char *url, size_t *size, int add_zero) {
125 	int cpipe[2];
126 	if (pipe(cpipe)) {
127 		uwsgi_error("pipe()");
128 		exit(1);
129 	}
130 	uwsgi_run_command(url, NULL, cpipe[1]);
131 	char *buffer = uwsgi_read_fd(cpipe[0], size, add_zero);
132 	close(cpipe[0]);
133 	close(cpipe[1]);
134 	return buffer;
135 }
136 
uwsgi_scheme_http(char * url,size_t * size,int add_zero)137 static char *uwsgi_scheme_http(char *url, size_t *size, int add_zero) {
138 	char byte;
139         int body = 0;
140 	char *buffer = NULL;
141 
142 		char *domain = url;
143 		char *uri = strchr(domain, '/');
144 		if (!uri) {
145 			uwsgi_log("invalid http url\n");
146 			exit(1);
147 		}
148 		uri[0] = 0;
149 		uwsgi_log("domain: %s\n", domain);
150 
151 		char *colon = uwsgi_get_last_char(domain, ':');
152 
153 		if (colon) {
154 			colon[0] = 0;
155 		}
156 
157 
158 		char *ip = uwsgi_resolve_ip(domain);
159 		if (!ip) {
160 			uwsgi_log("unable to resolve address %s\n", domain);
161 			exit(1);
162 		}
163 
164 		if (colon) {
165 			colon[0] = ':';
166 			ip = uwsgi_concat2(ip, colon);
167 		}
168 		else {
169 			ip = uwsgi_concat2(ip, ":80");
170 		}
171 
172 		int fd = uwsgi_connect(ip, 0, 0);
173 
174 		if (fd < 0) {
175 			uwsgi_error("uwsgi_scheme_http()/connect()");
176 			exit(1);
177 		}
178 
179 		free(ip);
180 
181 		uri[0] = '/';
182 
183 		if (write(fd, "GET ", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
184 		if (write(fd, uri, strlen(uri)) != (ssize_t) strlen(uri)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
185 		if (write(fd, " HTTP/1.0\r\n", 11) != 11) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
186 		if (write(fd, "Host: ", 6) != 6) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
187 
188 		uri[0] = 0;
189 		if (write(fd, domain, strlen(domain)) != (ssize_t) strlen(domain)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
190 		uri[0] = '/';
191 
192 		if (write(fd, "\r\nUser-Agent: uWSGI on ", 23) != 23) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
193 		if (write(fd, uwsgi.hostname, uwsgi.hostname_len) != uwsgi.hostname_len) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
194 		if (write(fd, "\r\n\r\n", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
195 
196 		int http_status_code_ptr = 0;
197 
198 		while (read(fd, &byte, 1) == 1) {
199 			if (byte == '\r' && body == 0) {
200 				body = 1;
201 			}
202 			else if (byte == '\n' && body == 1) {
203 				body = 2;
204 			}
205 			else if (byte == '\r' && body == 2) {
206 				body = 3;
207 			}
208 			else if (byte == '\n' && body == 3) {
209 				body = 4;
210 			}
211 			else if (body == 4) {
212 				*size = *size + 1;
213 				char *tmp = realloc(buffer, *size);
214 				if (!tmp) {
215 					uwsgi_error("uwsgi_open_and_read()/realloc()");
216 					exit(1);
217 				}
218 				buffer = tmp;
219 				buffer[*size - 1] = byte;
220 			}
221 			else {
222 				body = 0;
223 				http_status_code_ptr++;
224 				if (http_status_code_ptr == 10) {
225 					if (byte != '2') {
226 						uwsgi_log("Not usable HTTP response: %cxx\n", byte);
227 						if (uwsgi.has_emperor) {
228 							exit(UWSGI_EXILE_CODE);
229 						}
230 						else {
231 							exit(1);
232 						}
233 					}
234 				}
235 			}
236 		}
237 
238 		close(fd);
239 
240 		if (add_zero) {
241 			*size = *size + 1;
242 			char *tmp = realloc(buffer, *size);
243 			if (!tmp) {
244 				uwsgi_error("uwsgi_open_and_read()/realloc()");
245 				exit(1);
246 			}
247 			buffer = tmp;
248 			buffer[*size - 1] = 0;
249 		}
250 
251 	return buffer;
252 }
253 
254 
uwsgi_scheme_emperor(char * url,size_t * size,int add_zero)255 static char *uwsgi_scheme_emperor(char *url, size_t *size, int add_zero) {
256 
257 	if (uwsgi.emperor_fd_config < 0) {
258 		uwsgi_log("this is not a vassal instance\n");
259 		exit(1);
260 	}
261 	ssize_t rlen;
262 	struct uwsgi_header uh;
263 	size_t remains = 4;
264 	char *ptr = (char *) &uh;
265 	while(remains) {
266 		int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
267 		if (ret <= 0) {
268 			uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url);
269 			exit(1);
270 		}
271 		rlen = read(uwsgi.emperor_fd_config, ptr, remains);
272 		if (rlen <= 0) {
273 			uwsgi_log("[uwsgi-vassal] error reading config header from %s !!!\n", url);
274 			exit(1);
275 		}
276 		ptr+=rlen;
277 		remains-=rlen;
278 	}
279 
280 	remains = uh.pktsize;
281 	if (!remains) {
282 		uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url);
283 		exit(1);
284 	}
285 
286 	char *buffer = uwsgi_calloc(remains + add_zero);
287 	ptr = buffer;
288 	while (remains) {
289 		int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
290                 if (ret <= 0) {
291                 	uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url);
292                         exit(1);
293                 }
294 		rlen = read(uwsgi.emperor_fd_config, ptr, remains);
295 		if (rlen <= 0) {
296                 	uwsgi_log("[uwsgi-vassal] error reading config from %s !!!\n", url);
297                         exit(1);
298                 }
299                 ptr+=rlen;
300                 remains-=rlen;
301 	}
302 
303 	*size = uh.pktsize + add_zero;
304 	return buffer;
305 }
306 
uwsgi_scheme_data(char * url,size_t * size,int add_zero)307 static char *uwsgi_scheme_data(char *url, size_t *size, int add_zero) {
308 	char *buffer = NULL;
309 	int fd = open(uwsgi.binary_path, O_RDONLY);
310 	if (fd < 0) {
311 		uwsgi_error_open(uwsgi.binary_path);
312 		exit(1);
313 	}
314 	int slot = atoi(url);
315 	if (slot < 0) {
316 		uwsgi_log("invalid binary data slot requested\n");
317 		exit(1);
318 	}
319 	uwsgi_log("requesting binary data slot %d\n", slot);
320 	off_t fo = lseek(fd, 0, SEEK_END);
321 	if (fo < 0) {
322 		uwsgi_error("lseek()");
323 		uwsgi_log("invalid binary data slot requested\n");
324 		exit(1);
325 	}
326 	int i = 0;
327 	uint64_t datasize = 0;
328 	for (i = 0; i <= slot; i++) {
329 		fo = lseek(fd, -8, SEEK_CUR);
330 		if (fo < 0) {
331 			uwsgi_error("lseek()");
332 			uwsgi_log("invalid binary data slot requested\n");
333 			exit(1);
334 		}
335 		ssize_t len = read(fd, &datasize, 8);
336 		if (len != 8) {
337 			uwsgi_error("read()");
338 			uwsgi_log("invalid binary data slot requested\n");
339 			exit(1);
340 		}
341 		if (datasize == 0) {
342 			uwsgi_log("0 size binary data !!!\n");
343 			exit(1);
344 		}
345 		fo = lseek(fd, -(datasize + 8), SEEK_CUR);
346 		if (fo < 0) {
347 			uwsgi_error("lseek()");
348 			uwsgi_log("invalid binary data slot requested\n");
349 			exit(1);
350 		}
351 
352 		if (i == slot) {
353 			*size = datasize;
354 			if (add_zero) {
355 				*size += 1;
356 			}
357 			buffer = uwsgi_malloc(*size);
358 			memset(buffer, 0, *size);
359 			len = read(fd, buffer, datasize);
360 			if (len != (ssize_t) datasize) {
361 				uwsgi_error("read()");
362 				uwsgi_log("invalid binary data slot requested\n");
363 				exit(1);
364 			}
365 		}
366 	}
367 	close(fd);
368 
369 	return buffer;
370 }
371 
uwsgi_scheme_call(char * url,size_t * size,int add_zero)372 static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) {
373         char *(*func)(void) = dlsym(RTLD_DEFAULT, url);
374 	if (!func) {
375 		uwsgi_log("unable to find symbol %s\n", url);
376                 exit(1);
377 	}
378 
379 	char *s = func();
380 	if (!s) {
381 		uwsgi_log("called symbol %s did not return a string\n", url);
382                 exit(1);
383 	}
384         *size = strlen(s);
385         if (add_zero) {
386                 *size += 1;
387         }
388         char *buffer = uwsgi_malloc(*size);
389         memset(buffer, 0, *size);
390         memcpy(buffer, s, strlen(s));
391 
392         return buffer;
393 }
394 
uwsgi_scheme_callint(char * url,size_t * size,int add_zero)395 static char *uwsgi_scheme_callint(char *url, size_t *size, int add_zero) {
396         int (*func)(void) = dlsym(RTLD_DEFAULT, url);
397         if (!func) {
398                 uwsgi_log("unable to find symbol %s\n", url);
399                 exit(1);
400         }
401 
402 	char *s = uwsgi_num2str(func());
403         *size = strlen(s);
404         if (add_zero) {
405                 *size += 1;
406         }
407         char *buffer = uwsgi_malloc(*size);
408         memset(buffer, 0, *size);
409         memcpy(buffer, s, strlen(s));
410 	free(s);
411 
412         return buffer;
413 }
414 
415 
uwsgi_scheme_sym(char * url,size_t * size,int add_zero)416 static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) {
417 	void *sym_start_ptr = NULL, *sym_end_ptr = NULL;
418 	char **raw_symbol = dlsym(RTLD_DEFAULT, url);
419 	if (raw_symbol) {
420 		sym_start_ptr = *raw_symbol;
421 		sym_end_ptr = sym_start_ptr + strlen(sym_start_ptr);
422 		goto found;
423 	}
424 	char *symbol = uwsgi_concat3("_binary_", url, "_start");
425 	sym_start_ptr = dlsym(RTLD_DEFAULT, symbol);
426 	if (!sym_start_ptr) {
427 		uwsgi_log("unable to find symbol %s\n", symbol);
428 		exit(1);
429 	}
430 	free(symbol);
431 	symbol = uwsgi_concat3("_binary_", url, "_end");
432 	sym_end_ptr = dlsym(RTLD_DEFAULT, symbol);
433 	if (!sym_end_ptr) {
434 		uwsgi_log("unable to find symbol %s\n", symbol);
435 		exit(1);
436 	}
437 	free(symbol);
438 
439 found:
440 
441 	*size = sym_end_ptr - sym_start_ptr;
442 	if (add_zero) {
443 		*size += 1;
444 	}
445 	char *buffer = uwsgi_malloc(*size);
446 	memset(buffer, 0, *size);
447 	memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr);
448 
449 	return buffer;
450 }
451 
uwsgi_scheme_section(char * url,size_t * size,int add_zero)452 static char *uwsgi_scheme_section(char *url, size_t *size, int add_zero) {
453 #ifdef UWSGI_ELF
454 	size_t s_len = 0;
455 	char *buffer = uwsgi_elf_section(uwsgi.binary_path, url, &s_len);
456 	if (!buffer) {
457 		uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path);
458 		exit(1);
459 	}
460 	*size = s_len;
461 	if (add_zero)
462 		*size += 1;
463 	return buffer;
464 #else
465 	uwsgi_log("section:// scheme not supported on this platform\n");
466 	exit(1);
467 #endif
468 }
469 
uwsgi_register_scheme(char * name,char * (* func)(char *,size_t *,int))470 struct uwsgi_string_list *uwsgi_register_scheme(char *name, char * (*func)(char *, size_t *, int)) {
471 	struct uwsgi_string_list *usl = NULL;
472 	uwsgi_foreach(usl, uwsgi.schemes) {
473 		if (!strcmp(usl->value, name)) goto found;
474 	}
475 
476 	usl = uwsgi_string_new_list(&uwsgi.schemes, name);
477 
478 found:
479 	usl->custom_ptr = func;
480 	return usl;
481 }
482 
uwsgi_open_and_read(char * url,size_t * size,int add_zero,char * magic_table[])483 char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) {
484 
485         struct stat sb;
486         char *buffer = NULL;
487         ssize_t len;
488         char *magic_buf;
489 	int fd;
490 
491 	*size = 0;
492 
493         // stdin ?
494         if (!strcmp(url, "-")) {
495                 buffer = uwsgi_read_fd(0, size, add_zero);
496 		goto end;
497         }
498 #ifdef UWSGI_EMBED_CONFIG
499 	else if (url[0] == 0) {
500 		*size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG;
501 		if (add_zero) {
502 			*size += 1;
503 		}
504 		buffer = uwsgi_malloc(*size);
505 		memset(buffer, 0, *size);
506 		memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG);
507 		goto end;
508 	}
509 #endif
510 
511 	struct uwsgi_string_list *usl = uwsgi_check_scheme(url);
512 	if (!usl) goto fallback;
513 
514 	char *(*func)(char *, size_t *, int) = (char *(*)(char *, size_t *, int)) usl->custom_ptr;
515 	buffer = func(url + usl->len + 3, size, add_zero);
516 	if (buffer) goto end;
517 	// never here !!!
518 	uwsgi_log("unable to parse config file %s\n", url);
519 	exit(1);
520 
521 	// fallback to file
522 fallback:
523 		fd = open(url, O_RDONLY);
524 		if (fd < 0) {
525 			uwsgi_error_open(url);
526 			exit(1);
527 		}
528 
529 		if (fstat(fd, &sb)) {
530 			uwsgi_error("fstat()");
531 			exit(1);
532 		}
533 
534 		if (S_ISFIFO(sb.st_mode)) {
535 			buffer = uwsgi_read_fd(fd, size, add_zero);
536 			close(fd);
537 			goto end;
538 		}
539 
540 		// is it a potential virtual file (/proc, /sys...) ?
541 		int is_virtual = 0;
542 		if (sb.st_size == 0) {
543 			is_virtual = 1;
544 			sb.st_size = 4096;
545 		}
546 
547 		buffer = uwsgi_malloc(sb.st_size + add_zero);
548 
549 		len = read(fd, buffer, sb.st_size);
550 		if (!is_virtual) {
551 			if (len != sb.st_size) {
552 			}
553 		}
554 		else {
555 			if (len >= 0) {
556 				sb.st_size = len;
557 			}
558 			else {
559 				uwsgi_error("read()");
560 				exit(1);
561 			}
562 		}
563 
564 		close(fd);
565 
566 		*size = sb.st_size + add_zero;
567 
568 		if (add_zero)
569 			buffer[sb.st_size] = 0;
570 
571 end:
572 
573 	if (magic_table) {
574 		// here we inject blobs
575 		struct uwsgi_string_list *usl = NULL;
576 		if (uwsgi.inject_before || uwsgi.inject_after) {
577 			struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
578 			uwsgi_foreach(usl, uwsgi.inject_before) {
579 				size_t rlen = 0;
580 				char *before = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
581 				if (uwsgi_buffer_append(ub, before, rlen)) {
582 					uwsgi_log("unable to inject data in the config file\n");
583 					exit(1);
584 				}
585 				free(before);
586 			}
587 			if (uwsgi_buffer_append(ub, buffer, *size - add_zero)) {
588                         	uwsgi_log("unable to inject data in the config file\n");
589                                 exit(1);
590                         }
591 			uwsgi_foreach(usl, uwsgi.inject_after) {
592 				size_t rlen = 0;
593                                 char *after = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
594                                 if (uwsgi_buffer_append(ub, after, rlen)) {
595                                         uwsgi_log("unable to inject data in the config file\n");
596                                         exit(1);
597                                 }
598                                 free(after);
599 			}
600 			if (add_zero) {
601 				if (uwsgi_buffer_append(ub, "\0", 1)) {
602                                         uwsgi_log("unable to inject data in the config file\n");
603                                         exit(1);
604                                 }
605 			}
606 			*size = ub->pos;
607 			// free resources
608 			free(buffer);
609 			buffer = ub->buf;
610 			// aboid destroying buffer
611 			ub->buf = NULL;
612 			uwsgi_buffer_destroy(ub);
613 		}
614 		magic_buf = magic_sub(buffer, *size, size, magic_table);
615 		free(buffer);
616 		return magic_buf;
617 	}
618 
619 	return buffer;
620 }
621 
622 // attach an fd using UNIX sockets
uwsgi_attach_fd(int fd,int * count_ptr,char * code,size_t code_len)623 int *uwsgi_attach_fd(int fd, int *count_ptr, char *code, size_t code_len) {
624 
625 	struct msghdr msg;
626 	ssize_t len;
627 	char *id = NULL;
628 
629 	struct iovec iov;
630 	struct cmsghdr *cmsg;
631 	int *ret;
632 	int i;
633 	int count = *count_ptr;
634 
635 	void *msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * count));
636 
637 	memset(msg_control, 0, CMSG_SPACE(sizeof(int) * count));
638 
639 	if (code && code_len > 0) {
640 		// allocate space for code and num_sockets
641 		id = uwsgi_malloc(code_len + sizeof(int));
642 		memset(id, 0, code_len);
643 		iov.iov_len = code_len + sizeof(int);
644 	}
645 
646 	iov.iov_base = id;
647 
648 	memset(&msg, 0, sizeof(msg));
649 
650 	msg.msg_name = NULL;
651 	msg.msg_namelen = 0;
652 
653 	msg.msg_iov = &iov;
654 	msg.msg_iovlen = 1;
655 
656 	msg.msg_control = msg_control;
657 	msg.msg_controllen = CMSG_SPACE(sizeof(int) * count);
658 
659 	msg.msg_flags = 0;
660 
661 	len = recvmsg(fd, &msg, 0);
662 	if (len <= 0) {
663 		uwsgi_error("recvmsg()");
664 		free(msg_control);
665 		return NULL;
666 	}
667 
668 	if (code && code_len > 0) {
669 		if (uwsgi_strncmp(id, code_len, code, code_len)) {
670 			free(msg_control);
671 			return NULL;
672 		}
673 
674 		if ((size_t) len == code_len + sizeof(int)) {
675 			memcpy(&i, id + code_len, sizeof(int));
676 			if (i > count) {
677 				*count_ptr = i;
678 				free(msg_control);
679 				free(id);
680 				return NULL;
681 			}
682 		}
683 	}
684 
685 	cmsg = CMSG_FIRSTHDR(&msg);
686 	if (!cmsg) {
687 		free(msg_control);
688 		return NULL;
689 	}
690 
691 	if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
692 		free(msg_control);
693 		return NULL;
694 	}
695 
696 	if ((size_t) (cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)) > (size_t) (sizeof(int) * (count + 1))) {
697 		uwsgi_log("not enough space for sockets data, consider increasing it\n");
698 		free(msg_control);
699 		return NULL;
700 	}
701 
702 	ret = uwsgi_malloc(sizeof(int) * (count + 1));
703 	for (i = 0; i < count + 1; i++) {
704 		ret[i] = -1;
705 	}
706 
707 	memcpy(ret, CMSG_DATA(cmsg), cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg));
708 
709 	free(msg_control);
710 	if (code && code_len > 0) {
711 		free(id);
712 	}
713 
714 	return ret;
715 }
716 
717 // signal free close
uwsgi_protected_close(int fd)718 void uwsgi_protected_close(int fd) {
719 
720 	sigset_t mask, oset;
721 	sigfillset(&mask);
722 	if (sigprocmask(SIG_BLOCK, &mask, &oset)) {
723 		uwsgi_error("sigprocmask()");
724 		exit(1);
725 	}
726 	close(fd);
727 	if (sigprocmask(SIG_SETMASK, &oset, NULL)) {
728 		uwsgi_error("sigprocmask()");
729 		exit(1);
730 	}
731 }
732 
733 // signal free read
uwsgi_protected_read(int fd,void * buf,size_t len)734 ssize_t uwsgi_protected_read(int fd, void *buf, size_t len) {
735 
736 	sigset_t mask, oset;
737 	sigfillset(&mask);
738 	if (sigprocmask(SIG_BLOCK, &mask, &oset)) {
739 		uwsgi_error("sigprocmask()");
740 		exit(1);
741 	}
742 
743 	ssize_t ret = read(fd, buf, len);
744 
745 	if (sigprocmask(SIG_SETMASK, &oset, NULL)) {
746 		uwsgi_error("sigprocmask()");
747 		exit(1);
748 	}
749 	return ret;
750 }
751 
752 
753 // pipe datas from a fd to another (blocking)
uwsgi_pipe(int src,int dst,int timeout)754 ssize_t uwsgi_pipe(int src, int dst, int timeout) {
755 	char buf[8192];
756 	size_t written = -1;
757 	ssize_t len;
758 
759 	for (;;) {
760 		int ret = uwsgi_waitfd(src, timeout);
761 		if (ret > 0) {
762 			len = read(src, buf, 8192);
763 			if (len == 0) {
764 				return written;
765 			}
766 			else if (len < 0) {
767 				uwsgi_error("read()");
768 				return -1;
769 			}
770 
771 			size_t remains = len;
772 			while (remains > 0) {
773 				int ret = uwsgi_waitfd_write(dst, timeout);
774 				if (ret > 0) {
775 					len = write(dst, buf, remains);
776 					if (len > 0) {
777 						remains -= len;
778 						written += len;
779 					}
780 					else if (len == 0) {
781 						return written;
782 					}
783 					else {
784 						uwsgi_error("write()");
785 						return -1;
786 					}
787 				}
788 				else if (ret == 0) {
789 					goto timeout;
790 				}
791 				else {
792 					return -1;
793 				}
794 			}
795 		}
796 		else if (ret == 0) {
797 			goto timeout;
798 		}
799 		else {
800 			return -1;
801 		}
802 	}
803 
804 	return written;
805 timeout:
806 	uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst);
807 	return -1;
808 }
809 
810 /*
811 	even if it is marked as non-blocking, so not use in request plugins as it uses poll() and not the hooks
812 */
uwsgi_write_nb(int fd,char * buf,size_t remains,int timeout)813 int uwsgi_write_nb(int fd, char *buf, size_t remains, int timeout) {
814 	char *ptr = buf;
815 	while(remains > 0) {
816 		int ret = uwsgi_waitfd_write(fd, timeout);
817 		if (ret > 0) {
818 			ssize_t len = write(fd, ptr, remains);
819 			if (len <= 0) {
820 				return -1;
821 			}
822 			ptr += len;
823 			remains -= len;
824 			continue;
825 		}
826 		return -1;
827 	}
828 
829 	return 0;
830 }
831 
832 /*
833 	this is like uwsgi_write_nb() but with fast initial write and hooked wait (use it in request plugin)
834 */
uwsgi_write_true_nb(int fd,char * buf,size_t remains,int timeout)835 int uwsgi_write_true_nb(int fd, char *buf, size_t remains, int timeout) {
836         char *ptr = buf;
837 	int ret;
838 
839         while(remains > 0) {
840 		errno = 0;
841 		ssize_t len = write(fd, ptr, remains);
842 		if (len > 0) goto written;
843 		if (len == 0) return -1;
844 		if (len < 0) {
845 			if (uwsgi_is_again()) goto wait;
846 			return -1;
847 		}
848 wait:
849                 ret = uwsgi.wait_write_hook(fd, timeout);
850                 if (ret > 0) {
851 			len = write(fd, ptr, remains);
852 			if (len > 0) goto written;
853                 }
854                 return -1;
855 written:
856                 ptr += len;
857                 remains -= len;
858                 continue;
859         }
860 
861         return 0;
862 }
863 
864 
865 
866 
867 // like uwsgi_pipe but with fixed size
uwsgi_pipe_sized(int src,int dst,size_t required,int timeout)868 ssize_t uwsgi_pipe_sized(int src, int dst, size_t required, int timeout) {
869 	char buf[8192];
870 	size_t written = 0;
871 	ssize_t len;
872 
873 	while (written < required) {
874 		int ret = uwsgi_waitfd(src, timeout);
875 		if (ret > 0) {
876 			len = read(src, buf, UMIN(8192, required - written));
877 			if (len == 0) {
878 				return written;
879 			}
880 			else if (len < 0) {
881 				uwsgi_error("read()");
882 				return -1;
883 			}
884 
885 			size_t remains = len;
886 			while (remains > 0) {
887 				int ret = uwsgi_waitfd_write(dst, timeout);
888 				if (ret > 0) {
889 					len = write(dst, buf, remains);
890 					if (len > 0) {
891 						remains -= len;
892 						written += len;
893 					}
894 					else if (len == 0) {
895 						return written;
896 					}
897 					else {
898 						uwsgi_error("write()");
899 						return -1;
900 					}
901 				}
902 				else if (ret == 0) {
903 					goto timeout;
904 				}
905 				else {
906 					return -1;
907 				}
908 			}
909 		}
910 		else if (ret == 0) {
911 			goto timeout;
912 		}
913 		else {
914 			return -1;
915 		}
916 	}
917 
918 	return written;
919 timeout:
920 	uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst);
921 	return -1;
922 }
923 
924 
925 // check if an fd is valid
uwsgi_valid_fd(int fd)926 int uwsgi_valid_fd(int fd) {
927 	int ret = fcntl(fd, F_GETFL);
928 	if (ret == -1) {
929 		return 0;
930 	}
931 	return 1;
932 }
933 
uwsgi_close_all_fds(void)934 void uwsgi_close_all_fds(void) {
935 	int i;
936 	for (i = 3; i < (int) uwsgi.max_fd; i++) {
937 #ifdef __APPLE__
938         	fcntl(i, F_SETFD, FD_CLOEXEC);
939 #else
940                 close(i);
941 #endif
942 	}
943 }
944 
uwsgi_read_uh(int fd,struct uwsgi_header * uh,int timeout)945 int uwsgi_read_uh(int fd, struct uwsgi_header *uh, int timeout) {
946 	char *ptr = (char *) uh;
947 	size_t remains = 4;
948 	while(remains > 0) {
949 		int ret = uwsgi_waitfd(fd, timeout);
950 		if (ret > 0) {
951 			ssize_t len = read(fd, ptr, remains);
952 			if (len <= 0) {
953 				return -1;
954 			}
955 			remains -=len;
956 			ptr +=len;
957 			continue;
958 		}
959 		return -1;
960 	}
961 
962 	return 0;
963 }
964 
uwsgi_read_nb(int fd,char * buf,size_t remains,int timeout)965 int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) {
966 	char *ptr = buf;
967         while(remains > 0) {
968                 int ret = uwsgi_waitfd(fd, timeout);
969                 if (ret > 0) {
970                         ssize_t len = read(fd, ptr, remains);
971                         if (len <= 0) {
972                                 return -1;
973                         }
974                         remains -=len;
975                         ptr +=len;
976                         continue;
977                 }
978                 return -1;
979         }
980 
981         return 0;
982 }
983 
984 /*
985         this is like uwsgi_read_nb() but with fast initial read and hooked wait (use it in request plugin)
986 */
uwsgi_read_true_nb(int fd,char * buf,size_t len,int timeout)987 ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
988         int ret;
989 
990 	errno = 0;
991 	ssize_t rlen = read(fd, buf, len);
992         if (rlen > 0) {
993 		return rlen;
994 	}
995         if (rlen == 0) return -1;
996         if (rlen < 0) {
997         	if (uwsgi_is_again()) goto wait;
998         }
999         return -1;
1000 wait:
1001 	errno = 0;
1002         ret = uwsgi.wait_read_hook(fd, timeout);
1003         if (ret > 0) {
1004 		errno = 0;
1005         	rlen = read(fd, buf, len);
1006                 if (rlen > 0) {
1007 			return rlen;
1008                 }
1009 		return -1;
1010 	}
1011         return ret;
1012 }
1013 
1014 
1015 /*
1016 	like the previous one but consume the whole len (if possibile)
1017 */
1018 
uwsgi_read_whole_true_nb(int fd,char * buf,size_t remains,int timeout)1019 int uwsgi_read_whole_true_nb(int fd, char *buf, size_t remains, int timeout) {
1020 	char *ptr = buf;
1021 	while(remains > 0) {
1022 		ssize_t len = uwsgi_read_true_nb(fd, ptr, remains, timeout);
1023 		if (len <= 0) return -1;
1024 		ptr += len;
1025 		remains -= len;
1026 	}
1027 	return 0;
1028 }
1029 
1030 /*
1031 	this is a pretty magic function used for reading a full uwsgi response
1032 	it is true non blocking, so you can use it in request plugins
1033 	buffer is expected to be at least 4 bytes, rlen is a get/set value
1034 */
1035 
uwsgi_read_with_realloc(int fd,char ** buffer,size_t * rlen,int timeout,uint8_t * modifier1,uint8_t * modifier2)1036 int uwsgi_read_with_realloc(int fd, char **buffer, size_t *rlen, int timeout, uint8_t *modifier1, uint8_t *modifier2) {
1037 	if (*rlen < 4) return -1;
1038 	char *buf = *buffer;
1039 	int ret;
1040 
1041 	// start reading the header
1042 	char *ptr = buf;
1043 	size_t remains = 4;
1044 	while(remains > 0) {
1045 		ssize_t len = read(fd, ptr, remains);
1046                 if (len > 0) goto readok;
1047                 if (len == 0) return -1;
1048                 if (len < 0) {
1049                         if (uwsgi_is_again()) goto wait;
1050                         return -1;
1051                 }
1052 wait:
1053                 ret = uwsgi.wait_read_hook(fd, timeout);
1054                 if (ret > 0) {
1055                         len = read(fd, ptr, remains);
1056                         if (len > 0) goto readok;
1057                 }
1058                 return -1;
1059 readok:
1060                 ptr += len;
1061                 remains -= len;
1062                 continue;
1063         }
1064 
1065 	struct uwsgi_header *uh = (struct uwsgi_header *) buf;
1066 	uint16_t pktsize = uh->pktsize;
1067 	if (modifier1)
1068 		*modifier1 = uh->modifier1;
1069 	if (modifier2)
1070 		*modifier2 = uh->modifier2;
1071 
1072 	if (pktsize > *rlen) {
1073 		char *tmp_buf = realloc(buf, pktsize);
1074 		if (!tmp_buf) {
1075 			uwsgi_error("uwsgi_read_with_realloc()/realloc()");
1076 			return -1;
1077 		}
1078 		*buffer = tmp_buf;
1079 		buf = *buffer;
1080 	}
1081 
1082 	*rlen = pktsize;
1083 	// read the body
1084 	remains = pktsize;
1085 	ptr = buf;
1086 	while(remains > 0) {
1087                 ssize_t len = read(fd, ptr, remains);
1088                 if (len > 0) goto readok2;
1089                 if (len == 0) return -1;
1090                 if (len < 0) {
1091                         if (uwsgi_is_again()) goto wait2;
1092                         return -1;
1093                 }
1094 wait2:
1095                 ret = uwsgi.wait_read_hook(fd, timeout);
1096                 if (ret > 0) {
1097                         len = read(fd, ptr, remains);
1098                         if (len > 0) goto readok2;
1099                 }
1100                 return -1;
1101 readok2:
1102                 ptr += len;
1103                 remains -= len;
1104                 continue;
1105         }
1106 
1107 	return 0;
1108 
1109 }
1110 
1111 /*
1112 
1113 	this is a commodity (big) function to send a buffer and wsgi_req body to a socket
1114 	and to receive back data (and send them to the client)
1115 
1116 */
1117 
uwsgi_proxy_nb(struct wsgi_request * wsgi_req,char * addr,struct uwsgi_buffer * ub,size_t remains,int timeout)1118 int uwsgi_proxy_nb(struct wsgi_request *wsgi_req, char *addr, struct uwsgi_buffer *ub, size_t remains, int timeout) {
1119 
1120 	struct uwsgi_buffer *headers = NULL;
1121 
1122 	if (!ub) {
1123 		return -1;
1124 	}
1125 
1126 	int fd = uwsgi_connect(addr, 0, 1);
1127 	if (fd < 0) {
1128 		return -1;
1129 	}
1130 
1131 	int ret = uwsgi.wait_write_hook(fd, timeout);
1132 	if (ret <= 0) {
1133 		goto end;
1134 	}
1135 
1136 	// send the request (+ remaining data)
1137 	if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) {
1138 		goto end;
1139 	}
1140 
1141 	// send the body
1142 	while(remains > 0) {
1143 		ssize_t rlen = 0;
1144 		char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
1145 		if (!buf) {
1146 			goto end;
1147 		}
1148 		if (buf == uwsgi.empty) break;
1149 		// write data to the node
1150 		if (uwsgi_write_true_nb(fd, buf, rlen, timeout)) {
1151 			goto end;
1152 		}
1153 		remains -= rlen;
1154 	}
1155 
1156 	// read the response
1157 	headers = uwsgi_buffer_new(8192);
1158 	// max 64k headers
1159 	ub->limit = UMAX16;
1160 	for(;;) {
1161 		char buf[8192];
1162 		ssize_t rlen = uwsgi_read_true_nb(fd, buf, 8192, timeout);
1163 		if (rlen > 0) {
1164 			if (headers) {
1165 				if (uwsgi_buffer_append(headers, buf, rlen)) {
1166 					goto end;
1167 				}
1168 				// check if we have a full HTTP response
1169 				if (uwsgi_is_full_http(headers)) {
1170 					int ret = uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos);
1171 					if (ret) continue;
1172 					uwsgi_buffer_destroy(headers);
1173 					headers = NULL;
1174 				}
1175 			}
1176 			else {
1177 				if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
1178 					break;
1179 				}
1180 			}
1181 			continue;
1182 		}
1183 		break;
1184 	}
1185 	if (headers) uwsgi_buffer_destroy(headers);
1186 
1187 	close(fd);
1188 	return 0;
1189 end:
1190 	if (headers) uwsgi_buffer_destroy(headers);
1191 	close(fd);
1192 	return -1;
1193 }
1194 
uwsgi_file_write_do(struct uwsgi_string_list * usl)1195 void uwsgi_file_write_do(struct uwsgi_string_list *usl) {
1196 
1197 	struct uwsgi_string_list *fl = usl;
1198 	while(fl) {
1199 		char *equal = strchr(fl->value, '=');
1200 		if (equal) {
1201 			*equal = 0;
1202 			FILE *f = fopen(fl->value, "w");
1203 			if (!f) {
1204 				uwsgi_error_open("uwsgi_file_write_do()");
1205 				exit(1);
1206 			}
1207 			uwsgi_log("writing \"%s\" to \"%s\" ...\n", equal+1, fl->value);
1208 			if (fprintf(f, "%s\n", equal+1) <= 0 || ferror(f) || fclose(f)) {
1209 				uwsgi_error("uwsgi_file_write_do()");
1210 				exit(1);
1211 			}
1212 		}
1213 		else {
1214 			uwsgi_log("unable to write empty value for \"%s\"\n", fl->value);
1215 			exit(1);
1216 		}
1217 		*equal = '=';
1218 		fl = fl->next;
1219 	}
1220 }
1221 
uwsgi_fd_is_safe(int fd)1222 int uwsgi_fd_is_safe(int fd) {
1223 	int i;
1224 	for(i=0;i<uwsgi.safe_fds_cnt;i++) {
1225 		if (uwsgi.safe_fds[i] == fd) {
1226 			return 1;
1227 		}
1228 	}
1229 	return 0;
1230 }
uwsgi_add_safe_fd(int fd)1231 void uwsgi_add_safe_fd(int fd) {
1232 	// check if the fd is already safe
1233 	if (uwsgi_fd_is_safe(fd)) return;
1234 
1235 	size_t len = sizeof(int) * (uwsgi.safe_fds_cnt+1);
1236 	int *tmp = realloc(uwsgi.safe_fds, len);
1237 	if (!tmp) {
1238 		uwsgi_error("uwsgi_add_safe_fd()/realloc()");
1239 		exit(1);
1240 	}
1241 	uwsgi.safe_fds = tmp;
1242 	uwsgi.safe_fds[uwsgi.safe_fds_cnt] = fd;
1243 	uwsgi.safe_fds_cnt++;
1244 }
1245 
uwsgi_is_again()1246 int uwsgi_is_again() {
1247 	if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
1248 		return 1;
1249 	}
1250 	return 0;
1251 }
1252 
uwsgi_disconnect(struct wsgi_request * wsgi_req)1253 void uwsgi_disconnect(struct wsgi_request *wsgi_req) {
1254 	if (wsgi_req->socket) {
1255                 wsgi_req->socket->proto_close(wsgi_req);
1256         }
1257         wsgi_req->fd_closed = 1;
1258 }
1259 
uwsgi_ready_fd(struct wsgi_request * wsgi_req)1260 int uwsgi_ready_fd(struct wsgi_request *wsgi_req) {
1261 	if (wsgi_req->async_ready_fd) return wsgi_req->async_last_ready_fd;
1262 	return -1;
1263 }
1264 
uwsgi_setup_schemes()1265 void uwsgi_setup_schemes() {
1266 	uwsgi_register_scheme("emperor", uwsgi_scheme_emperor);
1267 	uwsgi_register_scheme("http", uwsgi_scheme_http);
1268 	uwsgi_register_scheme("data", uwsgi_scheme_data);
1269 	uwsgi_register_scheme("sym", uwsgi_scheme_sym);
1270 	uwsgi_register_scheme("section", uwsgi_scheme_section);
1271 	uwsgi_register_scheme("fd", uwsgi_scheme_fd);
1272 	uwsgi_register_scheme("exec", uwsgi_scheme_exec);
1273 	uwsgi_register_scheme("call", uwsgi_scheme_call);
1274 	uwsgi_register_scheme("callint", uwsgi_scheme_callint);
1275 }
1276 
uwsgi_check_scheme(char * file)1277 struct uwsgi_string_list *uwsgi_check_scheme(char *file) {
1278 	struct uwsgi_string_list *usl;
1279 	uwsgi_foreach(usl, uwsgi.schemes) {
1280 		char *url = uwsgi_concat2(usl->value, "://");
1281 		int ret = uwsgi_startswith(file, url, strlen(url));
1282 		free(url);
1283 		if (!ret) return usl;
1284 	}
1285 	return NULL;
1286 }
1287 
uwsgi_remap_fd(int fd,char * filename)1288 void uwsgi_remap_fd(int fd, char *filename) {
1289 
1290 	int fdin = open(filename, O_RDWR);
1291         if (fdin < 0) {
1292                 uwsgi_error_open(filename);
1293                 exit(1);
1294         }
1295 
1296         /* stdin */
1297         if (fdin != fd) {
1298                 if (dup2(fdin, fd) < 0) {
1299                         uwsgi_error("uwsgi_remap_fd()/dup2()");
1300                         exit(1);
1301                 }
1302                 close(fdin);
1303         }
1304 }
1305 
uwsgi_is_connected(int fd)1306 int uwsgi_is_connected(int fd) {
1307 	int soopt;
1308         socklen_t solen = sizeof(int);
1309 
1310         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
1311 		return 0;
1312         }
1313         /* is something bad ? */
1314         if (soopt) return 0;
1315 	return 1;
1316 }
1317 
1318 
uwsgi_pass_cred(int fd,char * code,size_t code_len)1319 int uwsgi_pass_cred(int fd, char *code, size_t code_len) {
1320 #ifdef SCM_CREDENTIALS
1321 	struct msghdr cr_msg;
1322         struct cmsghdr *cmsg;
1323         struct iovec cr_iov;
1324         void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1325 
1326         cr_iov.iov_base = code;
1327         cr_iov.iov_len = code_len;
1328 
1329         cr_msg.msg_name = NULL;
1330         cr_msg.msg_namelen = 0;
1331 
1332         cr_msg.msg_iov = &cr_iov;
1333         cr_msg.msg_iovlen = 1;
1334 
1335         cr_msg.msg_flags = 0;
1336         cr_msg.msg_control = cr_msg_control;
1337         cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1338 
1339         cmsg = CMSG_FIRSTHDR(&cr_msg);
1340         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
1341         cmsg->cmsg_level = SOL_SOCKET;
1342         cmsg->cmsg_type = SCM_CREDENTIALS;
1343 
1344         struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
1345 	u->pid = getpid();
1346 	u->uid = getuid();
1347 	u->gid = getgid();
1348 
1349         if (sendmsg(fd, &cr_msg, 0) < 0) {
1350                 uwsgi_error("uwsgi_pass_cred()/sendmsg()");
1351         	free(cr_msg_control);
1352 		return -1;
1353         }
1354 
1355         free(cr_msg_control);
1356 	return 0;
1357 #else
1358 	return -1;
1359 #endif
1360 }
1361 
uwsgi_pass_cred2(int fd,char * code,size_t code_len,struct sockaddr * addr,size_t addr_len)1362 int uwsgi_pass_cred2(int fd, char *code, size_t code_len, struct sockaddr *addr, size_t addr_len) {
1363 #ifdef SCM_CREDENTIALS
1364         struct msghdr cr_msg;
1365         struct cmsghdr *cmsg;
1366         struct iovec cr_iov;
1367         void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1368 
1369         cr_iov.iov_base = code;
1370         cr_iov.iov_len = code_len;
1371 
1372         cr_msg.msg_name = addr;
1373         cr_msg.msg_namelen = addr_len;
1374 
1375         cr_msg.msg_iov = &cr_iov;
1376         cr_msg.msg_iovlen = 1;
1377 
1378         cr_msg.msg_flags = 0;
1379         cr_msg.msg_control = cr_msg_control;
1380         cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1381 
1382         cmsg = CMSG_FIRSTHDR(&cr_msg);
1383         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
1384         cmsg->cmsg_level = SOL_SOCKET;
1385         cmsg->cmsg_type = SCM_CREDENTIALS;
1386 
1387         struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
1388         u->pid = getpid();
1389         u->uid = getuid();
1390         u->gid = getgid();
1391 
1392         if (sendmsg(fd, &cr_msg, 0) < 0) {
1393                 uwsgi_error("uwsgi_pass_cred2()/sendmsg()");
1394                 free(cr_msg_control);
1395                 return -1;
1396         }
1397 
1398         free(cr_msg_control);
1399         return 0;
1400 #else
1401         return -1;
1402 #endif
1403 }
1404 
1405 
uwsgi_recv_cred(int fd,char * code,size_t code_len,pid_t * pid,uid_t * uid,gid_t * gid)1406 int uwsgi_recv_cred(int fd, char *code, size_t code_len, pid_t *pid, uid_t *uid, gid_t *gid) {
1407 #ifdef SCM_CREDENTIALS
1408         struct iovec iov;
1409 	int ret = -1;
1410 
1411         void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1412 
1413         iov.iov_base = uwsgi_malloc(code_len);
1414         iov.iov_len = code_len;
1415 
1416 	struct msghdr msg;
1417         memset(&msg, 0, sizeof(msg));
1418 
1419         msg.msg_name = NULL;
1420         msg.msg_namelen = 0;
1421 
1422         msg.msg_iov = &iov;
1423         msg.msg_iovlen = 1;
1424 
1425         msg.msg_control = msg_control;
1426         msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1427 
1428         ssize_t len = recvmsg(fd, &msg, 0);
1429 	if (len <= 0) {
1430 		uwsgi_error("uwsgi_recv_cred()/recvmsg()");
1431 		goto clear;
1432 	}
1433 
1434 	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
1435 	if (!cmsg) goto clear;
1436 
1437 	if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
1438 		goto clear;
1439         }
1440 
1441 	if (uwsgi_strncmp(code, code_len, iov.iov_base, iov.iov_len)) goto clear;
1442 
1443 	struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
1444 	*pid = u->pid;
1445 	*uid = u->uid;
1446 	*gid = u->gid;
1447 	ret = 0;
1448 
1449 clear:
1450 	free(msg_control);
1451 	free(iov.iov_base);
1452 	return ret;
1453 #else
1454 	return -1;
1455 #endif
1456 }
1457 
uwsgi_recv_cred2(int fd,char * buf,size_t buf_len,pid_t * pid,uid_t * uid,gid_t * gid)1458 ssize_t uwsgi_recv_cred2(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid) {
1459 #ifdef SCM_CREDENTIALS
1460         struct iovec iov;
1461         ssize_t ret = -1;
1462 
1463         void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1464 
1465         iov.iov_base = buf;
1466         iov.iov_len = buf_len;
1467 
1468         struct msghdr msg;
1469         memset(&msg, 0, sizeof(msg));
1470 
1471         msg.msg_name = NULL;
1472         msg.msg_namelen = 0;
1473 
1474         msg.msg_iov = &iov;
1475         msg.msg_iovlen = 1;
1476 
1477         msg.msg_control = msg_control;
1478         msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1479 
1480         ssize_t len = recvmsg(fd, &msg, 0);
1481         if (len <= 0) {
1482                 uwsgi_error("uwsgi_recv_cred2()/recvmsg()");
1483                 goto clear;
1484         }
1485 
1486         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
1487         if (!cmsg) goto clear;
1488 
1489         if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
1490                 goto clear;
1491         }
1492 
1493         struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
1494         *pid = u->pid;
1495         *uid = u->uid;
1496         *gid = u->gid;
1497         ret = len;
1498 
1499 clear:
1500         free(msg_control);
1501         return ret;
1502 #else
1503         return -1;
1504 #endif
1505 }
1506 
1507