Fix #3090663: Re-authentication fails (2nd attempt)
[siplcs.git] / src / core / sip-transport.c
blob4d00d29dc3ed3fb77734b8d6ca3c35e8297dde3e
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /**
24 * This module incapsulates SIP (RFC3261) protocol and provides
25 * higher level API (a layer) to XML-based SIPE (SIP with Extensions).
26 * Underlying leyer for this is TCP/SSL layer.
28 * A diagram in pseudographics:
30 * === SIPE (XML-based) layer ======================
31 * === SIP RFC3261 transport layer (This module) ===
32 * === TCP/SSL layer ===============================
34 * Authentication (Kerberos and NTLM) is applicable to this layer only.
35 * The same with message integtity (signing). No sip-sec* code should
36 * be used ourside of this module.
38 * SIP errors as codes(both as a return codes and network conditions) should be
39 * escalated to higher leyer (SIPE). Network conditions include no response
40 * within timeout interval.
42 * This module should support redirect internally. No escalations to higher
43 * layers needed.
45 * NO SIP-messages (headers) composing and processing should be outside of
46 * this module (!) Like headers: Via, Route, Contact, Authorization, etc.
47 * It's all irrelevant to higher layer responsibilities.
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
55 #include <stdlib.h>
56 #include <string.h>
57 #include <stdio.h>
59 #include <glib.h>
61 #include "sipe-common.h"
62 #include "sipmsg.h"
63 #include "sip-sec.h"
64 #include "sip-transport.h"
65 #include "sipe-backend.h"
66 #include "sipe-core.h"
67 #include "sipe-core-private.h"
68 #include "sipe-dialog.h"
69 #include "sipe-digest.h"
70 #include "sipe-incoming.h"
71 #include "sipe-nls.h"
72 #include "sipe-schedule.h"
73 #include "sipe-sign.h"
74 #include "sipe-subscriptions.h"
75 #include "sipe-utils.h"
76 #include "uuid.h"
77 #include "sipe.h"
79 struct sip_auth {
80 guint type;
81 struct sip_sec_context *gssapi_context;
82 gchar *gssapi_data;
83 gchar *opaque;
84 gchar *realm;
85 gchar *target;
86 int version;
87 int nc;
88 int retries;
89 int ntlm_num;
90 int expires;
93 /* sip-transport.c private data */
94 struct sip_transport {
95 struct sipe_transport_connection *connection;
97 gchar *server_name;
98 guint server_port;
99 gchar *server_version;
101 gchar *user_agent;
103 GSList *transactions;
105 struct sip_auth registrar;
106 struct sip_auth proxy;
108 guint cseq;
110 gboolean processing_input; /* whether full header received */
111 gboolean reregister_set; /* whether reregister timer set */
112 gboolean reauthenticate_set; /* whether reauthenticate timer set */
113 gboolean subscribed; /* whether subscribed to events, except buddies presence */
116 /* Keep in sync with sipe_transport_type! */
117 static const char *transport_descriptor[] = { "", "tls", "tcp"};
118 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
120 static char *genbranch()
122 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
123 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
124 rand() & 0xFFFF, rand() & 0xFFFF);
127 static void sipe_auth_free(struct sip_auth *auth)
129 g_free(auth->opaque);
130 auth->opaque = NULL;
131 g_free(auth->realm);
132 auth->realm = NULL;
133 g_free(auth->target);
134 auth->target = NULL;
135 auth->version = 0;
136 auth->type = AUTH_TYPE_UNSET;
137 auth->retries = 0;
138 auth->expires = 0;
139 g_free(auth->gssapi_data);
140 auth->gssapi_data = NULL;
141 sip_sec_destroy_context(auth->gssapi_context);
142 auth->gssapi_context = NULL;
145 static void sipe_make_signature(struct sipe_core_private *sipe_private,
146 struct sipmsg *msg)
148 struct sip_transport *transport = sipe_private->transport;
149 if (transport->registrar.gssapi_context) {
150 struct sipmsg_breakdown msgbd;
151 gchar *signature_input_str;
152 msgbd.msg = msg;
153 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target);
154 msgbd.rand = g_strdup_printf("%08x", g_random_int());
155 transport->registrar.ntlm_num++;
156 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
157 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
158 if (signature_input_str != NULL) {
159 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
160 msg->signature = signature_hex;
161 msg->rand = g_strdup(msgbd.rand);
162 msg->num = g_strdup(msgbd.num);
163 g_free(signature_input_str);
165 sipmsg_breakdown_free(&msgbd);
169 static gchar *auth_header(struct sipe_core_private *sipe_private,
170 struct sip_auth *auth,
171 struct sipmsg * msg)
173 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
174 const char *authuser = sip->authuser;
175 gchar *ret;
177 if (!authuser || strlen(authuser) < 1) {
178 authuser = sipe_private->username;
181 if (auth->type == AUTH_TYPE_NTLM || auth->type == AUTH_TYPE_KERBEROS) { /* NTLM or Kerberos */
182 gchar *auth_protocol = (auth->type == AUTH_TYPE_NTLM ? "NTLM" : "Kerberos");
183 gchar *version_str;
185 // If we have a signature for the message, include that
186 if (msg->signature) {
187 return g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"", auth_protocol, auth->opaque, auth->realm, auth->target, msg->rand, msg->num, msg->signature);
190 if ((auth->type == AUTH_TYPE_NTLM && auth->nc == 3 && auth->gssapi_data && auth->gssapi_context == NULL)
191 || (auth->type == AUTH_TYPE_KERBEROS && auth->nc == 3)) {
192 gchar *gssapi_data;
193 gchar *opaque;
194 gchar *sign_str = NULL;
196 gssapi_data = sip_sec_init_context(&(auth->gssapi_context),
197 &(auth->expires),
198 auth->type,
199 SIPE_CORE_PUBLIC_FLAG_IS(SSO),
200 sip->authdomain ? sip->authdomain : "",
201 authuser,
202 sip->password,
203 auth->target,
204 auth->gssapi_data);
205 if (!gssapi_data || !auth->gssapi_context) {
206 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
207 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
208 _("Failed to authenticate to server"));
209 return NULL;
212 if (auth->version > 3) {
213 sipe_make_signature(sipe_private, msg);
214 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
215 msg->rand, msg->num, msg->signature);
216 } else {
217 sign_str = g_strdup("");
220 opaque = (auth->type == AUTH_TYPE_NTLM ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup(""));
221 version_str = auth->version > 2 ? g_strdup_printf(", version=%d", auth->version) : g_strdup("");
222 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\", gssapi-data=\"%s\"%s%s", auth_protocol, opaque, auth->realm, auth->target, gssapi_data, version_str, sign_str);
223 g_free(opaque);
224 g_free(gssapi_data);
225 g_free(version_str);
226 g_free(sign_str);
227 return ret;
230 version_str = auth->version > 2 ? g_strdup_printf(", version=%d", auth->version) : g_strdup("");
231 ret = g_strdup_printf("%s qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"%s", auth_protocol, auth->realm, auth->target, version_str);
232 g_free(version_str);
233 return ret;
235 } else { /* Digest */
236 gchar *string;
237 gchar *hex_digest;
238 guchar digest[SIPE_DIGEST_MD5_LENGTH];
240 /* Calculate new session key */
241 if (!auth->opaque) {
242 SIPE_DEBUG_INFO("Digest nonce: %s realm: %s", auth->gssapi_data, auth->realm);
243 if (sip->password) {
245 * Calculate a session key for HTTP MD5 Digest authentation
247 * See RFC 2617 for more information.
249 string = g_strdup_printf("%s:%s:%s",
250 authuser,
251 auth->realm,
252 sip->password);
253 sipe_digest_md5((guchar *)string, strlen(string), digest);
254 g_free(string);
255 auth->opaque = buff_to_hex_str(digest, sizeof(digest));
260 * Calculate a response for HTTP MD5 Digest authentication
262 * See RFC 2617 for more information.
264 string = g_strdup_printf("%s:%s", msg->method, msg->target);
265 sipe_digest_md5((guchar *)string, strlen(string), digest);
266 g_free(string);
268 hex_digest = buff_to_hex_str(digest, sizeof(digest));
269 string = g_strdup_printf("%s:%s:%s", auth->opaque, auth->gssapi_data, hex_digest);
270 g_free(hex_digest);
271 sipe_digest_md5((guchar *)string, strlen(string), digest);
272 g_free(string);
274 hex_digest = buff_to_hex_str(digest, sizeof(digest));
275 SIPE_DEBUG_INFO("Digest response %s", hex_digest);
276 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%08d\", response=\"%s\"", authuser, auth->realm, auth->gssapi_data, msg->target, auth->nc++, hex_digest);
277 g_free(hex_digest);
278 return ret;
282 static char *parse_attribute(const char *attrname, const char *source)
284 const char *tmp, *tmp2;
285 char *retval = NULL;
286 int len = strlen(attrname);
288 if (g_str_has_prefix(source, attrname)) {
289 tmp = source + len;
290 tmp2 = g_strstr_len(tmp, strlen(tmp), "\"");
291 if (tmp2)
292 retval = g_strndup(tmp, tmp2 - tmp);
293 else
294 retval = g_strdup(tmp);
297 return retval;
300 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
302 int i;
303 gchar **parts;
305 if (!hdr) {
306 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: hdr==NULL");
307 return;
310 if (!g_strncasecmp(hdr, "NTLM", 4)) {
311 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type NTLM");
312 auth->type = AUTH_TYPE_NTLM;
313 hdr += 5;
314 auth->nc = 1;
315 } else if (!g_strncasecmp(hdr, "Kerberos", 8)) {
316 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type Kerberos");
317 auth->type = AUTH_TYPE_KERBEROS;
318 hdr += 9;
319 auth->nc = 3;
320 } else {
321 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type Digest");
322 auth->type = AUTH_TYPE_DIGEST;
323 hdr += 7;
326 parts = g_strsplit(hdr, "\", ", 0);
327 for (i = 0; parts[i]; i++) {
328 char *tmp;
330 //SIPE_DEBUG_INFO("parts[i] %s", parts[i]);
332 if ((tmp = parse_attribute("gssapi-data=\"", parts[i]))) {
333 g_free(auth->gssapi_data);
334 auth->gssapi_data = tmp;
336 if (auth->type == AUTH_TYPE_NTLM) {
337 /* NTLM module extracts nonce from gssapi-data */
338 auth->nc = 3;
341 } else if ((tmp = parse_attribute("nonce=\"", parts[i]))) {
342 /* Only used with AUTH_TYPE_DIGEST */
343 g_free(auth->gssapi_data);
344 auth->gssapi_data = tmp;
345 } else if ((tmp = parse_attribute("opaque=\"", parts[i]))) {
346 g_free(auth->opaque);
347 auth->opaque = tmp;
348 } else if ((tmp = parse_attribute("realm=\"", parts[i]))) {
349 g_free(auth->realm);
350 auth->realm = tmp;
352 if (auth->type == AUTH_TYPE_DIGEST) {
353 /* Throw away old session key */
354 g_free(auth->opaque);
355 auth->opaque = NULL;
356 auth->nc = 1;
358 } else if ((tmp = parse_attribute("targetname=\"", parts[i]))) {
359 g_free(auth->target);
360 auth->target = tmp;
361 } else if ((tmp = parse_attribute("version=", parts[i]))) {
362 auth->version = atoi(tmp);
363 g_free(tmp);
365 // uncomment to revert to previous functionality if version 3+ does not work.
366 // auth->version = 2;
368 g_strfreev(parts);
370 return;
373 static void sign_outgoing_message (struct sipmsg * msg,
374 struct sipe_core_private *sipe_private,
375 const gchar *method)
377 struct sip_transport *transport = sipe_private->transport;
378 gchar *buf;
380 if (transport->registrar.type == AUTH_TYPE_UNSET) {
381 return;
384 sipe_make_signature(sipe_private, msg);
386 if (transport->registrar.type && sipe_strequal(method, "REGISTER")) {
387 buf = auth_header(sipe_private, &transport->registrar, msg);
388 if (buf) {
389 sipmsg_add_header_now_pos(msg, "Authorization", buf, 5);
391 g_free(buf);
392 } else if (sipe_strequal(method,"SUBSCRIBE") || sipe_strequal(method,"SERVICE") || sipe_strequal(method,"MESSAGE") || sipe_strequal(method,"INVITE") || sipe_strequal(method, "ACK") || sipe_strequal(method, "NOTIFY") || sipe_strequal(method, "BYE") || sipe_strequal(method, "INFO") || sipe_strequal(method, "OPTIONS") || sipe_strequal(method, "REFER") || sipe_strequal(method, "PRACK")) {
393 transport->registrar.nc = 3;
394 transport->registrar.type = AUTH_TYPE_NTLM;
395 #ifdef HAVE_LIBKRB5
396 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5)) {
397 transport->registrar.type = AUTH_TYPE_KERBEROS;
399 #else
400 /* that's why I don't like macros. It's unobvious what's hidden there */
401 (void)sipe_private;
402 #endif
405 buf = auth_header(sipe_private, &transport->registrar, msg);
406 sipmsg_add_header_now_pos(msg, "Authorization", buf, 5);
407 g_free(buf);
408 } else {
409 SIPE_DEBUG_INFO("not adding auth header to msg w/ method %s", method);
413 void sip_transport_response(struct sipe_core_private *sipe_private,
414 struct sipmsg *msg,
415 guint code,
416 const char *text,
417 const char *body)
419 gchar *name;
420 gchar *value;
421 GString *outstr = g_string_new("");
422 gchar *contact;
423 GSList *tmp;
424 const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
426 /* Can return NULL! */
427 contact = get_contact(sipe_private);
428 if (contact) {
429 sipmsg_add_header(msg, "Contact", contact);
430 g_free(contact);
433 if (body) {
434 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
435 sipmsg_add_header(msg, "Content-Length", len);
436 g_free(len);
437 } else {
438 sipmsg_add_header(msg, "Content-Length", "0");
441 msg->response = code;
443 sipmsg_strip_headers(msg, keepers);
444 sipmsg_merge_new_headers(msg);
445 sign_outgoing_message(msg, sipe_private, msg->method);
447 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
448 tmp = msg->headers;
449 while (tmp) {
450 name = ((struct sipnameval*) (tmp->data))->name;
451 value = ((struct sipnameval*) (tmp->data))->value;
453 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
454 tmp = g_slist_next(tmp);
456 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
457 sipe_utils_message_debug("SIP", outstr->str, NULL, TRUE);
458 sipe_backend_transport_message(sipe_private->transport->connection, outstr->str);
459 g_string_free(outstr, TRUE);
462 static void transactions_remove(struct sip_transport *transport,
463 struct transaction *trans)
465 if (transport->transactions) {
466 transport->transactions = g_slist_remove(transport->transactions,
467 trans);
468 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
470 if (trans->msg) sipmsg_free(trans->msg);
471 if (trans->payload) {
472 (*trans->payload->destroy)(trans->payload->data);
473 g_free(trans->payload);
475 g_free(trans->key);
476 g_free(trans);
480 static struct transaction *transactions_find(struct sip_transport *transport,
481 struct sipmsg *msg)
483 GSList *transactions = transport->transactions;
484 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
485 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
486 gchar *key;
488 if (!call_id || !cseq) {
489 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
490 return NULL;
493 key = g_strdup_printf("<%s><%s>", call_id, cseq);
494 while (transactions) {
495 struct transaction *trans = transactions->data;
496 if (!g_strcasecmp(trans->key, key)) {
497 g_free(key);
498 return trans;
500 transactions = transactions->next;
502 g_free(key);
504 return NULL;
507 const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
509 struct sip_transport *transport = sipe_private->transport;
511 if (!transport->user_agent) {
512 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
513 SIPE_SETTING_USER_AGENT);
514 if (is_empty(useragent)) {
515 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
516 /* ref: lzodefs.h */
517 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
518 #define SIPE_TARGET_PLATFORM "linux"
519 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
520 #define SIPE_TARGET_PLATFORM "bsd"
521 #elif defined(__APPLE__) || defined(__MACOS__)
522 #define SIPE_TARGET_PLATFORM "macosx"
523 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
524 #define SIPE_TARGET_PLATFORM "aix"
525 #elif defined(__solaris__) || defined(__sun)
526 #define SIPE_TARGET_PLATFORM "sun"
527 #elif defined(_WIN32)
528 #define SIPE_TARGET_PLATFORM "win"
529 #elif defined(__CYGWIN__)
530 #define SIPE_TARGET_PLATFORM "cygwin"
531 #elif defined(__hpux__)
532 #define SIPE_TARGET_PLATFORM "hpux"
533 #elif defined(__sgi__)
534 #define SIPE_TARGET_PLATFORM "irix"
535 #else
536 #define SIPE_TARGET_PLATFORM "unknown"
537 #endif
539 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
540 #define SIPE_TARGET_ARCH "x86_64"
541 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
542 #define SIPE_TARGET_ARCH "i386"
543 #elif defined(__ppc64__)
544 #define SIPE_TARGET_ARCH "ppc64"
545 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
546 #define SIPE_TARGET_ARCH "ppc"
547 #elif defined(__hppa__) || defined(__hppa)
548 #define SIPE_TARGET_ARCH "hppa"
549 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
550 #define SIPE_TARGET_ARCH "mips"
551 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
552 #define SIPE_TARGET_ARCH "s390"
553 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
554 #define SIPE_TARGET_ARCH "sparc"
555 #elif defined(__arm__)
556 #define SIPE_TARGET_ARCH "arm"
557 #else
558 #define SIPE_TARGET_ARCH "other"
559 #endif
560 gchar *backend = sipe_backend_version();
561 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
562 backend,
563 transport->server_version ? transport->server_version : "");
564 g_free(backend);
565 } else {
566 transport->user_agent = g_strdup(useragent);
569 return(transport->user_agent);
572 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
573 const gchar *method,
574 const gchar *url,
575 const gchar *to,
576 const gchar *addheaders,
577 const gchar *body,
578 struct sip_dialog *dialog,
579 TransCallback callback)
581 struct sip_transport *transport = sipe_private->transport;
582 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
583 char *buf;
584 struct sipmsg *msg;
585 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
586 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
587 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
588 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
589 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
590 gchar *route = g_strdup("");
591 gchar *epid = get_epid(sipe_private);
592 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
593 struct transaction *trans = NULL;
595 if (dialog && dialog->routes)
597 GSList *iter = dialog->routes;
599 while(iter)
601 char *tmp = route;
602 route = g_strdup_printf("%sRoute: <%s>\r\n", route, (char *)iter->data);
603 g_free(tmp);
604 iter = g_slist_next(iter);
608 if (!ourtag && !dialog) {
609 ourtag = gentag();
612 if (sipe_strequal(method, "REGISTER")) {
613 if (sip->regcallid) {
614 g_free(callid);
615 callid = g_strdup(sip->regcallid);
616 } else {
617 sip->regcallid = g_strdup(callid);
619 cseq = ++transport->cseq;
622 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
623 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
624 "From: <sip:%s>%s%s;epid=%s\r\n"
625 "To: <%s>%s%s%s%s\r\n"
626 "Max-Forwards: 70\r\n"
627 "CSeq: %d %s\r\n"
628 "User-Agent: %s\r\n"
629 "Call-ID: %s\r\n"
630 "%s%s"
631 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
632 method,
633 dialog && dialog->request ? dialog->request : url,
634 TRANSPORT_DESCRIPTOR,
635 sipe_backend_network_ip_address(),
636 transport->connection->client_port,
637 branch ? ";branch=" : "",
638 branch ? branch : "",
639 sipe_private->username,
640 ourtag ? ";tag=" : "",
641 ourtag ? ourtag : "",
642 epid,
644 theirtag ? ";tag=" : "",
645 theirtag ? theirtag : "",
646 theirepid ? ";epid=" : "",
647 theirepid ? theirepid : "",
648 cseq,
649 method,
650 sip_transport_user_agent(sipe_private),
651 callid,
652 route,
653 addheaders ? addheaders : "",
654 body ? (gsize) strlen(body) : 0,
655 body ? body : "");
658 //printf ("parsing msg buf:\n%s\n\n", buf);
659 msg = sipmsg_parse_msg(buf);
661 g_free(buf);
662 g_free(ourtag);
663 g_free(theirtag);
664 g_free(theirepid);
665 g_free(branch);
666 g_free(route);
667 g_free(epid);
669 sign_outgoing_message(msg, sipe_private, method);
671 buf = sipmsg_to_string(msg);
673 /* add to ongoing transactions */
674 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
675 if (!sipe_strequal(method, "ACK")) {
676 trans = g_new0(struct transaction, 1);
677 trans->callback = callback;
678 trans->msg = msg;
679 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
680 transport->transactions = g_slist_append(transport->transactions,
681 trans);
682 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
683 } else {
684 sipmsg_free(msg);
686 g_free(callid);
688 sipe_utils_message_debug("SIP", buf, NULL, TRUE);
689 sipe_backend_transport_message(transport->connection, buf);
690 g_free(buf);
692 return trans;
695 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
696 const gchar *method,
697 struct sip_dialog *dialog)
699 sip_transport_request(sipe_private,
700 method,
701 dialog->with,
702 dialog->with,
703 NULL,
704 NULL,
705 dialog,
706 NULL);
709 void sip_transport_ack(struct sipe_core_private *sipe_private,
710 struct sip_dialog *dialog)
712 sip_transport_simple_request(sipe_private, "ACK", dialog);
715 void sip_transport_bye(struct sipe_core_private *sipe_private,
716 struct sip_dialog *dialog)
718 sip_transport_simple_request(sipe_private, "BYE", dialog);
721 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
722 const gchar *addheaders,
723 const gchar *body,
724 struct sip_dialog *dialog,
725 TransCallback callback)
727 return sip_transport_request(sipe_private,
728 "INFO",
729 dialog->with,
730 dialog->with,
731 addheaders,
732 body,
733 dialog,
734 callback);
737 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
738 const gchar *addheaders,
739 const gchar *body,
740 struct sip_dialog *dialog,
741 TransCallback callback)
743 return sip_transport_request(sipe_private,
744 "INVITE",
745 dialog->with,
746 dialog->with,
747 addheaders,
748 body,
749 dialog,
750 callback);
753 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
754 const gchar *uri,
755 const gchar *addheaders,
756 const gchar *body,
757 TransCallback callback)
759 return sip_transport_request(sipe_private,
760 "SERVICE",
761 uri,
762 uri,
763 addheaders,
764 body,
765 NULL,
766 callback);
769 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
770 const gchar *uri,
771 const gchar *addheaders,
772 const gchar *body,
773 struct sip_dialog *dialog,
774 TransCallback callback)
776 sip_transport_request(sipe_private,
777 "SUBSCRIBE",
778 uri,
779 uri,
780 addheaders,
781 body,
782 dialog,
783 callback);
786 static const char*
787 sipe_get_auth_scheme_name(struct sipe_core_private *sipe_private)
789 const char *res = "NTLM";
790 #ifdef HAVE_LIBKRB5
791 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5)) {
792 res = "Kerberos";
794 #else
795 (void) sipe_private; /* make compiler happy */
796 #endif
797 return res;
800 static void do_register(struct sipe_core_private *sipe_private,
801 gboolean deregister);
803 static void do_register_cb(struct sipe_core_private *sipe_private,
804 SIPE_UNUSED_PARAMETER void *unused)
806 do_register(sipe_private, FALSE);
807 sipe_private->transport->reregister_set = FALSE;
810 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
811 SIPE_UNUSED_PARAMETER gpointer unused)
813 struct sip_transport *transport = sipe_private->transport;
815 /* register again when security token expires */
816 /* we have to start a new authentication as the security token
817 * is almost expired by sending a not signed REGISTER message */
818 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
819 sipe_auth_free(&transport->registrar);
820 sipe_auth_free(&transport->proxy);
821 do_register(sipe_private, FALSE);
822 transport->reauthenticate_set = FALSE;
825 static void sipe_server_register(struct sipe_core_private *sipe_private,
826 guint type,
827 gchar *server_name,
828 guint server_port);
830 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
832 struct sip_transport *transport = sipe_private->transport;
833 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
834 sipe_private->username,
835 transport->connection->client_port,
836 sipe_backend_network_ip_address(),
837 TRANSPORT_DESCRIPTOR);
840 static gboolean process_register_response(struct sipe_core_private *sipe_private,
841 struct sipmsg *msg,
842 SIPE_UNUSED_PARAMETER struct transaction *trans)
844 struct sip_transport *transport = sipe_private->transport;
845 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
846 gchar *tmp;
847 const gchar *expires_header;
848 int expires, i;
849 GSList *hdr = msg->headers;
850 struct sipnameval *elem;
852 expires_header = sipmsg_find_header(msg, "Expires");
853 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
854 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
856 switch (msg->response) {
857 case 200:
858 if (expires) {
859 const gchar *contact_hdr;
860 gchar *gruu = NULL;
861 gchar *epid;
862 gchar *uuid;
863 gchar *timeout;
864 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
865 const char *auth_scheme;
867 if (!transport->reregister_set) {
868 gchar *action_name = g_strdup_printf("<%s>", "registration");
869 sipe_schedule_seconds(sipe_private,
870 action_name,
871 NULL,
872 expires,
873 do_register_cb,
874 NULL);
875 g_free(action_name);
876 transport->reregister_set = TRUE;
879 if (server_hdr && !transport->server_version) {
880 transport->server_version = g_strdup(server_hdr);
881 g_free(transport->user_agent);
882 transport->user_agent = NULL;
885 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
886 tmp = sipmsg_find_auth_header(msg, auth_scheme);
888 if (tmp) {
889 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp);
890 fill_auth(tmp, &transport->registrar);
893 if (!transport->reauthenticate_set) {
894 gchar *action_name = g_strdup_printf("<%s>", "+reauthentication");
895 guint reauth_timeout;
896 if (transport->registrar.type == AUTH_TYPE_KERBEROS && transport->registrar.expires > 0) {
897 /* assuming normal Kerberos ticket expiration of about 8-10 hours */
898 reauth_timeout = transport->registrar.expires - 300;
899 } else {
900 /* NTLM: we have to reauthenticate as our security token expires
901 after eight hours (be five minutes early) */
902 reauth_timeout = (8 * 3600) - 300;
904 sipe_schedule_seconds(sipe_private,
905 action_name,
906 NULL,
907 reauth_timeout,
908 do_reauthenticate_cb,
909 NULL);
910 g_free(action_name);
911 transport->reauthenticate_set = TRUE;
914 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
916 epid = get_epid(sipe_private);
917 uuid = generateUUIDfromEPID(epid);
918 g_free(epid);
920 // There can be multiple Contact headers (one per location where the user is logged in) so
921 // make sure to only get the one for this uuid
922 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
923 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
924 if (valid_contact) {
925 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
926 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
927 g_free(valid_contact);
928 break;
929 } else {
930 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
933 g_free(uuid);
935 g_free(sipe_private->contact);
936 if(gruu) {
937 sipe_private->contact = g_strdup_printf("<%s>", gruu);
938 g_free(gruu);
939 } else {
940 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
941 sip_transport_default_contact(sipe_private);
943 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
944 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
945 sip->batched_support = FALSE;
947 while(hdr)
949 elem = hdr->data;
950 if (sipe_strcase_equal(elem->name, "Supported")) {
951 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
952 /* We interpret this as OCS2007+ indicator */
953 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
954 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem->value);
956 if (sipe_strcase_equal(elem->value, "adhoclist")) {
957 sip->batched_support = TRUE;
958 SIPE_DEBUG_INFO("Supported: %s", elem->value);
961 if (sipe_strcase_equal(elem->name, "Allow-Events")){
962 gchar **caps = g_strsplit(elem->value,",",0);
963 i = 0;
964 while (caps[i]) {
965 sip->allow_events = g_slist_append(sip->allow_events, g_strdup(caps[i]));
966 SIPE_DEBUG_INFO("Allow-Events: %s", caps[i]);
967 i++;
969 g_strfreev(caps);
971 if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
972 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
973 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
974 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
975 "via Edge Server)");
978 hdr = g_slist_next(hdr);
981 /* rejoin open chats to be able to use them by continue to send messages */
982 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
984 /* subscriptions */
985 if (!transport->subscribed) { //do it just once, not every re-register
987 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-contacts",
988 (GCompareFunc)g_ascii_strcasecmp)) {
989 sipe_subscribe_roaming_contacts(sipe_private);
992 /* For 2007+ it does not make sence to subscribe to:
993 * vnd-microsoft-roaming-ACL
994 * vnd-microsoft-provisioning (not v2)
995 * presence.wpending
996 * These are for backward compatibility.
998 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
1000 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-self",
1001 (GCompareFunc)g_ascii_strcasecmp)) {
1002 sipe_subscribe_roaming_self(sipe_private);
1004 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-provisioning-v2",
1005 (GCompareFunc)g_ascii_strcasecmp)) {
1006 sipe_subscribe_roaming_provisioning_v2(sipe_private);
1009 /* For 2005- servers */
1010 else
1012 //sipe_options_request(sip, sipe_private->public.sip_domain);
1014 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-ACL",
1015 (GCompareFunc)g_ascii_strcasecmp)) {
1016 sipe_subscribe_roaming_acl(sipe_private);
1018 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-provisioning",
1019 (GCompareFunc)g_ascii_strcasecmp)) {
1020 sipe_subscribe_roaming_provisioning(sipe_private);
1022 if (g_slist_find_custom(sip->allow_events, "presence.wpending",
1023 (GCompareFunc)g_ascii_strcasecmp)) {
1024 sipe_subscribe_presence_wpending(sipe_private,
1025 NULL);
1028 /* For 2007+ we publish our initial statuses and calendar data only after
1029 * received our existing publications in sipe_process_roaming_self()
1030 * Only in this case we know versions of current publications made
1031 * on our behalf.
1033 /* For 2005- we publish our initial statuses only after
1034 * received our existing UserInfo data in response to
1035 * self subscription.
1036 * Only in this case we won't override existing UserInfo data
1037 * set earlier or by other client on our behalf.
1041 transport->subscribed = TRUE;
1044 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1045 "timeout=", ";", NULL);
1046 if (timeout != NULL) {
1047 sscanf(timeout, "%u", &sipe_private->public.keepalive_timeout);
1048 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1049 sipe_private->public.keepalive_timeout);
1050 g_free(timeout);
1053 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1055 break;
1056 case 301:
1058 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1060 if (redirect && (g_strncasecmp("sip:", redirect, 4) == 0)) {
1061 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1062 gchar **tmp;
1063 gchar *hostname;
1064 int port = 0;
1065 guint transport = SIPE_TRANSPORT_TLS;
1066 int i = 1;
1068 tmp = g_strsplit(parts[0], ":", 0);
1069 hostname = g_strdup(tmp[0]);
1070 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1071 g_strfreev(tmp);
1073 while (parts[i]) {
1074 tmp = g_strsplit(parts[i], "=", 0);
1075 if (tmp[1]) {
1076 if (g_strcasecmp("transport", tmp[0]) == 0) {
1077 if (g_strcasecmp("tcp", tmp[1]) == 0) {
1078 transport = SIPE_TRANSPORT_TCP;
1082 g_strfreev(tmp);
1083 i++;
1085 g_strfreev(parts);
1087 /* Close old connection */
1088 sipe_connection_cleanup(sipe_private);
1090 /* Create new connection */
1091 sipe_server_register(sipe_private, transport, hostname, port);
1092 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1093 hostname, port, transport);
1095 g_free(redirect);
1097 break;
1098 case 401:
1100 const char *auth_scheme;
1101 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1102 if (transport->registrar.retries > 3) {
1103 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: still not authenticated after 3 tries - giving up.");
1104 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1105 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1106 _("Authentication failed"));
1107 return TRUE;
1110 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
1111 tmp = sipmsg_find_auth_header(msg, auth_scheme);
1113 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp ? tmp : "");
1114 if (!tmp) {
1115 char *tmp2 = g_strconcat(_("Incompatible authentication scheme chosen"), ": ", auth_scheme, NULL);
1116 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1117 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1118 tmp2);
1119 g_free(tmp2);
1120 return TRUE;
1122 fill_auth(tmp, &transport->registrar);
1123 do_register(sipe_private,
1124 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1126 break;
1127 case 403:
1129 const gchar *diagnostics = sipmsg_find_header(msg, "Warning");
1130 gchar **reason = NULL;
1131 gchar *warning;
1132 if (diagnostics != NULL) {
1133 /* Example header:
1134 Warning: 310 lcs.microsoft.com "You are currently not using the recommended version of the client"
1136 reason = g_strsplit(diagnostics, "\"", 0);
1138 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1139 (reason && reason[1]) ? reason[1] : _("no reason given"));
1140 g_strfreev(reason);
1142 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1143 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1144 warning);
1145 g_free(warning);
1146 return TRUE;
1148 break;
1149 case 404:
1151 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1152 gchar *reason = NULL;
1153 gchar *warning;
1154 if (diagnostics != NULL) {
1155 reason = sipmsg_find_part_of_header(diagnostics, "reason=\"", "\"", NULL);
1157 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1158 diagnostics ? (reason ? reason : _("no reason given")) :
1159 _("SIP is either not enabled for the destination URI or it does not exist"));
1160 g_free(reason);
1162 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1163 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1164 warning);
1165 g_free(warning);
1166 return TRUE;
1168 break;
1169 case 503:
1170 case 504: /* Server time-out */
1172 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1173 gchar *reason = NULL;
1174 gchar *warning;
1175 if (diagnostics != NULL) {
1176 reason = sipmsg_find_part_of_header(diagnostics, "reason=\"", "\"", NULL);
1178 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1179 g_free(reason);
1181 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1182 SIPE_CONNECTION_ERROR_NETWORK,
1183 warning);
1184 g_free(warning);
1185 return TRUE;
1187 break;
1189 return TRUE;
1192 static void do_register(struct sipe_core_private *sipe_private,
1193 gboolean deregister)
1195 struct sip_transport *transport = sipe_private->transport;
1196 char *uri;
1197 char *to;
1198 char *hdr;
1199 char *epid;
1200 char *uuid;
1202 if (!sipe_private->public.sip_domain) return;
1204 epid = get_epid(sipe_private);
1205 uuid = generateUUIDfromEPID(epid);
1206 hdr = g_strdup_printf("Contact: <sip:%s:%d;transport=%s;ms-opaque=d3470f2e1d>;methods=\"INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY\";proxy=replace;+sip.instance=\"<urn:uuid:%s>\"\r\n"
1207 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1208 "Event: registration\r\n"
1209 "Allow-Events: presence\r\n"
1210 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1211 "%s",
1212 sipe_backend_network_ip_address(),
1213 transport->connection->client_port,
1214 TRANSPORT_DESCRIPTOR,
1215 uuid,
1216 deregister ? "Expires: 0\r\n" : "");
1217 g_free(uuid);
1218 g_free(epid);
1220 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1221 to = sip_uri_self(sipe_private);
1222 sip_transport_request(sipe_private,
1223 "REGISTER",
1224 uri,
1226 hdr,
1228 NULL,
1229 process_register_response);
1230 g_free(to);
1231 g_free(uri);
1232 g_free(hdr);
1234 if (deregister) {
1235 /* Make sure that all messages are pushed to the server
1236 before the connection gets shut down */
1237 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1238 sipe_backend_transport_flush(transport->connection);
1242 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1244 do_register(sipe_private, TRUE);
1247 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1249 struct sip_transport *transport = sipe_private->transport;
1251 sipe_backend_transport_disconnect(transport->connection);
1253 sipe_auth_free(&transport->registrar);
1254 sipe_auth_free(&transport->proxy);
1256 g_free(transport->server_name);
1257 g_free(transport->server_version);
1258 g_free(transport->user_agent);
1260 while (transport->transactions)
1261 transactions_remove(transport,
1262 transport->transactions->data);
1264 g_free(transport);
1266 sipe_private->transport = NULL;
1267 sipe_private->service_data = NULL;
1269 if (sipe_private->dns_query)
1270 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1274 guint sip_transport_port(struct sipe_core_private *sipe_private)
1276 return sipe_private->transport->server_port;
1279 static void process_input_message(struct sipe_core_private *sipe_private,
1280 struct sipmsg *msg)
1282 struct sip_transport *transport = sipe_private->transport;
1283 gboolean notfound = FALSE;
1284 const char *method = msg->method ? msg->method : "NOT FOUND";
1286 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1287 msg->response, method);
1289 if (msg->response == 0) { /* request */
1290 if (sipe_strequal(method, "MESSAGE")) {
1291 process_incoming_message(sipe_private, msg);
1292 } else if (sipe_strequal(method, "NOTIFY")) {
1293 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1294 process_incoming_notify(sipe_private, msg, TRUE, FALSE);
1295 } else if (sipe_strequal(method, "BENOTIFY")) {
1296 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1297 process_incoming_notify(sipe_private, msg, TRUE, TRUE);
1298 } else if (sipe_strequal(method, "INVITE")) {
1299 process_incoming_invite(sipe_private, msg);
1300 } else if (sipe_strequal(method, "REFER")) {
1301 process_incoming_refer(sipe_private, msg);
1302 } else if (sipe_strequal(method, "OPTIONS")) {
1303 process_incoming_options(sipe_private, msg);
1304 } else if (sipe_strequal(method, "INFO")) {
1305 process_incoming_info(sipe_private, msg);
1306 } else if (sipe_strequal(method, "ACK")) {
1307 /* ACK's don't need any response */
1308 } else if (sipe_strequal(method, "PRACK")) {
1309 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1310 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1311 /* LCS 2005 sends us these - just respond 200 OK */
1312 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1313 } else if (sipe_strequal(method, "CANCEL")) {
1314 process_incoming_cancel(sipe_private, msg);
1315 } else if (sipe_strequal(method, "BYE")) {
1316 process_incoming_bye(sipe_private, msg);
1317 } else {
1318 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1319 notfound = TRUE;
1322 } else { /* response */
1323 struct transaction *trans = transactions_find(transport, msg);
1324 if (trans) {
1325 if (msg->response < 200) {
1326 if (msg->bodylen != 0) {
1327 SIPE_DEBUG_INFO("got provisional (%d) response with body", msg->response);
1328 if (trans->callback) {
1329 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1330 (trans->callback)(sipe_private, msg, trans);
1332 } else {
1333 /* ignore provisional response */
1334 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1337 } else if (msg->response == 407) {
1338 gchar *resend, *auth;
1339 const gchar *ptmp;
1341 if (transport->proxy.retries > 30) return;
1342 transport->proxy.retries++;
1343 /* do proxy authentication */
1345 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate");
1347 fill_auth(ptmp, &transport->proxy);
1348 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1349 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1350 sipmsg_add_header_now_pos(trans->msg, "Proxy-Authorization", auth, 5);
1351 g_free(auth);
1352 resend = sipmsg_to_string(trans->msg);
1353 /* resend request */
1354 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1355 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1356 g_free(resend);
1358 } else {
1359 transport->proxy.retries = 0;
1361 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1362 if (msg->response == 401) {
1363 transport->registrar.retries++;
1364 } else {
1365 transport->registrar.retries = 0;
1367 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1369 } else if (msg->response == 401) {
1370 gchar *resend, *auth, *ptmp;
1371 const char* auth_scheme;
1373 if (transport->registrar.retries > 4) return;
1374 transport->registrar.retries++;
1376 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
1377 ptmp = sipmsg_find_auth_header(msg, auth_scheme);
1379 SIPE_DEBUG_INFO("process_input_message: Auth header: %s", ptmp ? ptmp : "");
1380 if (!ptmp) {
1381 char *tmp2 = g_strconcat(_("Incompatible authentication scheme chosen"), ": ", auth_scheme, NULL);
1382 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1383 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1384 tmp2);
1385 g_free(tmp2);
1386 return;
1389 fill_auth(ptmp, &transport->registrar);
1390 auth = auth_header(sipe_private, &transport->registrar, trans->msg);
1391 sipmsg_remove_header_now(trans->msg, "Authorization");
1392 sipmsg_add_header_now_pos(trans->msg, "Authorization", auth, 5);
1393 g_free(auth);
1394 resend = sipmsg_to_string(trans->msg);
1395 /* resend request */
1396 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1397 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1398 g_free(resend);
1401 if (trans->callback) {
1402 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1403 /* call the callback to process response*/
1404 (trans->callback)(sipe_private, msg, trans);
1407 /* Redirect: old content of "transport" is no longer valid */
1408 transport = sipe_private->transport;
1410 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1411 transactions_remove(transport, trans);
1414 } else {
1415 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1416 notfound = TRUE;
1420 if (notfound) {
1421 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1425 static void sip_transport_input(struct sipe_transport_connection *conn)
1427 struct sipe_core_private *sipe_private = conn->user_data;
1428 struct sip_transport *transport = sipe_private->transport;
1429 gchar *cur = conn->buffer;
1431 /* according to the RFC remove CRLF at the beginning */
1432 while (*cur == '\r' || *cur == '\n') {
1433 cur++;
1435 if (cur != conn->buffer)
1436 sipe_utils_shrink_buffer(conn, cur);
1438 /* Received a full Header? */
1439 transport->processing_input = TRUE;
1440 while (transport->processing_input &&
1441 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1442 struct sipmsg *msg;
1443 guint remainder;
1445 cur += 2;
1446 cur[0] = '\0';
1447 msg = sipmsg_parse_header(conn->buffer);
1449 cur += 2;
1450 remainder = conn->buffer_used - (cur - conn->buffer);
1451 if (msg && remainder >= (guint) msg->bodylen) {
1452 char *dummy = g_malloc(msg->bodylen + 1);
1453 memcpy(dummy, cur, msg->bodylen);
1454 dummy[msg->bodylen] = '\0';
1455 msg->body = dummy;
1456 cur += msg->bodylen;
1457 sipe_utils_message_debug("SIP",
1458 conn->buffer,
1459 msg->body,
1460 FALSE);
1461 sipe_utils_shrink_buffer(conn, cur);
1462 } else {
1463 if (msg){
1464 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1465 sipmsg_free(msg);
1468 /* restore header for next try */
1469 cur[-2] = '\r';
1470 return;
1473 // Verify the signature before processing it
1474 if (transport->registrar.gssapi_context) {
1475 struct sipmsg_breakdown msgbd;
1476 gchar *signature_input_str;
1477 gchar *rspauth;
1478 msgbd.msg = msg;
1479 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target);
1480 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1482 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1484 if (rspauth != NULL) {
1485 if (!sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1486 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1487 process_input_message(sipe_private, msg);
1488 } else {
1489 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1490 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1491 SIPE_CONNECTION_ERROR_NETWORK,
1492 _("Invalid message signature received"));
1494 } else if (msg->response == 401) {
1495 if ((transport->registrar.retries < 2) &&
1496 sipe_strequal(msg->method, "REGISTER")) {
1497 struct transaction *trans = transactions_find(transport, msg);
1498 if (trans) transactions_remove(transport, trans);
1499 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: RE-REGISTER rejected, triggering re-authentication");
1500 do_reauthenticate_cb(sipe_private, NULL);
1501 } else {
1502 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: server rejected us - giving up");
1503 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1504 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1505 _("Authentication failed"));
1508 g_free(signature_input_str);
1510 g_free(rspauth);
1511 sipmsg_breakdown_free(&msgbd);
1512 } else {
1513 process_input_message(sipe_private, msg);
1516 sipmsg_free(msg);
1518 /* Redirect: old content of "transport" is no longer valid */
1519 transport = sipe_private->transport;
1523 static void sip_transport_connected(struct sipe_transport_connection *conn)
1525 struct sipe_core_private *sipe_private = conn->user_data;
1526 sipe_private->service_data = NULL;
1527 do_register(sipe_private, FALSE);
1530 static void resolve_next_service(struct sipe_core_private *sipe_private,
1531 const struct sip_service_data *start);
1532 static void sip_transport_error(struct sipe_transport_connection *conn,
1533 const gchar *msg)
1535 struct sipe_core_private *sipe_private = conn->user_data;
1537 /* This failed attempt was based on a DNS SRV record */
1538 if (sipe_private->service_data) {
1539 resolve_next_service(sipe_private, NULL);
1540 } else {
1541 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1542 SIPE_CONNECTION_ERROR_NETWORK,
1543 msg);
1547 /* server_name must be g_alloc()'ed */
1548 static void sipe_server_register(struct sipe_core_private *sipe_private,
1549 guint type,
1550 gchar *server_name,
1551 guint server_port)
1553 sipe_connect_setup setup = {
1554 type,
1555 server_name,
1556 (server_port != 0) ? server_port :
1557 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1558 sipe_private,
1559 sip_transport_connected,
1560 sip_transport_input,
1561 sip_transport_error
1563 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1565 transport->server_name = server_name;
1566 transport->server_port = setup.server_port;
1567 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1568 &setup);
1569 sipe_private->transport = transport;
1572 struct sip_service_data {
1573 const char *protocol;
1574 const char *transport;
1575 guint type;
1578 /* Service list for autodection */
1579 static const struct sip_service_data service_autodetect[] = {
1580 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1581 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1582 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1583 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1584 { NULL, NULL, 0 }
1587 /* Service list for SSL/TLS */
1588 static const struct sip_service_data service_tls[] = {
1589 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1590 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1591 { NULL, NULL, 0 }
1594 /* Service list for TCP */
1595 static const struct sip_service_data service_tcp[] = {
1596 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1597 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1598 { NULL, NULL, 0 }
1601 static const struct sip_service_data *services[] = {
1602 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1603 service_tls, /* SIPE_TRANSPORT_TLS */
1604 service_tcp /* SIPE_TRANSPORT_TCP */
1607 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1608 const gchar *hostname, guint port)
1610 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1612 sipe_private->dns_query = NULL;
1614 if (hostname) {
1615 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1616 hostname, port);
1617 sipe_server_register(sipe_private,
1618 sipe_private->service_data->type,
1619 g_strdup(hostname), port);
1620 } else {
1621 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1625 static void resolve_next_service(struct sipe_core_private *sipe_private,
1626 const struct sip_service_data *start)
1628 if (start) {
1629 sipe_private->service_data = start;
1630 } else {
1631 sipe_private->service_data++;
1632 if (sipe_private->service_data->protocol == NULL) {
1633 guint type = sipe_private->transport_type;
1635 /* We tried all services */
1636 sipe_private->service_data = NULL;
1638 /* Try connecting to the SIP hostname directly */
1639 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1640 if (type == SIPE_TRANSPORT_AUTO)
1641 type = SIPE_TRANSPORT_TLS;
1643 sipe_server_register(sipe_private, type,
1644 g_strdup(sipe_private->public.sip_domain),
1646 return;
1650 /* Try to resolve next service */
1651 sipe_private->dns_query = sipe_backend_dns_query_srv(
1652 sipe_private->service_data->protocol,
1653 sipe_private->service_data->transport,
1654 sipe_private->public.sip_domain,
1655 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
1656 SIPE_CORE_PUBLIC);
1659 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
1660 guint transport,
1661 const gchar *server,
1662 const gchar *port)
1664 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1666 if (server) {
1667 /* Use user specified server[:port] */
1668 int port_number = 0;
1670 if (port)
1671 port_number = atoi(port);
1673 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1674 server, port_number);
1676 sipe_server_register(sipe_private, transport,
1677 g_strdup(server), port_number);
1678 } else {
1679 /* Server auto-discovery */
1681 /* Remember user specified transport type */
1682 sipe_private->transport_type = transport;
1683 resolve_next_service(sipe_private, services[transport]);
1687 void sipe_core_transport_sip_keepalive(struct sipe_core_public *sipe_public)
1689 SIPE_DEBUG_INFO("sending keep alive %d",
1690 sipe_public->keepalive_timeout);
1691 sipe_utils_message_debug("SIP", "", NULL, TRUE);
1692 sipe_backend_transport_message(SIPE_CORE_PRIVATE->transport->connection,
1693 "\r\n\r\n");
1697 Local Variables:
1698 mode: c
1699 c-file-style: "bsd"
1700 indent-tabs-mode: t
1701 tab-width: 8
1702 End: