Browse code

authentication module - database support

Jan Janak authored on 06/03/2003 15:39:33
Showing 7 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,12 @@
1
+# $Id$
2
+#
3
+# Digest Authentication - Database support
4
+#
5
+# 
6
+# WARNING: do not run this directly, it should be run by the master Makefile
7
+
8
+auto_gen=
9
+NAME=auth_db.so
10
+LIBS=
11
+
12
+include ../../Makefile.modules
0 13
new file mode 100644
... ...
@@ -0,0 +1,211 @@
1
+/* 
2
+ * $Id$ 
3
+ *
4
+ * Digest Authentication Module
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ *
29
+ * History:
30
+ * --------
31
+ * 2003-02-26: checks and group moved to separate modules (janakj)
32
+ */
33
+
34
+#include <stdio.h>
35
+#include <string.h>
36
+#include "../../sr_module.h"
37
+#include "../../db/db.h"
38
+#include "../../dprint.h"
39
+#include "../../error.h"
40
+#include "authorize.h"
41
+#include "../auth/api.h"
42
+
43
+
44
+/*
45
+ * Module destroy function prototype
46
+ */
47
+static void destroy(void);
48
+
49
+
50
+/*
51
+ * Module child-init function prototype
52
+ */
53
+static int child_init(int rank);
54
+
55
+
56
+/*
57
+ * Module initialization function prototype
58
+ */
59
+static int mod_init(void);
60
+
61
+
62
+static int str_fixup(void** param, int param_no);
63
+
64
+
65
+pre_auth_f pre_auth_func = 0;
66
+post_auth_f post_auth_func = 0;
67
+
68
+/*
69
+ * Pointer to reply function in stateless module
70
+ */
71
+int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2);
72
+
73
+/*
74
+ * Module parameter variables
75
+ */
76
+char* db_url           = "sql://serro:47serro11@localhost/ser";
77
+char* username_column  = "username";
78
+char* domain_column    = "domain";
79
+char* pass_column      = "ha1";
80
+char* pass_column_2    = "ha1b";
81
+int   calc_ha1         = 0;
82
+
83
+db_con_t* db_handle;   /* Database connection handle */
84
+
85
+
86
+/*
87
+ * Module interface
88
+ */
89
+struct module_exports exports = {
90
+	"auth_db", 
91
+	(char*[]) { 
92
+		"www_authorize",
93
+		"proxy_authorize",
94
+	},
95
+	(cmd_function[]) {
96
+		www_authorize,
97
+		proxy_authorize,
98
+	},
99
+	(int[]) {2, 2},
100
+	(fixup_function[]) {
101
+		str_fixup, str_fixup
102
+	},
103
+	2,
104
+	
105
+	(char*[]) {
106
+		"db_url",              /* Database URL */
107
+		"username_column",     /* User column name */
108
+		"domain_column",       /* Domain column name */
109
+		"password_column",     /* HA1/password column name */
110
+		"password_column_2",
111
+		"calculate_ha1",       /* If set to yes, instead of ha1 value auth module will
112
+                                        * fetch plaintext password from database and calculate
113
+                                        * ha1 value itself */
114
+	},   /* Module parameter names */
115
+	(modparam_t[]) {
116
+		STR_PARAM,
117
+		STR_PARAM,
118
+		STR_PARAM,
119
+		STR_PARAM,
120
+		STR_PARAM,
121
+	        INT_PARAM
122
+	},   /* Module parameter types */
123
+	(void*[]) {
124
+		&db_url,
125
+		&username_column,
126
+		&domain_column,
127
+		&pass_column,
128
+		&pass_column_2,
129
+		&calc_ha1
130
+	},   /* Module parameter variable pointers */
131
+	6,          /* Numberof module parameters */
132
+	mod_init,   /* module initialization function */
133
+	0,          /* response function */
134
+	destroy,    /* destroy function */
135
+	0,          /* oncancel function */
136
+	child_init  /* child initialization function */
137
+};
138
+
139
+
140
+static int child_init(int rank)
141
+{
142
+	if (db_url == 0) {
143
+		LOG(L_ERR, "auth:init_child(): Use db_url parameter\n");
144
+		return -1;
145
+	}
146
+	db_handle = db_init(db_url);
147
+	if (!db_handle) {
148
+		LOG(L_ERR, "auth:init_child(): Unable to connect database\n");
149
+		return -1;
150
+	}
151
+	return 0;
152
+
153
+}
154
+
155
+
156
+static int mod_init(void)
157
+{
158
+	printf("auth module - initializing\n");
159
+	
160
+	     /* Find a database module */
161
+	if (bind_dbmod()) {
162
+		LOG(L_ERR, "mod_init(): Unable to bind database module\n");
163
+		return -1;
164
+	}
165
+
166
+	pre_auth_func = (pre_auth_f)find_export("~pre_auth", 0);
167
+	post_auth_func = (post_auth_f)find_export("~post_auth", 0);
168
+
169
+	if (!(pre_auth_func && post_auth_func)) {
170
+		LOG(L_ERR, "auth_db:mod_init(): This module requires auth module\n");
171
+		return -2;
172
+	}
173
+
174
+	sl_reply = find_export("sl_send_reply", 2);
175
+	if (!sl_reply) {
176
+		LOG(L_ERR, "auth_db:mod_init(): This module requires sl module\n");
177
+		return -2;
178
+	}
179
+
180
+	return 0;
181
+}
182
+
183
+
184
+
185
+static void destroy(void)
186
+{
187
+	db_close(db_handle);
188
+}
189
+
190
+
191
+/*
192
+ * Convert char* parameter to str* parameter
193
+ */
194
+static int str_fixup(void** param, int param_no)
195
+{
196
+	str* s;
197
+
198
+	if (param_no == 1) {
199
+		s = (str*)malloc(sizeof(str));
200
+		if (!s) {
201
+			LOG(L_ERR, "str_fixup(): No memory left\n");
202
+			return E_UNSPEC;
203
+		}
204
+
205
+		s->s = (char*)*param;
206
+		s->len = strlen(s->s);
207
+		*param = (void*)s;
208
+	}
209
+
210
+	return 0;
211
+}
0 212
new file mode 100644
... ...
@@ -0,0 +1,62 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Digest Authentication - Database support
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ */
29
+
30
+
31
+#ifndef AUTHDB_MOD_H
32
+#define AUTHDB_MOD_H
33
+
34
+#include "../../db/db.h"
35
+#include "../auth/api.h"
36
+#include "../../parser/msg_parser.h"
37
+
38
+
39
+/*
40
+ * Module parameters variables
41
+ */
42
+
43
+extern char* db_url;          /* Database URL */
44
+extern char* username_column; /* 'username' column name */
45
+extern char* domain_column;   /* 'domain' column name */
46
+extern char* pass_column;     /* 'password' column name */
47
+extern char* pass_column_2;   /* Column containg HA1 string constructed
48
+			       * of user@domain username
49
+			       */
50
+
51
+extern int calc_ha1;          /* if set to 1, ha1 is calculated by the server */
52
+extern db_con_t* db_handle;   /* Database connection handle */
53
+
54
+extern pre_auth_f pre_auth_func;
55
+extern post_auth_f post_auth_func;
56
+
57
+/*
58
+ * Pointer to reply function in stateless module
59
+ */
60
+extern int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2);
61
+
62
+#endif /* AUTHDB_MOD_H */
0 63
new file mode 100644
... ...
@@ -0,0 +1,238 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Digest Authentication - Database support
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ *
29
+ * history:
30
+ * ---------
31
+ * 2003-02-28 scratchpad compatibility abandoned
32
+ * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
33
+ */
34
+
35
+
36
+#include <string.h>
37
+#include "../../str.h"
38
+#include "../../db/db.h"
39
+#include "../../dprint.h"
40
+#include "../../parser/digest/digest.h"
41
+#include "../../parser/hf.h"
42
+#include "authdb_mod.h"
43
+#include "rfc2617.h"
44
+
45
+
46
+
47
+#define MESSAGE_500 "Server Internal Error"
48
+
49
+
50
+/*
51
+ * Get or calculate HA1 string, if calculate_ha1 is set, the function will
52
+ * simply fetch the string from the database, otherwise it will fetch plaintext
53
+ * password and will calculate the string
54
+ */
55
+static inline int get_ha1(str* _user, str* _realm, char* _table, char* _ha1)
56
+{
57
+	db_key_t keys[] = {username_column, domain_column};
58
+	db_val_t vals[2];
59
+	db_key_t col[] = {pass_column};
60
+	db_res_t* res;
61
+
62
+	str result;
63
+
64
+	char* at;
65
+
66
+	VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB_STR;
67
+	VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
68
+	
69
+	VAL_STR(vals) = *_user;
70
+	VAL_STR(vals + 1) = *_realm;
71
+
72
+	     /*
73
+	      * Some user agents put domain in the username, since we
74
+	      * have only usernames in database, remove domain part
75
+	      * if the server uses HA1 precalculated strings in the
76
+	      * database, then switch over to another column, which
77
+	      * contains HA1 strings calculated also with domain, the
78
+	      * original column contains HA1 strings calculated without
79
+	      * the domain part
80
+	      */
81
+	at = memchr(_user->s, '@', _user->len);
82
+	if (at) {
83
+		DBG("get_ha1(): @ found in username, removing domain part\n");
84
+		VAL_STR(vals).len = at - _user->s;
85
+		if (!calc_ha1) {
86
+			col[0] = pass_column_2;
87
+		}
88
+	}
89
+
90
+	     /* 
91
+	      * Query the database either for HA1 string or plaintext password,
92
+	      * it depends on calculate_ha1 variable value
93
+	      */
94
+	db_use_table(db_handle, _table);
95
+	if (db_query(db_handle, keys, 0, vals, col, 2, 1, 0, &res) < 0) {
96
+		LOG(L_ERR, "get_ha1(): Error while querying database\n");
97
+		return -1;
98
+	}
99
+
100
+	     /*
101
+	      * There is no such username in the database, return 1
102
+	      */
103
+	if (RES_ROW_N(res) == 0) {
104
+		DBG("get_ha1(): no result for user \'%.*s\'\n", _user->len, _user->s);
105
+		db_free_query(db_handle, res);
106
+		return 1;
107
+	}
108
+
109
+        result.s = (char*)ROW_VALUES(RES_ROWS(res))[0].val.string_val;
110
+	result.len = strlen(result.s);
111
+
112
+	     /*
113
+	      * If calculate_ha1 variable is set to true, calculate HA1 
114
+	      * string on the fly from username, realm and plaintext 
115
+	      * password obtained from the database and return the 
116
+	      * calculated HA1 string
117
+	      *
118
+	      * If calculate_ha1 is not set, we have the HA1 already,
119
+	      * just return it
120
+	      */
121
+	if (calc_ha1) {
122
+		     /* Only plaintext passwords are stored in database,
123
+		      * we have to calculate HA1 */
124
+		calc_HA1(HA_MD5, _user, _realm, &result, 0, 0, _ha1);
125
+		DBG("get_ha1(): HA1 string calculated: \'%s\'\n", _ha1);
126
+	} else {
127
+		memcpy(_ha1, result.s, result.len);
128
+		_ha1[result.len] = '\0';
129
+	}
130
+
131
+	db_free_query(db_handle, res);
132
+	return 0;
133
+}
134
+
135
+
136
+/*
137
+ * Calculate the response and compare with the given response string
138
+ * Authorization is successfull if this two strings are same
139
+ */
140
+static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
141
+{
142
+	HASHHEX resp, hent;
143
+
144
+	     /*
145
+	      * First, we have to verify that the response received has
146
+	      * the same length as responses created by us
147
+	      */
148
+	if (_cred->response.len != 32) {
149
+		DBG("check_response(): Receive response len != 32\n");
150
+		return 1;
151
+	}
152
+
153
+	     /*
154
+	      * Now, calculate our response from parameters received
155
+	      * from the user agent
156
+	      */
157
+	calc_response(_ha1, &(_cred->nonce), 
158
+		      &(_cred->nc), &(_cred->cnonce), 
159
+		      &(_cred->qop.qop_str), _cred->qop.qop_parsed == QOP_AUTHINT,
160
+		      _method, &(_cred->uri), hent, resp);
161
+	
162
+	DBG("check_response(): Our result = \'%s\'\n", resp);
163
+	
164
+	     /*
165
+	      * And simply compare the strings, the user is
166
+	      * authorized if they match
167
+	      */
168
+	if (!memcmp(resp, _cred->response.s, 32)) {
169
+		DBG("check_response(): Authorization is OK\n");
170
+		return 0;
171
+	} else {
172
+		DBG("check_response(): Authorization failed\n");
173
+		return 2;
174
+	}
175
+}
176
+
177
+
178
+/*
179
+ * Authorize digest credentials
180
+ */
181
+static inline int authorize(struct sip_msg* _m, str* _realm, char* _table, int _hftype)
182
+{
183
+	char ha1[256];
184
+	int res;
185
+	struct hdr_field* h;
186
+	auth_body_t* cred;
187
+	auth_result_t ret;
188
+
189
+	ret = pre_auth_func(_m, &_realm, _hftype, &h);
190
+	
191
+	switch(ret) {
192
+	case ERROR:            return 0;
193
+	case NOT_AUTHORIZED:   return -1;
194
+	case DO_AUTHORIZATION: break;
195
+	case AUTHORIZED:       return 1;
196
+	}
197
+
198
+	cred = (auth_body_t*)h->parsed;
199
+
200
+	res = get_ha1(&cred->digest.username.whole, _realm, _table, ha1);
201
+        if (res < 0) {
202
+		     /* Error while accessing the database */
203
+		if (sl_reply(_m, (char*)500, MESSAGE_500) == -1) {
204
+			LOG(L_ERR, "authorize(): Error while sending 500 reply\n");
205
+		}
206
+		return 0;
207
+	} else if (res > 0) {
208
+		     /* Username not found in the database */
209
+		return -1;
210
+	}
211
+
212
+	     /* Recalculate response, it must be same to authorize sucessfully */
213
+        if (!check_response(&(cred->digest), &_m->first_line.u.request.method, ha1)) {
214
+		ret = post_auth_func(_m, h);
215
+		if (ret == AUTHORIZED) return 1;
216
+	}
217
+
218
+	return -1;
219
+}
220
+
221
+
222
+/*
223
+ * Authorize using Proxy-Authorize header field
224
+ */
225
+int proxy_authorize(struct sip_msg* _m, char* _realm, char* _table)
226
+{
227
+	     /* realm parameter is converted to str* in str_fixup */
228
+	return authorize(_m, (str*)_realm, _table, HDR_PROXYAUTH);
229
+}
230
+
231
+
232
+/*
233
+ * Authorize using WWW-Authorize header field
234
+ */
235
+int www_authorize(struct sip_msg* _m, char* _realm, char* _table)
236
+{
237
+	return authorize(_m, (str*)_realm, _table, HDR_AUTHORIZATION);
238
+}
0 239
new file mode 100644
... ...
@@ -0,0 +1,50 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Digest Authentication - Database support
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ */
29
+
30
+
31
+#ifndef AUTHORIZE_H
32
+#define AUTHORIZE_H
33
+
34
+
35
+#include "../../parser/msg_parser.h"
36
+
37
+
38
+/*
39
+ * Authorize using Proxy-Authorization header field
40
+ */
41
+int proxy_authorize(struct sip_msg* _msg, char* _realm, char* _table);
42
+
43
+
44
+/*
45
+ * Authorize using WWW-Authorization header field
46
+ */
47
+int www_authorize(struct sip_msg* _msg, char* _realm, char* _table);
48
+
49
+
50
+#endif /* AUTHORIZE_H */
0 51
new file mode 100644
... ...
@@ -0,0 +1,148 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Digest response calculation as per RFC2617
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ */
29
+
30
+
31
+#include <sys/types.h>
32
+#include <stdlib.h>
33
+#include <string.h>
34
+
35
+#include "rfc2617.h"
36
+#include "../../md5global.h"
37
+#include "../../md5.h"
38
+
39
+
40
+inline void cvt_hex(HASH _b, HASHHEX _h)
41
+{
42
+	unsigned short i;
43
+	unsigned char j;
44
+	
45
+	for (i = 0; i < HASHLEN; i++) {
46
+		j = (_b[i] >> 4) & 0xf;
47
+		if (j <= 9) {
48
+			_h[i * 2] = (j + '0');
49
+		} else {
50
+			_h[i * 2] = (j + 'a' - 10);
51
+		}
52
+
53
+		j = _b[i] & 0xf;
54
+
55
+		if (j <= 9) {
56
+			_h[i * 2 + 1] = (j + '0');
57
+		} else {
58
+			_h[i * 2 + 1] = (j + 'a' - 10);
59
+		}
60
+	};
61
+
62
+	_h[HASHHEXLEN] = '\0';
63
+}
64
+
65
+
66
+/* 
67
+ * calculate H(A1) as per spec 
68
+ */
69
+void calc_HA1(ha_alg_t _alg, str* _username, str* _realm, str* _password,
70
+	      str* _nonce, str* _cnonce, HASHHEX _sess_key)
71
+{
72
+	MD5_CTX Md5Ctx;
73
+	HASH HA1;
74
+	
75
+	MD5Init(&Md5Ctx);
76
+	MD5Update(&Md5Ctx, _username->s, _username->len);
77
+	MD5Update(&Md5Ctx, ":", 1);
78
+	MD5Update(&Md5Ctx, _realm->s, _realm->len);
79
+	MD5Update(&Md5Ctx, ":", 1);
80
+	MD5Update(&Md5Ctx, _password->s, _password->len);
81
+	MD5Final(HA1, &Md5Ctx);
82
+
83
+	if (_alg == HA_MD5_SESS) {
84
+		MD5Init(&Md5Ctx);
85
+		MD5Update(&Md5Ctx, HA1, HASHLEN);
86
+		MD5Update(&Md5Ctx, ":", 1);
87
+		MD5Update(&Md5Ctx, _nonce->s, _nonce->len);
88
+		MD5Update(&Md5Ctx, ":", 1);
89
+		MD5Update(&Md5Ctx, _cnonce->s, _cnonce->len);
90
+		MD5Final(HA1, &Md5Ctx);
91
+	};
92
+
93
+	cvt_hex(HA1, _sess_key);
94
+}
95
+
96
+
97
+/* 
98
+ * calculate request-digest/response-digest as per HTTP Digest spec 
99
+ */
100
+void calc_response(HASHHEX _ha1,      /* H(A1) */
101
+		   str* _nonce,       /* nonce from server */
102
+		   str* _nc,          /* 8 hex digits */
103
+		   str* _cnonce,      /* client nonce */
104
+		   str* _qop,         /* qop-value: "", "auth", "auth-int" */
105
+		   int _auth_int,     /* 1 if auth-int is used */
106
+		   str* _method,      /* method from the request */
107
+		   str* _uri,         /* requested URL */
108
+		   HASHHEX _hentity,  /* H(entity body) if qop="auth-int" */
109
+		   HASHHEX _response) /* request-digest or response-digest */
110
+{
111
+	MD5_CTX Md5Ctx;
112
+	HASH HA2;
113
+	HASH RespHash;
114
+	HASHHEX HA2Hex;
115
+	
116
+	     /* calculate H(A2) */
117
+	MD5Init(&Md5Ctx);
118
+	MD5Update(&Md5Ctx, _method->s, _method->len);
119
+	MD5Update(&Md5Ctx, ":", 1);
120
+	MD5Update(&Md5Ctx, _uri->s, _uri->len);
121
+
122
+	if (_auth_int) {
123
+		MD5Update(&Md5Ctx, ":", 1);
124
+		MD5Update(&Md5Ctx, _hentity, HASHHEXLEN);
125
+	};
126
+
127
+	MD5Final(HA2, &Md5Ctx);
128
+	cvt_hex(HA2, HA2Hex);
129
+	
130
+	     /* calculate response */
131
+	MD5Init(&Md5Ctx);
132
+	MD5Update(&Md5Ctx, _ha1, HASHHEXLEN);
133
+	MD5Update(&Md5Ctx, ":", 1);
134
+	MD5Update(&Md5Ctx, _nonce->s, _nonce->len);
135
+	MD5Update(&Md5Ctx, ":", 1);
136
+
137
+	if (_qop->len) {
138
+		MD5Update(&Md5Ctx, _nc->s, _nc->len);
139
+		MD5Update(&Md5Ctx, ":", 1);
140
+		MD5Update(&Md5Ctx, _cnonce->s, _cnonce->len);
141
+		MD5Update(&Md5Ctx, ":", 1);
142
+		MD5Update(&Md5Ctx, _qop->s, _qop->len);
143
+		MD5Update(&Md5Ctx, ":", 1);
144
+	};
145
+	MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
146
+	MD5Final(RespHash, &Md5Ctx);
147
+	cvt_hex(RespHash, _response);
148
+}
0 149
new file mode 100644
... ...
@@ -0,0 +1,85 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Digest response calculation as per RFC2617
5
+ *
6
+ * Copyright (C) 2001-2003 Fhg Fokus
7
+ *
8
+ * This file is part of ser, a free SIP server.
9
+ *
10
+ * ser is free software; you can redistribute it and/or modify
11
+ * it under the terms of the GNU General Public License as published by
12
+ * the Free Software Foundation; either version 2 of the License, or
13
+ * (at your option) any later version
14
+ *
15
+ * For a license to use the ser software under conditions
16
+ * other than those described here, or to purchase support for this
17
+ * software, please contact iptel.org by e-mail at the following addresses:
18
+ *    info@iptel.org
19
+ *
20
+ * ser is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License 
26
+ * along with this program; if not, write to the Free Software 
27
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
+ */
29
+
30
+
31
+#ifndef RFC2617_H
32
+#define RFC2617_H
33
+
34
+#include "../../str.h"
35
+
36
+
37
+#define HASHLEN 16
38
+typedef char HASH[HASHLEN];
39
+
40
+
41
+#define HASHHEXLEN 32
42
+typedef char HASHHEX[HASHHEXLEN+1];
43
+
44
+
45
+/*
46
+ * Type of algorithm used
47
+ */
48
+typedef enum {
49
+	HA_MD5,      /* Plain MD5 */
50
+	HA_MD5_SESS, /* MD5-Session */
51
+} ha_alg_t;
52
+
53
+
54
+/*
55
+ * Convert to hex form
56
+ */
57
+void cvt_hex(HASH Bin, HASHHEX Hex);
58
+
59
+
60
+/* 
61
+ * calculate H(A1) as per HTTP Digest spec 
62
+ */
63
+void calc_HA1(ha_alg_t _alg,      /* Type of algorithm */
64
+	      str* _username,     /* username */
65
+	      str* _realm,        /* realm */
66
+	      str* _password,     /* password */
67
+	      str* _nonce,        /* nonce string */
68
+	      str* _cnonce,       /* cnonce */
69
+	      HASHHEX _sess_key); /* Result will be stored here */
70
+
71
+
72
+/* calculate request-digest/response-digest as per HTTP Digest spec */
73
+void calc_response(HASHHEX _ha1,       /* H(A1) */
74
+		   str* _nonce,        /* nonce from server */
75
+		   str* _nc,           /* 8 hex digits */
76
+		   str* _cnonce,       /* client nonce */
77
+		   str* _qop,          /* qop-value: "", "auth", "auth-int" */
78
+		   int _auth_int,      /* 1 if auth-int is used */
79
+		   str* _method,       /* method from the request */
80
+		   str* _uri,          /* requested URL */
81
+		   HASHHEX _hentity,   /* H(entity body) if qop="auth-int" */
82
+		   HASHHEX _response); /* request-digest or response-digest */
83
+
84
+
85
+#endif /* RFC2617_H */