Ver código fonte

uac: use auth_ha1 field if set for remote registrations

- has priority over auth_password field
Daniel-Constantin Mierla 6 anos atrás
pai
commit
9b501c4945
3 arquivos alterados com 152 adições e 48 exclusões
  1. 7 4
      src/modules/uac/auth.h
  2. 43 11
      src/modules/uac/auth_alg.c
  3. 102 33
      src/modules/uac/uac_reg.c

+ 7 - 4
src/modules/uac/auth.h

@@ -26,14 +26,17 @@
 
 #include "../../core/parser/msg_parser.h"
 
-struct uac_credential {
+#define UAC_FLCRED_HA1 (1<<0)
+
+typedef struct uac_credential {
 	str realm;
 	str user;
 	str passwd;
+	uint32_t aflags;
 	struct uac_credential *next;
-};
+} uac_credential_t;
 
-struct authenticate_body {
+typedef struct authenticate_body {
 	int flags;
 	str realm;
 	str domain;
@@ -42,7 +45,7 @@ struct authenticate_body {
 	str qop;
 	str *nc;
 	str *cnonce;
-};
+} uac_authenticate_body_t;
 
 #define AUTHENTICATE_MD5         (1<<0)
 #define AUTHENTICATE_MD5SESS     (1<<1)

+ 43 - 11
src/modules/uac/auth_alg.c

@@ -61,8 +61,31 @@ static inline void cvt_hex(HASH bin, HASHHEX hex)
 }
 
 
+static inline void cvt_bin(HASHHEX hex, HASH bin)
+{
+	unsigned short i;
+	unsigned char j;
+	for (i = 0; i<HASHLEN; i++) {
+		if(hex[2*i]>='0' && hex[2*i]<='9')
+			j = (hex[2*i]-'0') << 4;
+		else if(hex[2*i]>='a'&&hex[2*i]<='f')
+			j = (hex[2*i]-'a'+10) << 4;
+		else if(hex[2*i]>='A'&&hex[2*i]<='F')
+			j = (hex[2*i]-'A'+10) << 4;
+		else j = 0;
+
+		if(hex[2*i+1]>='0'&&hex[2*i+1]<='9')
+			j += hex[2*i+1]-'0';
+		else if(hex[2*i+1]>='a'&&hex[2*i+1]<='f')
+			j += hex[2*i+1]-'a'+10;
+		else if(hex[2*i+1]>='A'&&hex[2*i+1]<='F')
+			j += hex[2*i+1]-'A'+10;
+
+		bin[i] = j;
+	}
+}
 
-/* 
+/*
  * calculate H(A1)
  */
 void uac_calc_HA1( struct uac_credential *crd,
@@ -73,16 +96,25 @@ void uac_calc_HA1( struct uac_credential *crd,
 	MD5_CTX Md5Ctx;
 	HASH HA1;
 
-	MD5Init(&Md5Ctx);
-	MD5Update(&Md5Ctx, crd->user.s, crd->user.len);
-	MD5Update(&Md5Ctx, ":", 1);
-	MD5Update(&Md5Ctx, crd->realm.s, crd->realm.len);
-	MD5Update(&Md5Ctx, ":", 1);
-	MD5Update(&Md5Ctx, crd->passwd.s, crd->passwd.len);
-	MD5Final(HA1, &Md5Ctx);
+	if(UAC_FLCRED_HA1 & UAC_FLCRED_HA1) {
+		memcpy(sess_key, crd->passwd.s, HASHHEXLEN);
+		sess_key[HASHHEXLEN] = '\0';
+		if ( auth->flags& AUTHENTICATE_MD5SESS ) {
+			cvt_bin(sess_key, HA1);
+		} else {
+			return;
+		}
+	} else {
+		MD5Init(&Md5Ctx);
+		MD5Update(&Md5Ctx, crd->user.s, crd->user.len);
+		MD5Update(&Md5Ctx, ":", 1);
+		MD5Update(&Md5Ctx, crd->realm.s, crd->realm.len);
+		MD5Update(&Md5Ctx, ":", 1);
+		MD5Update(&Md5Ctx, crd->passwd.s, crd->passwd.len);
+		MD5Final(HA1, &Md5Ctx);
+	}
 
-	if ( auth->flags& AUTHENTICATE_MD5SESS )
-	{
+	if ( auth->flags& AUTHENTICATE_MD5SESS ) {
 		MD5Init(&Md5Ctx);
 		MD5Update(&Md5Ctx, HA1, HASHLEN);
 		MD5Update(&Md5Ctx, ":", 1);
@@ -90,7 +122,7 @@ void uac_calc_HA1( struct uac_credential *crd,
 		MD5Update(&Md5Ctx, ":", 1);
 		MD5Update(&Md5Ctx, cnonce->s, cnonce->len);
 		MD5Final(HA1, &Md5Ctx);
-	};
+	}
 
 	cvt_hex(HA1, sess_key);
 }

+ 102 - 33
src/modules/uac/uac_reg.c

@@ -75,6 +75,7 @@ typedef struct _reg_uac
 	str   auth_proxy;
 	str   auth_username;
 	str   auth_password;
+	str   auth_ha1;
 	str   callid;
 	str   socket;
 	unsigned int cseq;
@@ -133,6 +134,7 @@ str r_domain_column = str_init("r_domain");
 str realm_column = str_init("realm");
 str auth_username_column = str_init("auth_username");
 str auth_password_column = str_init("auth_password");
+str auth_ha1_column = str_init("auth_ha1");
 str auth_proxy_column = str_init("auth_proxy");
 str expires_column = str_init("expires");
 str flags_column = str_init("flags");
@@ -513,6 +515,7 @@ int reg_ht_add(reg_uac_t *reg)
 	int len;
 	reg_uac_t *nr = NULL;
 	char *p;
+	int i;
 
 	if(reg==NULL || _reg_htable==NULL)
 	{
@@ -528,6 +531,7 @@ int reg_ht_add(reg_uac_t *reg)
 		+ reg->auth_proxy.len + 1
 		+ reg->auth_username.len + 1
 		+ reg->auth_password.len + 1
+		+ reg->auth_ha1.len + 1
 		+ reg->socket.len + 1
 		+ (reg_keep_callid ? UAC_REG_TM_CALLID_SIZE : 0) + 1;
 	nr = (reg_uac_t*)shm_malloc(sizeof(reg_uac_t) + len);
@@ -558,9 +562,17 @@ int reg_ht_add(reg_uac_t *reg)
 	reg_copy_shm(&nr->auth_proxy, &reg->auth_proxy, 0);
 	reg_copy_shm(&nr->auth_username, &reg->auth_username, 0);
 	reg_copy_shm(&nr->auth_password, &reg->auth_password, 0);
+	reg_copy_shm(&nr->auth_ha1, &reg->auth_ha1, 0);
 	reg_copy_shm(&nr->socket, &reg->socket, 0);
 	reg_copy_shm(&nr->callid, &str_empty, reg_keep_callid ? UAC_REG_TM_CALLID_SIZE : 0);
 
+	for(i=0; i<nr->auth_ha1.len; i++) {
+		/* ha1 to lowercase */
+		if(nr->auth_ha1.s[i] >= 'A' && nr->auth_ha1.s[i] <= 'F') {
+			nr->auth_ha1.s[i] += 32;
+		}
+	}
+
 	reg_ht_add_byuser(nr);
 	reg_ht_add_byuuid(nr);
 	counter_inc(regtotal);
@@ -810,7 +822,7 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 	HASHHEX response;
 	str *new_auth_hdr = NULL;
 	static struct authenticate_body auth;
-	struct uac_credential cred;
+	uac_credential_t cred;
 	char  b_ruri[MAX_URI_SIZE];
 	str   s_ruri;
 	char  b_hdrs[MAX_UACH_SIZE];
@@ -936,9 +948,15 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 				goto error;
 			}
 		}
+		cred.aflags = 0;
 		cred.realm = auth.realm;
 		cred.user = ri->auth_username;
-		cred.passwd = ri->auth_password;
+		if(ri->auth_ha1.len > 0) {
+			cred.passwd = ri->auth_ha1;
+			cred.aflags |= UAC_FLCRED_HA1;
+		} else {
+			cred.passwd = ri->auth_password;
+		}
 		cred.next = NULL;
 
 		snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
@@ -1206,45 +1224,75 @@ void uac_reg_timer(unsigned int ticks)
 	}
 }
 
-#define reg_db_set_attr(attr, pos) do { \
+static int uac_reg_check_password(reg_uac_t *reg)
+{
+	int i;
+
+	if(reg->auth_password.len<=0 && reg->auth_ha1.len<=0) {
+		LM_ERR("no password value provided - ignoring record\n");
+		return -1;
+	}
+
+	if(reg->auth_ha1.len > 0 && reg->auth_ha1.len != HASHHEXLEN) {
+		LM_ERR("invalid HA2 length: %d - ignoring record\n", reg->auth_ha1.len);
+		return -1;
+	}
+	for(i=0; i<reg->auth_ha1.len; i++) {
+		if(!((reg->auth_ha1.s[i]>='0' && reg->auth_ha1.s[i]<'9')
+				|| (reg->auth_ha1.s[i]>='a' && reg->auth_ha1.s[i]<='f')
+				|| (reg->auth_ha1.s[i]>='A' && reg->auth_ha1.s[i]<='F'))) {
+			LM_ERR("invalid char %d in HA1 string: %.*s\n", i,
+					reg->auth_ha1.len, reg->auth_ha1.s);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+#define reg_db_set_attr(attr, pos, eval) do { \
 	if(!VAL_NULL(&RES_ROWS(db_res)[i].values[pos])) { \
 		reg->attr.s = \
-		(char*)(RES_ROWS(db_res)[i].values[pos].val.string_val); \
+				(char*)(RES_ROWS(db_res)[i].values[pos].val.string_val); \
 		reg->attr.len = strlen(reg->attr.s); \
 		if(reg->attr.len == 0) { \
-			LM_ERR("empty value not allowed for column[%d]='%.*s' - ignoring record\n", \
-					pos, db_cols[pos]->len, db_cols[pos]->s); \
-			return -1; \
+			if(eval == 0) { \
+				LM_ERR("empty value not allowed for column[%d]='%.*s' - ignoring record\n", \
+						pos, db_cols[pos]->len, db_cols[pos]->s); \
+				return -1; \
+			}  else { \
+				reg->attr.s = NULL; \
+			} \
 		} \
 	} \
 } while(0);
 
 
-static inline int uac_reg_db_to_reg(reg_uac_t *reg, db1_res_t* db_res, int i, db_key_t *db_cols)
+static int uac_reg_db_to_reg(reg_uac_t *reg, db1_res_t* db_res, int i, db_key_t *db_cols)
 {
 	memset(reg, 0, sizeof(reg_uac_t));;
 	/* check for NULL values ?!?! */
-	reg_db_set_attr(l_uuid, 0);
-	reg_db_set_attr(l_username, 1);
-	reg_db_set_attr(l_domain, 2);
-	reg_db_set_attr(r_username, 3);
-	reg_db_set_attr(r_domain, 4);
+	reg_db_set_attr(l_uuid, 0, 0);
+	reg_db_set_attr(l_username, 1, 0);
+	reg_db_set_attr(l_domain, 2, 0);
+	reg_db_set_attr(r_username, 3, 0);
+	reg_db_set_attr(r_domain, 4, 0);
 	/* realm may be empty */
-	if(!VAL_NULL(&RES_ROWS(db_res)[i].values[5])) {
-		reg->realm.s = (char*)(RES_ROWS(db_res)[i].values[5].val.string_val);
-		reg->realm.len = strlen(reg->realm.s);
-	}
-	reg_db_set_attr(auth_username, 6);
-	reg_db_set_attr(auth_password, 7);
-	reg_db_set_attr(auth_proxy, 8);
-	reg->expires = (unsigned int)RES_ROWS(db_res)[i].values[9].val.int_val;
-	reg->flags = (unsigned int)RES_ROWS(db_res)[i].values[10].val.int_val;
-	reg->reg_delay = (unsigned int)RES_ROWS(db_res)[i].values[11].val.int_val;
-	/* socket may be empty */
-	if(!VAL_NULL(&RES_ROWS(db_res)[i].values[12])) {
-		reg->socket.s = (char*)(RES_ROWS(db_res)[i].values[12].val.string_val);
-		reg->socket.len = strlen(reg->socket.s);
+	reg_db_set_attr(realm, 5, 1);
+	reg_db_set_attr(auth_username, 6, 0);
+	reg_db_set_attr(auth_password, 7, 1);
+	reg_db_set_attr(auth_ha1, 8, 1);
+	if(uac_reg_check_password(reg) < 0) {
+		return -1;
 	}
+	reg_db_set_attr(auth_proxy, 9, 0);
+	reg->expires = (unsigned int)RES_ROWS(db_res)[i].values[10].val.int_val;
+	reg->flags = (unsigned int)RES_ROWS(db_res)[i].values[11].val.int_val;
+	reg->reg_delay = (unsigned int)RES_ROWS(db_res)[i].values[12].val.int_val;
+
+	/* socket may be empty */
+	reg_db_set_attr(socket, 13, 1);
+
 	return 0;
 }
 
@@ -1257,7 +1305,7 @@ int uac_reg_load_db(void)
 	db1_con_t *reg_db_con = NULL;
 	db_func_t reg_dbf;
 	reg_uac_t reg;
-	db_key_t db_cols[13] = {
+	db_key_t db_cols[14] = {
 		&l_uuid_column,
 		&l_username_column,
 		&l_domain_column,
@@ -1266,6 +1314,7 @@ int uac_reg_load_db(void)
 		&realm_column,
 		&auth_username_column,
 		&auth_password_column,
+		&auth_ha1_column,
 		&auth_proxy_column,
 		&expires_column,
 		&flags_column,
@@ -1392,7 +1441,7 @@ int uac_reg_db_refresh(str *pl_uuid)
 	db_func_t reg_dbf;
 	reg_uac_t reg;
 	reg_uac_t *cur_reg;
-	db_key_t db_cols[13] = {
+	db_key_t db_cols[14] = {
 		&l_uuid_column,
 		&l_username_column,
 		&l_domain_column,
@@ -1401,6 +1450,7 @@ int uac_reg_db_refresh(str *pl_uuid)
 		&realm_column,
 		&auth_username_column,
 		&auth_password_column,
+		&auth_ha1_column,
 		&auth_proxy_column,
 		&expires_column,
 		&flags_column,
@@ -1782,7 +1832,7 @@ static int rpc_uac_reg_add_node_helper(rpc_t* rpc, void* ctx, reg_uac_t *reg, ti
 		rpc->fault(ctx, 500, "Internal error creating rpc");
 		return -1;
 	}
-	if (rpc->struct_add(th, "SSSSSSSSSddddddS",
+	if (rpc->struct_add(th, "SSSSSSSSSSddddddS",
 				"l_uuid",        &reg->l_uuid,
 				"l_username",    &reg->l_username,
 				"l_domain",      &reg->l_domain,
@@ -1790,9 +1840,12 @@ static int rpc_uac_reg_add_node_helper(rpc_t* rpc, void* ctx, reg_uac_t *reg, ti
 				"r_domain",      &reg->r_domain,
 				"realm",         &reg->realm,
 				"auth_username", &reg->auth_username,
-				"auth_password", &reg->auth_password,
+				"auth_password", (reg->auth_password.len)?
+										&reg->auth_password:&none,
+				"auth_ha1",      (reg->auth_ha1.len)?
+										&reg->auth_ha1:&none,
 				"auth_proxy",    (reg->auth_proxy.len)?
-				&reg->auth_proxy:&none,
+										&reg->auth_proxy:&none,
 				"expires",       (int)reg->expires,
 				"flags",         (int)reg->flags,
 				"diff_expires",  (int)(reg->timer_expires - tn),
@@ -2043,7 +2096,7 @@ static void rpc_uac_reg_add(rpc_t* rpc, void* ctx)
 	reg_uac_t reg;
 	reg_uac_t *cur_reg;
 
-	if(rpc->scan(ctx, "SSSSSSSSSdddS",
+	if(rpc->scan(ctx, "SSSSSSSSSSdddS",
 				&reg.l_uuid,
 				&reg.l_username,
 				&reg.l_domain,
@@ -2052,6 +2105,7 @@ static void rpc_uac_reg_add(rpc_t* rpc, void* ctx)
 				&reg.realm,
 				&reg.auth_username,
 				&reg.auth_password,
+				&reg.auth_ha1,
 				&reg.auth_proxy,
 				&reg.expires,
 				&reg.flags,
@@ -2063,6 +2117,21 @@ static void rpc_uac_reg_add(rpc_t* rpc, void* ctx)
 		return;
 	}
 
+	if(reg.auth_password.len==1 && reg.auth_password.s[0] == '.') {
+		reg.auth_password.s = NULL;
+		reg.auth_password.len = 0;
+	}
+
+	if(reg.auth_ha1.len==1 && reg.auth_ha1.s[0] == '.') {
+		reg.auth_ha1.s = NULL;
+		reg.auth_ha1.len = 0;
+	}
+
+	if(uac_reg_check_password(&reg) < 0) {
+		rpc->fault(ctx, 500, "Failed to add record - invalid password or ha1");
+		return;
+	}
+
 	cur_reg = reg_ht_get_byuuid(&reg.l_uuid);
 	if (cur_reg) {
 		lock_release(cur_reg->lock);