source: mediastreamer2/linphone/coreapi/authentication.c @ 774:6ffd7188b328

Last change on this file since 774:6ffd7188b328 was 774:6ffd7188b328, checked in by smorlat <smorlat@…>, 4 years ago

fix bugs with login window and authentication faillure after several bad attempts from user.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@762 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 10.7 KB
Line 
1/***************************************************************************
2 *            authentication.c
3 *
4 *  Fri Jul 16 12:08:34 2004
5 *  Copyright  2004-2009  Simon MORLAT
6 *  simon.morlat@linphone.org
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License as published by
12 *  the Free Software Foundation; either version 2 of the License, or
13 *  (at your option) any later version.
14 *
15 *  This program is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU Library General Public License for more details.
19 *
20 *  You should have received a copy of the GNU General Public License
21 *  along with this program; if not, write to the Free Software
22 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24 
25#include "linphonecore.h"
26#include "private.h"
27#include <eXosip2/eXosip.h>
28#include <osipparser2/osip_message.h>
29#include "lpconfig.h"
30
31extern LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid);
32
33LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid,
34                                                                                                                const char *passwd, const char *ha1,const char *realm)
35{
36        LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1);
37        if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username);
38        if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid);
39        if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd);
40        if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1);
41        if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm);
42        obj->works=FALSE;
43        obj->first_time=TRUE;
44        return obj;
45}
46
47void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd){
48        if (info->passwd!=NULL) {
49                ms_free(info->passwd);
50                info->passwd=NULL;
51        }
52        if (passwd!=NULL && (strlen(passwd)>0)) info->passwd=ms_strdup(passwd);
53}
54
55void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username){
56        if (info->username){
57                ms_free(info->username);
58                info->username=NULL;
59        }
60        if (username && strlen(username)>0) info->username=ms_strdup(username);
61}
62
63void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid){
64        if (info->userid){
65                ms_free(info->userid);
66                info->userid=NULL;
67        }
68        if (userid && strlen(userid)>0) info->userid=ms_strdup(userid);
69}
70
71void linphone_auth_info_destroy(LinphoneAuthInfo *obj){
72        if (obj->username!=NULL) ms_free(obj->username);
73        if (obj->userid!=NULL) ms_free(obj->userid);
74        if (obj->passwd!=NULL) ms_free(obj->passwd);
75        if (obj->ha1!=NULL) ms_free(obj->ha1);
76        if (obj->realm!=NULL) ms_free(obj->realm);
77        ms_free(obj);
78}
79
80void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, int pos)
81{
82        char key[50];
83        sprintf(key,"auth_info_%i",pos);
84        lp_config_clean_section(config,key);
85       
86        if (obj==NULL){
87                return;
88        }               
89        if (obj->username!=NULL){
90                lp_config_set_string(config,key,"username",obj->username);
91        }
92        if (obj->userid!=NULL){
93                lp_config_set_string(config,key,"userid",obj->userid);
94        }
95        if (obj->passwd!=NULL){
96                lp_config_set_string(config,key,"passwd",obj->passwd);
97        }
98        if (obj->ha1!=NULL){
99                lp_config_set_string(config,key,"ha1",obj->ha1);
100        }
101        if (obj->realm!=NULL){
102                lp_config_set_string(config,key,"realm",obj->realm);
103        }
104}
105
106LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos)
107{
108        char key[50];
109        const char *username,*userid,*passwd,*ha1,*realm;
110       
111        sprintf(key,"auth_info_%i",pos);
112        if (!lp_config_has_section(config,key)){
113                return NULL;
114        }
115       
116        username=lp_config_get_string(config,key,"username",NULL);
117        userid=lp_config_get_string(config,key,"userid",NULL);
118        passwd=lp_config_get_string(config,key,"passwd",NULL);
119        ha1=lp_config_get_string(config,key,"ha1",NULL);
120        realm=lp_config_get_string(config,key,"realm",NULL);
121        return linphone_auth_info_new(username,userid,passwd,ha1,realm);
122}
123
124static bool_t key_match(const char *tmp1, const char *tmp2){
125        if (tmp1==NULL && tmp2==NULL) return TRUE;
126        if (tmp1!=NULL && tmp2!=NULL && strcmp(tmp1,tmp2)==0) return TRUE;
127        return FALSE;
128       
129}
130
131static char * remove_quotes(char * input){
132        char *tmp;
133        if (*input=='"') input++;
134        tmp=strchr(input,'"');
135        if (tmp) *tmp='\0';
136        return input;
137}
138
139static int realm_match(const char *realm1, const char *realm2){
140        if (realm1==NULL && realm2==NULL) return TRUE;
141        if (realm1!=NULL && realm2!=NULL){
142                if (strcmp(realm1,realm2)==0) return TRUE;
143                else{
144                        char tmp1[128];
145                        char tmp2[128];
146                        char *p1,*p2;
147                        strncpy(tmp1,realm1,sizeof(tmp1)-1);
148                        strncpy(tmp2,realm2,sizeof(tmp2)-1);
149                        p1=remove_quotes(tmp1);
150                        p2=remove_quotes(tmp2);
151                        return strcmp(p1,p2)==0;
152                }
153        }
154        return FALSE;
155}
156
157
158LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username)
159{
160        MSList *elem;
161        LinphoneAuthInfo *ret=NULL,*candidate=NULL;
162        for (elem=lc->auth_info;elem!=NULL;elem=elem->next){
163                LinphoneAuthInfo *pinfo=(LinphoneAuthInfo*)elem->data;
164                if (realm==NULL){
165                        /*return the authinfo for any realm provided that there is only one for that username*/
166                        if (key_match(pinfo->username,username)){
167                                if (ret!=NULL){
168                                        ms_warning("There are several auth info for username '%s'",username);
169                                        return NULL;
170                                }
171                                ret=pinfo;
172                        }
173                }else{
174                        /*return the exact authinfo, or an authinfo for which realm was not supplied yet*/
175                        if (pinfo->realm!=NULL){
176                                if (realm_match(pinfo->realm,realm) 
177                                        && key_match(pinfo->username,username))
178                                        ret=pinfo;
179                        }else{
180                                if (key_match(pinfo->username,username))
181                                        candidate=pinfo;
182                        }
183                }
184        }
185        if (ret==NULL && candidate!=NULL)
186                ret=candidate;
187        return ret;
188}
189
190static void refresh_exosip_auth_info(LinphoneCore *lc){
191        MSList *elem;
192        eXosip_lock();
193        eXosip_clear_authentication_info();
194        for (elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem)){
195                LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data;
196                char *userid;
197                if (info->userid==NULL || info->userid[0]=='\0') userid=info->username;
198                else userid=info->userid;
199                eXosip_add_authentication_info(info->username,userid,
200                                info->passwd,info->ha1,info->realm);
201        }
202        eXosip_unlock();
203}
204
205void linphone_core_add_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info)
206{
207        MSList *elem;
208        LinphoneAuthInfo *ai;
209       
210        /* find if we are attempting to modify an existing auth info */
211        ai=linphone_core_find_auth_info(lc,info->realm,info->username);
212        if (ai!=NULL){
213                elem=ms_list_find(lc->auth_info,ai);
214                if (elem==NULL){
215                        ms_error("AuthInfo list corruption ?");
216                        return;
217                }
218                linphone_auth_info_destroy((LinphoneAuthInfo*)elem->data);
219                elem->data=(void *)info;
220        }else {
221                lc->auth_info=ms_list_append(lc->auth_info,(void *)info);
222        }
223        refresh_exosip_auth_info(lc);
224        /* if the user was prompted, re-allow automatic_action */
225        if (lc->automatic_action>0) lc->automatic_action--;
226}
227
228void linphone_core_abort_authentication(LinphoneCore *lc,  LinphoneAuthInfo *info){
229        if (lc->automatic_action>0) lc->automatic_action--;
230}
231
232void linphone_core_remove_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info){
233        int len=ms_list_size(lc->auth_info);
234        int newlen;
235        int i;
236        MSList *elem;
237        lc->auth_info=ms_list_remove(lc->auth_info,info);
238        newlen=ms_list_size(lc->auth_info);
239        /*printf("len=%i newlen=%i\n",len,newlen);*/
240        linphone_auth_info_destroy(info);
241        for (i=0;i<len;i++){
242                linphone_auth_info_write_config(lc->config,NULL,i);
243        }
244        for (elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
245                linphone_auth_info_write_config(lc->config,(LinphoneAuthInfo*)elem->data,i);
246        }
247        refresh_exosip_auth_info(lc);
248       
249}
250
251const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc){
252        return lc->auth_info;
253}
254
255void linphone_core_clear_all_auth_info(LinphoneCore *lc){
256        MSList *elem;
257        int i;
258        eXosip_lock();
259        eXosip_clear_authentication_info();
260        eXosip_unlock();
261        for(i=0,elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem),i++){
262                LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data;
263                linphone_auth_info_destroy(info);
264                linphone_auth_info_write_config(lc->config,NULL,i);
265        }
266        ms_list_free(lc->auth_info);
267        lc->auth_info=NULL;
268}
269
270void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev){
271        char *prx_realm=NULL,*www_realm=NULL;
272        osip_proxy_authorization_t *prx_auth;
273        osip_authorization_t *www_auth;
274        osip_message_t *msg=ev->request;
275        char *username;
276        LinphoneAuthInfo *as=NULL;
277
278        username=osip_uri_get_username(msg->from->url);
279        osip_message_get_proxy_authorization(msg,0,&prx_auth);
280        osip_message_get_authorization(msg,0,&www_auth);
281        if (prx_auth!=NULL)
282                prx_realm=osip_proxy_authorization_get_realm(prx_auth);
283        if (www_auth!=NULL)
284                www_realm=osip_authorization_get_realm(www_auth);
285       
286        if (prx_realm==NULL && www_realm==NULL){
287                ms_message("No authentication info in the request, ignoring");
288                return;
289        }
290        /* see if we already have this auth information , not to ask it everytime to the user */
291        if (prx_realm!=NULL)
292                as=linphone_core_find_auth_info(lc,prx_realm,username);
293        if (www_realm!=NULL) 
294                as=linphone_core_find_auth_info(lc,www_realm,username);
295        if (as){
296                ms_message("Authentication for user=%s realm=%s is working.",username,prx_realm ? prx_realm : www_realm);
297                as->works=TRUE;
298        }
299}
300
301
302void linphone_core_find_or_ask_for_auth_info(LinphoneCore *lc,const char *username,const char* realm, int tid)
303{
304        LinphoneAuthInfo *as=linphone_core_find_auth_info(lc,realm,username);
305        if ( as==NULL || (as!=NULL && as->works==FALSE && as->first_time==FALSE)){
306                if (lc->vtable.auth_info_requested!=NULL){
307                        lc->vtable.auth_info_requested(lc,realm,username);
308                        lc->automatic_action++;/*suspends eXosip_automatic_action until the user supplies a password */
309                }
310        }
311        if (as) as->first_time=FALSE;
312}
313
314void linphone_process_authentication(LinphoneCore *lc, eXosip_event_t *ev)
315{
316        char *prx_realm=NULL,*www_realm=NULL;
317        osip_proxy_authenticate_t *prx_auth;
318        osip_www_authenticate_t *www_auth;
319        osip_message_t *resp=ev->response;
320        char *username;
321       
322        if (strcmp(ev->request->sip_method,"REGISTER")==0) {
323                gstate_new_state(lc, GSTATE_REG_FAILED, "Authentication required");
324        }
325
326        username=osip_uri_get_username(resp->from->url);
327        prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0);
328        www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0);
329        if (prx_auth!=NULL)
330                prx_realm=osip_proxy_authenticate_get_realm(prx_auth);
331        if (www_auth!=NULL)
332                www_realm=osip_www_authenticate_get_realm(www_auth);
333       
334        if (prx_realm==NULL && www_realm==NULL){
335                ms_warning("No realm in the server response.");
336                return;
337        }
338        /* see if we already have this auth information , not to ask it everytime to the user */
339        if (prx_realm!=NULL) 
340                linphone_core_find_or_ask_for_auth_info(lc,username,prx_realm,ev->tid);
341        if (www_realm!=NULL) 
342                linphone_core_find_or_ask_for_auth_info(lc,username,www_realm,ev->tid);
343}
344
Note: See TracBrowser for help on using the repository browser.