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