1 /*
2  * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2013-2014, Grasshopper
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is Grasshopper
20  * Portions created by the Initial Developer are Copyright (C)
21  * the Initial Developer. All Rights Reserved.
22  *
23  * Contributor(s):
24  * Chris Rienzo <chris.rienzo@grasshopper.com>
25  *
26  * iks_helpers.c -- iksemel helpers
27  *
28  */
29 #include "iks_helpers.h"
30 #include <switch.h>
31 #include <openssl/hmac.h>
32 #include <openssl/sha.h>
33 
34 #undef XMPP_ERROR
35 #define XMPP_ERROR(def_name, name, type) \
36 	const struct xmpp_error def_name##_val = { name, type }; \
37 	const struct xmpp_error *def_name = &def_name##_val;
38 #include "xmpp_errors.def"
39 
40 /**
41  * Create a <presence> event
42  * @param name the event name
43  * @param namespace the event namespace
44  * @param from
45  * @param to
46  * @return the event XML node
47  */
iks_new_presence(const char * name,const char * namespace,const char * from,const char * to)48 iks *iks_new_presence(const char *name, const char *namespace, const char *from, const char *to)
49 {
50 	iks *event = iks_new("presence");
51 	iks *x;
52 	/* iks makes copies of attrib name and value */
53 	iks_insert_attrib(event, "from", from);
54 	iks_insert_attrib(event, "to", to);
55 	x = iks_insert(event, name);
56 	if (!zstr(namespace)) {
57 		iks_insert_attrib(x, "xmlns", namespace);
58 	}
59 	return event;
60 }
61 
62 /**
63  * Create error response from request
64  * @param req the request
65  * @param from
66  * @param to
67  * @param err the XMPP stanza error
68  * @return the error response
69  */
iks_new_error(iks * req,const struct xmpp_error * err)70 iks *iks_new_error(iks *req, const struct xmpp_error *err)
71 {
72 	iks *response = iks_copy(req);
73 	iks *x;
74 
75 	/* <iq> */
76 	iks_insert_attrib(response, "from", iks_find_attrib(req, "to"));
77 	iks_insert_attrib(response, "to", iks_find_attrib(req, "from"));
78 	iks_insert_attrib(response, "type", "error");
79 
80 	/* <error> */
81 	x = iks_insert(response, "error");
82 	iks_insert_attrib(x, "type", err->type);
83 
84 	/* e.g. <feature-not-implemented> */
85 	x = iks_insert(x, err->name);
86 	iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_STANZAS);
87 
88 	return response;
89 }
90 
91 /**
92  * Create error response from request
93  * @param req the request
94  * @param from
95  * @param to
96  * @param err the XMPP stanza error
97  * @param detail_text optional text to include in message
98  * @return the <iq> error response
99  */
iks_new_error_detailed(iks * req,const struct xmpp_error * err,const char * detail_text)100 iks *iks_new_error_detailed(iks *req, const struct xmpp_error *err, const char *detail_text)
101 {
102 	iks *reply = iks_new_error(req, err);
103 	if (!zstr(detail_text)) {
104 		iks *error = iks_find(reply, "error");
105 		iks *text = iks_insert(error, "text");
106 		iks_insert_attrib(text, "xml:lang", "en");
107 		iks_insert_attrib(text, "xmlns", IKS_NS_XMPP_STANZAS);
108 		iks_insert_cdata(text, detail_text, strlen(detail_text));
109 	}
110 	return reply;
111 }
112 
113 /**
114  * Create error response from request
115  * @param req the request
116  * @param from
117  * @param to
118  * @param err the XMPP stanza error
119  * @param detail_text_format format string
120  * @param ...
121  * @return the error response
122  */
iks_new_error_detailed_printf(iks * req,const struct xmpp_error * err,const char * detail_text_format,...)123 iks *iks_new_error_detailed_printf(iks *req, const struct xmpp_error *err, const char *detail_text_format, ...)
124 {
125 	iks *reply = NULL;
126 	char *data;
127 	va_list ap;
128 	int ret;
129 
130 	va_start(ap, detail_text_format);
131 	ret = switch_vasprintf(&data, detail_text_format, ap);
132 	va_end(ap);
133 
134 	if (ret == -1) {
135 		return NULL;
136 	}
137 	reply = iks_new_error_detailed(req, err, data);
138 	free(data);
139 	return reply;
140 }
141 
142 /**
143  * Create <iq> result response from request
144  * @param iq the request
145  * @return the result response
146  */
iks_new_iq_result(iks * iq)147 iks *iks_new_iq_result(iks *iq)
148 {
149 	iks *response = iks_new("iq");
150 	iks_insert_attrib(response, "from", iks_find_attrib(iq, "to"));
151 	iks_insert_attrib(response, "to", iks_find_attrib(iq, "from"));
152 	iks_insert_attrib(response, "type", "result");
153 	iks_insert_attrib(response, "id", iks_find_attrib(iq, "id"));
154 	return response;
155 }
156 
157 /**
158  * Get attribute value of node, returning empty string if non-existent or not set.
159  * @param xml the XML node to search
160  * @param attrib the Attribute name
161  * @return the attribute value
162  */
iks_find_attrib_soft(iks * xml,const char * attrib)163 const char *iks_find_attrib_soft(iks *xml, const char *attrib)
164 {
165 	char *value = iks_find_attrib(xml, attrib);
166 	return zstr(value) ? "" : value;
167 }
168 
169 /**
170  * Get attribute value of node, returning default value if missing.  The default value
171  * is set in the node if missing.
172  * @param xml the XML node to search
173  * @param attrib the Attribute name
174  * @return the attribute value
175  */
iks_find_attrib_default(iks * xml,const char * attrib,const char * def)176 const char *iks_find_attrib_default(iks *xml, const char *attrib, const char *def)
177 {
178 	char *value = iks_find_attrib(xml, attrib);
179 	if (!value) {
180 		iks_insert_attrib(xml, attrib, def);
181 		return def;
182 	}
183 	return value;
184 }
185 
186 /**
187  * Get attribute integer value of node
188  * @param xml the XML node to search
189  * @param attrib the Attribute name
190  * @return the attribute value
191  */
iks_find_int_attrib(iks * xml,const char * attrib)192 int iks_find_int_attrib(iks *xml, const char *attrib)
193 {
194 	return atoi(iks_find_attrib_soft(xml, attrib));
195 }
196 
197 /**
198  * Get attribute boolean value of node
199  * @param xml the XML node to search
200  * @param attrib the Attribute name
201  * @return the attribute value
202  */
iks_find_bool_attrib(iks * xml,const char * attrib)203 int iks_find_bool_attrib(iks *xml, const char *attrib)
204 {
205 	return switch_true(iks_find_attrib_soft(xml, attrib));
206 }
207 
208 /**
209  * Get attribute double value of node
210  * @param xml the XML node to search
211  * @param attrib the Attribute name
212  * @return the attribute value
213  */
iks_find_decimal_attrib(iks * xml,const char * attrib)214 double iks_find_decimal_attrib(iks *xml, const char *attrib)
215 {
216 	return atof(iks_find_attrib_soft(xml, attrib));
217 }
218 
219 /**
220  * Get attribute character value of node
221  * @param xml the XML node to search
222  * @param attrib the Attribute name
223  * @return the attribute value
224  */
iks_find_char_attrib(iks * xml,const char * attrib)225 char iks_find_char_attrib(iks *xml, const char *attrib)
226 {
227 	return iks_find_attrib_soft(xml, attrib)[0];
228 }
229 
230 /**
231  * Convert iksemel XML node type to string
232  * @param type the XML node type
233  * @return the string value of type or "UNKNOWN"
234  */
iks_node_type_to_string(int type)235 const char *iks_node_type_to_string(int type)
236 {
237 	switch(type) {
238 		case IKS_NODE_START: return "NODE_START";
239 		case IKS_NODE_NORMAL: return "NODE_NORMAL";
240 		case IKS_NODE_ERROR: return "NODE_ERROR";
241 		case IKS_NODE_STOP: return "NODE_START";
242 		default: return "NODE_UNKNOWN";
243 	}
244 }
245 
246 /**
247  * Convert iksemel error code to string
248  * @param err the iksemel error code
249  * @return the string value of error or "UNKNOWN"
250  */
iks_net_error_to_string(int err)251 const char *iks_net_error_to_string(int err)
252 {
253 	switch (err) {
254 		case IKS_OK: return "OK";
255 		case IKS_NOMEM: return "NOMEM";
256 		case IKS_BADXML: return "BADXML";
257 		case IKS_HOOK: return "HOOK";
258 		case IKS_NET_NODNS: return "NET_NODNS";
259 		case IKS_NET_NOSOCK: return "NET_NOSOCK";
260 		case IKS_NET_NOCONN: return "NET_NOCONN";
261 		case IKS_NET_RWERR: return "NET_RWERR";
262 		case IKS_NET_NOTSUPP: return "NET_NOTSUPP";
263 		case IKS_NET_TLSFAIL: return "NET_TLSFAIL";
264 		case IKS_NET_DROPPED: return "NET_DROPPED";
265 		case IKS_NET_UNKNOWN: return "NET_UNKNOWN";
266 		default: return "UNKNOWN";
267 	}
268 }
269 
270 /**
271  * Insert attribute using format string
272  * @param xml node to insert attribute into
273  * @param name of attribute
274  * @param fmt format string
275  * @param ... format string args
276  */
iks_insert_attrib_printf(iks * xml,const char * name,const char * fmt,...)277 iks *iks_insert_attrib_printf(iks *xml, const char *name, const char *fmt, ...)
278 {
279 	iks *node;
280 	char *data;
281 	va_list ap;
282 	int ret;
283 
284 	va_start(ap, fmt);
285 	ret = switch_vasprintf(&data, fmt, ap);
286 	va_end(ap);
287 
288 	if (ret == -1) {
289 		return NULL;
290 	}
291 	node = iks_insert_attrib(xml, name, data);
292 	free(data);
293 
294 	return node;
295 }
296 
297 /**
298  * @param value to match
299  * @param rule to check
300  * @return true if value is one of the comma-separated values in rule
301  */
value_matches(const char * value,const char * rule)302 int value_matches(const char *value, const char *rule)
303 {
304 	if (rule && *rule && value && *value && !strchr(value, ',')) {
305 		const char *begin = strstr(rule, value);
306 		const char *end = begin + strlen(value);
307 		if (!begin) {
308 			return 0;
309 		}
310 		if ((begin == rule || *(begin - 1) == ',') && (*end == ',' || *end == '\0')) {
311 				return 1;
312 		}
313 		/* substring matched... try farther down the string */
314 		return value_matches(value, end);
315 	}
316 	return 0;
317 }
318 
319 /**
320  * Validate boolean
321  * @param value
322  * @return SWTICH_TRUE if boolean
323  */
iks_attrib_is_bool(const char * value)324 int iks_attrib_is_bool(const char *value)
325 {
326 	if (value && *value && (!strcasecmp("true", value) || !strcasecmp("false", value))) {
327 		return SWITCH_TRUE;
328 	}
329 	return SWITCH_FALSE;
330 }
331 
332 /**
333  * Validate integer
334  * @param value
335  * @return SWTICH_TRUE if not negative
336  */
iks_attrib_is_not_negative(const char * value)337 int iks_attrib_is_not_negative(const char *value)
338 {
339 	if (value && *value && switch_is_number(value)) {
340 		int value_i = atoi(value);
341 		if (value_i >= 0) {
342 			return SWITCH_TRUE;
343 		}
344 	}
345 	return SWITCH_FALSE;
346 }
347 
348 /**
349  * Validate integer
350  * @param value
351  * @return SWTICH_TRUE if positive
352  */
iks_attrib_is_positive(const char * value)353 int iks_attrib_is_positive(const char *value)
354 {
355 	if (value && *value && switch_is_number(value)) {
356 		int value_i = atoi(value);
357 		if (value_i > 0) {
358 			return SWITCH_TRUE;
359 		}
360 	}
361 	return SWITCH_FALSE;
362 }
363 
364 /**
365  * Validate integer
366  * @param value
367  * @return SWTICH_TRUE if positive or -1
368  */
iks_attrib_is_positive_or_neg_one(const char * value)369 int iks_attrib_is_positive_or_neg_one(const char *value)
370 {
371 	if (value && *value && switch_is_number(value)) {
372 		int value_i = atoi(value);
373 		if (value_i == -1 || value_i > 0) {
374 			return SWITCH_TRUE;
375 		}
376 	}
377 	return SWITCH_FALSE;
378 }
379 
380 /**
381  * Validate string
382  * @param value
383  * @return SWTICH_TRUE
384  */
iks_attrib_is_any(const char * value)385 int iks_attrib_is_any(const char *value)
386 {
387 	return SWITCH_TRUE;
388 }
389 
390 /**
391  * Validate decimal
392  * @param value
393  * @return SWTICH_TRUE if 0.0 <= x <= 1.0
394  */
iks_attrib_is_decimal_between_zero_and_one(const char * value)395 int iks_attrib_is_decimal_between_zero_and_one(const char *value)
396 {
397 	if (value && *value && switch_is_number(value)) {
398 		double value_d = atof(value);
399 		if (value_d >= 0.0 && value_d <= 1.0) {
400 			return SWITCH_TRUE;
401 		}
402 	}
403 	return SWITCH_FALSE;
404 }
405 
406 /**
407  * Validate dtmf digit
408  * @param value
409  * @return SWITCH_TRUE if 0-9,a,b,c,d,A,B,C,D,*,#
410  */
iks_attrib_is_dtmf_digit(const char * value)411 int iks_attrib_is_dtmf_digit(const char *value)
412 {
413 	if (value && *value && strlen(value) == 1) {
414 		switch (*value) {
415 			case '0':
416 			case '1':
417 			case '2':
418 			case '3':
419 			case '4':
420 			case '5':
421 			case '6':
422 			case '7':
423 			case '8':
424 			case '9':
425 			case 'A':
426 			case 'a':
427 			case 'B':
428 			case 'b':
429 			case 'C':
430 			case 'c':
431 			case 'D':
432 			case 'd':
433 			case '*':
434 			case '#':
435 				return SWITCH_TRUE;
436 		}
437 	}
438 	return SWITCH_FALSE;
439 }
440 
441 /**
442  * @param fn to evaluate attribute
443  * @param attrib to evaluate
444  * @return true if not set or is valid
445  */
validate_optional_attrib(iks_attrib_validation_function fn,const char * attrib)446 int validate_optional_attrib(iks_attrib_validation_function fn, const char *attrib)
447 {
448 	if (!attrib || !*attrib) {
449 		return SWITCH_TRUE;
450 	}
451 	return fn(attrib);
452 }
453 
454 #define IKS_SHA256_HEX_DIGEST_LENGTH ((SHA256_DIGEST_LENGTH * 2) + 1)
455 
456 /**
457  * Convert hash to a hex string.
458  * @param hash hash to convert
459  * @param str buffer to store hash - this buffer must be hashlen * 2 + 1 in size.
460  */
iks_hash_to_hex_string(unsigned char * hash,int hashlen,unsigned char * str)461 static void iks_hash_to_hex_string(unsigned char *hash, int hashlen, unsigned char *str)
462 {
463 	static const char *HEX = "0123456789abcdef";
464 	int i;
465 
466 	/* convert to hex string with in-place algorithm */
467 	for (i = hashlen - 1; i >= 0; i--) {
468 		str[i * 2 + 1] = HEX[hash[i] & 0x0f];
469 		str[i * 2] = HEX[(hash[i] >> 4) & 0x0f];
470 	}
471 	str[hashlen * 2] = '\0';
472 }
473 
474 /**
475  * Generate SHA-256 hash of value as hex string
476  * @param data to hash
477  * @param datalen length of data to hash
478  * @return hash as a hex string
479  */
iks_sha256_hex_string(const unsigned char * data,int datalen,unsigned char * hash)480 static void iks_sha256_hex_string(const unsigned char *data, int datalen, unsigned char *hash)
481 {
482 	/* hash data */
483 	SHA256(data, datalen, hash);
484 	iks_hash_to_hex_string(hash, SHA256_DIGEST_LENGTH, hash);
485 }
486 
487 /**
488  * Generate HMAC SHA-256
489  * @param key the key
490  * @param keylen length of key
491  * @param message the message
492  * @param messagelen length of message
493  * @param hash buffer to store the hash - must be IKS_SHA256_HEX_DIGEST_LENGTH
494  */
iks_hmac_sha256_hex_string(const unsigned char * key,int keylen,const unsigned char * message,int messagelen,unsigned char * hash)495 static void iks_hmac_sha256_hex_string(const unsigned char *key, int keylen, const unsigned char *message, int messagelen, unsigned char *hash)
496 {
497 	unsigned int hash_len = SHA256_DIGEST_LENGTH;
498 	HMAC(EVP_sha256(), key, keylen, message, messagelen, hash, &hash_len);
499 	iks_hash_to_hex_string(hash, SHA256_DIGEST_LENGTH, hash);
500 }
501 
502 /**
503  * Generate server dialback key.  free() the returned value
504  * @param secret originating server shared secret
505  * @param receiving_server domain
506  * @param originating_server domain
507  * @param stream_id stream ID
508  * @return the dialback key
509  */
iks_server_dialback_key(const char * secret,const char * receiving_server,const char * originating_server,const char * stream_id)510 char *iks_server_dialback_key(const char *secret, const char *receiving_server, const char *originating_server, const char *stream_id)
511 {
512 	if (!zstr(secret) && !zstr(receiving_server) && !zstr(originating_server) && !zstr(stream_id)) {
513 		unsigned char secret_hash[IKS_SHA256_HEX_DIGEST_LENGTH];
514 		unsigned char *message = NULL;
515 		unsigned char *dialback_key = malloc(sizeof(unsigned char) * IKS_SHA256_HEX_DIGEST_LENGTH);
516 		iks_sha256_hex_string((unsigned char *)secret, strlen(secret), secret_hash);
517 		message = (unsigned char *)switch_mprintf("%s %s %s", receiving_server, originating_server, stream_id);
518 		iks_hmac_sha256_hex_string(secret_hash, strlen((char *)secret_hash), message, strlen((char *)message), dialback_key);
519 		free(message);
520 		return (char *)dialback_key;
521 	}
522 	return NULL;
523 }
524 
525 /**
526  * Print base 64 encoded SHA-1 hash
527  * @param sha hash to print
528  * @param buf to store baes 64 encoded hash
529  */
iks_sha_print_base64(iksha * sha,char * buf)530 void iks_sha_print_base64(iksha *sha, char *buf)
531 {
532 	int i;
533 	char hex_digit[3] = { 0 };
534 	char hex_buf[SHA_1_HASH_BUF_SIZE];
535 	unsigned char bin_buf[SHA_1_HASH_BUF_SIZE / 2];
536 	iks_sha_print(sha, hex_buf);
537 
538 	/* convert hex string to octets */
539 	for (i = 0; i < SHA_1_HASH_BUF_SIZE; i += 2) {
540 		hex_digit[0] = hex_buf[i];
541 		hex_digit[1] = hex_buf[i + 1];
542 		bin_buf[i / 2] = strtol(hex_digit, NULL, 16);
543 	}
544 
545 	switch_b64_encode(bin_buf, SHA_1_HASH_BUF_SIZE / 2, (unsigned char *)buf, SHA_1_HASH_BUF_SIZE);
546 }
547 
548 /* For Emacs:
549  * Local Variables:
550  * mode:c
551  * indent-tabs-mode:t
552  * tab-width:4
553  * c-basic-offset:4
554  * End:
555  * For VIM:
556  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
557  */
558