# Backport of PHP 4.3.8 security patches to 4.3.7

- Thread: https://externals.io/message/11244
- Original archive: https://news-web.php.net/php.internals/11244
- Started by Albert Chin on 2004-07-14T21:12:47+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #11244 — Albert Chin — 2004-07-14T21:12:47+00:00

URL: https://externals.io/message/11244#11244

Is the following patch correct in addressing the security fixes from
4.3.8 for 4.3.7?

-- 
albert chin (china@thewrittenword.com)

-- snip snip
--- ext/wddx/wddx.c.orig	2003-10-20 10:42:10.000000000 -0500
+++ ext/wddx/wddx.c	2004-07-14 14:26:30.978747000 -0500
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: wddx.c,v 1.96.2.5 2003/10/20 15:42:10 moriyoshi Exp $ */
+/* $Id: wddx.c,v 1.96.2.5.2.1 2004/07/13 13:15:30 iliaa Exp $ */
 
 #include "php.h"
 #include "php_wddx.h"
@@ -1069,7 +1069,7 @@
 			case ST_DATETIME: {
 				char *tmp;
 
-				tmp = do_alloca(len + 1);
+				tmp = emalloc(len + 1);
 				memcpy(tmp, s, len);
 				tmp[len] = '\0';
 
@@ -1080,7 +1080,7 @@
 					Z_STRLEN_P(ent->data) = len;
 					Z_STRVAL_P(ent->data) = estrndup(s, len);
 				}
-				free_alloca(tmp);
+				efree(tmp);
 			}
 			default:
 				break;
--- ext/pcntl/pcntl.c.orig	2004-01-23 01:02:54.000000000 -0600
+++ ext/pcntl/pcntl.c	2004-07-14 14:24:51.154535000 -0500
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: pcntl.c,v 1.28.4.4 2004/01/23 07:02:54 sniper Exp $ */
+/* $Id: pcntl.c,v 1.28.4.4.2.1 2004/07/13 13:15:29 iliaa Exp $ */
 
 #define PCNTL_DEBUG 0
 
@@ -386,7 +386,7 @@
 		args_hash = HASH_OF(args);
 		argc = zend_hash_num_elements(args_hash);
 		
-		argv = alloca((argc+2) * sizeof(char *));
+		argv = safe_emalloc((argc + 2), sizeof(char *), 0);
 		*argv = path;
 		for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1; 
 			(argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
@@ -397,7 +397,7 @@
 		}
 		*(current_arg) = NULL;
 	} else {
-		argv = alloca(2 * sizeof(char *));
+		argv = emalloc(2 * sizeof(char *));
 		*argv = path;
 		*(argv+1) = NULL;
 	}
@@ -407,13 +407,13 @@
 		envs_hash = HASH_OF(envs);
 		envc = zend_hash_num_elements(envs_hash);
 		
-		envp = alloca((envc+1) * sizeof(char *));
+		envp = safe_emalloc((envc + 1), sizeof(char *), 0);
 		for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp; 
 			(envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
 			(envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
 			switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
 				case HASH_KEY_IS_LONG:
-					key = alloca(101);
+					key = emalloc(101);
 					snprintf(key, 100, "%ld", key_num);
 					key_length = strlen(key);
 					break;
@@ -432,7 +432,7 @@
 			strlcat(*pair, Z_STRVAL_PP(element), pair_length);
 			
 			/* Cleanup */
-			if (return_val == HASH_KEY_IS_LONG) free_alloca(key);
+			if (return_val == HASH_KEY_IS_LONG) efree(key);
 		}
 		*(pair) = NULL;
 	}
@@ -445,10 +445,10 @@
 	/* Cleanup */
 	if (envp != NULL) {
 		for (pair = envp; *pair != NULL; pair++) efree(*pair);
-		free_alloca(envp);
+		efree(envp);
 	}
 
-	free_alloca(argv);
+	efree(argv);
 	
 	RETURN_FALSE;
 }
--- ext/session/mod_mm.c.orig	2002-12-31 10:35:20.000000000 -0600
+++ ext/session/mod_mm.c	2004-07-14 14:25:03.384703000 -0500
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: mod_mm.c,v 1.39.4.3 2002/12/31 16:35:20 sebastian Exp $ */
+/* $Id: mod_mm.c,v 1.39.4.3.2.1 2004/07/13 13:15:29 iliaa Exp $ */
 
 #include "php.h"
 
@@ -264,7 +264,7 @@
 		return FAILURE;
 		
     /* Directory + '/' + File + Module Name + Effective UID + \0 */	
-	ps_mm_path = do_alloca(save_path_len+1+sizeof(PS_MM_FILE)+mod_name_len+strlen(euid)+1);
+	ps_mm_path = emalloc(save_path_len+1+sizeof(PS_MM_FILE)+mod_name_len+strlen(euid)+1);
 	
 	memcpy(ps_mm_path, PS(save_path), save_path_len + 1);
 	if (save_path_len > 0 && ps_mm_path[save_path_len - 1] != DEFAULT_SLASH) {
@@ -277,7 +277,7 @@
 	
 	ret = ps_mm_initialize(ps_mm_instance, ps_mm_path);
 		
-	free_alloca(ps_mm_path);
+	efree(ps_mm_path);
    
 	if (ret != SUCCESS) {
 		free(ps_mm_instance);
--- ext/session/session.c.orig	2004-05-08 01:01:11.000000000 -0500
+++ ext/session/session.c	2004-07-14 14:25:25.099784000 -0500
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: session.c,v 1.336.2.39 2004/05/08 06:01:11 pollita Exp $ */
+/* $Id: session.c,v 1.336.2.39.2.1 2004/07/13 13:15:29 iliaa Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -503,13 +503,16 @@
 
 static void php_session_track_init(TSRMLS_D)
 {
+	zval *session_vars = NULL;
+	
 	/* Unconditionally destroy existing arrays -- possible dirty data */
 	zend_hash_del(&EG(symbol_table), "HTTP_SESSION_VARS", 
 			sizeof("HTTP_SESSION_VARS"));
 	zend_hash_del(&EG(symbol_table), "_SESSION", sizeof("_SESSION"));
 
-	MAKE_STD_ZVAL(PS(http_session_vars));
-	array_init(PS(http_session_vars));
+	MAKE_STD_ZVAL(session_vars);
+	array_init(session_vars);
+	PS(http_session_vars) = session_vars;
 
 	ZEND_SET_GLOBAL_VAR_WITH_LENGTH("HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS"), PS(http_session_vars), 2, 1);
 	ZEND_SET_GLOBAL_VAR_WITH_LENGTH("_SESSION", sizeof("_SESSION"), PS(http_session_vars), 2, 1);
--- ext/standard/ftok.c.orig	2002-12-31 10:35:28.000000000 -0600
+++ ext/standard/ftok.c	2004-07-14 14:25:37.603235000 -0500
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: ftok.c,v 1.9.2.1 2002/12/31 16:35:28 sebastian Exp $ */
+/* $Id: ftok.c,v 1.9.2.1.2.1 2004/07/13 13:15:29 iliaa Exp $ */
 
 #include "php.h"
 
@@ -52,6 +52,10 @@
         RETURN_LONG(-1);
     }
 
+	if ((PG(safe_mode) && (!php_checkuid(Z_STRVAL_PP(pathname), NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(Z_STRVAL_PP(pathname) TSRMLS_CC)) {
+		RETURN_LONG(-1);
+	}
+
     k = ftok(Z_STRVAL_PP(pathname),Z_STRVAL_PP(proj)[0]);
 
     RETURN_LONG(k);
--- ext/standard/iptc.c.orig	2004-03-06 11:41:31.000000000 -0600
+++ ext/standard/iptc.c	2004-07-14 14:25:46.707062000 -0500
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: iptc.c,v 1.41.4.3 2004/03/06 17:41:31 pajoye Exp $ */
+/* $Id: iptc.c,v 1.41.4.3.2.1 2004/07/13 13:15:29 iliaa Exp $ */
 
 /*
  * Functions to parse & compse IPTC data.
@@ -208,6 +208,10 @@
         break;
     }
 
+    if (PG(safe_mode) && (!php_checkuid(Z_STRVAL_PP(jpeg_file), NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+		RETURN_FALSE;
+	}
+
     if (php_check_open_basedir(Z_STRVAL_PP(jpeg_file) TSRMLS_CC)) {
 		RETURN_FALSE;
 	}
@@ -347,7 +351,7 @@
 			inx += 2;
 		}
 
-		sprintf(key, "%d#%03d", (unsigned int) dataset, (unsigned int) recnum);
+		snprintf(key, sizeof(key), "%d#%03d", (unsigned int) dataset, (unsigned int) recnum);
 
 		if ((len > length) || (inx + len) > length)
 			break;
--- ext/standard/string.c.orig	2004-05-13 12:44:32.000000000 -0500
+++ ext/standard/string.c	2004-07-14 14:25:56.776113000 -0500
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: string.c,v 1.333.2.39 2004/05/13 17:44:32 iliaa Exp $ */
+/* $Id: string.c,v 1.333.2.39.2.1 2004/07/13 13:15:30 iliaa Exp $ */
 
 /* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */
 
@@ -3339,6 +3339,8 @@
 
 	while (i < len) {
 		switch (c) {
+			case '\0':
+				break;
 			case '<':
 				if (isspace(*(p + 1))) {
 					goto reg_char;
--- ext/msession/msession.c.orig	2002-12-31 10:34:56.000000000 -0600
+++ ext/msession/msession.c	2004-07-14 14:24:12.365918000 -0500
@@ -1266,7 +1266,7 @@
 {
 	int port;
 	int len = strlen(save_path)+1;
-	char * path = alloca(len);
+	char * path = emalloc(len);
 	char * szport;
 
 	strcpy(path, save_path);
@@ -1285,7 +1285,13 @@
 	
 	ELOG( "ps_open_msession");
 	PS_SET_MOD_DATA((void *)1); /* session.c needs a non-zero here! */
-	return PHPMsessionConnect(path, port) ? SUCCESS : FAILURE;
+	if (PHPMsessionConnect(path, port)) {
+		efree(path);
+		return SUCCESS;
+	} else {
+		efree(path);
+		return FAILURE;
+	}
 }
 
 PS_CLOSE_FUNC(msession)
--- Zend/zend_alloc.c.orig	2004-05-17 08:15:14.000000000 -0500
+++ Zend/zend_alloc.c	2004-07-14 14:04:34.989754000 -0500
@@ -67,7 +67,7 @@
 #define _CHECK_MEMORY_LIMIT(s, rs, file, lineno) { AG(allocated_memory) += rs;\
 								if (AG(memory_limit)<AG(allocated_memory)) {\
 									int php_mem_limit = AG(memory_limit); \
-									if (AG(memory_limit)+1048576 > AG(allocated_memory) - rs) { \
+									if (EG(in_execution) && AG(memory_limit)+1048576 > AG(allocated_memory) - rs) { \
 										AG(memory_limit) = AG(allocated_memory) + 1048576; \
 										if (file) { \
 											zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes)", php_mem_limit, file, lineno, s); \
--- Zend/zend_constants.c.orig	2004-05-26 16:02:12.000000000 -0500
+++ Zend/zend_constants.c	2004-07-14 14:22:51.435252000 -0500
@@ -220,8 +220,7 @@
 	int retval = 1;
 
 	if (zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c) == FAILURE) {
-		lookup_name = do_alloca(name_len+1);
-		memcpy(lookup_name, name, name_len+1);
+		lookup_name = estrndup(name, name_len);
 		zend_str_tolower(lookup_name, name_len);
 
 		if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) {
@@ -231,7 +230,7 @@
 		} else {
 			retval=0;
 		}
-		free_alloca(lookup_name);
+		efree(lookup_name);
 	}
 
 	if (retval) {
@@ -256,8 +255,7 @@
 #endif
 
 	if (!(c->flags & CONST_CS)) {
-		lowercase_name = do_alloca(c->name_len);
-		memcpy(lowercase_name, c->name, c->name_len);
+		lowercase_name = estrndup(c->name, c->name_len);
 		zend_str_tolower(lowercase_name, c->name_len);
 		name = lowercase_name;
 	} else {
@@ -273,7 +271,7 @@
 		ret = FAILURE;
 	}
 	if (lowercase_name) {
-		free_alloca(lowercase_name);
+		efree(lowercase_name);
 	}
 	return ret;
 }
--- Zend/zend_execute.c.orig	2004-04-01 16:05:38.000000000 -0600
+++ Zend/zend_execute.c	2004-07-14 14:23:01.665848000 -0500
@@ -1038,7 +1038,7 @@
 	EX(ce) = NULL;
 	EX(object).ptr = NULL;
 	EX(op_array) = op_array;
-	EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable)*op_array->T);
+	EX(Ts) = (temp_variable *) safe_emalloc(sizeof(temp_variable), op_array->T, 0);
 	EX(prev_execute_data) = EG(current_execute_data);
 	EX(original_in_execution)=EG(in_execution);
 
@@ -1757,7 +1757,7 @@
 							(*EG(return_value_ptr_ptr))->is_ref = 0;
 						}
 					}
-					free_alloca(EX(Ts));
+					efree(EX(Ts));
 					EG(in_execution) = EX(original_in_execution);
 					EG(current_execute_data) = EX(prev_execute_data);
 					return;
--- Zend/zend_hash.c.orig	2003-08-12 01:22:05.000000000 -0500
+++ Zend/zend_hash.c	2004-07-14 14:23:22.659337000 -0500
@@ -174,6 +174,7 @@
 ZEND_API int zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, int persistent)
 {
 	uint i = 3;
+	Bucket **tmp;
 
 	SET_INCONSISTENT(HT_OK);
 
@@ -183,14 +184,6 @@
 
 	ht->nTableSize = 1 << i;
 	ht->nTableMask = ht->nTableSize - 1;
-
-	/* Uses ecalloc() so that Bucket* == `NULL` */
-	ht->arBuckets = (Bucket **) pecalloc(ht->nTableSize, sizeof(Bucket *), persistent);
-
-	if (!ht->arBuckets) {
-		return FAILURE;
-	}
-
 	ht->pDestructor = pDestructor;
 	ht->pListHead = NULL;
 	ht->pListTail = NULL;
@@ -200,6 +193,16 @@
 	ht->persistent = persistent;
 	ht->nApplyCount = 0;
 	ht->bApplyProtection = 1;
+	ht->arBuckets = NULL;
+
+	/* Uses ecalloc() so that Bucket* == `NULL` */
+	tmp = (Bucket **) pecalloc(ht->nTableSize, sizeof(Bucket *), persistent);
+
+	if (!tmp) {
+		return FAILURE;
+	}
+	ht->arBuckets = tmp;
+
 	return SUCCESS;
 }
 
--- Zend/zend_variables.c.orig	2002-12-31 10:23:05.000000000 -0600
+++ Zend/zend_variables.c	2004-07-14 14:23:38.185102000 -0500
@@ -114,27 +114,31 @@
 		case IS_CONSTANT_ARRAY: {
 				zval *tmp;
 				HashTable *original_ht = zvalue->value.ht;
+				HashTable *tmp_ht = NULL;
 				TSRMLS_FETCH();
 
 				if (zvalue->value.ht == &EG(symbol_table)) {
 					return SUCCESS; /* do nothing */
 				}
-				ALLOC_HASHTABLE_REL(zvalue->value.ht);
-				zend_hash_init(zvalue->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
-				zend_hash_copy(zvalue->value.ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+				ALLOC_HASHTABLE_REL(tmp_ht);
+				zend_hash_init(tmp_ht, 0, NULL, ZVAL_PTR_DTOR, 0);
+				zend_hash_copy(tmp_ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+				zvalue->value.ht = tmp_ht;
 			}
 			break;
 		case IS_OBJECT: {
 				zval *tmp;
 				HashTable *original_ht = zvalue->value.obj.properties;
+				HashTable *tmp_ht = NULL;
 				TSRMLS_FETCH();
 
 				if (zvalue->value.obj.properties == &EG(symbol_table)) {
 					return SUCCESS; /* do nothing */
 				}
-				ALLOC_HASHTABLE_REL(zvalue->value.obj.properties);
-				zend_hash_init(zvalue->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
-				zend_hash_copy(zvalue->value.obj.properties, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+				ALLOC_HASHTABLE_REL(tmp_ht);
+				zend_hash_init(tmp_ht, 0, NULL, ZVAL_PTR_DTOR, 0);
+				zend_hash_copy(tmp_ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+				zvalue->value.obj.properties = tmp_ht;
 			}
 			break;
 	}
--- main/main.c.orig	2004-02-08 22:05:56.000000000 -0600
+++ main/main.c	2004-07-14 14:27:05.913272000 -0500
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: main.c,v 1.512.2.53 2004/02/09 04:05:56 iliaa Exp $ */
+/* $Id: main.c,v 1.512.2.53.2.1 2004/07/13 13:15:31 iliaa Exp $ */
 
 /* {{{ includes
  */
@@ -1369,6 +1369,7 @@
 	int _gpc_flags[5] = {0, 0, 0, 0, 0};
 	zend_bool have_variables_order;
 	zval *dummy_track_vars_array = NULL;
+	zval *env_vars = NULL;
 	zend_bool initialized_dummy_track_vars_array=0;
 	int i;
 	char *variables_order;
@@ -1401,9 +1402,10 @@
 	} else {
 		variables_order = PG(gpc_order);
 		have_variables_order=0;
-		ALLOC_ZVAL(PG(http_globals)[TRACK_VARS_ENV]);
-		array_init(PG(http_globals)[TRACK_VARS_ENV]);
-		INIT_PZVAL(PG(http_globals)[TRACK_VARS_ENV]);
+		ALLOC_ZVAL(env_vars);
+		array_init(env_vars);
+		INIT_PZVAL(env_vars);
+		PG(http_globals)[TRACK_VARS_ENV] = env_vars;
 		php_import_environment_variables(PG(http_globals)[TRACK_VARS_ENV] TSRMLS_CC);
 		if (PG(register_globals)) {
 			php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV]) TSRMLS_CC);
@@ -1446,9 +1448,10 @@
 			case 'E':
 				if (!_gpc_flags[3]) {
 					if (have_variables_order) {
-						ALLOC_ZVAL(PG(http_globals)[TRACK_VARS_ENV]);
-						array_init(PG(http_globals)[TRACK_VARS_ENV]);
-						INIT_PZVAL(PG(http_globals)[TRACK_VARS_ENV]);
+						ALLOC_ZVAL(env_vars);
+						array_init(env_vars);
+						INIT_PZVAL(env_vars);
+						PG(http_globals)[TRACK_VARS_ENV] = env_vars;
 						php_import_environment_variables(PG(http_globals)[TRACK_VARS_ENV] TSRMLS_CC);
 						if (PG(register_globals)) {
 							php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV]) TSRMLS_CC);
--- main/rfc1867.c.orig	2004-05-23 05:15:24.000000000 -0500
+++ main/rfc1867.c	2004-07-14 14:27:24.097730000 -0500
@@ -16,7 +16,7 @@
    |          Jani Taskinen <sniper@php.net>                              |
    +----------------------------------------------------------------------+
  */
-/* $Id: rfc1867.c,v 1.122.2.21 2004/05/23 10:15:24 sesser Exp $ */
+/* $Id: rfc1867.c,v 1.122.2.21.2.1 2004/07/13 13:15:31 iliaa Exp $ */
 
 /*
  *  This product includes software developed by the Apache Group
@@ -760,7 +760,7 @@
 	char *boundary, *s=NULL, *boundary_end = NULL, *start_arr=NULL, *array_index=NULL;
 	char *temp_filename=NULL, *lbuf=NULL, *abuf=NULL;
 	int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0, max_file_size=0, skip_upload=0;
-	zval *http_post_files=NULL;
+	zval *http_post_files=NULL; HashTable *uploaded_files=NULL;
 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
 	int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
 	char **val_list = NULL;
@@ -811,8 +811,9 @@
 	/* Initialize $_FILES[] */
 	zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
 
-	ALLOC_HASHTABLE(SG(rfc1867_uploaded_files));
-	zend_hash_init(SG(rfc1867_uploaded_files), 5, NULL, (dtor_func_t) free_estring, 0);
+	ALLOC_HASHTABLE(uploaded_files);
+	zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
+	SG(rfc1867_uploaded_files) = uploaded_files;
 
 	ALLOC_ZVAL(http_post_files);
 	array_init(http_post_files);

---

## #11249 — Derick Rethans — 2004-07-15T09:55:33+00:00

URL: https://externals.io/message/11244#11249 · In reply to: #11244

> Is the following patch correct in addressing the security fixes from
> 4.3.8 for 4.3.7?

Why would you want to do this? 4.3.8 is exactly 4.3.7 + all the security
patches. Backporting makes absolutely no sense as you'd be re-creating
4.3.8.

Derick

---

## #11257 — Albert Chin — 2004-07-15T11:38:13+00:00

URL: https://externals.io/message/11244#11257 · In reply to: #11249

> 
> 
> > […]
> 
> Why would you want to do this? 4.3.8 is exactly 4.3.7 + all the security
> patches. Backporting makes absolutely no sense as you'd be re-creating
> 4.3.8.

Depends on how you've built PHP. We install PHP into a separate
directory for each version, to make testing new versions less painful.
Backporting the fixes means less work for those currently running
4.3.7.

-- 
albert chin (china@thewrittenword.com)
