1  /*
2  tester - liblinphone test suite
3  Copyright (C) 2013  Belledonne Communications SARL
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "liblinphone_tester.h"
20 #include "private.h"
21 
22 struct _Account{
23 	LinphoneAddress *identity;
24 	LinphoneAddress *modified_identity;
25 	char *password;
26 	int registered;
27 	int done;
28 	int created;
29 	char *phone_alias;
30 };
31 
32 typedef struct _Account Account;
33 
account_new(LinphoneAddress * identity,const char * unique_id)34 static Account *account_new(LinphoneAddress *identity, const char *unique_id){
35 	char *modified_username;
36 	Account *obj=ms_new0(Account,1);
37 
38 	/* we need to inhibit leak detector because the two LinphoneAddress will remain behond the scope of the test being run */
39 	belle_sip_object_inhibit_leak_detector(TRUE);
40 	obj->identity=linphone_address_clone(identity);
41 	obj->password=sal_get_random_token(8);
42 	obj->phone_alias = NULL;
43 	obj->modified_identity=linphone_address_clone(identity);
44 	modified_username=ms_strdup_printf("%s_%s",linphone_address_get_username(identity), unique_id);
45 	linphone_address_set_username(obj->modified_identity, modified_username);
46 	ms_free(modified_username);
47 	belle_sip_object_inhibit_leak_detector(FALSE);
48 	return obj;
49 };
50 
account_destroy(Account * obj)51 void account_destroy(Account *obj){
52 	linphone_address_unref(obj->identity);
53 	linphone_address_unref(obj->modified_identity);
54 	ms_free(obj->password);
55 	ms_free(obj);
56 }
57 
58 struct _AccountManager{
59 	char *unique_id;
60 	bctbx_list_t *accounts;
61 };
62 
63 typedef struct _AccountManager AccountManager;
64 
65 static AccountManager *the_am=NULL;
66 
account_manager_get(void)67 AccountManager *account_manager_get(void){
68 	if (the_am==NULL){
69 		the_am=ms_new0(AccountManager,1);
70 		the_am->unique_id=sal_get_random_token(6);
71 	}
72 	return the_am;
73 }
74 
account_manager_destroy(void)75 void account_manager_destroy(void){
76 	if (the_am){
77 		ms_free(the_am->unique_id);
78 		bctbx_list_free_with_data(the_am->accounts,(void(*)(void*))account_destroy);
79 		ms_free(the_am);
80 	}
81 	the_am=NULL;
82 	ms_message("Test account manager destroyed.");
83 }
84 
account_manager_get_account(AccountManager * m,const LinphoneAddress * identity)85 Account *account_manager_get_account(AccountManager *m, const LinphoneAddress *identity){
86 	bctbx_list_t *it;
87 
88 	for(it=m->accounts;it!=NULL;it=it->next){
89 		Account *a=(Account*)it->data;
90 		if (linphone_address_weak_equal(a->identity,identity)){
91 			return a;
92 		}
93 	}
94 	return NULL;
95 }
96 
account_created_on_server_cb(LinphoneCore * lc,LinphoneProxyConfig * cfg,LinphoneRegistrationState state,const char * info)97 static void account_created_on_server_cb(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *info){
98 	Account *account=(Account*)linphone_core_get_user_data(lc);
99 	switch(state){
100 		case LinphoneRegistrationOk: {
101 			char * phrase = sal_op_get_error_info((SalOp*)cfg->op)->full_string;
102 			if (phrase && strcasecmp("Test account created", phrase) == 0) {
103 				account->created=1;
104 			} else {
105 				account->registered=1;
106 			}
107 			break;
108 		}
109 		case LinphoneRegistrationCleared:
110 			account->done=1;
111 		break;
112 		default:
113 		break;
114 	}
115 }
116 
117 // TEMPORARY CODE: remove function below when flexisip is updated, this is not needed anymore!
118 // The new flexisip now answer "200 Test account created" when creating a test account, and do not
119 // challenge authentication anymore! so this code is not used for newer version
account_created_auth_requested_cb(LinphoneCore * lc,const char * username,const char * realm,const char * domain)120 static void account_created_auth_requested_cb(LinphoneCore *lc, const char *username, const char *realm, const char *domain){
121 	Account *account=(Account*)linphone_core_get_user_data(lc);
122 	account->created=1;
123 }
124 // TEMPORARY CODE: remove line above when flexisip is updated, this is not needed anymore!
125 
account_create_on_server(Account * account,const LinphoneProxyConfig * refcfg,const char * phone_alias)126 void account_create_on_server(Account *account, const LinphoneProxyConfig *refcfg, const char* phone_alias){
127 	LinphoneCoreVTable vtable={0};
128 	LinphoneCore *lc;
129 	LinphoneAddress *tmp_identity=linphone_address_clone(account->modified_identity);
130 	LinphoneProxyConfig *cfg;
131 	LinphoneAuthInfo *ai;
132 	char *tmp;
133 	LinphoneAddress *server_addr;
134 	LinphoneSipTransports tr;
135 	char *chatdb;
136 
137 	vtable.registration_state_changed=account_created_on_server_cb;
138 	// TEMPORARY CODE: remove line below when flexisip is updated, this is not needed anymore!
139 	vtable.auth_info_requested=account_created_auth_requested_cb;
140 	lc=configure_lc_from(&vtable,bc_tester_get_resource_dir_prefix(),NULL,account);
141 	chatdb = ms_strdup(linphone_core_get_chat_database_path(lc));
142 	tr.udp_port=LC_SIP_TRANSPORT_RANDOM;
143 	tr.tcp_port=LC_SIP_TRANSPORT_RANDOM;
144 	tr.tls_port=LC_SIP_TRANSPORT_RANDOM;
145 	linphone_core_set_sip_transports(lc,&tr);
146 
147 	cfg=linphone_core_create_proxy_config(lc);
148 	linphone_address_set_secure(tmp_identity, FALSE);
149 	linphone_address_set_password(tmp_identity,account->password);
150 	linphone_address_set_header(tmp_identity,"X-Create-Account","yes");
151 	if (phone_alias) linphone_address_set_header(tmp_identity, "X-Phone-Alias", phone_alias);
152 	tmp=linphone_address_as_string(tmp_identity);
153 	linphone_proxy_config_set_identity(cfg,tmp);
154 	ms_free(tmp);
155 	linphone_address_unref(tmp_identity);
156 
157 	server_addr=linphone_address_new(linphone_proxy_config_get_server_addr(refcfg));
158 	linphone_address_set_secure(server_addr, FALSE);
159 	linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation, we may not have certificates configured at this stage*/
160 	linphone_address_set_port(server_addr,0);
161 	tmp=linphone_address_as_string(server_addr);
162 	linphone_proxy_config_set_server_addr(cfg,tmp);
163 	ms_free(tmp);
164 	linphone_address_unref(server_addr);
165 	linphone_proxy_config_set_expires(cfg,3*3600); //accounts are valid 3 hours
166 
167 	linphone_core_add_proxy_config(lc,cfg);
168 	/*wait 25 seconds, since the DNS SRV resolution may take a while - and
169 	especially if router does NOT support DNS SRV and we have to wait its timeout*/
170 	if (wait_for_until(lc,NULL,&account->created,1,25000)==FALSE){
171 		ms_fatal("Account for %s could not be created on server.", linphone_proxy_config_get_identity(refcfg));
172 	}
173 	linphone_proxy_config_edit(cfg);
174 	tmp_identity=linphone_address_clone(account->modified_identity);
175 	linphone_address_set_secure(tmp_identity, FALSE);
176 	tmp=linphone_address_as_string(tmp_identity);
177 	linphone_proxy_config_set_identity(cfg,tmp); /*remove the X-Create-Account header*/
178 	linphone_address_unref(tmp_identity);
179 	ms_free(tmp);
180 	linphone_proxy_config_done(cfg);
181 
182 	ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity),
183 				NULL,
184 				account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity));
185 	linphone_core_add_auth_info(lc,ai);
186 	linphone_auth_info_unref(ai);
187 
188 	if (wait_for_until(lc,NULL,&account->registered,1,3000)==FALSE){
189 		ms_fatal("Account for %s is not working on server.", linphone_proxy_config_get_identity(refcfg));
190 	}
191 	linphone_core_remove_proxy_config(lc,cfg);
192 	linphone_proxy_config_unref(cfg);
193 	if (wait_for_until(lc,NULL,&account->done,1,3000)==FALSE){
194 		ms_error("Account creation could not clean the registration context.");
195 	}
196 	linphone_core_unref(lc);
197 	unlink(chatdb);
198 	ms_free(chatdb);
199 }
200 
account_manager_check_account(AccountManager * m,LinphoneProxyConfig * cfg,const char * phone_alias)201 static LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg,const char* phone_alias){
202 	LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
203 	const char *identity=linphone_proxy_config_get_identity(cfg);
204 	LinphoneAddress *id_addr=linphone_address_new(identity);
205 	Account *account=account_manager_get_account(m,id_addr);
206 	LinphoneAuthInfo *ai;
207 	bool_t create_account=FALSE;
208 	const LinphoneAuthInfo *original_ai = linphone_core_find_auth_info(lc
209 																		,NULL
210 																		, linphone_address_get_username(id_addr)
211 																		, linphone_address_get_domain(id_addr));
212 
213 	if (!account||(phone_alias&&(!account->phone_alias||strcmp(phone_alias,account->phone_alias)!=0))){
214 		if (account) {
215 			m->accounts=bctbx_list_remove(m->accounts,account);
216 			account_destroy(account);
217 		}
218 		account=account_new(id_addr,m->unique_id);
219 		account->phone_alias=ms_strdup(phone_alias);
220 		ms_message("No account for %s exists, going to create one.",identity);
221 		create_account=TRUE;
222 		m->accounts=bctbx_list_append(m->accounts,account);
223 	}
224 	/*modify the username of the identity of the proxy config*/
225 	linphone_address_set_username(id_addr, linphone_address_get_username(account->modified_identity));
226 	linphone_proxy_config_set_identity_address(cfg, id_addr);
227 
228 	if (create_account){
229 		account_create_on_server(account,cfg,phone_alias);
230 	}
231 
232 	/*remove previous auth info to avoid mismatching*/
233 	if (original_ai)
234 		linphone_core_remove_auth_info(lc,original_ai);
235 
236 	ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity),
237 				NULL,
238 				account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity));
239 	linphone_core_add_auth_info(lc,ai);
240 	linphone_auth_info_unref(ai);
241 
242 	linphone_address_unref(id_addr);
243 	return account->modified_identity;
244 }
245 
linphone_core_manager_check_accounts(LinphoneCoreManager * m)246 void linphone_core_manager_check_accounts(LinphoneCoreManager *m){
247 	const bctbx_list_t *it;
248 	AccountManager *am=account_manager_get();
249 	int logmask = ortp_get_log_level_mask(NULL);
250 
251 	if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
252 	for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){
253 		LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data;
254 		account_manager_check_account(am,cfg,m->phone_alias);
255 	}
256 	if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(logmask);
257 }
258