xref: /PHP-7.0/sapi/fpm/fpm/fpm_php.c (revision 7aa76271)
1 
2 	/* $Id: fpm_php.c,v 1.22.2.4 2008/12/13 03:21:18 anight Exp $ */
3 	/* (c) 2007,2008 Andrei Nigmatulin */
4 
5 #include "fpm_config.h"
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 
11 #include "php.h"
12 #include "php_main.h"
13 #include "php_ini.h"
14 #include "ext/standard/dl.h"
15 
16 #include "fastcgi.h"
17 
18 #include "fpm.h"
19 #include "fpm_php.h"
20 #include "fpm_cleanup.h"
21 #include "fpm_worker_pool.h"
22 #include "zlog.h"
23 
24 static char **limit_extensions = NULL;
25 
fpm_php_zend_ini_alter_master(char * name,int name_length,char * new_value,int new_value_length,int mode,int stage)26 static int fpm_php_zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int mode, int stage) /* {{{ */
27 {
28 	zend_ini_entry *ini_entry;
29 	zend_string *duplicate;
30 
31 	if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length)) == NULL) {
32 		return FAILURE;
33 	}
34 
35 	duplicate = zend_string_init(new_value, new_value_length, 1);
36 
37 	if (!ini_entry->on_modify
38 			|| ini_entry->on_modify(ini_entry, duplicate,
39 				ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage) == SUCCESS) {
40 		ini_entry->value = duplicate;
41 		ini_entry->modifiable = mode;
42 	} else {
43 		zend_string_release(duplicate);
44 	}
45 
46 	return SUCCESS;
47 }
48 /* }}} */
49 
fpm_php_disable(char * value,int (* zend_disable)(char *,size_t))50 static void fpm_php_disable(char *value, int (*zend_disable)(char *, size_t)) /* {{{ */
51 {
52 	char *s = 0, *e = value;
53 
54 	while (*e) {
55 		switch (*e) {
56 			case ' ':
57 			case ',':
58 				if (s) {
59 					*e = '\0';
60 					zend_disable(s, e - s);
61 					s = 0;
62 				}
63 				break;
64 			default:
65 				if (!s) {
66 					s = e;
67 				}
68 				break;
69 		}
70 		e++;
71 	}
72 
73 	if (s) {
74 		zend_disable(s, e - s);
75 	}
76 }
77 /* }}} */
78 
fpm_php_apply_defines_ex(struct key_value_s * kv,int mode)79 int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */
80 {
81 
82 	char *name = kv->key;
83 	char *value = kv->value;
84 	int name_len = strlen(name);
85 	int value_len = strlen(value);
86 
87 	if (!strcmp(name, "extension") && *value) {
88 		zval zv;
89 		php_dl(value, MODULE_PERSISTENT, &zv, 1);
90 		return Z_TYPE(zv) == IS_TRUE;
91 	}
92 
93 	if (fpm_php_zend_ini_alter_master(name, name_len, value, value_len, mode, PHP_INI_STAGE_ACTIVATE) == FAILURE) {
94 		return -1;
95 	}
96 
97 	if (!strcmp(name, "disable_functions") && *value) {
98 		char *v = strdup(value);
99 		PG(disable_functions) = v;
100 		fpm_php_disable(v, zend_disable_function);
101 		return 1;
102 	}
103 
104 	if (!strcmp(name, "disable_classes") && *value) {
105 		char *v = strdup(value);
106 		PG(disable_classes) = v;
107 		fpm_php_disable(v, zend_disable_class);
108 		return 1;
109 	}
110 
111 	return 1;
112 }
113 /* }}} */
114 
fpm_php_apply_defines(struct fpm_worker_pool_s * wp)115 static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp) /* {{{ */
116 {
117 	struct key_value_s *kv;
118 
119 	for (kv = wp->config->php_values; kv; kv = kv->next) {
120 		if (fpm_php_apply_defines_ex(kv, ZEND_INI_USER) == -1) {
121 			zlog(ZLOG_ERROR, "Unable to set php_value '%s'", kv->key);
122 		}
123 	}
124 
125 	for (kv = wp->config->php_admin_values; kv; kv = kv->next) {
126 		if (fpm_php_apply_defines_ex(kv, ZEND_INI_SYSTEM) == -1) {
127 			zlog(ZLOG_ERROR, "Unable to set php_admin_value '%s'", kv->key);
128 		}
129 	}
130 
131 	return 0;
132 }
133 /* }}} */
134 
fpm_php_set_allowed_clients(struct fpm_worker_pool_s * wp)135 static int fpm_php_set_allowed_clients(struct fpm_worker_pool_s *wp) /* {{{ */
136 {
137 	if (wp->listen_address_domain == FPM_AF_INET) {
138 		fcgi_set_allowed_clients(wp->config->listen_allowed_clients);
139 	}
140 	return 0;
141 }
142 /* }}} */
143 
144 #if 0 /* Comment out this non used function. It could be used later. */
145 static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp) /* {{{ */
146 {
147 	char max_workers[10 + 1]; /* 4294967295 */
148 	int len;
149 
150 	len = sprintf(max_workers, "%u", (unsigned int) wp->config->pm_max_children);
151 
152 	fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, max_workers, len);
153 	fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  max_workers, len);
154 	return 0;
155 }
156 /* }}} */
157 #endif
158 
fpm_php_script_filename(void)159 char *fpm_php_script_filename(void) /* {{{ */
160 {
161 	return SG(request_info).path_translated;
162 }
163 /* }}} */
164 
fpm_php_request_uri(void)165 char *fpm_php_request_uri(void) /* {{{ */
166 {
167 	return (char *) SG(request_info).request_uri;
168 }
169 /* }}} */
170 
fpm_php_request_method(void)171 char *fpm_php_request_method(void) /* {{{ */
172 {
173 	return (char *) SG(request_info).request_method;
174 }
175 /* }}} */
176 
fpm_php_query_string(void)177 char *fpm_php_query_string(void) /* {{{ */
178 {
179 	return SG(request_info).query_string;
180 }
181 /* }}} */
182 
fpm_php_auth_user(void)183 char *fpm_php_auth_user(void) /* {{{ */
184 {
185 	return SG(request_info).auth_user;
186 }
187 /* }}} */
188 
fpm_php_content_length(void)189 size_t fpm_php_content_length(void) /* {{{ */
190 {
191 	return SG(request_info).content_length;
192 }
193 /* }}} */
194 
fpm_php_cleanup(int which,void * arg)195 static void fpm_php_cleanup(int which, void *arg) /* {{{ */
196 {
197 	php_module_shutdown();
198 	sapi_shutdown();
199 }
200 /* }}} */
201 
fpm_php_soft_quit()202 void fpm_php_soft_quit() /* {{{ */
203 {
204 	fcgi_terminate();
205 }
206 /* }}} */
207 
fpm_php_init_main()208 int fpm_php_init_main() /* {{{ */
209 {
210 	if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT, fpm_php_cleanup, 0)) {
211 		return -1;
212 	}
213 	return 0;
214 }
215 /* }}} */
216 
fpm_php_init_child(struct fpm_worker_pool_s * wp)217 int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
218 {
219 	if (0 > fpm_php_apply_defines(wp) ||
220 		0 > fpm_php_set_allowed_clients(wp)) {
221 		return -1;
222 	}
223 
224 	if (wp->limit_extensions) {
225 		limit_extensions = wp->limit_extensions;
226 	}
227 	return 0;
228 }
229 /* }}} */
230 
fpm_php_limit_extensions(char * path)231 int fpm_php_limit_extensions(char *path) /* {{{ */
232 {
233 	char **p;
234 	size_t path_len;
235 
236 	if (!path || !limit_extensions) {
237 		return 0; /* allowed by default */
238 	}
239 
240 	p = limit_extensions;
241 	path_len = strlen(path);
242 	while (p && *p) {
243 		size_t ext_len = strlen(*p);
244 		if (path_len > ext_len) {
245 			char *path_ext = path + path_len - ext_len;
246 			if (strcmp(*p, path_ext) == 0) {
247 				return 0; /* allow as the extension has been found */
248 			}
249 		}
250 		p++;
251 	}
252 
253 
254 	zlog(ZLOG_NOTICE, "Access to the script '%s' has been denied (see security.limit_extensions)", path);
255 	return 1; /* extension not found: not allowed  */
256 }
257 /* }}} */
258 
fpm_php_get_string_from_table(zend_string * table,char * key)259 char* fpm_php_get_string_from_table(zend_string *table, char *key) /* {{{ */
260 {
261 	zval *data, *tmp;
262 	zend_string *str;
263 	if (!table || !key) {
264 		return NULL;
265 	}
266 
267 	/* inspired from ext/standard/info.c */
268 
269 	zend_is_auto_global(table);
270 
271 	/* find the table and ensure it's an array */
272 	data = zend_hash_find(&EG(symbol_table), table);
273 	if (!data || Z_TYPE_P(data) != IS_ARRAY) {
274 		return NULL;
275 	}
276 
277 	ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(data), str, tmp) {
278 		if (str && !strncmp(ZSTR_VAL(str), key, ZSTR_LEN(str))) {
279 			return Z_STRVAL_P(tmp);
280 		}
281 	} ZEND_HASH_FOREACH_END();
282 
283 	return NULL;
284 }
285 /* }}} */
286 
287