transport: search also ms-diagnostics-public for login failure reason
[siplcs.git] / src / core / sip-transport.c
blob0616b0c368817533edcf1ae54e9c086468d21156
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 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;
109 guint register_attempt;
111 gboolean processing_input; /* whether full header received */
112 gboolean reregister_set; /* whether reregister timer set */
113 gboolean reauthenticate_set; /* whether reauthenticate timer set */
114 gboolean subscribed; /* whether subscribed to events, except buddies presence */
117 /* Keep in sync with sipe_transport_type! */
118 static const char *transport_descriptor[] = { "", "tls", "tcp"};
119 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
121 static char *genbranch()
123 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
124 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
125 rand() & 0xFFFF, rand() & 0xFFFF);
128 static void sipe_auth_free(struct sip_auth *auth)
130 g_free(auth->opaque);
131 auth->opaque = NULL;
132 g_free(auth->realm);
133 auth->realm = NULL;
134 g_free(auth->target);
135 auth->target = NULL;
136 auth->version = 0;
137 auth->type = AUTH_TYPE_UNSET;
138 auth->retries = 0;
139 auth->expires = 0;
140 g_free(auth->gssapi_data);
141 auth->gssapi_data = NULL;
142 sip_sec_destroy_context(auth->gssapi_context);
143 auth->gssapi_context = NULL;
146 static void sipe_make_signature(struct sipe_core_private *sipe_private,
147 struct sipmsg *msg)
149 struct sip_transport *transport = sipe_private->transport;
150 if (transport->registrar.gssapi_context) {
151 struct sipmsg_breakdown msgbd;
152 gchar *signature_input_str;
153 msgbd.msg = msg;
154 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target);
155 msgbd.rand = g_strdup_printf("%08x", g_random_int());
156 transport->registrar.ntlm_num++;
157 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
158 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
159 if (signature_input_str != NULL) {
160 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
161 msg->signature = signature_hex;
162 msg->rand = g_strdup(msgbd.rand);
163 msg->num = g_strdup(msgbd.num);
164 g_free(signature_input_str);
166 sipmsg_breakdown_free(&msgbd);
170 static gchar *auth_header(struct sipe_core_private *sipe_private,
171 struct sip_auth *auth,
172 struct sipmsg * msg)
174 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
175 const char *authuser = sip->authuser;
176 gchar *ret;
178 if (!authuser || strlen(authuser) < 1) {
179 authuser = sipe_private->username;
182 if (auth->type == AUTH_TYPE_NTLM || auth->type == AUTH_TYPE_KERBEROS) { /* NTLM or Kerberos */
183 gchar *auth_protocol = (auth->type == AUTH_TYPE_NTLM ? "NTLM" : "Kerberos");
184 gchar *version_str;
186 // If we have a signature for the message, include that
187 if (msg->signature) {
188 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);
191 if ((auth->type == AUTH_TYPE_NTLM && auth->nc == 3 && auth->gssapi_data && auth->gssapi_context == NULL)
192 || (auth->type == AUTH_TYPE_KERBEROS && auth->nc == 3)) {
193 gchar *gssapi_data;
194 gchar *opaque;
195 gchar *sign_str = NULL;
197 gssapi_data = sip_sec_init_context(&(auth->gssapi_context),
198 &(auth->expires),
199 auth->type,
200 SIPE_CORE_PUBLIC_FLAG_IS(SSO),
201 sip->authdomain ? sip->authdomain : "",
202 authuser,
203 sip->password,
204 auth->target,
205 auth->gssapi_data);
206 if (!gssapi_data || !auth->gssapi_context) {
207 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
208 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
209 _("Failed to authenticate to server"));
210 return NULL;
213 if (auth->version > 3) {
214 sipe_make_signature(sipe_private, msg);
215 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
216 msg->rand, msg->num, msg->signature);
217 } else {
218 sign_str = g_strdup("");
221 opaque = (auth->type == AUTH_TYPE_NTLM ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup(""));
222 version_str = auth->version > 2 ? g_strdup_printf(", version=%d", auth->version) : g_strdup("");
223 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);
224 g_free(opaque);
225 g_free(gssapi_data);
226 g_free(version_str);
227 g_free(sign_str);
228 return ret;
231 version_str = auth->version > 2 ? g_strdup_printf(", version=%d", auth->version) : g_strdup("");
232 ret = g_strdup_printf("%s qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"%s", auth_protocol, auth->realm, auth->target, version_str);
233 g_free(version_str);
234 return ret;
236 } else { /* Digest */
237 gchar *string;
238 gchar *hex_digest;
239 guchar digest[SIPE_DIGEST_MD5_LENGTH];
241 /* Calculate new session key */
242 if (!auth->opaque) {
243 SIPE_DEBUG_INFO("Digest nonce: %s realm: %s", auth->gssapi_data, auth->realm);
244 if (sip->password) {
246 * Calculate a session key for HTTP MD5 Digest authentation
248 * See RFC 2617 for more information.
250 string = g_strdup_printf("%s:%s:%s",
251 authuser,
252 auth->realm,
253 sip->password);
254 sipe_digest_md5((guchar *)string, strlen(string), digest);
255 g_free(string);
256 auth->opaque = buff_to_hex_str(digest, sizeof(digest));
261 * Calculate a response for HTTP MD5 Digest authentication
263 * See RFC 2617 for more information.
265 string = g_strdup_printf("%s:%s", msg->method, msg->target);
266 sipe_digest_md5((guchar *)string, strlen(string), digest);
267 g_free(string);
269 hex_digest = buff_to_hex_str(digest, sizeof(digest));
270 string = g_strdup_printf("%s:%s:%s", auth->opaque, auth->gssapi_data, hex_digest);
271 g_free(hex_digest);
272 sipe_digest_md5((guchar *)string, strlen(string), digest);
273 g_free(string);
275 hex_digest = buff_to_hex_str(digest, sizeof(digest));
276 SIPE_DEBUG_INFO("Digest response %s", hex_digest);
277 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);
278 g_free(hex_digest);
279 return ret;
283 static char *parse_attribute(const char *attrname, const char *source)
285 const char *tmp, *tmp2;
286 char *retval = NULL;
287 int len = strlen(attrname);
289 if (g_str_has_prefix(source, attrname)) {
290 tmp = source + len;
291 tmp2 = g_strstr_len(tmp, strlen(tmp), "\"");
292 if (tmp2)
293 retval = g_strndup(tmp, tmp2 - tmp);
294 else
295 retval = g_strdup(tmp);
298 return retval;
301 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
303 int i;
304 gchar **parts;
306 if (!hdr) {
307 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: hdr==NULL");
308 return;
311 if (!g_strncasecmp(hdr, "NTLM", 4)) {
312 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type NTLM");
313 auth->type = AUTH_TYPE_NTLM;
314 hdr += 5;
315 auth->nc = 1;
316 } else if (!g_strncasecmp(hdr, "Kerberos", 8)) {
317 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type Kerberos");
318 auth->type = AUTH_TYPE_KERBEROS;
319 hdr += 9;
320 auth->nc = 3;
321 } else {
322 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type Digest");
323 auth->type = AUTH_TYPE_DIGEST;
324 hdr += 7;
327 parts = g_strsplit(hdr, "\", ", 0);
328 for (i = 0; parts[i]; i++) {
329 char *tmp;
331 //SIPE_DEBUG_INFO("parts[i] %s", parts[i]);
333 if ((tmp = parse_attribute("gssapi-data=\"", parts[i]))) {
334 g_free(auth->gssapi_data);
335 auth->gssapi_data = tmp;
337 if (auth->type == AUTH_TYPE_NTLM) {
338 /* NTLM module extracts nonce from gssapi-data */
339 auth->nc = 3;
342 } else if ((tmp = parse_attribute("nonce=\"", parts[i]))) {
343 /* Only used with AUTH_TYPE_DIGEST */
344 g_free(auth->gssapi_data);
345 auth->gssapi_data = tmp;
346 } else if ((tmp = parse_attribute("opaque=\"", parts[i]))) {
347 g_free(auth->opaque);
348 auth->opaque = tmp;
349 } else if ((tmp = parse_attribute("realm=\"", parts[i]))) {
350 g_free(auth->realm);
351 auth->realm = tmp;
353 if (auth->type == AUTH_TYPE_DIGEST) {
354 /* Throw away old session key */
355 g_free(auth->opaque);
356 auth->opaque = NULL;
357 auth->nc = 1;
359 } else if ((tmp = parse_attribute("targetname=\"", parts[i]))) {
360 g_free(auth->target);
361 auth->target = tmp;
362 } else if ((tmp = parse_attribute("version=", parts[i]))) {
363 auth->version = atoi(tmp);
364 g_free(tmp);
366 // uncomment to revert to previous functionality if version 3+ does not work.
367 // auth->version = 2;
369 g_strfreev(parts);
371 return;
374 static void sign_outgoing_message (struct sipmsg * msg,
375 struct sipe_core_private *sipe_private,
376 const gchar *method)
378 struct sip_transport *transport = sipe_private->transport;
379 gchar *buf;
381 if (transport->registrar.type == AUTH_TYPE_UNSET) {
382 return;
385 sipe_make_signature(sipe_private, msg);
387 if (transport->registrar.type && sipe_strequal(method, "REGISTER")) {
388 buf = auth_header(sipe_private, &transport->registrar, msg);
389 if (buf) {
390 sipmsg_add_header_now_pos(msg, "Authorization", buf, 5);
392 g_free(buf);
393 } 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")) {
394 transport->registrar.nc = 3;
395 transport->registrar.type = AUTH_TYPE_NTLM;
396 #ifdef HAVE_LIBKRB5
397 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5)) {
398 transport->registrar.type = AUTH_TYPE_KERBEROS;
400 #else
401 /* that's why I don't like macros. It's unobvious what's hidden there */
402 (void)sipe_private;
403 #endif
406 buf = auth_header(sipe_private, &transport->registrar, msg);
407 sipmsg_add_header_now_pos(msg, "Authorization", buf, 5);
408 g_free(buf);
409 } else {
410 SIPE_DEBUG_INFO("not adding auth header to msg w/ method %s", method);
414 static const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
416 struct sip_transport *transport = sipe_private->transport;
418 if (!transport->user_agent) {
419 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
420 SIPE_SETTING_USER_AGENT);
421 if (is_empty(useragent)) {
422 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
423 /* ref: lzodefs.h */
424 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
425 #define SIPE_TARGET_PLATFORM "linux"
426 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
427 #define SIPE_TARGET_PLATFORM "bsd"
428 #elif defined(__APPLE__) || defined(__MACOS__)
429 #define SIPE_TARGET_PLATFORM "macosx"
430 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
431 #define SIPE_TARGET_PLATFORM "aix"
432 #elif defined(__solaris__) || defined(__sun)
433 #define SIPE_TARGET_PLATFORM "sun"
434 #elif defined(_WIN32)
435 #define SIPE_TARGET_PLATFORM "win"
436 #elif defined(__CYGWIN__)
437 #define SIPE_TARGET_PLATFORM "cygwin"
438 #elif defined(__hpux__)
439 #define SIPE_TARGET_PLATFORM "hpux"
440 #elif defined(__sgi__)
441 #define SIPE_TARGET_PLATFORM "irix"
442 #else
443 #define SIPE_TARGET_PLATFORM "unknown"
444 #endif
446 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
447 #define SIPE_TARGET_ARCH "x86_64"
448 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
449 #define SIPE_TARGET_ARCH "i386"
450 #elif defined(__ppc64__)
451 #define SIPE_TARGET_ARCH "ppc64"
452 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
453 #define SIPE_TARGET_ARCH "ppc"
454 #elif defined(__hppa__) || defined(__hppa)
455 #define SIPE_TARGET_ARCH "hppa"
456 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
457 #define SIPE_TARGET_ARCH "mips"
458 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
459 #define SIPE_TARGET_ARCH "s390"
460 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
461 #define SIPE_TARGET_ARCH "sparc"
462 #elif defined(__arm__)
463 #define SIPE_TARGET_ARCH "arm"
464 #else
465 #define SIPE_TARGET_ARCH "other"
466 #endif
467 gchar *backend = sipe_backend_version();
468 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
469 backend,
470 transport->server_version ? transport->server_version : "");
471 g_free(backend);
472 } else {
473 transport->user_agent = g_strdup(useragent);
476 return(transport->user_agent);
479 void sip_transport_response(struct sipe_core_private *sipe_private,
480 struct sipmsg *msg,
481 guint code,
482 const char *text,
483 const char *body)
485 gchar *name;
486 gchar *value;
487 GString *outstr = g_string_new("");
488 gchar *contact;
489 GSList *tmp;
490 const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
492 /* Can return NULL! */
493 contact = get_contact(sipe_private);
494 if (contact) {
495 sipmsg_add_header(msg, "Contact", contact);
496 g_free(contact);
499 if (body) {
500 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
501 sipmsg_add_header(msg, "Content-Length", len);
502 g_free(len);
503 } else {
504 sipmsg_add_header(msg, "Content-Length", "0");
507 sipmsg_add_header(msg, "User-Agent", sip_transport_user_agent(sipe_private));
509 msg->response = code;
511 sipmsg_strip_headers(msg, keepers);
512 sipmsg_merge_new_headers(msg);
513 sign_outgoing_message(msg, sipe_private, msg->method);
515 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
516 tmp = msg->headers;
517 while (tmp) {
518 name = ((struct sipnameval*) (tmp->data))->name;
519 value = ((struct sipnameval*) (tmp->data))->value;
521 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
522 tmp = g_slist_next(tmp);
524 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
525 sipe_utils_message_debug("SIP", outstr->str, NULL, TRUE);
526 sipe_backend_transport_message(sipe_private->transport->connection, outstr->str);
527 g_string_free(outstr, TRUE);
530 static void transactions_remove(struct sipe_core_private *sipe_private,
531 struct transaction *trans)
533 struct sip_transport *transport = sipe_private->transport;
534 if (transport->transactions) {
535 transport->transactions = g_slist_remove(transport->transactions,
536 trans);
537 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
539 if (trans->msg) sipmsg_free(trans->msg);
540 if (trans->payload) {
541 (*trans->payload->destroy)(trans->payload->data);
542 g_free(trans->payload);
544 g_free(trans->key);
545 if (trans->timeout_key) {
546 sipe_schedule_cancel(sipe_private, trans->timeout_key);
547 g_free(trans->timeout_key);
549 g_free(trans);
553 static struct transaction *transactions_find(struct sip_transport *transport,
554 struct sipmsg *msg)
556 GSList *transactions = transport->transactions;
557 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
558 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
559 gchar *key;
561 if (!call_id || !cseq) {
562 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
563 return NULL;
566 key = g_strdup_printf("<%s><%s>", call_id, cseq);
567 while (transactions) {
568 struct transaction *trans = transactions->data;
569 if (!g_strcasecmp(trans->key, key)) {
570 g_free(key);
571 return trans;
573 transactions = transactions->next;
575 g_free(key);
577 return NULL;
580 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
581 gpointer data)
583 struct transaction *trans = data;
584 (trans->timeout_callback)(sipe_private, trans->msg, trans);
585 transactions_remove(sipe_private, trans);
588 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
589 const gchar *method,
590 const gchar *url,
591 const gchar *to,
592 const gchar *addheaders,
593 const gchar *body,
594 struct sip_dialog *dialog,
595 TransCallback callback,
596 guint timeout,
597 TransCallback timeout_callback)
599 struct sip_transport *transport = sipe_private->transport;
600 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
601 char *buf;
602 struct sipmsg *msg;
603 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
604 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
605 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
606 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
607 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
608 gchar *route = g_strdup("");
609 gchar *epid = get_epid(sipe_private);
610 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
611 struct transaction *trans = NULL;
613 if (dialog && dialog->routes)
615 GSList *iter = dialog->routes;
617 while(iter)
619 char *tmp = route;
620 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
621 g_free(tmp);
622 iter = g_slist_next(iter);
626 if (!ourtag && !dialog) {
627 ourtag = gentag();
630 if (sipe_strequal(method, "REGISTER")) {
631 if (sip->regcallid) {
632 g_free(callid);
633 callid = g_strdup(sip->regcallid);
634 } else {
635 sip->regcallid = g_strdup(callid);
637 cseq = ++transport->cseq;
640 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
641 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
642 "From: <sip:%s>%s%s;epid=%s\r\n"
643 "To: <%s>%s%s%s%s\r\n"
644 "Max-Forwards: 70\r\n"
645 "CSeq: %d %s\r\n"
646 "User-Agent: %s\r\n"
647 "Call-ID: %s\r\n"
648 "%s%s"
649 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
650 method,
651 dialog && dialog->request ? dialog->request : url,
652 TRANSPORT_DESCRIPTOR,
653 sipe_backend_network_ip_address(),
654 transport->connection->client_port,
655 branch ? ";branch=" : "",
656 branch ? branch : "",
657 sipe_private->username,
658 ourtag ? ";tag=" : "",
659 ourtag ? ourtag : "",
660 epid,
662 theirtag ? ";tag=" : "",
663 theirtag ? theirtag : "",
664 theirepid ? ";epid=" : "",
665 theirepid ? theirepid : "",
666 cseq,
667 method,
668 sip_transport_user_agent(sipe_private),
669 callid,
670 route,
671 addheaders ? addheaders : "",
672 body ? (gsize) strlen(body) : 0,
673 body ? body : "");
676 //printf ("parsing msg buf:\n%s\n\n", buf);
677 msg = sipmsg_parse_msg(buf);
679 g_free(buf);
680 g_free(ourtag);
681 g_free(theirtag);
682 g_free(theirepid);
683 g_free(branch);
684 g_free(route);
685 g_free(epid);
687 sign_outgoing_message(msg, sipe_private, method);
689 buf = sipmsg_to_string(msg);
691 /* add to ongoing transactions */
692 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
693 if (!sipe_strequal(method, "ACK")) {
694 trans = g_new0(struct transaction, 1);
695 trans->callback = callback;
696 trans->msg = msg;
697 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
698 if (timeout_callback) {
699 trans->timeout_callback = timeout_callback;
700 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
701 sipe_schedule_seconds(sipe_private,
702 trans->timeout_key,
703 trans,
704 timeout,
705 transaction_timeout_cb,
706 NULL);
708 transport->transactions = g_slist_append(transport->transactions,
709 trans);
710 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
711 } else {
712 sipmsg_free(msg);
714 g_free(callid);
716 sipe_utils_message_debug("SIP", buf, NULL, TRUE);
717 sipe_backend_transport_message(transport->connection, buf);
718 g_free(buf);
720 return trans;
723 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
724 const gchar *method,
725 const gchar *url,
726 const gchar *to,
727 const gchar *addheaders,
728 const gchar *body,
729 struct sip_dialog *dialog,
730 TransCallback callback)
732 return sip_transport_request_timeout(sipe_private,
733 method,
734 url,
736 addheaders,
737 body,
738 dialog,
739 callback,
741 NULL);
744 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
745 const gchar *method,
746 struct sip_dialog *dialog)
748 sip_transport_request(sipe_private,
749 method,
750 dialog->with,
751 dialog->with,
752 NULL,
753 NULL,
754 dialog,
755 NULL);
758 void sip_transport_ack(struct sipe_core_private *sipe_private,
759 struct sip_dialog *dialog)
761 sip_transport_simple_request(sipe_private, "ACK", dialog);
764 void sip_transport_bye(struct sipe_core_private *sipe_private,
765 struct sip_dialog *dialog)
767 sip_transport_simple_request(sipe_private, "BYE", dialog);
770 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
771 const gchar *addheaders,
772 const gchar *body,
773 struct sip_dialog *dialog,
774 TransCallback callback)
776 return sip_transport_request(sipe_private,
777 "INFO",
778 dialog->with,
779 dialog->with,
780 addheaders,
781 body,
782 dialog,
783 callback);
786 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
787 const gchar *addheaders,
788 const gchar *body,
789 struct sip_dialog *dialog,
790 TransCallback callback)
792 return sip_transport_request(sipe_private,
793 "INVITE",
794 dialog->with,
795 dialog->with,
796 addheaders,
797 body,
798 dialog,
799 callback);
802 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
803 const gchar *uri,
804 const gchar *addheaders,
805 const gchar *body,
806 TransCallback callback)
808 return sip_transport_request(sipe_private,
809 "SERVICE",
810 uri,
811 uri,
812 addheaders,
813 body,
814 NULL,
815 callback);
818 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
819 const gchar *uri,
820 const gchar *addheaders,
821 const gchar *body,
822 struct sip_dialog *dialog,
823 TransCallback callback)
825 sip_transport_request(sipe_private,
826 "SUBSCRIBE",
827 uri,
828 uri,
829 addheaders,
830 body,
831 dialog,
832 callback);
835 static const char*
836 sipe_get_auth_scheme_name(struct sipe_core_private *sipe_private)
838 const char *res = "NTLM";
839 #ifdef HAVE_LIBKRB5
840 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5)) {
841 res = "Kerberos";
843 #else
844 (void) sipe_private; /* make compiler happy */
845 #endif
846 return res;
849 static void do_register(struct sipe_core_private *sipe_private,
850 gboolean deregister);
852 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
853 SIPE_UNUSED_PARAMETER gpointer unused)
855 struct sip_transport *transport = sipe_private->transport;
857 /* register again when security token expires */
858 /* we have to start a new authentication as the security token
859 * is almost expired by sending a not signed REGISTER message */
860 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
861 sipe_auth_free(&transport->registrar);
862 sipe_auth_free(&transport->proxy);
863 sipe_schedule_cancel(sipe_private, "<registration>");
864 transport->reregister_set = FALSE;
865 transport->register_attempt = 0;
866 do_register(sipe_private, FALSE);
867 transport->reauthenticate_set = FALSE;
870 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
872 struct sip_transport *transport = sipe_private->transport;
873 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
874 sipe_private->username,
875 transport->connection->client_port,
876 sipe_backend_network_ip_address(),
877 TRANSPORT_DESCRIPTOR);
880 static void do_register_cb(struct sipe_core_private *sipe_private,
881 SIPE_UNUSED_PARAMETER void *unused)
883 do_register(sipe_private, FALSE);
886 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
887 int expires)
889 sipe_schedule_seconds(sipe_private,
890 "<registration>",
891 NULL,
892 expires,
893 do_register_cb,
894 NULL);
897 static void sipe_server_register(struct sipe_core_private *sipe_private,
898 guint type,
899 gchar *server_name,
900 guint server_port);
902 static gboolean process_register_response(struct sipe_core_private *sipe_private,
903 struct sipmsg *msg,
904 SIPE_UNUSED_PARAMETER struct transaction *trans)
906 struct sip_transport *transport = sipe_private->transport;
907 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
908 gchar *tmp;
909 const gchar *expires_header;
910 int expires, i;
911 GSList *hdr = msg->headers;
912 struct sipnameval *elem;
914 expires_header = sipmsg_find_header(msg, "Expires");
915 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
916 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
918 switch (msg->response) {
919 case 200:
920 if (expires) {
921 const gchar *contact_hdr;
922 gchar *gruu = NULL;
923 gchar *epid;
924 gchar *uuid;
925 gchar *timeout;
926 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
927 const char *auth_scheme;
929 if (!transport->reregister_set) {
930 sip_transport_set_reregister(sipe_private,
931 expires);
932 transport->reregister_set = TRUE;
935 if (server_hdr && !transport->server_version) {
936 transport->server_version = g_strdup(server_hdr);
937 g_free(transport->user_agent);
938 transport->user_agent = NULL;
941 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
942 tmp = sipmsg_find_auth_header(msg, auth_scheme);
944 if (tmp) {
945 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp);
946 fill_auth(tmp, &transport->registrar);
949 if (!transport->reauthenticate_set) {
950 gchar *action_name = g_strdup_printf("<%s>", "+reauthentication");
951 guint reauth_timeout;
952 if (transport->registrar.type == AUTH_TYPE_KERBEROS && transport->registrar.expires > 0) {
953 /* assuming normal Kerberos ticket expiration of about 8-10 hours */
954 reauth_timeout = transport->registrar.expires - 300;
955 } else {
956 /* NTLM: we have to reauthenticate as our security token expires
957 after eight hours (be five minutes early) */
958 reauth_timeout = (8 * 3600) - 300;
960 sipe_schedule_seconds(sipe_private,
961 action_name,
962 NULL,
963 reauth_timeout,
964 do_reauthenticate_cb,
965 NULL);
966 g_free(action_name);
967 transport->reauthenticate_set = TRUE;
970 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
972 epid = get_epid(sipe_private);
973 uuid = generateUUIDfromEPID(epid);
974 g_free(epid);
976 // There can be multiple Contact headers (one per location where the user is logged in) so
977 // make sure to only get the one for this uuid
978 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
979 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
980 if (valid_contact) {
981 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
982 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
983 g_free(valid_contact);
984 break;
985 } else {
986 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
989 g_free(uuid);
991 g_free(sipe_private->contact);
992 if(gruu) {
993 sipe_private->contact = g_strdup_printf("<%s>", gruu);
994 g_free(gruu);
995 } else {
996 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
997 sip_transport_default_contact(sipe_private);
999 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1000 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1001 sip->batched_support = FALSE;
1003 while(hdr)
1005 elem = hdr->data;
1006 if (sipe_strcase_equal(elem->name, "Supported")) {
1007 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1008 /* We interpret this as OCS2007+ indicator */
1009 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1010 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem->value);
1012 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1013 sip->batched_support = TRUE;
1014 SIPE_DEBUG_INFO("Supported: %s", elem->value);
1017 if (sipe_strcase_equal(elem->name, "Allow-Events")){
1018 gchar **caps = g_strsplit(elem->value,",",0);
1019 i = 0;
1020 while (caps[i]) {
1021 sip->allow_events = g_slist_append(sip->allow_events, g_strdup(caps[i]));
1022 SIPE_DEBUG_INFO("Allow-Events: %s", caps[i]);
1023 i++;
1025 g_strfreev(caps);
1027 if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1028 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1029 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1030 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1031 "via Edge Server)");
1034 hdr = g_slist_next(hdr);
1037 /* rejoin open chats to be able to use them by continue to send messages */
1038 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1040 /* subscriptions */
1041 if (!transport->subscribed) { //do it just once, not every re-register
1043 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-contacts",
1044 (GCompareFunc)g_ascii_strcasecmp)) {
1045 sipe_subscribe_roaming_contacts(sipe_private);
1048 /* For 2007+ it does not make sence to subscribe to:
1049 * vnd-microsoft-roaming-ACL
1050 * vnd-microsoft-provisioning (not v2)
1051 * presence.wpending
1052 * These are for backward compatibility.
1054 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
1056 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-self",
1057 (GCompareFunc)g_ascii_strcasecmp)) {
1058 sipe_subscribe_roaming_self(sipe_private);
1060 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-provisioning-v2",
1061 (GCompareFunc)g_ascii_strcasecmp)) {
1062 sipe_subscribe_roaming_provisioning_v2(sipe_private);
1065 /* For 2005- servers */
1066 else
1068 //sipe_options_request(sip, sipe_private->public.sip_domain);
1070 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-ACL",
1071 (GCompareFunc)g_ascii_strcasecmp)) {
1072 sipe_subscribe_roaming_acl(sipe_private);
1074 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-provisioning",
1075 (GCompareFunc)g_ascii_strcasecmp)) {
1076 sipe_subscribe_roaming_provisioning(sipe_private);
1078 if (g_slist_find_custom(sip->allow_events, "presence.wpending",
1079 (GCompareFunc)g_ascii_strcasecmp)) {
1080 sipe_subscribe_presence_wpending(sipe_private,
1081 NULL);
1084 /* For 2007+ we publish our initial statuses and calendar data only after
1085 * received our existing publications in sipe_process_roaming_self()
1086 * Only in this case we know versions of current publications made
1087 * on our behalf.
1089 /* For 2005- we publish our initial statuses only after
1090 * received our existing UserInfo data in response to
1091 * self subscription.
1092 * Only in this case we won't override existing UserInfo data
1093 * set earlier or by other client on our behalf.
1097 transport->subscribed = TRUE;
1100 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1101 "timeout=", ";", NULL);
1102 if (timeout != NULL) {
1103 sscanf(timeout, "%u", &sipe_private->public.keepalive_timeout);
1104 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1105 sipe_private->public.keepalive_timeout);
1106 g_free(timeout);
1109 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1111 break;
1112 case 301:
1114 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1116 if (redirect && (g_strncasecmp("sip:", redirect, 4) == 0)) {
1117 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1118 gchar **tmp;
1119 gchar *hostname;
1120 int port = 0;
1121 guint transport = SIPE_TRANSPORT_TLS;
1122 int i = 1;
1124 tmp = g_strsplit(parts[0], ":", 0);
1125 hostname = g_strdup(tmp[0]);
1126 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1127 g_strfreev(tmp);
1129 while (parts[i]) {
1130 tmp = g_strsplit(parts[i], "=", 0);
1131 if (tmp[1]) {
1132 if (g_strcasecmp("transport", tmp[0]) == 0) {
1133 if (g_strcasecmp("tcp", tmp[1]) == 0) {
1134 transport = SIPE_TRANSPORT_TCP;
1138 g_strfreev(tmp);
1139 i++;
1141 g_strfreev(parts);
1143 /* Close old connection */
1144 sipe_connection_cleanup(sipe_private);
1146 /* Create new connection */
1147 sipe_server_register(sipe_private, transport, hostname, port);
1148 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1149 hostname, port, transport);
1151 g_free(redirect);
1153 break;
1154 case 401:
1156 const char *auth_scheme;
1157 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1158 if (transport->registrar.retries > 2) {
1159 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: still not authenticated after 3 tries - giving up.");
1160 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1161 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1162 _("Authentication failed"));
1163 return TRUE;
1166 if (transport->reauthenticate_set) {
1167 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1168 do_reauthenticate_cb(sipe_private, NULL);
1169 return TRUE;
1172 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
1173 tmp = sipmsg_find_auth_header(msg, auth_scheme);
1175 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp ? tmp : "");
1176 if (!tmp) {
1177 char *tmp2 = g_strconcat(_("Incompatible authentication scheme chosen"), ": ", auth_scheme, NULL);
1178 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1179 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1180 tmp2);
1181 g_free(tmp2);
1182 return TRUE;
1184 fill_auth(tmp, &transport->registrar);
1185 transport->reregister_set = FALSE;
1186 transport->register_attempt = 0;
1187 do_register(sipe_private,
1188 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1190 break;
1191 case 403:
1193 gchar *reason;
1194 gchar *warning;
1195 sipmsg_parse_warning(msg, &reason);
1196 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1197 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1198 reason ? reason : _("no reason given"));
1199 g_free(reason);
1201 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1202 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1203 warning);
1204 g_free(warning);
1205 return TRUE;
1207 break;
1208 case 404:
1210 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1211 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1212 gchar *warning;
1213 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1214 diagnostics ? (reason ? reason : _("no reason given")) :
1215 _("SIP is either not enabled for the destination URI or it does not exist"));
1216 g_free(reason);
1218 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1219 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1220 warning);
1221 g_free(warning);
1222 return TRUE;
1224 break;
1225 case 504: /* Server time-out */
1226 /* first attempt + 5 retries */
1227 if (transport->register_attempt < 6) {
1228 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1229 transport->register_attempt);
1230 sip_transport_set_reregister(sipe_private, 60);
1231 return TRUE;
1233 /* FALLTHROUGH */
1234 case 503:
1236 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1237 gchar *warning;
1238 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1239 g_free(reason);
1241 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1242 SIPE_CONNECTION_ERROR_NETWORK,
1243 warning);
1244 g_free(warning);
1245 return TRUE;
1247 break;
1249 return TRUE;
1252 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1253 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1254 SIPE_UNUSED_PARAMETER struct transaction *trans)
1256 struct sip_transport *transport = sipe_private->transport;
1257 if (transport->register_attempt < 6) {
1258 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1259 transport->register_attempt);
1260 do_register(sipe_private, FALSE);
1261 } else {
1262 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1263 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1264 SIPE_CONNECTION_ERROR_NETWORK,
1265 warning);
1266 g_free(warning);
1268 return TRUE;
1271 static void do_register(struct sipe_core_private *sipe_private,
1272 gboolean deregister)
1274 struct sip_transport *transport = sipe_private->transport;
1275 char *uri;
1276 char *to;
1277 char *hdr;
1278 char *epid;
1279 char *uuid;
1281 if (!sipe_private->public.sip_domain) return;
1283 if (!deregister) {
1284 if (transport->reregister_set) {
1285 transport->reregister_set = FALSE;
1286 transport->register_attempt = 1;
1287 } else {
1288 transport->register_attempt++;
1292 epid = get_epid(sipe_private);
1293 uuid = generateUUIDfromEPID(epid);
1294 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"
1295 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1296 "Event: registration\r\n"
1297 "Allow-Events: presence\r\n"
1298 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1299 "%s",
1300 sipe_backend_network_ip_address(),
1301 transport->connection->client_port,
1302 TRANSPORT_DESCRIPTOR,
1303 uuid,
1304 deregister ? "Expires: 0\r\n" : "");
1305 g_free(uuid);
1306 g_free(epid);
1308 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1309 to = sip_uri_self(sipe_private);
1310 sip_transport_request_timeout(sipe_private,
1311 "REGISTER",
1312 uri,
1314 hdr,
1316 NULL,
1317 process_register_response,
1319 deregister ? NULL : register_response_timeout);
1320 g_free(to);
1321 g_free(uri);
1322 g_free(hdr);
1324 if (deregister) {
1325 /* Make sure that all messages are pushed to the server
1326 before the connection gets shut down */
1327 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1328 sipe_backend_transport_flush(transport->connection);
1332 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1334 do_register(sipe_private, TRUE);
1337 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1339 struct sip_transport *transport = sipe_private->transport;
1341 sipe_backend_transport_disconnect(transport->connection);
1343 sipe_auth_free(&transport->registrar);
1344 sipe_auth_free(&transport->proxy);
1346 g_free(transport->server_name);
1347 g_free(transport->server_version);
1348 g_free(transport->user_agent);
1350 while (transport->transactions)
1351 transactions_remove(sipe_private,
1352 transport->transactions->data);
1354 g_free(transport);
1356 sipe_private->transport = NULL;
1357 sipe_private->service_data = NULL;
1359 if (sipe_private->dns_query)
1360 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1364 guint sip_transport_port(struct sipe_core_private *sipe_private)
1366 return sipe_private->transport->server_port;
1369 static void process_input_message(struct sipe_core_private *sipe_private,
1370 struct sipmsg *msg)
1372 struct sip_transport *transport = sipe_private->transport;
1373 gboolean notfound = FALSE;
1374 const char *method = msg->method ? msg->method : "NOT FOUND";
1376 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1377 msg->response, method);
1379 if (msg->response == 0) { /* request */
1380 if (sipe_strequal(method, "MESSAGE")) {
1381 process_incoming_message(sipe_private, msg);
1382 } else if (sipe_strequal(method, "NOTIFY")) {
1383 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1384 process_incoming_notify(sipe_private, msg, TRUE, FALSE);
1385 } else if (sipe_strequal(method, "BENOTIFY")) {
1386 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1387 process_incoming_notify(sipe_private, msg, TRUE, TRUE);
1388 } else if (sipe_strequal(method, "INVITE")) {
1389 process_incoming_invite(sipe_private, msg);
1390 } else if (sipe_strequal(method, "REFER")) {
1391 process_incoming_refer(sipe_private, msg);
1392 } else if (sipe_strequal(method, "OPTIONS")) {
1393 process_incoming_options(sipe_private, msg);
1394 } else if (sipe_strequal(method, "INFO")) {
1395 process_incoming_info(sipe_private, msg);
1396 } else if (sipe_strequal(method, "ACK")) {
1397 /* ACK's don't need any response */
1398 } else if (sipe_strequal(method, "PRACK")) {
1399 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1400 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1401 /* LCS 2005 sends us these - just respond 200 OK */
1402 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1403 } else if (sipe_strequal(method, "CANCEL")) {
1404 process_incoming_cancel(sipe_private, msg);
1405 } else if (sipe_strequal(method, "BYE")) {
1406 process_incoming_bye(sipe_private, msg);
1407 } else {
1408 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1409 notfound = TRUE;
1412 } else { /* response */
1413 struct transaction *trans = transactions_find(transport, msg);
1414 if (trans) {
1415 if (msg->response < 200) {
1416 if (msg->bodylen != 0) {
1417 SIPE_DEBUG_INFO("got provisional (%d) response with body", msg->response);
1418 if (trans->callback) {
1419 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1420 (trans->callback)(sipe_private, msg, trans);
1422 } else {
1423 /* ignore provisional response */
1424 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1427 /* Transaction not yet completed */
1428 trans = NULL;
1430 } else if (msg->response == 401) { /* Unauthorized */
1432 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1433 /* Expected response during authentication handshake */
1434 transport->registrar.retries++;
1435 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1436 } else {
1437 gchar *resend;
1439 /* Are we registered? */
1440 if (transport->reregister_set) {
1441 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1442 sign_outgoing_message(trans->msg,
1443 sipe_private,
1444 trans->msg->method);
1445 } else {
1447 * We don't have a valid authentication at the moment.
1448 * Resend message unchanged. It will be rejected again
1449 * and hopefully by then we have a valid authentication.
1451 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1454 /* Resend request */
1455 resend = sipmsg_to_string(trans->msg);
1456 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1457 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1458 g_free(resend);
1460 /* Transaction not yet completed */
1461 trans = NULL;
1464 } else if (msg->response == 407) { /* Proxy Authentication Required */
1466 if (transport->proxy.retries > 30) {
1467 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1468 } else {
1469 gchar *resend, *auth;
1470 const gchar *ptmp;
1472 transport->proxy.retries++;
1474 /* do proxy authentication */
1475 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate");
1476 fill_auth(ptmp, &transport->proxy);
1477 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1478 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1479 sipmsg_add_header_now_pos(trans->msg, "Proxy-Authorization", auth, 5);
1480 g_free(auth);
1482 /* resend request */
1483 resend = sipmsg_to_string(trans->msg);
1484 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1485 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1486 g_free(resend);
1488 /* Transaction not yet completed */
1489 trans = NULL;
1492 } else {
1493 transport->registrar.retries = 0;
1494 transport->proxy.retries = 0;
1497 /* Is transaction completed? */
1498 if (trans) {
1499 if (trans->callback) {
1500 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1501 /* call the callback to process response */
1502 (trans->callback)(sipe_private, msg, trans);
1505 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1506 transactions_remove(sipe_private, trans);
1508 } else {
1509 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1510 notfound = TRUE;
1514 if (notfound) {
1515 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1519 static void sip_transport_input(struct sipe_transport_connection *conn)
1521 struct sipe_core_private *sipe_private = conn->user_data;
1522 struct sip_transport *transport = sipe_private->transport;
1523 gchar *cur = conn->buffer;
1525 /* according to the RFC remove CRLF at the beginning */
1526 while (*cur == '\r' || *cur == '\n') {
1527 cur++;
1529 if (cur != conn->buffer)
1530 sipe_utils_shrink_buffer(conn, cur);
1532 /* Received a full Header? */
1533 transport->processing_input = TRUE;
1534 while (transport->processing_input &&
1535 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1536 struct sipmsg *msg;
1537 guint remainder;
1539 cur += 2;
1540 cur[0] = '\0';
1541 msg = sipmsg_parse_header(conn->buffer);
1543 cur += 2;
1544 remainder = conn->buffer_used - (cur - conn->buffer);
1545 if (msg && remainder >= (guint) msg->bodylen) {
1546 char *dummy = g_malloc(msg->bodylen + 1);
1547 memcpy(dummy, cur, msg->bodylen);
1548 dummy[msg->bodylen] = '\0';
1549 msg->body = dummy;
1550 cur += msg->bodylen;
1551 sipe_utils_message_debug("SIP",
1552 conn->buffer,
1553 msg->body,
1554 FALSE);
1555 sipe_utils_shrink_buffer(conn, cur);
1556 } else {
1557 if (msg){
1558 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1559 sipmsg_free(msg);
1562 /* restore header for next try */
1563 cur[-2] = '\r';
1564 return;
1567 // Verify the signature before processing it
1568 if (transport->registrar.gssapi_context) {
1569 struct sipmsg_breakdown msgbd;
1570 gchar *signature_input_str;
1571 gchar *rspauth;
1572 msgbd.msg = msg;
1573 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target);
1574 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1576 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1578 if (rspauth != NULL) {
1579 if (!sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1580 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1581 process_input_message(sipe_private, msg);
1582 } else {
1583 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1584 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1585 SIPE_CONNECTION_ERROR_NETWORK,
1586 _("Invalid message signature received"));
1588 } else if ((msg->response == 401) ||
1589 sipe_strequal(msg->method, "REGISTER")) {
1590 /* a) Retry non-REGISTER requests with updated authentication */
1591 /* b) We must always process REGISTER responses */
1592 process_input_message(sipe_private, msg);
1593 } else {
1594 /* OCS sends provisional messages that are *not* signed */
1595 if (msg->response >= 200) {
1596 /* We are not calling process_input_message(),
1597 so we need to drop the transaction here. */
1598 struct transaction *trans = transactions_find(transport, msg);
1599 if (trans) transactions_remove(sipe_private, trans);
1601 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1603 g_free(signature_input_str);
1605 g_free(rspauth);
1606 sipmsg_breakdown_free(&msgbd);
1607 } else {
1608 process_input_message(sipe_private, msg);
1611 sipmsg_free(msg);
1613 /* Redirect: old content of "transport" is no longer valid */
1614 transport = sipe_private->transport;
1618 static void sip_transport_connected(struct sipe_transport_connection *conn)
1620 struct sipe_core_private *sipe_private = conn->user_data;
1621 sipe_private->service_data = NULL;
1622 do_register(sipe_private, FALSE);
1625 static void resolve_next_service(struct sipe_core_private *sipe_private,
1626 const struct sip_service_data *start);
1627 static void sip_transport_error(struct sipe_transport_connection *conn,
1628 const gchar *msg)
1630 struct sipe_core_private *sipe_private = conn->user_data;
1632 /* This failed attempt was based on a DNS SRV record */
1633 if (sipe_private->service_data) {
1634 resolve_next_service(sipe_private, NULL);
1635 } else {
1636 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1637 SIPE_CONNECTION_ERROR_NETWORK,
1638 msg);
1642 /* server_name must be g_alloc()'ed */
1643 static void sipe_server_register(struct sipe_core_private *sipe_private,
1644 guint type,
1645 gchar *server_name,
1646 guint server_port)
1648 sipe_connect_setup setup = {
1649 type,
1650 server_name,
1651 (server_port != 0) ? server_port :
1652 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1653 sipe_private,
1654 sip_transport_connected,
1655 sip_transport_input,
1656 sip_transport_error
1658 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1660 transport->server_name = server_name;
1661 transport->server_port = setup.server_port;
1662 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1663 &setup);
1664 sipe_private->transport = transport;
1667 struct sip_service_data {
1668 const char *protocol;
1669 const char *transport;
1670 guint type;
1673 /* Service list for autodection */
1674 static const struct sip_service_data service_autodetect[] = {
1675 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1676 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1677 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1678 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1679 { NULL, NULL, 0 }
1682 /* Service list for SSL/TLS */
1683 static const struct sip_service_data service_tls[] = {
1684 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1685 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1686 { NULL, NULL, 0 }
1689 /* Service list for TCP */
1690 static const struct sip_service_data service_tcp[] = {
1691 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1692 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1693 { NULL, NULL, 0 }
1696 static const struct sip_service_data *services[] = {
1697 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1698 service_tls, /* SIPE_TRANSPORT_TLS */
1699 service_tcp /* SIPE_TRANSPORT_TCP */
1702 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1703 const gchar *hostname, guint port)
1705 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1707 sipe_private->dns_query = NULL;
1709 if (hostname) {
1710 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1711 hostname, port);
1712 sipe_server_register(sipe_private,
1713 sipe_private->service_data->type,
1714 g_strdup(hostname), port);
1715 } else {
1716 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1720 static void resolve_next_service(struct sipe_core_private *sipe_private,
1721 const struct sip_service_data *start)
1723 if (start) {
1724 sipe_private->service_data = start;
1725 } else {
1726 sipe_private->service_data++;
1727 if (sipe_private->service_data->protocol == NULL) {
1728 guint type = sipe_private->transport_type;
1730 /* We tried all services */
1731 sipe_private->service_data = NULL;
1733 /* Try connecting to the SIP hostname directly */
1734 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1735 if (type == SIPE_TRANSPORT_AUTO)
1736 type = SIPE_TRANSPORT_TLS;
1738 sipe_server_register(sipe_private, type,
1739 g_strdup(sipe_private->public.sip_domain),
1741 return;
1745 /* Try to resolve next service */
1746 sipe_private->dns_query = sipe_backend_dns_query_srv(
1747 sipe_private->service_data->protocol,
1748 sipe_private->service_data->transport,
1749 sipe_private->public.sip_domain,
1750 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
1751 SIPE_CORE_PUBLIC);
1754 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
1755 guint transport,
1756 const gchar *server,
1757 const gchar *port)
1759 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1761 if (server) {
1762 /* Use user specified server[:port] */
1763 int port_number = 0;
1765 if (port)
1766 port_number = atoi(port);
1768 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1769 server, port_number);
1771 sipe_server_register(sipe_private, transport,
1772 g_strdup(server), port_number);
1773 } else {
1774 /* Server auto-discovery */
1776 /* Remember user specified transport type */
1777 sipe_private->transport_type = transport;
1778 resolve_next_service(sipe_private, services[transport]);
1782 void sipe_core_transport_sip_keepalive(struct sipe_core_public *sipe_public)
1784 SIPE_DEBUG_INFO("sending keep alive %d",
1785 sipe_public->keepalive_timeout);
1786 sipe_utils_message_debug("SIP", "", NULL, TRUE);
1787 sipe_backend_transport_message(SIPE_CORE_PRIVATE->transport->connection,
1788 "\r\n\r\n");
1791 int sip_transaction_cseq(struct transaction *trans)
1793 int cseq;
1795 g_return_val_if_fail(trans && trans->key, 0);
1797 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
1798 return cseq;
1802 Local Variables:
1803 mode: c
1804 c-file-style: "bsd"
1805 indent-tabs-mode: t
1806 tab-width: 8
1807 End: