Browse code

modules/auth_ephemeral: Added MI commands for shared secret management

- Can add, remove, and display shared secrets with MI commands
- This means you can add/revoke secrets without a restart

Peter Dunkley authored on 02/10/2013 00:30:37
Showing 5 changed files
... ...
@@ -39,6 +39,12 @@ Peter Dunkley
39 39
               4.6. autheph_check_to([username])
40 40
               4.7. autheph_check_timestamp(username)
41 41
 
42
+        5. MI Commands
43
+
44
+              5.1. autheph.add_secret
45
+              5.2. autheph.dump_secrets
46
+              5.3. autheph.rm_secret
47
+
42 48
    List of Examples
43 49
 
44 50
    1.1. Request example
... ...
@@ -84,6 +90,12 @@ Chapter 1. Admin Guide
84 84
         4.6. autheph_check_to([username])
85 85
         4.7. autheph_check_timestamp(username)
86 86
 
87
+   5. MI Commands
88
+
89
+        5.1. autheph.add_secret
90
+        5.2. autheph.dump_secrets
91
+        5.3. autheph.rm_secret
92
+
87 93
 1. Overview
88 94
 
89 95
    1.1. How ephemeral credentials work
... ...
@@ -421,3 +433,65 @@ if (!autheph_check_timestamp("$var(username)")) {
421 421
     exit;
422 422
 }
423 423
 ...
424
+
425
+5. MI Commands
426
+
427
+   5.1. autheph.add_secret
428
+   5.2. autheph.dump_secrets
429
+   5.3. autheph.rm_secret
430
+
431
+5.1. autheph.add_secret
432
+
433
+   Add a secret to the head of the shared secret list. The secret will be
434
+   the first one tried during future authentication attempts. This MI
435
+   command allows you to update the shared secret list without having to
436
+   restart Kamailio.
437
+
438
+Note
439
+
440
+   If you want your new shared secret list to persist across restarts you
441
+   must add it to your Kamailio configuration file.
442
+
443
+   Name: autheph.add_secret
444
+
445
+   Parameters:
446
+     * secret
447
+
448
+   MI FIFO Command Format:
449
+                        :autheph.add_secret:fifo_reply
450
+                        kamailio_rules
451
+                        _empty_line_
452
+
453
+5.2. autheph.dump_secrets
454
+
455
+   Dump the set of shared secrets.
456
+
457
+   Name: autheph.dump_secrets
458
+
459
+   Parameters:
460
+     * none
461
+
462
+   MI FIFO Command Format:
463
+                        :autheph.dump_secrets:fifo_reply
464
+                        _empty_line_
465
+
466
+5.3. autheph.rm_secret
467
+
468
+   Remove the secret with the specified integer ID. This MI command allows
469
+   you to update the shared secret list without having to restart
470
+   Kamailio.
471
+
472
+Note
473
+
474
+   If you want your new shared secret list to persist across restarts you
475
+   must add it to your Kamailio configuration file.
476
+
477
+   Name: autheph.rm_secret
478
+
479
+   Parameters:
480
+     * ID - the ID of the secret to remove
481
+
482
+   MI FIFO Command Format:
483
+                        :autheph.rm_secret:fifo_reply
484
+                        0
485
+                        _empty_line_
... ...
@@ -21,9 +21,11 @@
21 21
  *
22 22
  */
23 23
 #include "../../dprint.h"
24
+#include "../../locking.h"
24 25
 #include "../../mod_fix.h"
25 26
 #include "../../sr_module.h"
26 27
 #include "../../str.h"
28
+#include "../../lib/kmi/mi.h"
27 29
 #include "../../modules/auth/api.h"
28 30
 
29 31
 #include "autheph_mod.h"
... ...
@@ -37,6 +39,10 @@ static void destroy(void);
37 37
 
38 38
 static int secret_param(modparam_t _type, void *_val);
39 39
 struct secret *secret_list = NULL;
40
+static struct mi_root *mi_dump_secrets(struct mi_root *cmd, void *param);
41
+static struct mi_root *mi_add_secret(struct mi_root *cmd, void *param);
42
+static struct mi_root *mi_rm_secret(struct mi_root *cmd, void *param);
43
+gen_lock_t *autheph_secret_lock = NULL;
40 44
 
41 45
 autheph_username_format_t autheph_username_format = AUTHEPH_USERNAME_IETF;
42 46
 
... ...
@@ -86,6 +92,15 @@ static param_export_t params[]=
86 86
 	{0, 0, 0}
87 87
 };
88 88
 
89
+static mi_export_t mi_cmds[] =
90
+{
91
+	{ "autheph.add_secret",		mi_add_secret,	0, 0, 0 },
92
+	{ "autheph.dump_secrets",	mi_dump_secrets,0, 0, 0 },
93
+	{ "autheph.rm_secret",		mi_rm_secret,	0, 0, 0 },
94
+
95
+	{ 0, 0, 0, 0, 0 }
96
+};
97
+
89 98
 struct module_exports exports=
90 99
 {
91 100
 	"auth_ephemeral", 
... ...
@@ -93,7 +108,7 @@ struct module_exports exports=
93 93
 	cmds,			/* Exported functions */
94 94
 	params,			/* Exported parameters */
95 95
 	0,			/* exported statistics */
96
-	0,			/* exported MI functions */
96
+	mi_cmds,		/* exported MI functions */
97 97
 	0,			/* exported pseudo-variables */
98 98
 	0,			/* extra processes */
99 99
 	mod_init,		/* module initialization function */
... ...
@@ -106,6 +121,12 @@ static int mod_init(void)
106 106
 {
107 107
 	bind_auth_s_t bind_auth;
108 108
 
109
+	if (register_mi_mod(exports.name, mi_cmds) != 0)
110
+	{
111
+		LM_ERR("registering MI commands\n");
112
+		return -1;
113
+	}
114
+
109 115
 	if (secret_list == NULL)
110 116
 	{
111 117
 		LM_ERR("secret modparam not set\n");
... ...
@@ -153,16 +174,28 @@ static void destroy(void)
153 153
 {
154 154
 	struct secret *secret_struct;
155 155
 
156
-	while (secret_list != NULL)
156
+	if (secret_list != NULL)
157 157
 	{
158
-		secret_struct = secret_list;
159
-		secret_list = secret_struct->next;
160
-
161
-		if (secret_struct->secret_key.s != NULL)
158
+		SECRET_UNLOCK;
159
+		SECRET_LOCK;
160
+		while (secret_list != NULL)
162 161
 		{
163
-			shm_free(secret_struct->secret_key.s);
162
+			secret_struct = secret_list;
163
+			secret_list = secret_struct->next;
164
+
165
+			if (secret_struct->secret_key.s != NULL)
166
+			{
167
+				shm_free(secret_struct->secret_key.s);
168
+			}
169
+			shm_free(secret_struct);
164 170
 		}
165
-		shm_free(secret_struct);
171
+		SECRET_UNLOCK;
172
+	}
173
+
174
+	if (autheph_secret_lock != NULL)
175
+	{
176
+		lock_destroy(autheph_secret_lock);
177
+		lock_dealloc((void *) autheph_secret_lock);
166 178
 	}
167 179
 }
168 180
 
... ...
@@ -170,6 +203,21 @@ static inline int add_secret(str _secret_key)
170 170
 {
171 171
 	struct secret *secret_struct;
172 172
 
173
+	if (autheph_secret_lock == NULL)
174
+	{
175
+		autheph_secret_lock = lock_alloc();
176
+		if (autheph_secret_lock == NULL)
177
+		{
178
+			LM_ERR("allocating lock\n");
179
+			return -1;
180
+		}
181
+		if (lock_init(autheph_secret_lock) == 0)
182
+		{
183
+			LM_ERR("initialising lock\n");
184
+			return -1;
185
+		}
186
+	}
187
+
173 188
 	secret_struct = (struct secret *) shm_malloc(sizeof(struct secret));
174 189
 	if (secret_struct == NULL)
175 190
 	{
... ...
@@ -178,13 +226,64 @@ static inline int add_secret(str _secret_key)
178 178
 	}
179 179
 
180 180
 	memset(secret_struct, 0, sizeof (struct secret));
181
+	secret_struct->secret_key = _secret_key;
182
+	SECRET_LOCK;
183
+	if (secret_list != NULL)
184
+	{
185
+		secret_list->prev = secret_struct;
186
+	}
181 187
 	secret_struct->next = secret_list;
182 188
 	secret_list = secret_struct;
183
-	secret_struct->secret_key = _secret_key;
189
+	SECRET_UNLOCK;
184 190
 
185 191
 	return 0;
186 192
 }
187 193
 
194
+static inline int rm_secret(int _id)
195
+{
196
+	int pos = 0;
197
+	struct secret *secret_struct;
198
+
199
+	if (secret_list == NULL)
200
+	{
201
+		LM_ERR("secret list empty\n");
202
+		return -1;
203
+	}
204
+
205
+	SECRET_LOCK;
206
+	secret_struct = secret_list;
207
+	while (pos <= _id && secret_struct != NULL)
208
+	{
209
+		if (pos == _id)
210
+		{
211
+			if (secret_struct->prev != NULL)
212
+			{
213
+				secret_struct->prev->next = secret_struct->next;
214
+			}
215
+			if (secret_struct->next != NULL)
216
+			{
217
+				secret_struct->next->prev = secret_struct->prev;
218
+			}
219
+			if (pos == 0)
220
+			{
221
+				secret_list = secret_struct->next;
222
+			}
223
+			SECRET_UNLOCK;
224
+			shm_free(secret_struct->secret_key.s);
225
+			shm_free(secret_struct);
226
+			return 0;
227
+		}
228
+
229
+		pos++;
230
+		secret_struct = secret_struct->next;
231
+
232
+	}
233
+	SECRET_UNLOCK;
234
+
235
+	LM_ERR("ID %d not found\n", _id);
236
+	return -1;
237
+}
238
+
188 239
 static int secret_param(modparam_t _type, void *_val)
189 240
 {
190 241
 	str sval;
... ...
@@ -208,3 +307,143 @@ static int secret_param(modparam_t _type, void *_val)
208 208
 
209 209
 	return add_secret(sval);
210 210
 }
211
+
212
+static str str_status_too_many_params = str_init("Too many parameters");
213
+static str str_status_empty_param = str_init("Not enough parameters");
214
+static str str_status_no_memory = str_init("Unable to allocate shared memory");
215
+static str str_status_string_error = str_init("Error converting string to int");
216
+static str str_status_adding_secret = str_init("Error adding secret");
217
+static str str_status_removing_secret = str_init("Error removing secret");
218
+
219
+static struct mi_root *mi_dump_secrets(struct mi_root *cmd, void *param)
220
+{
221
+	int pos = 0;
222
+	struct secret *secret_struct = secret_list;
223
+	struct mi_root *rpl_tree;
224
+
225
+	if (cmd->node.kids != NULL)
226
+	{
227
+		LM_WARN("too many parameters\n");
228
+		return init_mi_tree(400, str_status_too_many_params.s,
229
+					str_status_too_many_params.len);
230
+	}
231
+
232
+	rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
233
+	if (rpl_tree == NULL)
234
+		return 0;
235
+
236
+	SECRET_LOCK;
237
+	while (secret_struct != NULL)
238
+	{
239
+		if (addf_mi_node_child(&rpl_tree->node, 0, 0, 0,
240
+					"ID %d: %.*s", pos++,
241
+					secret_struct->secret_key.len,
242
+					secret_struct->secret_key.s) == 0)
243
+		{
244
+			free_mi_tree(rpl_tree);
245
+			SECRET_UNLOCK;
246
+			return 0;
247
+		}
248
+		secret_struct = secret_struct->next;
249
+	}
250
+	SECRET_UNLOCK;
251
+
252
+	return rpl_tree;
253
+}
254
+
255
+static struct mi_root *mi_add_secret(struct mi_root *cmd, void *param)
256
+{
257
+	str sval;
258
+	struct mi_node *node = NULL;
259
+
260
+	node = cmd->node.kids;
261
+	if (node == NULL)
262
+	{
263
+		LM_WARN("no secret parameter\n");
264
+		return init_mi_tree(400, str_status_empty_param.s,
265
+						str_status_empty_param.len);
266
+	}
267
+
268
+	if (node->value.s == NULL || node->value.len == 0)
269
+	{
270
+		LM_WARN("empty secret parameter\n");
271
+		return init_mi_tree(400, str_status_empty_param.s,
272
+					str_status_empty_param.len);
273
+	}
274
+
275
+	if (node->next != NULL)
276
+	{
277
+		LM_WARN("too many parameters\n");
278
+		return init_mi_tree(400, str_status_too_many_params.s,
279
+					str_status_too_many_params.len);
280
+	}
281
+
282
+	sval.len = node->value.len;
283
+	sval.s = shm_malloc(sizeof(char) * sval.len);
284
+	if (sval.s == NULL)
285
+	{
286
+		LM_ERR("Unable to allocate shared memory\n");
287
+		return init_mi_tree(400, str_status_no_memory.s,
288
+					str_status_no_memory.len);
289
+	}
290
+	memcpy(sval.s, node->value.s, sval.len);
291
+
292
+	if (add_secret(sval) == 0)
293
+	{
294
+		return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
295
+	}
296
+	else
297
+	{
298
+		LM_ERR("Adding secret\n");
299
+		return init_mi_tree(400, str_status_adding_secret.s,
300
+					str_status_adding_secret.len);
301
+	}
302
+}
303
+
304
+static struct mi_root *mi_rm_secret(struct mi_root *cmd, void *param)
305
+{
306
+	unsigned int id;
307
+	struct mi_node *node = NULL;
308
+
309
+	node = cmd->node.kids;
310
+	if (node == NULL)
311
+	{
312
+		LM_WARN("no id parameter\n");
313
+		return init_mi_tree(400, str_status_empty_param.s,
314
+						str_status_empty_param.len);
315
+	}
316
+
317
+	if (node->value.s == NULL || node->value.len == 0)
318
+	{
319
+		LM_WARN("empty id parameter\n");
320
+		return init_mi_tree(400, str_status_empty_param.s,
321
+					str_status_empty_param.len);
322
+	}
323
+
324
+	if (str2int(&node->value, &id) < 0)
325
+	{
326
+		LM_ERR("converting string to int\n");
327
+		return init_mi_tree(400, str_status_string_error.s,
328
+					str_status_string_error.len);
329
+	}
330
+
331
+	if (node->next != NULL)
332
+	{
333
+		LM_WARN("too many parameters\n");
334
+		return init_mi_tree(400, str_status_too_many_params.s,
335
+					str_status_too_many_params.len);
336
+	}
337
+
338
+	if (rm_secret(id) == 0)
339
+	{
340
+		return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
341
+	}
342
+	else
343
+	{
344
+		LM_ERR("Removing secret\n");
345
+		return init_mi_tree(400, str_status_removing_secret.s,
346
+					str_status_removing_secret.len);
347
+	}
348
+
349
+	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
350
+}
... ...
@@ -23,12 +23,14 @@
23 23
 #ifndef AUTHEPH_MOD_H
24 24
 #define AUTHEPH_MOD_H
25 25
 
26
+#include "../../locking.h"
26 27
 #include "../../str.h"
27 28
 #include "../../modules/auth/api.h"
28 29
 
29 30
 struct secret
30 31
 {
31 32
 	str secret_key;
33
+	struct secret *prev;
32 34
 	struct secret *next;
33 35
 };
34 36
 extern struct secret *secret_list;
... ...
@@ -41,4 +43,8 @@ extern autheph_username_format_t autheph_username_format;
41 41
 
42 42
 extern auth_api_s_t eph_auth_api;
43 43
 
44
+extern gen_lock_t *autheph_secret_lock;
45
+#define SECRET_LOCK	lock_get(autheph_secret_lock)
46
+#define SECRET_UNLOCK	lock_release(autheph_secret_lock)
47
+
44 48
 #endif /* AUTHEPH_MOD_H */
... ...
@@ -170,7 +170,7 @@ static inline int digest_authenticate(struct sip_msg *_m, str *_realm,
170 170
 {
171 171
 	struct hdr_field* h;
172 172
 	int ret;
173
-	struct secret *secret_struct = secret_list;
173
+	struct secret *secret_struct;
174 174
 	str username;
175 175
 
176 176
 	LM_DBG("realm: %.*s\n", _realm->len, _realm->s);
... ...
@@ -216,6 +216,8 @@ static inline int digest_authenticate(struct sip_msg *_m, str *_realm,
216 216
 		return AUTH_ERROR;
217 217
 	}
218 218
 
219
+	SECRET_LOCK;
220
+	secret_struct = secret_list;
219 221
 	while (secret_struct != NULL)
220 222
 	{
221 223
 		ret = do_auth(_m, h, _realm, _method,
... ...
@@ -226,6 +228,7 @@ static inline int digest_authenticate(struct sip_msg *_m, str *_realm,
226 226
 		}
227 227
 		secret_struct = secret_struct->next;
228 228
 	}
229
+	SECRET_UNLOCK;
229 230
 
230 231
 	return ret;
231 232
 }
... ...
@@ -407,7 +410,7 @@ int autheph_authenticate(struct sip_msg *_m, char *_username, char *_password)
407 407
 	str susername, spassword;
408 408
 	char generated_password[base64_enc_len(SHA_DIGEST_LENGTH)];
409 409
 	str sgenerated_password;
410
-	struct secret *secret_struct = secret_list;
410
+	struct secret *secret_struct;
411 411
 
412 412
 	if (_m == NULL || _username == NULL || _password == NULL)
413 413
 	{
... ...
@@ -449,6 +452,8 @@ int autheph_authenticate(struct sip_msg *_m, char *_username, char *_password)
449 449
 	LM_DBG("password: %.*s\n", spassword.len, spassword.s);
450 450
 
451 451
 	sgenerated_password.s = generated_password;
452
+	SECRET_LOCK;
453
+	secret_struct = secret_list;
452 454
 	while (secret_struct != NULL)
453 455
 	{
454 456
 		LM_DBG("trying secret: %.*s\n",
... ...
@@ -462,11 +467,13 @@ int autheph_authenticate(struct sip_msg *_m, char *_username, char *_password)
462 462
 			if (strncmp(spassword.s, sgenerated_password.s,
463 463
 					spassword.len) == 0)
464 464
 			{
465
+				SECRET_UNLOCK;
465 466
 				return AUTH_OK;
466 467
 			}
467 468
 		}
468 469
 		secret_struct = secret_struct->next;
469 470
 	}
471
+	SECRET_UNLOCK;
470 472
 
471 473
 	return AUTH_ERROR;
472 474
 }
... ...
@@ -502,5 +502,73 @@ if (!autheph_check_timestamp("$var(username)")) {
502 502
 		</example>
503 503
 	</section>
504 504
 	</section>
505
+
506
+	<section>
507
+	<title>MI Commands</title>
508
+	<section id="auth_eph.m.autheph.add_secret">
509
+		<title><function moreinfo="none">autheph.add_secret</function></title>
510
+		<para>Add a secret to the head of the shared secret list. The
511
+		secret will be the first one tried during future authentication
512
+		attempts. This MI command allows you to update the shared secret
513
+		list without having to restart Kamailio.</para>
514
+		<note><para>If you want your new shared secret list to persist
515
+		across restarts you must add it to your Kamailio configuration
516
+		file.</para></note>
517
+		<para>Name: <emphasis>autheph.add_secret</emphasis></para>
518
+		<para>Parameters:</para>
519
+		<itemizedlist>
520
+			<listitem>
521
+				<para>secret</para>
522
+			</listitem>
523
+		</itemizedlist>
524
+		<para>MI FIFO Command Format:</para>
525
+		<programlisting  format="linespecific">
526
+			:autheph.add_secret:fifo_reply
527
+			kamailio_rules
528
+			_empty_line_
529
+</programlisting>
530
+	</section>
531
+
532
+	<section id="auth_eph.m.autheph.dump_secrets">
533
+		<title><function moreinfo="none">autheph.dump_secrets</function></title>
534
+		<para>Dump the set of shared secrets.</para>
535
+		<para>Name: <emphasis>autheph.dump_secrets</emphasis></para>
536
+		<para>Parameters:</para>
537
+		<itemizedlist>
538
+			<listitem>
539
+				<para><emphasis>none</emphasis></para>
540
+			</listitem>
541
+		</itemizedlist>
542
+		<para>MI FIFO Command Format:</para>
543
+		<programlisting  format="linespecific">
544
+			:autheph.dump_secrets:fifo_reply
545
+			_empty_line_
546
+</programlisting>
547
+	</section>
548
+
549
+	<section id="auth_eph.m.autheph.rm_secret">
550
+		<title><function moreinfo="none">autheph.rm_secret</function></title>
551
+		<para>Remove the secret with the specified integer ID.  This MI
552
+		command allows you to update the shared secret list without
553
+		having to restart Kamailio.</para>
554
+		<note><para>If you want your new shared secret list to persist
555
+		across restarts you must add it to your Kamailio configuration
556
+		file.</para></note>
557
+		<para>Name: <emphasis>autheph.rm_secret</emphasis></para>
558
+		<para>Parameters:</para>
559
+		<itemizedlist>
560
+			<listitem>
561
+				<para>ID - the ID of the secret to remove</para>
562
+			</listitem>
563
+		</itemizedlist>
564
+		<para>MI FIFO Command Format:</para>
565
+		<programlisting  format="linespecific">
566
+			:autheph.rm_secret:fifo_reply
567
+			0
568
+			_empty_line_
569
+</programlisting>
570
+	</section>
571
+
572
+	</section>
505 573
 </chapter>
506 574