Browse code

- Aligned to the new database schema - Support for multiple credentials instances - Support for uid (internal user identity) - Support for credentials flags - always use username and realm when selecting credentials - support for distinct digest and serweb credentials

Jan Janak authored on 21/11/2005 00:04:15
Showing 4 changed files
... ...
@@ -49,7 +49,7 @@
49 49
 
50 50
 MODULE_VERSION
51 51
 
52
-#define TABLE_VERSION 3
52
+#define TABLE_VERSION 6
53 53
 
54 54
 /*
55 55
  * Module destroy function prototype
... ...
@@ -75,46 +75,48 @@ static int authdb_fixup(void** param, int param_no);
75 75
 /*
76 76
  * Pointer to reply function in stateless module
77 77
  */
78
-int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2);
78
+int (*sl_reply)(struct sip_msg* msg, char* str1, char* str2);
79 79
 
80 80
 
81
-#define USER_COL "username"
82
-
83
-#define DOMAIN_COL "domain"
84 81
 
82
+#define USERNAME_COL "auth_username"
83
+#define REALM_COL "realm"
85 84
 #define PASS_COL "ha1"
86
-
87 85
 #define PASS_COL_2 "ha1b"
88
-
89
-#define DEFAULT_CRED_LIST "rpid"
86
+#define DEFAULT_CRED_LIST "uid"
87
+#define FLAGS_COL "flags"
90 88
 
91 89
 /*
92 90
  * Module parameter variables
93 91
  */
94 92
 static char* db_url         = DEFAULT_RODB_URL;
95
-str user_column             = STR_STATIC_INIT(USER_COL);
96
-str domain_column           = STR_STATIC_INIT(DOMAIN_COL);
93
+
94
+str username_column         = STR_STATIC_INIT(USERNAME_COL);
95
+str realm_column            = STR_STATIC_INIT(REALM_COL);
97 96
 str pass_column             = STR_STATIC_INIT(PASS_COL);
98 97
 str pass_column_2           = STR_STATIC_INIT(PASS_COL_2);
99
-
98
+str flags_column            = STR_STATIC_INIT(FLAGS_COL);
100 99
 
101 100
 int calc_ha1                = 0;
102
-int use_domain              = 0;   /* Use also domain when looking up a table row */
103 101
 
104 102
 db_con_t* auth_db_handle = 0;      /* database connection handle */
105 103
 db_func_t auth_dbf;
106 104
 auth_api_t auth_api;
107 105
 
108 106
 str credentials_list        = STR_STATIC_INIT(DEFAULT_CRED_LIST);
107
+
109 108
 str* credentials;          /* Parsed list of credentials to load */
110 109
 int credentials_n;         /* Number of credentials in the list */
111 110
 
111
+
112 112
 /*
113 113
  * Exported functions
114 114
  */
115 115
 static cmd_export_t cmds[] = {
116
-	{"www_authorize",   www_authorize,   2, authdb_fixup, REQUEST_ROUTE},
117
-	{"proxy_authorize", proxy_authorize, 2, authdb_fixup, REQUEST_ROUTE},
116
+	{"www_authenticate",   www_authenticate,    2, authdb_fixup, REQUEST_ROUTE},
117
+	{"www_authenticate",   www_authenticate1,   1, authdb_fixup, REQUEST_ROUTE},
118
+	{"proxy_authenticate", proxy_authenticate,  2, authdb_fixup, REQUEST_ROUTE},
119
+	{"proxy_authenticate", proxy_authenticate1, 1, authdb_fixup, REQUEST_ROUTE},
118 120
 	{0, 0, 0, 0, 0}
119 121
 };
120 122
 
... ...
@@ -124,12 +126,12 @@ static cmd_export_t cmds[] = {
124 126
  */
125 127
 static param_export_t params[] = {
126 128
 	{"db_url",            STR_PARAM, &db_url             },
127
-	{"user_column",       STR_PARAM, &user_column.s      },
128
-	{"domain_column",     STR_PARAM, &domain_column.s    },
129
+	{"username_column",   STR_PARAM, &username_column.s  },
130
+	{"realm_column",      STR_PARAM, &realm_column.s     },
129 131
 	{"password_column",   STR_PARAM, &pass_column.s      },
130 132
 	{"password_column_2", STR_PARAM, &pass_column_2.s    },
133
+	{"flags_column",      STR_PARAM, &flags_column.s     },
131 134
 	{"calculate_ha1",     INT_PARAM, &calc_ha1           },
132
-	{"use_domain",        INT_PARAM, &use_domain         },
133 135
 	{"load_credentials",  STR_PARAM, &credentials_list.s },
134 136
 	{0, 0, 0}
135 137
 };
... ...
@@ -168,10 +170,11 @@ static int mod_init(void)
168 170
 
169 171
 	DBG("auth_db module - initializing\n");
170 172
 
171
-	user_column.len = strlen(user_column.s);
172
-	domain_column.len = strlen(domain_column.s);
173
+	username_column.len = strlen(username_column.s);
174
+	realm_column.len = strlen(realm_column.s);
173 175
 	pass_column.len = strlen(pass_column.s);
174 176
 	pass_column_2.len = strlen(pass_column.s);
177
+	flags_column.len = strlen(flags_column.s);
175 178
 
176 179
 	credentials_list.len = strlen(credentials_list.s);
177 180
 
... ...
@@ -195,7 +198,7 @@ static int mod_init(void)
195 198
 
196 199
 	sl_reply = find_export("sl_send_reply", 2, 0);
197 200
 	if (!sl_reply) {
198
-		LOG(L_ERR, "auth_db:mod_init(): This module requires sl module\n");
201
+		LOG(L_ERR, "auth_db:mod_init: This module requires sl module\n");
199 202
 		return -4;
200 203
 	}
201 204
 
... ...
@@ -41,15 +41,15 @@
41 41
  * Module parameters variables
42 42
  */
43 43
 
44
-extern str user_column;     /* 'username' column name */
45
-extern str domain_column;   /* 'domain' column name */
44
+extern str username_column; /* 'username' column name */
45
+extern str realm_column;    /* 'realm' column name */
46 46
 extern str pass_column;     /* 'password' column name */
47 47
 extern str pass_column_2;   /* Column containing HA1 string constructed
48 48
 			     * of user@domain username
49 49
 			     */
50
+extern str flags_column;    /* Flags column in credentials table */
50 51
 
51 52
 extern int calc_ha1;          /* if set to 1, ha1 is calculated by the server */
52
-extern int use_domain;        /* If set to 1 then the domain will be used when selecting a row */
53 53
 
54 54
 extern db_con_t* auth_db_handle; /* database connection handle */
55 55
 extern db_func_t auth_dbf;
... ...
@@ -62,6 +62,6 @@ extern int credentials_n;
62 62
 /*
63 63
  * Pointer to reply function in stateless module
64 64
  */
65
-extern int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2);
65
+extern int (*sl_reply)(struct sip_msg* msg, char* str1, char* str2);
66 66
 
67 67
 #endif /* AUTHDB_MOD_H */
... ...
@@ -52,73 +52,88 @@
52 52
 #define MESSAGE_500 "Server Internal Error"
53 53
 
54 54
 
55
-static inline int get_ha1(struct username* _username, str* _domain,
56
-			  char* _table, char* _ha1, db_res_t** res)
55
+static inline int get_ha1(struct username* username, str* realm,
56
+			  char* table, char* ha1, db_res_t** res, int* row)
57 57
 {
58 58
 	db_key_t keys[2];
59 59
 	db_val_t vals[2];
60
-	db_key_t *col;
60
+	db_val_t* val;
61
+	db_key_t* col;
61 62
 	str result;
62
-	int n, nc;
63
+	int n, nc, i;
63 64
 
64
-	col = pkg_malloc(sizeof(*col) * (credentials_n + 1));
65
+	col = pkg_malloc(sizeof(*col) * (credentials_n + 2));
65 66
 	if (col == NULL) {
66
-		LOG(L_ERR, "get_ha1(): Error while allocating memory\n");
67
+		LOG(L_ERR, "auth_db:get_ha1: Error while allocating memory\n");
67 68
 		return -1;
68 69
 	}
69 70
 
70
-	keys[0] = user_column.s;
71
-	keys[1] = domain_column.s;
72
-	col[0] = (_username->domain.len && !calc_ha1) ? (pass_column_2.s) : (pass_column.s);
71
+	keys[0] = username_column.s;
72
+	keys[1] = realm_column.s;
73
+	col[0] = (username->domain.len && !calc_ha1) ? (pass_column_2.s) : (pass_column.s);
74
+	col[1] = flags_column.s;
73 75
 
74 76
 	for (n = 0; n < credentials_n; n++) {
75
-		col[1 + n] = credentials[n].s;
77
+		col[2 + n] = credentials[n].s;
76 78
 	}
77 79
 
78
-	VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB_STR;
79
-	VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
80
+	vals[0].type = vals[1].type = DB_STR;
81
+	vals[0].nul = vals[1].nul = 0;
82
+	vals[0].val.str_val = username->user;
80 83
 
81
-	VAL_STR(vals).s = _username->user.s;
82
-	VAL_STR(vals).len = _username->user.len;
83
-
84
-	if (_username->domain.len) {
85
-		VAL_STR(vals + 1) = _username->domain;
84
+	if (username->domain.len) {
85
+		vals[1].val.str_val = username->domain;
86 86
 	} else {
87
-		VAL_STR(vals + 1) = *_domain;
87
+		vals[1].val.str_val = *realm;
88 88
 	}
89 89
 
90
-	n = (use_domain ? 2 : 1);
91
-	nc = 1 + credentials_n;
92
-	if (auth_dbf.use_table(auth_db_handle, _table) < 0) {
93
-		LOG(L_ERR, "get_ha1(): Error in use_table\n");
90
+	n = 2;
91
+	nc = 2 + credentials_n;
92
+	if (auth_dbf.use_table(auth_db_handle, table) < 0) {
93
+		LOG(L_ERR, "auth_db:get_ha1: Error in use_table\n");
94 94
 		pkg_free(col);
95 95
 		return -1;
96 96
 	}
97 97
 
98 98
 	if (auth_dbf.query(auth_db_handle, keys, 0, vals, col, n, nc, 0, res) < 0) {
99
-		LOG(L_ERR, "get_ha1(): Error while querying database\n");
99
+		LOG(L_ERR, "auth_db:get_ha1: Error while querying database\n");
100 100
 		pkg_free(col);
101 101
 		return -1;
102 102
 	}
103 103
 	pkg_free(col);
104 104
 
105
-	if ((RES_ROW_N(*res) == 0) || VAL_NULL(ROW_VALUES(RES_ROWS(*res)))) {
106
-		DBG("get_ha1(): no result for user \'%.*s@%.*s\'\n",
107
-		    _username->user.len, ZSW(_username->user.s), (use_domain ? (_domain->len) : 0), ZSW(_domain->s));
108
-		return 1;
105
+	for(i = 0; i < (*res)->n; i++) {
106
+		val = ((*res)->rows[i].values);
107
+
108
+		if (val[0].nul || val[1].nul) {
109
+			LOG(L_ERR, "auth_db:get_ha1: Credentials for '%.*s'@'%.*s' contain NULL value, skipping\n",
110
+			    username->user.len, ZSW(username->user.s), realm->len, ZSW(realm->s));
111
+			return 1;
112
+		}
113
+
114
+		if (val[1].val.int_val & DB_LOAD_SER) {
115
+			*row = i;
116
+			break;
117
+		}
109 118
 	}
110 119
 
111
-        result.s = (char*)ROW_VALUES(RES_ROWS(*res))[0].val.string_val;
120
+	if (i == (*res)->n) {
121
+		DBG("auth_db:get_ha1: Credentials for '%.*s'@'%.*s' not found",
122
+		    username->user.len, ZSW(username->user.s), realm->len, ZSW(realm->s));
123
+		return 1;
124
+	}		
125
+
126
+        result.s = (char*)val[0].val.string_val;
112 127
 	result.len = strlen(result.s);
113 128
 
114 129
 	if (calc_ha1) {
115 130
 		     /* Only plaintext passwords are stored in database,
116 131
 		      * we have to calculate HA1 */
117
-		calc_HA1(HA_MD5, &_username->whole, _domain, &result, 0, 0, _ha1);
118
-		DBG("HA1 string calculated: %s\n", _ha1);
132
+		calc_HA1(HA_MD5, &username->whole, realm, &result, 0, 0, ha1);
133
+		DBG("auth_db:get_ha1: HA1 string calculated: %s\n", ha1);
119 134
 	} else {
120
-		memcpy(_ha1, result.s, result.len);
121
-		_ha1[result.len] = '\0';
135
+		memcpy(ha1, result.s, result.len);
136
+		ha1[result.len] = '\0';
122 137
 	}
123 138
 
124 139
 	return 0;
... ...
@@ -128,7 +143,7 @@ static inline int get_ha1(struct username* _username, str* _domain,
128 143
  * Calculate the response and compare with the given response string
129 144
  * Authorization is successful if this two strings are same
130 145
  */
131
-static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
146
+static inline int check_response(dig_cred_t* cred, str* method, char* ha1)
132 147
 {
133 148
 	HASHHEX resp, hent;
134 149
 
... ...
@@ -136,8 +151,8 @@ static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
136 151
 	      * First, we have to verify that the response received has
137 152
 	      * the same length as responses created by us
138 153
 	      */
139
-	if (_cred->response.len != 32) {
140
-		DBG("check_response(): Receive response len != 32\n");
154
+	if (cred->response.len != 32) {
155
+		DBG("auth_db:check_response: Receive response len != 32\n");
141 156
 		return 1;
142 157
 	}
143 158
 
... ...
@@ -145,22 +160,22 @@ static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
145 160
 	      * Now, calculate our response from parameters received
146 161
 	      * from the user agent
147 162
 	      */
148
-	calc_response(_ha1, &(_cred->nonce), 
149
-		      &(_cred->nc), &(_cred->cnonce), 
150
-		      &(_cred->qop.qop_str), _cred->qop.qop_parsed == QOP_AUTHINT,
151
-		      _method, &(_cred->uri), hent, resp);
163
+	calc_response(ha1, &(cred->nonce), 
164
+		      &(cred->nc), &(cred->cnonce), 
165
+		      &(cred->qop.qop_str), cred->qop.qop_parsed == QOP_AUTHINT,
166
+		      method, &(cred->uri), hent, resp);
152 167
 	
153
-	DBG("check_response(): Our result = \'%s\'\n", resp);
168
+	DBG("auth_db:check_response: Our result = \'%s\'\n", resp);
154 169
 	
155 170
 	     /*
156 171
 	      * And simply compare the strings, the user is
157 172
 	      * authorized if they match
158 173
 	      */
159
-	if (!memcmp(resp, _cred->response.s, 32)) {
160
-		DBG("check_response(): Authorization is OK\n");
174
+	if (!memcmp(resp, cred->response.s, 32)) {
175
+		DBG("auth_db:check_response: Authorization is OK\n");
161 176
 		return 0;
162 177
 	} else {
163
-		DBG("check_response(): Authorization failed\n");
178
+		DBG("auth_db:check_response: Authorization failed\n");
164 179
 		return 2;
165 180
 	}
166 181
 }
... ...
@@ -169,30 +184,30 @@ static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
169 184
 /*
170 185
  * Generate AVPs from the database result
171 186
  */
172
-static int generate_avps(db_res_t* result)
187
+static int generate_avps(db_res_t* result, unsigned int row)
173 188
 {
174 189
 	int i;
175 190
 	int_str iname, ivalue;
176 191
 	str value;
177 192
 
178
-	for (i = 1; i <= credentials_n; i++) {
179
-		value.s = (char*)VAL_STRING(&(result->rows[0].values[i]));
193
+	for (i = 2; i < credentials_n + 2; i++) {
194
+		value.s = (char*)VAL_STRING(&(result->rows[row].values[i]));
180 195
 
181
-		if (VAL_NULL(&(result->rows[0].values[i]))
196
+		if (VAL_NULL(&(result->rows[row].values[i]))
182 197
 		    || value.s == NULL) {
183 198
 			continue;
184 199
 		}
185 200
 		
186
-		iname.s = &credentials[i - 1];
201
+		iname.s = &credentials[i - 2];
187 202
 		value.len = strlen(value.s);
188 203
 		ivalue.s = &value;
189 204
 
190 205
 		if (add_avp(AVP_NAME_STR | AVP_VAL_STR, iname, ivalue) < 0) {
191
-			LOG(L_ERR, "generate_avps: Error while creating AVPs\n");
206
+			LOG(L_ERR, "auth_db:generate_avps: Error while creating AVPs\n");
192 207
 			return -1;
193 208
 		}
194 209
 
195
-		DBG("generate_avps: set string AVP \'%.*s = %.*s\'\n",
210
+		DBG("auth_db:generate_avps: set string AVP \'%.*s = %.*s\'\n",
196 211
 		    iname.s->len, ZSW(iname.s->s), value.len, ZSW(value.s));
197 212
 	}
198 213
 
... ...
@@ -201,37 +216,37 @@ static int generate_avps(db_res_t* result)
201 216
 
202 217
 
203 218
 /*
204
- * Authorize digest credentials
219
+ * Authenticate digest credentials
205 220
  */
206
-static inline int authorize(struct sip_msg* _m, str* _realm, char* _table,
207
-								hdr_types_t _hftype)
221
+static inline int authenticate(struct sip_msg* msg, str* realm, char* table,
222
+			       hdr_types_t hftype)
208 223
 {
209 224
 	char ha1[256];
210
-	int res;
225
+	int res, row;
211 226
 	struct hdr_field* h;
212 227
 	auth_body_t* cred;
213 228
 	auth_result_t ret;
214
-	str domain;
229
+	str r;
215 230
 	db_res_t* result;
216 231
 
217
-	domain = *_realm;
232
+	r = *realm;
218 233
 
219
-	ret = auth_api.pre_auth(_m, &domain, _hftype, &h);
234
+	ret = auth_api.pre_auth(msg, &r, hftype, &h);
220 235
 
221 236
 	switch(ret) {
222
-	case ERROR:            return 0;
223
-	case NOT_AUTHORIZED:   return -1;
224
-	case DO_AUTHORIZATION: break;
225
-	case AUTHORIZED:       return 1;
237
+	case ERROR:             return 0;
238
+	case NOT_AUTHENTICATED: return -1;
239
+	case DO_AUTHENTICATION: break;
240
+	case AUTHENTICATED:     return 1;
226 241
 	}
227 242
 
228 243
 	cred = (auth_body_t*)h->parsed;
229 244
 
230
-	res = get_ha1(&cred->digest.username, &domain, _table, ha1, &result);
245
+	res = get_ha1(&cred->digest.username, &r, table, ha1, &result, &row);
231 246
         if (res < 0) {
232 247
 		     /* Error while accessing the database */
233
-		if (sl_reply(_m, (char*)500, MESSAGE_500) == -1) {
234
-			LOG(L_ERR, "authorize(): Error while sending 500 reply\n");
248
+		if (sl_reply(msg, (char*)500, MESSAGE_500) == -1) {
249
+			LOG(L_ERR, "auth_db:authenticate: Error while sending 500 reply\n");
235 250
 		}
236 251
 		return 0;
237 252
 	}
... ...
@@ -242,19 +257,19 @@ static inline int authorize(struct sip_msg* _m, str* _realm, char* _table,
242 257
 	}
243 258
 
244 259
 	     /* Recalculate response, it must be same to authorize successfully */
245
-        if (!check_response(&(cred->digest), &_m->first_line.u.request.method, ha1)) {
246
-		ret = auth_api.post_auth(_m, h);
260
+        if (!check_response(&(cred->digest), &msg->first_line.u.request.method, ha1)) {
261
+		ret = auth_api.post_auth(msg, h);
247 262
 		switch(ret) {
248 263
 		case ERROR:
249 264
 			auth_dbf.free_result(auth_db_handle, result);
250 265
 			return 1;
251 266
 
252
-		case NOT_AUTHORIZED:
267
+		case NOT_AUTHENTICATED:
253 268
 			auth_dbf.free_result(auth_db_handle, result);
254 269
 			return -1;
255 270
 
256
-		case AUTHORIZED:
257
-			generate_avps(result);
271
+		case AUTHENTICATED:
272
+			generate_avps(result, row);
258 273
 			auth_dbf.free_result(auth_db_handle, result);
259 274
 			return 1;
260 275
 		default:
... ...
@@ -268,20 +283,39 @@ static inline int authorize(struct sip_msg* _m, str* _realm, char* _table,
268 283
 }
269 284
 
270 285
 
286
+/*
287
+ * Authenticate using Proxy-Authorize header field
288
+ */
289
+int proxy_authenticate(struct sip_msg* msg, char* realm, char* table)
290
+{
291
+	     /* realm parameter is converted to str* in str_fixup */
292
+	return authenticate(msg, (str*)realm, table, HDR_PROXYAUTH_T);
293
+}
294
+
295
+
296
+/*
297
+ * Authorize using WWW-Authorize header field
298
+ */
299
+int www_authenticate(struct sip_msg* msg, char* realm, char* table)
300
+{
301
+	return authenticate(msg, (str*)realm, table, HDR_AUTHORIZATION_T);
302
+}
303
+
304
+
271 305
 /*
272 306
  * Authorize using Proxy-Authorize header field
273 307
  */
274
-int proxy_authorize(struct sip_msg* _m, char* _realm, char* _table)
308
+int proxy_authenticate1(struct sip_msg* msg, char* table)
275 309
 {
276 310
 	     /* realm parameter is converted to str* in str_fixup */
277
-	return authorize(_m, (str*)_realm, _table, HDR_PROXYAUTH_T);
311
+	return authenticate(msg, 0, table, HDR_PROXYAUTH_T);
278 312
 }
279 313
 
280 314
 
281 315
 /*
282 316
  * Authorize using WWW-Authorize header field
283 317
  */
284
-int www_authorize(struct sip_msg* _m, char* _realm, char* _table)
318
+int www_authenticate1(struct sip_msg* msg, char* table)
285 319
 {
286
-	return authorize(_m, (str*)_realm, _table, HDR_AUTHORIZATION_T);
320
+	return authenticate(msg, 0, table, HDR_AUTHORIZATION_T);
287 321
 }
... ...
@@ -41,13 +41,24 @@ void auth_db_close();
41 41
 /*
42 42
  * Authorize using Proxy-Authorization header field
43 43
  */
44
-int proxy_authorize(struct sip_msg* _msg, char* _realm, char* _table);
44
+int proxy_authenticate(struct sip_msg* msg, char* realm, char* table);
45 45
 
46 46
 
47 47
 /*
48 48
  * Authorize using WWW-Authorization header field
49 49
  */
50
-int www_authorize(struct sip_msg* _msg, char* _realm, char* _table);
50
+int www_authenticate(struct sip_msg* msg, char* realm, char* table);
51
+
52
+/*
53
+ * Authorize using Proxy-Authorization header field
54
+ */
55
+int proxy_authenticate1(struct sip_msg* msg, char* table, char* s);
56
+
57
+
58
+/*
59
+ * Authorize using WWW-Authorization header field
60
+ */
61
+int www_authenticate1(struct sip_msg* msg, char* table, char* s);
51 62
 
52 63
 
53 64
 #endif /* AUTHORIZE_H */