Browse code

Update version of auth module

Jan Janak authored on 09/08/2002 11:17:14
Showing 18 changed files
... ...
@@ -1,5 +1,7 @@
1 1
 /* 
2 2
  * $Id$ 
3
+ *
4
+ * Digest Authentication Module
3 5
  */
4 6
 
5 7
 #include "auth_mod.h"
... ...
@@ -8,11 +10,12 @@
8 10
 #include "../../dprint.h"
9 11
 #include "defs.h"
10 12
 #include <string.h>
11
-#include "auth.h"
12 13
 #include "checks.h"
13 14
 #include "group.h"
14 15
 #include "../../ut.h"
15 16
 #include "../../error.h"
17
+#include "authorize.h"
18
+#include "challenge.h"
16 19
 
17 20
 
18 21
 /*
... ...
@@ -34,6 +37,7 @@ static int mod_init(void);
34 37
 
35 38
 
36 39
 static int challenge_fixup(void** param, int param_no);
40
+static int str_fixup(void** param, int param_no);
37 41
 
38 42
 
39 43
 /*
... ...
@@ -46,7 +50,7 @@ int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2);
46 50
  * Module parameter variables
47 51
  */
48 52
 char* db_url       = "sql://janakj:heslo@localhost/ser";
49
-char* user_column  = "user_id";
53
+char* user_column  = "user";
50 54
 char* realm_column = "realm";
51 55
 char* pass_column  = "ha1";
52 56
 
... ...
@@ -83,7 +87,9 @@ struct module_exports exports = {
83 87
 		"is_user",
84 88
 		"is_in_group",
85 89
 		"check_to",
86
-		"check_from"
90
+		"check_from",
91
+		"consume_credentials",
92
+		"is_user_in"
87 93
 	},
88 94
 	(cmd_function[]) {
89 95
 		www_authorize,
... ...
@@ -93,13 +99,18 @@ struct module_exports exports = {
93 99
 		is_user,
94 100
 		is_in_group,
95 101
 		check_to,
96
-		check_from
102
+		check_from,
103
+		consume_credentials,
104
+		is_user_in,
97 105
 	},
98
-	(int[]) {2, 2, 2, 2, 1, 1, 0, 0},
106
+	(int[]) {2, 2, 2, 2, 1, 1, 0, 0, 0, 1},
99 107
 	(fixup_function[]) {
100
-		NULL, NULL, challenge_fixup, challenge_fixup, NULL, NULL, NULL, NULL
108
+		str_fixup, str_fixup, 
109
+		challenge_fixup, challenge_fixup, 
110
+		str_fixup, str_fixup, 0, 0,
111
+		0, str_fixup
101 112
 	},
102
-	8,
113
+	9,
103 114
 	
104 115
 	(char*[]) {
105 116
 		"db_url",              /* Database URL */
... ...
@@ -237,3 +248,26 @@ static int challenge_fixup(void** param, int param_no)
237 248
 
238 249
 	return 0;
239 250
 }
251
+
252
+
253
+/*
254
+ * Convert char* parameter to str* parameter
255
+ */
256
+static int str_fixup(void** param, int param_no)
257
+{
258
+	str* s;
259
+
260
+	if (param_no == 1) {
261
+		s = (str*)malloc(sizeof(str));
262
+		if (!s) {
263
+			LOG(L_ERR, "authorize_fixup(): No memory left\n");
264
+			return E_UNSPEC;
265
+		}
266
+
267
+		s->s = (char*)*param;
268
+		s->len = strlen(s->s);
269
+		*param = (void*)s;
270
+	}
271
+
272
+	return 0;
273
+}
... ...
@@ -1,13 +1,18 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Digest Authentication Module
3 5
  */
4 6
 
5
-#ifndef auth_mod_h
6
-#define auth_mod_h
7
+#ifndef AUTH_MOD_H
8
+#define AUTH_MOD_H
7 9
 
8 10
 #include "../../db/db.h"
9 11
 #include "defs.h"
10 12
 #include "../../str.h"
13
+#include "../../parser/digest/digest.h" /* auth_body_t */
14
+#include "../../parser/msg_parser.h"    /* struct sip_msg */
15
+
11 16
 
12 17
 /*
13 18
  * Module parameters variables
... ...
@@ -19,7 +24,9 @@ extern char* realm_column;  /* 'realm' column name */
19 24
 extern char* pass_column;   /* 'password' column name */
20 25
 
21 26
 #ifdef USER_DOMAIN_HACK
22
-extern char* pass_column_2;
27
+extern char* pass_column_2; /* Column containg HA1 string constructed
28
+			     * of user@domain username
29
+			     */
23 30
 #endif
24 31
 
25 32
 extern str secret;          /* secret phrase used to generate nonce */
... ...
@@ -32,4 +39,9 @@ extern int retry_count;     /* How many time a client can retry */
32 39
  
33 40
 extern db_con_t* db_handle; /* Database connection handle */
34 41
 
35
-#endif
42
+
43
+/* Stateless reply function pointer */
44
+extern int (*sl_reply)(struct sip_msg* _m, char* _str1, char* _str2);
45
+
46
+
47
+#endif /* AUTH_MOD_H */
36 48
new file mode 100644
... ...
@@ -0,0 +1,321 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Authorize related functions
5
+ */
6
+
7
+#include "authorize.h"
8
+#include "../../parser/hf.h"            /* HDR_PROXYAUTH & HDR_AUTHORIZATION */
9
+#include "defs.h"                       /* ACK_CANCEL_HACK */
10
+#include "../../str.h"
11
+#include <string.h>                     /* memcmp */
12
+#include "nonce.h"
13
+#include "../../parser/digest/digest.h" /* dig_cred_t */
14
+#include "common.h"                     /* send_resp */
15
+#include "auth_mod.h"
16
+#include "../../db/db.h"
17
+#include "../../mem/mem.h"
18
+#include "rfc2617.h"
19
+
20
+
21
+#define MESSAGE_400 "Bad Request"
22
+
23
+
24
+static inline int get_ha1(str* _user, str* _realm, char* _table, char* _ha1)
25
+{
26
+	db_key_t keys[] = {user_column, realm_column};
27
+	db_val_t vals[2];
28
+	db_key_t col[] = {pass_column};
29
+	db_res_t* res;
30
+
31
+	str result;
32
+
33
+#ifdef USER_DOMAIN_HACK
34
+	char* at;
35
+#endif
36
+
37
+	VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB_STR;
38
+	VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
39
+	
40
+	VAL_STR(vals).s = _user->s;
41
+	VAL_STR(vals).len = _user->len;
42
+	
43
+	VAL_STR(vals + 1).s = _realm->s;
44
+	VAL_STR(vals + 1).len = _realm->len;
45
+
46
+#ifdef USER_DOMAIN_HACK
47
+	at = memchr(_user->s, '@', _user->len);
48
+	if (at) {
49
+		DBG("get_ha1(): @ found in username, removing domain part\n");
50
+		VAL_STR(vals).len = at - _user->s;
51
+		if (!calc_ha1) {
52
+			col[0] = pass_column_2;
53
+		}
54
+	}
55
+#endif
56
+
57
+	db_use_table(db_handle, _table);
58
+	if (db_query(db_handle, keys, vals, col, 2, 1, NULL, &res) < 0) {
59
+		LOG(L_ERR, "get_ha1(): Error while querying database\n");
60
+		return -1;
61
+	}
62
+
63
+	if (RES_ROW_N(res) == 0) {
64
+		DBG("get_ha1(): no result\n");
65
+		db_free_query(db_handle, res);
66
+		return -1;
67
+	}
68
+
69
+        result.s = (char*)ROW_VALUES(RES_ROWS(res))[0].val.string_val;
70
+	result.len = strlen(result.s);
71
+
72
+	if (calc_ha1) {
73
+		     /* Only plaintext passwords are stored in database,
74
+		      * we have to calculate HA1 */
75
+		calc_HA1(HA_MD5, _user, _realm, &result, NULL, NULL, _ha1);
76
+		DBG("HA1 string calculated: %s\n", _ha1);
77
+	} else {
78
+		memcpy(_ha1, result.s, result.len);
79
+		_ha1[result.len] = '\0';
80
+	}
81
+
82
+	db_free_query(db_handle, res);
83
+	return 0;
84
+}
85
+
86
+
87
+static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
88
+{
89
+	HASHHEX resp;
90
+	HASHHEX hent;
91
+
92
+	if (_cred->response.len != 32) {
93
+		LOG(L_ERR, "check_response(): Receive response len != 32\n");
94
+		return -1;
95
+	}
96
+
97
+	calc_response(_ha1, &(_cred->nonce), 
98
+		      &(_cred->nc), &(_cred->cnonce), 
99
+		      &(_cred->qop.qop_str), _cred->qop.qop_parsed == QOP_AUTHINT,
100
+		      _method, &(_cred->uri), hent, resp);
101
+	
102
+	DBG("check_response(): Our result = %s\n", resp);
103
+	
104
+	if (!memcmp(resp, _cred->response.s, 32)) {
105
+		DBG("check_cred(): Authorization is OK\n");
106
+		return 1;
107
+	} else {
108
+		DBG("check_cred(): Authorization failed\n");
109
+		return -1;
110
+	}
111
+}
112
+
113
+
114
+static inline int find_credentials(struct sip_msg* _m, str* _realm, int _hftype, struct hdr_field** _h)
115
+{
116
+	struct hdr_field** hook;
117
+	struct hdr_field* ptr;
118
+	int res;
119
+	str* r;
120
+
121
+	switch(_hftype) {
122
+	case HDR_AUTHORIZATION: hook = &(_m->authorization); break;
123
+	case HDR_PROXYAUTH:     hook = &(_m->proxy_auth);    break;
124
+	default:
125
+		LOG(L_ERR, "find_credentials(): Invalid header field typ as parameter\n");
126
+		return -1;
127
+	}
128
+
129
+	*_h = 0;
130
+	
131
+	if (!(*hook)) {
132
+		     /* No credentials parsed yet */
133
+		if (parse_headers(_m, _hftype, 0) == -1) {
134
+			LOG(L_ERR, "find_credentials(): Error while parsing headers\n");
135
+			return -2;
136
+		}
137
+	}
138
+
139
+	ptr = *hook;
140
+
141
+	while(ptr) {
142
+		res = parse_credentials(ptr);
143
+		if (res < 0) {
144
+			LOG(L_ERR, "find_credentials(): Error while parsing credentials\n");
145
+			if (send_resp(_m, 400, MESSAGE_400, NULL, 0) == -1) {
146
+				LOG(L_ERR, "authorize(): Error while sending 400 reply\n");
147
+			}
148
+			return -1;
149
+		} else if (res == 0) {
150
+			r = &(((auth_body_t*)(ptr->parsed))->digest.realm);
151
+
152
+			if (r->len == _realm->len) {
153
+				if (!strncasecmp(_realm->s, r->s, r->len)) {
154
+					*_h = ptr;
155
+					return 0;
156
+				}
157
+			}
158
+			
159
+			if (parse_headers(_m, _hftype, 1) == -1) {
160
+				LOG(L_ERR, "find_credentials(): Error while parsing headers\n");
161
+				return -3;
162
+			} else {
163
+				if (_m->last_header->type == _hftype) ptr = _m->last_header;
164
+				else ptr = 0;
165
+			}
166
+		}
167
+	}
168
+	return 0;
169
+}
170
+
171
+
172
+/*
173
+ * Authorize digest credentials
174
+ */
175
+static inline int authorize(struct sip_msg* _msg, str* _realm, char* _table, int _hftype)
176
+{
177
+	char ha1[256];
178
+	int res;
179
+	struct hdr_field* h;
180
+	auth_body_t* cred;
181
+
182
+#ifdef ACK_CANCEL_HACK
183
+	     /* ACK must be always authorized, there is
184
+	      * no way how to challenge ACK
185
+	      */
186
+	if (_msg->REQ_METHOD == METHOD_ACK) {
187
+	        return 1;
188
+	}
189
+#endif
190
+
191
+	     /* Try to find credentials with corresponding realm
192
+	      * in the message, parse them and return pointer to
193
+	      * parsed structure
194
+	      */
195
+	if (find_credentials(_msg, _realm, _hftype, &h) < 0) {
196
+		LOG(L_ERR, "authorize(): Error while looking for credentials\n");
197
+		return -1;
198
+	}
199
+
200
+	     /*
201
+	      * No credentials with given realm found, dont' authorize
202
+	      */
203
+	if (h == 0) {
204
+		DBG("authorize(): Credentials with given realm not found\n");
205
+		return -1;
206
+	}
207
+
208
+	cred = (auth_body_t*)(h->parsed);
209
+
210
+	     /* Check credentials correctness here 
211
+	      * FIXME: 400s should be sent from routing scripts, but we will need
212
+	      * variables for that
213
+	      */
214
+	if (check_dig_cred(&(cred->digest)) != E_DIG_OK) {
215
+		DBG("authorize(): Credentials received are not filled properly\n");
216
+
217
+		if (send_resp(_msg, 400, MESSAGE_400, NULL, 0) == -1) {
218
+			LOG(L_ERR, "authorize(): Error while sending 400 reply\n");
219
+		}
220
+		return 0;
221
+	}
222
+
223
+	if (check_nonce(&(cred->digest.nonce), &secret) == 0) {
224
+		LOG(L_ALERT, "authorize(): Invalid nonce value received, very suspicious !\n");
225
+		return -1;
226
+	}
227
+
228
+	     /* Retrieve number of retries with the received nonce and
229
+	      * save it
230
+	      */
231
+	cred->nonce_retries = get_nonce_retry(&(cred->digest.nonce));
232
+
233
+	     /* Calculate or fetch from the dabase HA1 string, which
234
+	      * is necessary for request recalculation
235
+	      */
236
+        if (get_ha1(&(cred->digest.username), _realm, _table, ha1) == -1) {
237
+		LOG(L_ERR, "authorize(): Error while obtaining HA1 string for user \'%.*s\'\n", 
238
+		    cred->digest.username.len, cred->digest.username.s);
239
+		return -1;
240
+	}
241
+
242
+	     /* Recalculate response, it must be same to authorize sucessfully */
243
+        res = check_response(&(cred->digest), &_msg->first_line.u.request.method, ha1);
244
+
245
+	if (res == 1) {  /* response was OK */
246
+		if (nonce_is_stale(&(cred->digest.nonce))) {
247
+			if ((_msg->REQ_METHOD == METHOD_ACK) || 
248
+			    (_msg->REQ_METHOD == METHOD_CANCEL)) {
249
+				     /* Method is ACK or CANCEL, we must accept stale
250
+				      * nonces because there is no way how to challenge
251
+				      * with new nonce (ACK and CANCEL have no responses
252
+				      * associated)
253
+				      */
254
+				goto mark;
255
+			} else {
256
+				DBG("authorize(): Response is OK, but nonce is stale\n");
257
+				cred->stale = 1;
258
+				return -1;
259
+			}
260
+		} else {
261
+			DBG("authorize(): Authorization OK\n");
262
+			goto mark;
263
+		}
264
+	} else {
265
+		DBG("authorize(): Recalculated response is different\n");
266
+		return -1;
267
+	}
268
+
269
+ mark:
270
+	if (mark_authorized_cred(_msg, h) < 0) {
271
+		LOG(L_ERR, "authorize(): Error while marking parsed credentials\n");
272
+		return -1;
273
+	}
274
+	return 1;
275
+}
276
+
277
+
278
+/*
279
+ * Authorize using Proxy-Authorize header field
280
+ */
281
+int proxy_authorize(struct sip_msg* _msg, char* _realm, char* _table)
282
+{
283
+	     /* realm parameter is converted to str* in str_fixup */
284
+	return authorize(_msg, (str*)_realm, _table, HDR_PROXYAUTH);
285
+}
286
+
287
+
288
+/*
289
+ * Authorize using WWW-Authorize header field
290
+ */
291
+int www_authorize(struct sip_msg* _msg, char* _realm, char* _table)
292
+{
293
+	return authorize(_msg, (str*)_realm, _table, HDR_AUTHORIZATION);
294
+}
295
+
296
+
297
+/*
298
+ * Remove used credentials
299
+ */
300
+int consume_credentials(struct sip_msg* _m, char* _s1, char* _s2)
301
+{
302
+	struct hdr_field* h;
303
+
304
+	get_authorized_cred(_m->authorization, &h);
305
+	if (!h) {
306
+		get_authorized_cred(_m->proxy_auth, &h);
307
+		if (!h) {
308
+			LOG(L_ERR, "consume_credentials(): No authorized credentials found (error in scripts)\n");
309
+			return -1;
310
+		}
311
+	}
312
+	
313
+	if (del_lump(&_m->add_rm, h->name.s - _m->buf, h->name.len + h->body.len, 0) == 0) {
314
+		LOG(L_ERR, "consume_credentials(): Can't remove credentials\n");
315
+		return -1;
316
+	}
317
+
318
+	return 1;
319
+}
320
+
321
+
0 322
new file mode 100644
... ...
@@ -0,0 +1,32 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Authorize related functions
5
+ */
6
+
7
+#ifndef AUTHORIZE_H
8
+#define AUTHORIZE_H
9
+
10
+
11
+#include "../../parser/msg_parser.h"
12
+
13
+
14
+/*
15
+ * Authorize using Proxy-Authorization header field
16
+ */
17
+int proxy_authorize(struct sip_msg* _msg, char* _realm, char* _table);
18
+
19
+
20
+/*
21
+ * Authorize using WWW-Authorization header field
22
+ */
23
+int www_authorize(struct sip_msg* _msg, char* _realm, char* _table);
24
+
25
+
26
+/*
27
+ * Remove used credentials
28
+ */
29
+int consume_credentials(struct sip_msg* _msg, char* _s1, char* _s2);
30
+
31
+
32
+#endif /* AUTHORIZE_H */
0 33
new file mode 100644
... ...
@@ -0,0 +1,118 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Challenge related functions
5
+ */
6
+
7
+#include "challenge.h"
8
+#include <time.h>
9
+#include <stdio.h>
10
+#include "../../dprint.h"
11
+#include "nonce.h"                      /* calc_nonce */
12
+#include "common.h"                     /* send_resp */
13
+#include "../../parser/digest/digest.h" /* cred_body_t get_authorized_cred*/
14
+#include "auth_mod.h"                   /* Module parameters */
15
+#include "defs.h"                       /* PRINT_MD5 */
16
+
17
+
18
+#define MESSAGE_407 "Proxy Authentication Required"
19
+#define MESSAGE_401 "Unauthorized"
20
+#define MESSAGE_403 "Forbidden"
21
+
22
+#define WWW_AUTH_CHALLENGE   "WWW-Authenticate"
23
+#define PROXY_AUTH_CHALLENGE "Proxy-Authenticate"
24
+
25
+#define AUTH_HF_LEN 512
26
+
27
+static char auth_hf[AUTH_HF_LEN];
28
+
29
+
30
+/*
31
+ * Create {WWW,Proxy}-Authenticate header field
32
+ */
33
+static inline void build_auth_hf(int _retries, int _stale, char* _realm, char* _buf, 
34
+				 int* _len, int _qop, char* _hf_name)
35
+{
36
+	char nonce[NONCE_LEN + 1];
37
+	
38
+	calc_nonce(nonce, time(NULL) + nonce_expire, _retries, &secret);
39
+	nonce[NONCE_LEN] = '\0';
40
+	
41
+	*_len = snprintf(_buf, AUTH_HF_LEN,
42
+			 "%s: Digest realm=\"%s\", nonce=\"%s\"%s%s"
43
+#ifdef PRINT_MD5
44
+			 ", algorithm=MD5"
45
+#endif
46
+			 "\r\n", 
47
+			 _hf_name, 
48
+			 _realm, 
49
+			 nonce,
50
+			 (_qop) ? (", qop=\"auth\"") : (""),
51
+			 (_stale) ? (", stale=true") : ("")
52
+			 );		
53
+	
54
+	DBG("build_auth_hf(): %s\n", _buf);
55
+}
56
+
57
+
58
+/*
59
+ * Create and send a challenge
60
+ */
61
+static inline int challenge(struct sip_msg* _msg, char* _realm, int _qop, 
62
+			    int _code, char* _message, char* _challenge_msg)
63
+{
64
+	int auth_hf_len;
65
+	struct hdr_field* h;
66
+	auth_body_t* cred = 0;
67
+
68
+	switch(_code) {
69
+	case 401: get_authorized_cred(_msg->authorization, &h); break;
70
+	case 407: get_authorized_cred(_msg->proxy_auth, &h);    break;
71
+	}
72
+
73
+	if (h) cred = (auth_body_t*)(h->parsed);
74
+
75
+	if (cred != 0) {
76
+		if (cred->nonce_retries > retry_count) {
77
+			DBG("challenge(): Retry count exceeded, sending Forbidden\n");
78
+			_code = 403;
79
+			_message = MESSAGE_403;
80
+		} else {
81
+			if (cred->stale == 0) {
82
+				cred->nonce_retries++;
83
+			} else {
84
+				cred->nonce_retries = 0;
85
+			}
86
+			
87
+			build_auth_hf(cred->nonce_retries, cred->stale, 
88
+				      _realm, auth_hf, &auth_hf_len,
89
+				      _qop, _challenge_msg);
90
+		}
91
+	} else {
92
+		build_auth_hf(0, 0, _realm, auth_hf, &auth_hf_len, _qop, _challenge_msg);
93
+	}
94
+	
95
+	if (send_resp(_msg, _code, _message, auth_hf, auth_hf_len) == -1) {
96
+		LOG(L_ERR, "www_challenge(): Error while sending response\n");
97
+		return -1;
98
+	}
99
+	return 0;
100
+}
101
+
102
+
103
+/*
104
+ * Challenge a user to send credentials using WWW-Authorize header field
105
+ */
106
+int www_challenge(struct sip_msg* _msg, char* _realm, char* _qop)
107
+{
108
+	return challenge(_msg, _realm, (int)_qop, 401, MESSAGE_401, WWW_AUTH_CHALLENGE);
109
+}
110
+
111
+
112
+/*
113
+ * Challenge a user to send credentials using Proxy-Authorize header field
114
+ */
115
+int proxy_challenge(struct sip_msg* _msg, char* _realm, char* _qop)
116
+{
117
+	return challenge(_msg, _realm, (int)_qop, 407, MESSAGE_407, PROXY_AUTH_CHALLENGE);
118
+}
0 119
new file mode 100644
... ...
@@ -0,0 +1,25 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Challenge related functions
5
+ */
6
+
7
+#ifndef CHALLENGE_H
8
+#define CHALLENGE_H
9
+
10
+#include "../../parser/msg_parser.h"
11
+
12
+
13
+/* 
14
+ * Challenge a user agent using WWW-Authenticate header field
15
+ */
16
+int www_challenge(struct sip_msg* _msg, char* _realm, char* _str2);
17
+
18
+
19
+/*
20
+ * Challenge a user agent using Proxy-Authenticate header field
21
+ */
22
+int proxy_challenge(struct sip_msg* _msg, char* _realm, char* _str2);
23
+
24
+
25
+#endif /* CHALLENGE_H */
... ...
@@ -1,45 +1,102 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Checks if To and From header fields contain the same
5
+ * username as digest credentials
3 6
  */
4 7
 
5 8
 #include "checks.h"
6 9
 #include "../../str.h"
7 10
 #include "../../dprint.h"
8 11
 #include <string.h>
9
-#include "utils.h"
10
-#include "auth.h"
11 12
 #include "defs.h"
13
+#include "../../parser/digest/digest.h" /* get_authorized_cred */
12 14
 
15
+
16
+/*
17
+ * Finds specified character, that is not quoted 
18
+ * If there is no such character, returns NULL
19
+ *
20
+ * PARAMS : char* _b : input buffer
21
+ *        : char _c  : character to find
22
+ * RETURNS: char*    : points to character found, NULL if not found
23
+ */
24
+static inline char* find_not_quoted(str* _b, char _c)
25
+{
26
+	int quoted = 0, i;
27
+	
28
+	if (_b->s == 0) return NULL;
29
+
30
+	for(i = 0; i < _b->len; i++) {
31
+		if (!quoted) {
32
+			if (_b->s[i] == '\"') quoted = 1;
33
+			else if (_b->s[i] == _c) return _b->s + i;
34
+		} else {
35
+			if ((_b->s[i] == '\"') && (_b->s[i - 1] != '\\')) quoted = 0;
36
+		}
37
+	}
38
+	return NULL;
39
+}
40
+
41
+
42
+/*
43
+ * Cut username part of a URL
44
+ */
13 45
 static inline void get_username(str* _s)
14 46
 {
15 47
 	char* at, *dcolon, *dc;
16
-	dcolon = find_not_quoted(_s->s, ':');
17 48
 
49
+	     /* Find double colon, double colon
50
+	      * separates schema and the rest of
51
+	      * URL
52
+	      */
53
+	dcolon = find_not_quoted(_s, ':');
54
+
55
+	     /* No double colon found means error */
18 56
 	if (!dcolon) {
19 57
 		_s->len = 0;
20 58
 		return;
21 59
 	}
60
+
61
+	     /* Skip the double colon */
62
+	_s->len -= dcolon + 1 - _s->s;
22 63
 	_s->s = dcolon + 1;
23 64
 
24
-	at = strchr(_s->s, '@');
25
-	dc = strchr(_s->s, ':');
65
+	     /* Try to find @ or another doublecolon
66
+	      * if the URL contains also pasword, username
67
+	      * and password will be delimited by double
68
+	      * colon, if there is no password, @ delimites
69
+	      * username from the rest of the URL, if there
70
+	      * is no @, there is no username in the URL
71
+	      */
72
+	at = memchr(_s->s, '@', _s->len); /* FIXME: one pass */
73
+	dc = memchr(_s->s, ':', _s->len);
26 74
 	if (at) {
75
+		     /* The double colon must be before
76
+		      * @ to delimit username, otherwise
77
+		      * it delimits hostname from port number
78
+		      */
27 79
 		if ((dc) && (dc < at)) {
28 80
 			_s->len = dc - dcolon - 1;
29 81
 			return;
30 82
 		}
31 83
 		
32 84
 		_s->len = at - dcolon - 1;
33
-		/*	_s->s[_s->len] = '\0'; */
34 85
 	} else {
35 86
 		_s->len = 0;
36 87
 	} 
37 88
 }
38 89
 
39 90
 
40
-
41
-int check_to(struct sip_msg* _msg, char* _str1, char* _str2)
91
+/*
92
+ * Check if To header field contains the same username
93
+ * as digest credentials
94
+ */
95
+static inline int check_username(struct sip_msg* _m, struct hdr_field* _h)
42 96
 {
97
+	struct hdr_field* h;
98
+	auth_body_t* c;
99
+
43 100
 #ifdef USER_DOMAIN_HACK
44 101
 	char* ptr;
45 102
 #endif
... ...
@@ -47,78 +104,63 @@ int check_to(struct sip_msg* _msg, char* _str1, char* _str2)
47 104
 	str user;
48 105
 	int len;
49 106
 
50
-	if (!_msg->to) {
51
-		LOG(L_ERR, "check_to(): To HF not found\n");
107
+	if (!_h) {
108
+		LOG(L_ERR, "check_username(): To HF not found\n");
52 109
 		return -1;
53 110
 	}
54 111
 
55
-	user.s = _msg->to->body.s;
56
-	user.len = _msg->to->body.len;
112
+	get_authorized_cred(_m->authorization, &h);
113
+	if (!h) {
114
+		get_authorized_cred(_m->proxy_auth, &h);
115
+		if (!h) {
116
+			LOG(L_ERR, "is_user(): No authorized credentials found (error in scripts)\n");
117
+			return -1;
118
+		}
119
+	}
120
+
121
+	c = (auth_body_t*)(h->parsed);
122
+
123
+	user.s = _h->body.s;
124
+	user.len = _h->body.len;
57 125
 
58 126
 	get_username(&user);
59 127
 
60 128
 	if (!user.len) return -1;
61 129
 
62
-	len = state.cred.username.len;
130
+	len = c->digest.username.len;
63 131
 
64 132
 #ifdef USER_DOMAIN_HACK
65
-	ptr = memchr(state.cred.username.s, '@', len);
133
+	ptr = memchr(c->digest.username.s, '@', len);
66 134
 	if (ptr) {
67
-		len = ptr - state.cred.username.s;
135
+		len = ptr - c->digest.username.s;
68 136
 	}
69 137
 #endif
70 138
 
71
-	/* FIXME !! */
72 139
 	if (user.len == len) {
73
-		if (!strncasecmp(user.s, state.cred.username.s, user.len)) {
74
-			DBG("check_to(): auth id and To username are equal\n");
140
+		if (strncasecmp(user.s, c->digest.username.s, len) == 0) {
141
+			DBG("check_username(): auth id and To username are equal\n");
75 142
 			return 1;
76 143
 		}
77 144
 	}
78
-
79
-	DBG("check_to(): auth id and To username differ\n");
145
+	
146
+	DBG("check_username(): auth id and To username differ\n");
80 147
 	return -1;
81 148
 }
82 149
 
83 150
 
84
-int check_from(struct sip_msg* _msg, char* _str1, char* _str2)
151
+/*
152
+ * Check username part in To header field
153
+ */
154
+int check_to(struct sip_msg* _msg, char* _s1, char* _s2)
85 155
 {
86
-#ifdef USER_DOMAIN_HACK
87
-	char* ptr;
88
-#endif
89
-
90
-	int len;
91
-	str user;
92
-
93
-	if (!_msg->from) {
94
-		LOG(L_ERR, "check_from(): From HF not found\n");
95
-		return -1;
96
-	}
97
-
98
-	user.s = _msg->from->body.s;
99
-	user.len = _msg->from->body.len;
100
-
101
-	get_username(&user);
102
-
103
-	if (!user.len) return -1;
104
-
105
-	len = state.cred.username.len;
106
-
107
-#ifdef USER_DOMAIN_HACK
108
-	ptr = memchr(state.cred.username.s, '@', len);
109
-	if (ptr) {
110
-		len = ptr - state.cred.username.s;
111
-	}
112
-#endif
156
+	return check_username(_msg, _msg->to);
157
+}
113 158
 
114
-	/* FIXME !! */
115
-	if (user.len == len) {
116
-		if (!strncasecmp(user.s, state.cred.username.s, user.len)) {
117
-			DBG("check_from(): auth id and From username are equal\n");
118
-			return 1;
119
-		}
120
-	}
121 159
 
122
-	DBG("check_from(): auth id and From username differ\n");
123
-	return -1;
160
+/*
161
+ * Check username part in From header field
162
+ */
163
+int check_from(struct sip_msg* _msg, char* _s1, char* _s2)
164
+{
165
+	return check_username(_msg, _msg->from);
124 166
 }
... ...
@@ -1,15 +1,28 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Check if to and from contain the same username as
5
+ * in digest credentials
3 6
  */
4 7
 
5 8
 #ifndef CHECKS_H
6 9
 #define CHECKS_H
7 10
 
8 11
 #include "../../parser/msg_parser.h"
9
-#include "../../str.h"
10 12
 
11 13
 
14
+/*
15
+ * Check if To header field contains the same username
16
+ * as digest credentials
17
+ */
12 18
 int check_to(struct sip_msg* _msg, char* _str1, char* _str2);
19
+
20
+
21
+/*
22
+ * Check if From header field contains the same username
23
+ * as digest credentials
24
+ */
13 25
 int check_from(struct sip_msg* _msg, char* _str1, char* _str2);
14 26
 
15
-#endif
27
+
28
+#endif /* CHECKS_H */
16 29
new file mode 100644
... ...
@@ -0,0 +1,29 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Common functions needed by authorize
5
+ * and challenge functions
6
+ */
7
+
8
+#include "common.h"
9
+#include "../../data_lump_rpl.h"
10
+#include "auth_mod.h"            /* sl_reply */
11
+
12
+
13
+/*
14
+ * Create a response with given code and reason phrase
15
+ * Optionaly add new headers specified in _hdr
16
+ */
17
+int send_resp(struct sip_msg* _m, int _code, char* _reason, char* _hdr, int _hdr_len)
18
+{
19
+	struct lump_rpl* ptr;
20
+	
21
+	     /* Add new headers if there are any */
22
+	if (_hdr) {
23
+		ptr = build_lump_rpl(_hdr, _hdr_len);
24
+		add_lump_rpl(_m, ptr);
25
+	}
26
+	
27
+	sl_reply(_m, (char*)_code, _reason);
28
+	return 0;
29
+}
0 30
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Common function needed by authorize
5
+ * and challenge related functions
6
+ */
7
+
8
+#ifndef COMMON_H
9
+#define COMMON_H
10
+
11
+#include "../../parser/msg_parser.h"
12
+
13
+
14
+/*
15
+ * Send a response
16
+ */
17
+int send_resp(struct sip_msg* _m, int _code, char* _reason, char* _hdr, int _hdr_len);
18
+
19
+
20
+#endif /* COMMON_H */
... ...
@@ -1,32 +1,35 @@
1 1
 /* 
2 2
  * $Id$ 
3
+ *
4
+ * Common definitions
3 5
  */
4
-#ifndef __DEFS_H__
5
-#define __DEFS_H__
6 6
 
7
-#define PARANOID
8
-
9
-#define WWW_AUTH_RESPONSE "Authorization"
10
-#define PROXY_AUTH_RESPONSE  "Proxy-Authorization"
7
+#ifndef DEFS_H
8
+#define DEFS_H
11 9
 
12
-#define WWW_AUTH_CHALLENGE "WWW-Authenticate"
13
-#define PROXY_AUTH_CHALLENGE "Proxy-Authenticate"
14
-
15
-#define AUTH_HF_LEN 512
10
+#define PARANOID
16 11
 
17 12
 /*
18 13
  * Helper definitions
19 14
  */
20 15
 
21
-#define MESSAGE_407 "Proxy Authentication Required"
22
-#define MESSAGE_401 "Unauthorized"
23
-#define MESSAGE_400 "Bad Request"
24
-#define MESSAGE_403 "Forbidden"
25
-
16
+/*
17
+ * the module will accept and authorize also username
18
+ * of form user@domain which some broken clients send
19
+ */
26 20
 #define USER_DOMAIN_HACK
21
+
22
+
23
+/*
24
+ * If the method is ACK, it is always authorized
25
+ */
27 26
 #define ACK_CANCEL_HACK
28 27
 
29
-/* print algorithm name in challenge explicitely */
28
+
29
+/* 
30
+ * Send algorithm=MD5 in challenge
31
+ */
30 32
 #define PRINT_MD5
31 33
 
32
-#endif
34
+
35
+#endif /* DEFS_H */
... ...
@@ -1,25 +1,51 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Checks if a username matche those in digest credentials
5
+ * or is member of a group
3 6
  */
4 7
 
8
+
5 9
 #include "group.h"
6 10
 #include <string.h>
7 11
 #include "../../dprint.h"
8 12
 #include "../../db/db.h"
9
-#include "auth.h"
10
-#include "auth_mod.h"
11
-#include "utils.h"
13
+#include "auth_mod.h"                   /* Module parameters */
14
+#include "../../parser/digest/digest.h" /* get_authorized_cred */
15
+
12 16
 
13 17
 /*
14
- * Check if the given username matches username in credentials
18
+ * Check if the username matches the username in credentials
15 19
  */
16 20
 int is_user(struct sip_msg* _msg, char* _user, char* _str2)
17 21
 {
18
-	if (!state.cred.username.len) {
22
+	str* s;
23
+	struct hdr_field* h;
24
+	auth_body_t* c;
25
+
26
+	s = (str*)_user;
27
+
28
+	get_authorized_cred(_msg->authorization, &h);
29
+	if (!h) {
30
+		get_authorized_cred(_msg->proxy_auth, &h);
31
+		if (!h) {
32
+			LOG(L_ERR, "is_user(): No authorized credentials found (error in scripts)\n");
33
+			return -1;
34
+		}
35
+	}
36
+
37
+	c = (auth_body_t*)(h->parsed);
38
+
39
+	if (!c->digest.username.len) {
19 40
 		DBG("is_user(): Username not found in credentials\n");
20 41
 		return -1;
21 42
 	}
22
-	if (!memcmp(_user, state.cred.username.s, state.cred.username.len)) {
43
+
44
+	if (s->len != c->digest.username.len) {
45
+		return -1;
46
+	}
47
+
48
+	if (!memcmp(s->s, c->digest.username.s, s->len)) {
23 49
 		DBG("is_user(): Username matches\n");
24 50
 		return 1;
25 51
 	} else {
... ...
@@ -29,7 +55,6 @@ int is_user(struct sip_msg* _msg, char* _user, char* _str2)
29 55
 }
30 56
 
31 57
 
32
-
33 58
 /*
34 59
  * Check if the user specified in credentials is a member
35 60
  * of given group
... ...
@@ -37,26 +62,91 @@ int is_user(struct sip_msg* _msg, char* _user, char* _str2)
37 62
 int is_in_group(struct sip_msg* _msg, char* _group, char* _str2)
38 63
 {
39 64
 	db_key_t keys[] = {grp_user_col, grp_grp_col};
40
-	db_val_t vals[] = {{DB_STRING, 0, {.string_val = state.cred.username.s}},
41
-			   {DB_STRING, 0, {.string_val = _group}}
42
-	};
65
+	db_val_t vals[2];
43 66
 	db_key_t col[] = {grp_grp_col};
44 67
 	db_res_t* res;
68
+	struct hdr_field* h;
69
+	auth_body_t* c;
70
+
71
+	get_authorized_cred(_msg->authorization, &h);
72
+	if (!h) {
73
+		get_authorized_cred(_msg->proxy_auth, &h);
74
+		if (!h) {
75
+			LOG(L_ERR, "is_in_group(): No authorized credentials found (error in scripts)\n");
76
+			return -1;
77
+		}
78
+	}
79
+
80
+	c = (auth_body_t*)(h->parsed);
45 81
 
82
+	VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB_STR;
83
+	VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
84
+
85
+	VAL_STR(vals).s = c->digest.username.s;
86
+	VAL_STR(vals).len = c->digest.username.len;
87
+	
88
+	VAL_STR(vals + 1).s = ((str*)_group)->s;
89
+	VAL_STR(vals + 1).len = ((str*)_group)->len;
90
+	
46 91
 	db_use_table(db_handle, grp_table);
47 92
 	if (db_query(db_handle, keys, vals, col, 2, 1, NULL, &res) < 0) {
48 93
 		LOG(L_ERR, "is_in_group(): Error while querying database\n");
49 94
 		return -1;
50 95
 	}
51
-
96
+	
52 97
 	if (RES_ROW_N(res) == 0) {
53
-		DBG("is_in_group(): User %s is not in group %s\n", state.cred.username.s, _group);
98
+		DBG("is_in_group(): User %s is not in group %s\n", c->digest.username.s, _group);
54 99
 		db_free_query(db_handle, res);
55 100
 		return -1;
56 101
 	} else {
57
-		DBG("is_in_group(): User %s is member of group %s\n", state.cred.username.s, _group);
102
+		DBG("is_in_group(): User %s is member of group %s\n", c->digest.username.s, _group);
58 103
 		db_free_query(db_handle, res);
59 104
 		return 1;
60 105
 	}
61 106
 }
62 107
 
108
+
109
+/*
110
+ * Check if user specified in credentials is in a table
111
+ */
112
+int is_user_in(struct sip_msg* _msg, char* _table, char* _s)
113
+{
114
+	db_key_t key = grp_user_col;
115
+	db_val_t val;
116
+	db_key_t col = grp_user_col;
117
+	db_res_t* res;
118
+
119
+	struct hdr_field* h;
120
+	auth_body_t* c;
121
+
122
+	get_authorized_cred(_msg->authorization, &h);
123
+	if (!h) {
124
+		get_authorized_cred(_msg->proxy_auth, &h);
125
+		if (!h) {
126
+			LOG(L_ERR, "is_user_in(): No authorized credentials found (error in scripts)\n");
127
+			return -1;
128
+		}
129
+	}
130
+
131
+	c = (auth_body_t*)(h->parsed);	
132
+
133
+	VAL_TYPE(&val) = DB_STR;
134
+	VAL_NULL(&val) = 0;
135
+	VAL_STR(&val).s = ((str*)_table)->s;
136
+	VAL_STR(&val).len = ((str*)_table)->len;
137
+
138
+	db_use_table(db_handle, grp_table);
139
+
140
+	if (db_query(db_handle, &key, &val, &col, 1, 1, NULL, &res) < 0) {
141
+		LOG(L_ERR, "is_user_in(): Error while querying database\n");
142
+		return -1;
143
+	}
144
+	
145
+	if (RES_ROW_N(res) == 0) {
146
+		db_free_query(db_handle, res);
147
+		return -1;
148
+	} else {
149
+		db_free_query(db_handle, res);
150
+		return 1;
151
+	}
152
+}
... ...
@@ -1,5 +1,8 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Check, if a username matches those in digest credentials
5
+ * or if a user is member of a group
3 6
  */
4 7
 
5 8
 #ifndef GROUP_H
... ...
@@ -8,9 +11,22 @@
8 11
 #include "../../parser/msg_parser.h"
9 12
 
10 13
 
14
+/*
15
+ * Check if given username matches those in digest credentials
16
+ */
11 17
 int is_user(struct sip_msg* _msg, char* _user, char* _str2);
12 18
 
19
+
20
+/*
21
+ * Check if a user is member of a group
22
+ */
13 23
 int is_in_group(struct sip_msg* _msg, char* _group, char* _str2);
14 24
 
15 25
 
16
-#endif
26
+/*
27
+ * Check if user specified in credentials is in a table
28
+ */
29
+int is_user_in(struct sip_msg* _msg, char* _table, char* _s);
30
+
31
+
32
+#endif /* GROUP_H */
... ...
@@ -1,115 +1,151 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Nonce related functions
3 5
  */
4 6
 
5 7
 #include "nonce.h"
6
-#include "calc.h"
8
+#include "rfc2617.h"
7 9
 #include <time.h>
8
-#include "utils.h"
9
-#include "../../dprint.h"
10
-#include "auth_mod.h"  /* module parameters */
11 10
 #include "../../md5global.h"
12 11
 #include "../../md5.h"
13 12
 #include <string.h>
14 13
 
14
+
15 15
 /*
16
- * Nonce related functions
16
+ * Convert an integer to its hex representation,
17
+ * destination array must be at least 8 bytes long,
18
+ * this string is NOT zero terminated
17 19
  */
20
+static inline void int2hex(char* _d, int _s)
21
+{
22
+	int i;
23
+	unsigned char j;
24
+	char* s = (char*)&_s;
25
+    
26
+	for (i = 0; i < 4; i++) {
27
+		
28
+		j = (s[4 - i - 1] >> 4) & 0xf;
29
+		if (j <= 9) {
30
+			_d[i * 2] = (j + '0');
31
+		} else { 
32
+			_d[i * 2] = (j + 'a' - 10);
33
+		}
34
+
35
+		j = s[4 - i - 1] & 0xf;
36
+		if (j <= 9) {
37
+			_d[i * 2 + 1] = (j + '0');
38
+		} else {
39
+		       _d[i * 2 + 1] = (j + 'a' - 10);
40
+		}
41
+	}
42
+}
43
+
44
+
45
+/*
46
+ * Convert hex string to integer
47
+ */
48
+static inline int hex2int(char* _s)
49
+{
50
+	unsigned int i, res = 0;
51
+
52
+	for(i = 0; i < 8; i++) {
53
+		res *= 16;
54
+		if ((_s[i] >= '0') && (_s[i] <= '9')) {
55
+			res += _s[i] - '0';
56
+		} else if ((_s[i] >= 'a') && (_s[i] <= 'f')) {
57
+			res += _s[i] - 'a' + 10;
58
+		} else if ((_s[i] >= 'A') && (_s[i] <= 'F')) {
59
+			res += _s[i] - 'A' + 10;
60
+		} else return 0;
61
+	}
62
+
63
+	return res;
64
+}
65
+
18 66
 
19 67
 /*
20 68
  * Calculate nonce value
21 69
  * Nonce value consists of time in seconds since 1.1 1970 and
22 70
  * secret phrase
23 71
  */
24
-void calc_nonce(char* _nonce, int _expires, int _retry, str* _secret)
72
+inline void calc_nonce(char* _nonce, int _expires, int _retry, str* _secret)
25 73
 {
26 74
 	MD5_CTX ctx;
27 75
 	char bin[16];
28 76
 
29
-	DBG("exipires: %d, retry: %d\n", _expires, _retry);
30
-
31 77
 	MD5Init(&ctx);
32 78
 	
33
-	to_hex(_nonce, (char*)&_expires, 4);
79
+	int2hex(_nonce, _expires);
34 80
 	MD5Update(&ctx, _nonce, 8);
35 81
 
36
-	to_hex(_nonce + 8, (char*)&_retry, 4);
82
+	int2hex(_nonce + 8, _retry);
37 83
 	MD5Update(&ctx, _nonce + 8, 8);
38 84
 
39 85
 	MD5Update(&ctx, _secret->s, _secret->len);
40 86
 	MD5Final(bin, &ctx);
41
-	CvtHex(bin, _nonce + 16);
87
+	cvt_hex(bin, _nonce + 16);
88
+}
89
+
42 90
 
43
-	DBG("calc_nonce(): nonce=%s\n", _nonce);
91
+/*
92
+ * Get expiry time from nonce string
93
+ */
94
+inline time_t get_nonce_expires(str* _n)
95
+{
96
+	return (time_t)hex2int(_n->s);
44 97
 }
45 98
 
46 99
 
47
-int check_nonce(char* _nonce, str* _secret)
100
+/*
101
+ * Get retry counter from nonce string
102
+ */
103
+inline int get_nonce_retry(str* _n)
104
+{
105
+	if (!_n->s) return 0;
106
+	return hex2int(_n->s + 8);
107
+}
108
+
109
+
110
+/*
111
+ * Check, if the nonce received from client is
112
+ * correct
113
+ */
114
+int check_nonce(str* _nonce, str* _secret)
48 115
 {
49 116
 	int expires, retry;
50
-	char non[NONCE_LEN];
117
+	char non[NONCE_LEN + 1];
51 118
 
52
-	if (!_nonce) return 0;  /* Invalid nonce */
119
+	if (_nonce->s == 0) {
120
+		return 0;  /* Invalid nonce */
121
+	}
53 122
 
54 123
 	expires = get_nonce_expires(_nonce);
55 124
 	retry = get_nonce_retry(_nonce);
56 125
 
57
-	DBG("expires: %d\n", expires);
58
-	DBG("retry: %d\n", retry);
59
-
60 126
 	calc_nonce(non, expires, retry, _secret);
61 127
 
62
-	if (!memcmp(non, _nonce, NONCE_LEN)) return 1;
63
-
64
-	return 0;
65
-}
66
-
67
-
68
-static inline int hex_to_int(char* _str)
69
-{
70
-	unsigned int i, res = 0;
71
-#ifdef PARANOID
72
-	if (!_str) {
73
-		return 0;
74
-	}
75
-#endif
76
-	for(i = 0; i < 8; i++) {
77
-		res *= 16;
78
-		if ((_str[i] >= '0') && (_str[i] <= '9'))      res += _str[i] - '0';
79
-		else if ((_str[i] >= 'a') && (_str[i] <= 'f')) res += _str[i] - 'a' + 10;
80
-		else if ((_str[i] >= 'A') && (_str[i] <= 'F')) res += _str[i] - 'A' + 10;
81
-		else return 0;
128
+	if (NONCE_LEN != _nonce->len) {
129
+		return 0; /* Lengths must be equal */
82 130
 	}
83
-	return res;
84
-}
85
-
86 131
 
132
+	if (!memcmp(non, _nonce->s, _nonce->len)) {
133
+		return 1;
134
+	}
87 135
 
88
-/*
89
- * Get expiry time from nonce string
90
- */
91
-time_t get_nonce_expires(char* _nonce)
92
-{
93
-	return (time_t)hex_to_int(_nonce);
136
+	return 0;
94 137
 }
95 138
 
96 139
 
97 140
 /*
98
- * Get retry counter from nonce string
141
+ * Returns 1 if nonce is stale
142
+ * 0 otherwise
99 143
  */
100
-int get_nonce_retry(char* _nonce)
101
-{
102
-	if (!_nonce) return 0;
103
-	return hex_to_int(_nonce + 8);
104
-}
105
-
106
-
107
-
108
-int nonce_is_stale(char* _nonce) 
144
+int nonce_is_stale(str* _n) 
109 145
 {
110
-	if (!_nonce) return 0;
146
+	if (!_n->s) return 0;
111 147
 
112
-	if (get_nonce_expires(_nonce) < time(NULL)) {
148
+	if (get_nonce_expires(_n) < time(NULL)) {
113 149
 		return 1;
114 150
 	} else {
115 151
 		return 0;
... ...
@@ -1,5 +1,7 @@
1 1
 /*
2 2
  * $Id$
3
+ *
4
+ * Nonce related functions
3 5
  */
4 6
 
5 7
 #ifndef NONCE_H
... ...
@@ -8,6 +10,10 @@
8 10
 #include "../../str.h"
9 11
 #include <time.h>
10 12
 
13
+
14
+/*
15
+ * Length of nonce string in bytes