Project

General

Profile

Feature #752 » lighttp-1.4.18-r2-mysql_auth.patch

patch for lighttpd 1.4.18 - include fix sql injection & md5 crypt() -- drJeckyll - Anonymous, 2008-03-13 06:25

View differences:

lighttpd-1.4.18-patched/src/Makefile.in 2008-01-06 22:44:47.000000000 +0200
708
mod_auth_la_LIBADD = $(CRYPT_LIB) $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
708
mod_auth_la_LIBADD = $(MYSQL_LIBS) $(CRYPT_LIB) $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
lighttpd-1.4.18-patched/src/http_auth.c 2008-01-06 22:18:40.000000000 +0200
25 25
#include <unistd.h>
26 26
#include <ctype.h>
27
#include <mysql/mysql.h>
28

  
27 29
#include "server.h"
28 30
#include "log.h"
29 31
#include "http_auth.h"
......
287 289
		stream_close(&f);
288 290
	} else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
289 291
		ret = 0;
292
	} else if (p->conf.auth_backend == AUTH_BACKEND_MYSQL) {
293
		MYSQL_RES *result;
294
		MYSQL_ROW row;
295
		int port = atoi(p->conf.auth_mysql_port->ptr);
296
		char q[255];
297

  
298
		if (p->conf.auth_mysql_socket->ptr != NULL)
299
		    if (0 == strcmp(p->conf.auth_mysql_socket->ptr, "")) p->conf.auth_mysql_socket->ptr = NULL;
300

  
301
		p->conf.mysql_conn = mysql_init(NULL);
302

  
303
		if (mysql_real_connect(p->conf.mysql_conn, p->conf.auth_mysql_host->ptr, p->conf.auth_mysql_user->ptr, p->conf.auth_mysql_pass->ptr, p->conf.auth_mysql_db->ptr, port, p->conf.auth_mysql_socket->ptr, 0))
304
		{
305
//#define MY_HOSTING
306

  
307
#ifdef MY_HOSTING
308
		    char my_full_realm[255];
309
		    char *my_realm = NULL;
310
		    char *my_domain = NULL;
311

  
312
		    char *uname;
313
		    size_t unamelen;
314

  
315
		    unamelen = strlen(username->ptr);
316
		    uname = malloc(unamelen*2+1);
317

  
318
		    mysql_real_escape_string(p->conf.mysql_conn,
319
					     uname, username->ptr,
320
					     (unsigned long)unamelen);
321

  
322
		    strcpy(my_full_realm, realm->ptr);
323
		    my_realm = strtok(my_full_realm, "@");
324

  
325
		    if (my_realm != NULL)
326
		    my_domain = strtok(NULL, "@");
327

  
328
		    sprintf(q, "SELECT %s FROM %s, %s WHERE %s='%s' AND %s='%s' AND %s='%s' AND %s=%s",
329
				p->conf.auth_mysql_col_pass->ptr,
330

  
331
				p->conf.auth_mysql_users_table->ptr,
332
				p->conf.auth_mysql_domains_table->ptr,
333

  
334
				p->conf.auth_mysql_col_user->ptr,
335
				uname,
336

  
337
				p->conf.auth_mysql_col_realm->ptr,
338
				my_realm,
339

  
340
				p->conf.auth_mysql_col_domain->ptr,
341
				my_domain,
342

  
343
				p->conf.auth_mysql_domains_table_col_domain_id->ptr,
344
				p->conf.auth_mysql_users_table_col_domain_id->ptr
345
		    );
346

  
347
		    free(uname);
348
#else
349
		    // sanitize username & realm by taguchi@ff.iij4u.or.jp
350
		    char *uname, *urealm;
351
		    size_t unamelen, urealmlen;
352

  
353
		    unamelen = strlen(username->ptr);
354
		    urealmlen = strlen(realm->ptr);
355
		    uname = malloc(unamelen*2+1);
356
		    urealm = malloc(urealmlen*2+1);
357

  
358
		    mysql_real_escape_string(p->conf.mysql_conn,
359
					     uname, username->ptr,
360
					     (unsigned long)unamelen);
361

  
362
		    mysql_real_escape_string(p->conf.mysql_conn,
363
					     urealm, realm->ptr,
364
					     (unsigned long)urealmlen);
365

  
366
		    sprintf(q, "SELECT %s FROM %s WHERE %s='%s' AND %s='%s'",
367
				p->conf.auth_mysql_col_pass->ptr,
368
				p->conf.auth_mysql_users_table->ptr,
369
				p->conf.auth_mysql_col_user->ptr,
370
				uname,
371
				p->conf.auth_mysql_col_realm->ptr,
372
				urealm
373
		    );
374

  
375
		    free(uname);
376
		    free(urealm);
377
#endif
378

  
379
		    mysql_query(p->conf.mysql_conn, q);
380
		    result = mysql_store_result(p->conf.mysql_conn);
381
		    if (mysql_num_rows(result) == 1)
382
		    {
383
			/* found */
384
			row = mysql_fetch_row(result);
385
			buffer_copy_string_len(password, row[0], strlen(row[0]));
386

  
387
			ret = 0;
388
		    } else
389
		    {
390
			/* not found */
391
			ret = -1;
392
		    }
393

  
394
		    mysql_free_result(result);
395
		    mysql_close(p->conf.mysql_conn);
396

  
397
		    p->conf.mysql_conn = NULL;
398
		}
290 399
	} else {
291 400
		return -1;
292 401
	}
......
816 893
		return 0;
817 894
#endif
895
	} else if (p->conf.auth_backend == AUTH_BACKEND_MYSQL) {
896
		/*
897
		    we check for md5 crypt() now
898
		    request by Nicola Tiling <nti@w4w.net>
899
		*/
900
		if (password->ptr[0] == '$' && password->ptr[2] == '$')
901
		{
902
		    char salt[32];
903
		    char *crypted;
904
		    size_t salt_len = 0;
905
		    char *dollar = NULL;
906

  
907
		    if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
908
			fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
909
			return -1;
910
		    }
911

  
912
		    salt_len = dollar - password->ptr;
913

  
914
		    if (salt_len > sizeof(salt) - 1)
915
		    {
916
			fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
917
			return -1;
918
		    }
919

  
920
		    strncpy(salt, password->ptr, salt_len);
921

  
922
		    salt[salt_len] = '\0';
923

  
924
		    crypted = crypt(pw, salt);
925

  
926
		    if (0 == strcmp(password->ptr, crypted))
927
		    {
928
			return 0;
929
		    } else {
930
			fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
931
		    }
932
		} else
933
		/* plain md5 check now */
934
		{
935
			MD5_CTX Md5Ctx;
936
			HASH HA1;
937
			char a1[256];
938

  
939
			MD5_Init(&Md5Ctx);
940
			MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
941
			MD5_Final(HA1, &Md5Ctx);
942

  
943
			CvtHex(HA1, a1);
944

  
945
			if (0 == strcmp(password->ptr, a1)) {
946
				return 0;
947
			}
948
	    	}
818 949
	}
819 950
	return -1;
820 951
}
lighttpd-1.4.18-patched/src/http_auth.h 2008-01-06 22:20:44.000000000 +0200
9 9
# include <ldap.h>
10 10
#endif
11
#include <mysql/mysql.h>
12

  
11 13
typedef enum {
12 14
	AUTH_BACKEND_UNSET,
13 15
	AUTH_BACKEND_PLAIN,
14 16
	AUTH_BACKEND_LDAP,
15 17
	AUTH_BACKEND_HTPASSWD,
16
	AUTH_BACKEND_HTDIGEST
18
	AUTH_BACKEND_HTDIGEST,
19
	AUTH_BACKEND_MYSQL
17 20
} auth_backend_t;
18 21
typedef struct {
......
49 52
	buffer *ldap_filter_pre;
50 53
	buffer *ldap_filter_post;
51 54
#endif
55

  
56
	MYSQL  *mysql_conn;
57
	buffer *auth_mysql_host;
58
	buffer *auth_mysql_user;
59
	buffer *auth_mysql_pass;
60
	buffer *auth_mysql_db;
61
	buffer *auth_mysql_port;
62
	buffer *auth_mysql_socket;
63
	buffer *auth_mysql_users_table;
64
	buffer *auth_mysql_col_user;
65
	buffer *auth_mysql_col_pass;
66
	buffer *auth_mysql_col_realm;
67
	buffer *auth_mysql_domains_table;
68
	buffer *auth_mysql_col_domain;
69
	buffer *auth_mysql_domains_table_col_domain_id;
70
	buffer *auth_mysql_users_table_col_domain_id;
52 71
} mod_auth_plugin_config;
53 72
typedef struct {
lighttpd-1.4.18-patched/src/mod_auth.c 2008-01-06 22:28:35.000000000 +0200
7 7
#include <fcntl.h>
8 8
#include <unistd.h>
9
#include <mysql/mysql.h>
10

  
9 11
#include "plugin.h"
10 12
#include "http_auth.h"
11 13
#include "log.h"
......
83 85
			if (s->ldap) ldap_unbind_s(s->ldap);
84 86
#endif
87
			buffer_free(s->auth_mysql_host);
88
			buffer_free(s->auth_mysql_user);
89
			buffer_free(s->auth_mysql_pass);
90
			buffer_free(s->auth_mysql_db);
91
			buffer_free(s->auth_mysql_socket);
92
			buffer_free(s->auth_mysql_users_table);
93
			buffer_free(s->auth_mysql_col_user);
94
			buffer_free(s->auth_mysql_col_pass);
95
			buffer_free(s->auth_mysql_col_realm);
96
			buffer_free(s->auth_mysql_domains_table);
97
			buffer_free(s->auth_mysql_col_domain);
98
			buffer_free(s->auth_mysql_domains_table_col_domain_id);
99
			buffer_free(s->auth_mysql_users_table_col_domain_id);
100

  
85 101
			free(s);
86 102
		}
87 103
		free(p->config_storage);
......
120 136
	PATCH(ldap_filter_post);
121 137
#endif
138
	PATCH(auth_mysql_host);
139
	PATCH(auth_mysql_user);
140
	PATCH(auth_mysql_pass);
141
	PATCH(auth_mysql_db);
142
	PATCH(auth_mysql_port);
143
	PATCH(auth_mysql_socket);
144
	PATCH(auth_mysql_users_table);
145
	PATCH(auth_mysql_col_user);
146
	PATCH(auth_mysql_col_pass);
147
	PATCH(auth_mysql_col_realm);
148
	PATCH(auth_mysql_domains_table);
149
	PATCH(auth_mysql_col_domain);
150
	PATCH(auth_mysql_domains_table_col_domain_id);
151
	PATCH(auth_mysql_users_table_col_domain_id);
152

  
122 153
	/* skip the first, the global context */
123 154
	for (i = 1; i < srv->config_context->used; i++) {
124 155
		data_config *dc = (data_config *)srv->config_context->data[i];
......
163 194
				PATCH(auth_ldap_starttls);
164 195
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) {
165 196
				PATCH(auth_ldap_allow_empty_pw);
197
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.host"))) {
198
				PATCH(auth_mysql_host);
199
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.user"))) {
200
				PATCH(auth_mysql_user);
201
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.pass"))) {
202
				PATCH(auth_mysql_pass);
203
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.db"))) {
204
				PATCH(auth_mysql_db);
205
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.port"))) {
206
				PATCH(auth_mysql_port);
207
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.socket"))) {
208
				PATCH(auth_mysql_user);
209
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.users_table"))) {
210
				PATCH(auth_mysql_users_table);
211
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_user"))) {
212
				PATCH(auth_mysql_col_user);
213
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_pass"))) {
214
				PATCH(auth_mysql_col_pass);
215
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_realm"))) {
216
				PATCH(auth_mysql_col_realm);
217
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.domains_table"))) {
218
				PATCH(auth_mysql_domains_table);
219
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.col_domain"))) {
220
				PATCH(auth_mysql_col_domain);
221
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.domains_table_col_domain_id"))) {
222
				PATCH(auth_mysql_domains_table_col_domain_id);
223
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.mysql.users_table_col_domain_id"))) {
224
				PATCH(auth_mysql_users_table_col_domain_id);
166 225
			}
167 226
		}
168 227
	}
......
315 374
		{ "auth.backend.ldap.starttls",     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
316 375
 		{ "auth.backend.ldap.bind-dn",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
317 376
 		{ "auth.backend.ldap.bind-pw",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
318
		{ "auth.backend.ldap.allow-empty-pw",     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
377
		{ "auth.backend.ldap.allow-empty-pw",     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
319 378
		{ "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
320 379
		{ "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
321 380
		{ "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 13 */
381
		{ "auth.backend.mysql.host",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
382
		{ "auth.backend.mysql.user",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
383
		{ "auth.backend.mysql.pass",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
384
		{ "auth.backend.mysql.db",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
385
		{ "auth.backend.mysql.port",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
386
		{ "auth.backend.mysql.socket",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
387
		{ "auth.backend.mysql.users_table", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
388
		{ "auth.backend.mysql.col_user",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
389
		{ "auth.backend.mysql.col_pass",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
390
		{ "auth.backend.mysql.col_realm",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 23 */
391
		{ "auth.backend.mysql.domains_table",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
392
		{ "auth.backend.mysql.col_domain",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
393
		{ "auth.backend.mysql.domains_table_col_domain_id", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
394
		{ "auth.backend.mysql.users_table_col_domain_id",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
322 395
		{ NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
323 396
	};
......
348 421
		s->auth_require = array_init();
422
		s->mysql_conn                             = NULL;
423
		s->auth_mysql_host                        = buffer_init();
424
		s->auth_mysql_user                        = buffer_init();
425
		s->auth_mysql_pass                        = buffer_init();
426
		s->auth_mysql_db                          = buffer_init();
427
		s->auth_mysql_port                        = buffer_init();
428
		s->auth_mysql_socket                      = buffer_init();
429
		s->auth_mysql_users_table                 = buffer_init();
430
		s->auth_mysql_col_user                    = buffer_init();
431
		s->auth_mysql_col_pass                    = buffer_init();
432
		s->auth_mysql_col_realm                   = buffer_init();
433
		s->auth_mysql_domains_table               = buffer_init();
434
		s->auth_mysql_col_domain                  = buffer_init();
435
		s->auth_mysql_domains_table_col_domain_id = buffer_init();
436
		s->auth_mysql_users_table_col_domain_id   = buffer_init();
437

  
349 438
#ifdef USE_LDAP
350 439
		s->ldap_filter_pre = buffer_init();
351 440
		s->ldap_filter_post = buffer_init();
......
369 458
		cv[12].destination = s->auth_htdigest_userfile;
370 459
		cv[13].destination = s->auth_htpasswd_userfile;
371 460
		cv[14].destination = &(s->auth_debug);
461
		cv[15].destination = s->auth_mysql_host;
462
		cv[16].destination = s->auth_mysql_user;
463
		cv[17].destination = s->auth_mysql_pass;
464
		cv[18].destination = s->auth_mysql_db;
465
		cv[19].destination = s->auth_mysql_port;
466
		cv[20].destination = s->auth_mysql_socket;
467
		cv[21].destination = s->auth_mysql_users_table;
468
		cv[22].destination = s->auth_mysql_col_user;
469
		cv[23].destination = s->auth_mysql_col_pass;
470
		cv[24].destination = s->auth_mysql_col_realm;
471
		cv[25].destination = s->auth_mysql_domains_table;
472
		cv[26].destination = s->auth_mysql_col_domain;
473
		cv[27].destination = s->auth_mysql_domains_table_col_domain_id;
474
		cv[28].destination = s->auth_mysql_users_table_col_domain_id;
372 475
		p->config_storage[i] = s;
373 476
		ca = ((data_config *)srv->config_context->data[i])->value;
......
386 489
				s->auth_backend = AUTH_BACKEND_PLAIN;
387 490
			} else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
388 491
				s->auth_backend = AUTH_BACKEND_LDAP;
492
			} else if (0 == strcmp(s->auth_backend_conf->ptr, "mysql")) {
493
				s->auth_backend = AUTH_BACKEND_MYSQL;
389 494
			} else {
390 495
				log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
......
509 614
				return (ret);
510 615
                        break;
511 616
		}
617
		case AUTH_BACKEND_MYSQL: {
618
			int port = atoi(s->auth_mysql_port->ptr);
619

  
620
			if (p->conf.auth_mysql_socket->ptr != NULL)
621
			    if (0 == strcmp(s->auth_mysql_socket->ptr, "")) s->auth_mysql_socket->ptr = NULL;
622

  
623
			s->mysql_conn = mysql_init(NULL);
624
			if (!mysql_real_connect(s->mysql_conn, s->auth_mysql_host->ptr, s->auth_mysql_user->ptr, s->auth_mysql_pass->ptr, s->auth_mysql_db->ptr, port, NULL, 0))
625
			{
626
			    log_error_write(srv, __FILE__, __LINE__, "sbsbsbsbss",
627
				"opening connection to mysql:", s->auth_mysql_host,
628
				"user:", s->auth_mysql_user,
629
				"pass:", s->auth_mysql_pass,
630
				"db:", s->auth_mysql_db,
631
				"failed:", strerror(errno));
632

  
633
			    return HANDLER_ERROR;
634
			}
635
			mysql_close(s->mysql_conn);
636

  
637
			break;
638
		}
512 639
                default:
513 640
                        break;
514 641
                }
(2-2/4)