Handle 401 response to non-REGISTER requests correctly
[siplcs.git] / src / core / sip-transport.c
blob1d78795629d245194e08343c7be496f9d67b2942
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;
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 void sip_transport_response(struct sipe_core_private *sipe_private,
415 struct sipmsg *msg,
416 guint code,
417 const char *text,
418 const char *body)
420 gchar *name;
421 gchar *value;
422 GString *outstr = g_string_new("");
423 gchar *contact;
424 GSList *tmp;
425 const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
427 /* Can return NULL! */
428 contact = get_contact(sipe_private);
429 if (contact) {
430 sipmsg_add_header(msg, "Contact", contact);
431 g_free(contact);
434 if (body) {
435 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
436 sipmsg_add_header(msg, "Content-Length", len);
437 g_free(len);
438 } else {
439 sipmsg_add_header(msg, "Content-Length", "0");
442 msg->response = code;
444 sipmsg_strip_headers(msg, keepers);
445 sipmsg_merge_new_headers(msg);
446 sign_outgoing_message(msg, sipe_private, msg->method);
448 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
449 tmp = msg->headers;
450 while (tmp) {
451 name = ((struct sipnameval*) (tmp->data))->name;
452 value = ((struct sipnameval*) (tmp->data))->value;
454 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
455 tmp = g_slist_next(tmp);
457 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
458 sipe_utils_message_debug("SIP", outstr->str, NULL, TRUE);
459 sipe_backend_transport_message(sipe_private->transport->connection, outstr->str);
460 g_string_free(outstr, TRUE);
463 static void transactions_remove(struct sipe_core_private *sipe_private,
464 struct transaction *trans)
466 struct sip_transport *transport = sipe_private->transport;
467 if (transport->transactions) {
468 transport->transactions = g_slist_remove(transport->transactions,
469 trans);
470 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
472 if (trans->msg) sipmsg_free(trans->msg);
473 if (trans->payload) {
474 (*trans->payload->destroy)(trans->payload->data);
475 g_free(trans->payload);
477 g_free(trans->key);
478 if (trans->timeout_key) {
479 sipe_schedule_cancel(sipe_private, trans->timeout_key);
480 g_free(trans->timeout_key);
482 g_free(trans);
486 static struct transaction *transactions_find(struct sip_transport *transport,
487 struct sipmsg *msg)
489 GSList *transactions = transport->transactions;
490 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
491 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
492 gchar *key;
494 if (!call_id || !cseq) {
495 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
496 return NULL;
499 key = g_strdup_printf("<%s><%s>", call_id, cseq);
500 while (transactions) {
501 struct transaction *trans = transactions->data;
502 if (!g_strcasecmp(trans->key, key)) {
503 g_free(key);
504 return trans;
506 transactions = transactions->next;
508 g_free(key);
510 return NULL;
513 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
514 gpointer data)
516 struct transaction *trans = data;
517 (trans->timeout_callback)(sipe_private, trans->msg, trans);
518 transactions_remove(sipe_private, trans);
521 const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
523 struct sip_transport *transport = sipe_private->transport;
525 if (!transport->user_agent) {
526 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
527 SIPE_SETTING_USER_AGENT);
528 if (is_empty(useragent)) {
529 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
530 /* ref: lzodefs.h */
531 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
532 #define SIPE_TARGET_PLATFORM "linux"
533 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
534 #define SIPE_TARGET_PLATFORM "bsd"
535 #elif defined(__APPLE__) || defined(__MACOS__)
536 #define SIPE_TARGET_PLATFORM "macosx"
537 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
538 #define SIPE_TARGET_PLATFORM "aix"
539 #elif defined(__solaris__) || defined(__sun)
540 #define SIPE_TARGET_PLATFORM "sun"
541 #elif defined(_WIN32)
542 #define SIPE_TARGET_PLATFORM "win"
543 #elif defined(__CYGWIN__)
544 #define SIPE_TARGET_PLATFORM "cygwin"
545 #elif defined(__hpux__)
546 #define SIPE_TARGET_PLATFORM "hpux"
547 #elif defined(__sgi__)
548 #define SIPE_TARGET_PLATFORM "irix"
549 #else
550 #define SIPE_TARGET_PLATFORM "unknown"
551 #endif
553 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
554 #define SIPE_TARGET_ARCH "x86_64"
555 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
556 #define SIPE_TARGET_ARCH "i386"
557 #elif defined(__ppc64__)
558 #define SIPE_TARGET_ARCH "ppc64"
559 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
560 #define SIPE_TARGET_ARCH "ppc"
561 #elif defined(__hppa__) || defined(__hppa)
562 #define SIPE_TARGET_ARCH "hppa"
563 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
564 #define SIPE_TARGET_ARCH "mips"
565 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
566 #define SIPE_TARGET_ARCH "s390"
567 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
568 #define SIPE_TARGET_ARCH "sparc"
569 #elif defined(__arm__)
570 #define SIPE_TARGET_ARCH "arm"
571 #else
572 #define SIPE_TARGET_ARCH "other"
573 #endif
574 gchar *backend = sipe_backend_version();
575 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
576 backend,
577 transport->server_version ? transport->server_version : "");
578 g_free(backend);
579 } else {
580 transport->user_agent = g_strdup(useragent);
583 return(transport->user_agent);
586 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
587 const gchar *method,
588 const gchar *url,
589 const gchar *to,
590 const gchar *addheaders,
591 const gchar *body,
592 struct sip_dialog *dialog,
593 TransCallback callback,
594 guint timeout,
595 TransCallback timeout_callback)
597 struct sip_transport *transport = sipe_private->transport;
598 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
599 char *buf;
600 struct sipmsg *msg;
601 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
602 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
603 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
604 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
605 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
606 gchar *route = g_strdup("");
607 gchar *epid = get_epid(sipe_private);
608 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
609 struct transaction *trans = NULL;
611 if (dialog && dialog->routes)
613 GSList *iter = dialog->routes;
615 while(iter)
617 char *tmp = route;
618 route = g_strdup_printf("%sRoute: <%s>\r\n", route, (char *)iter->data);
619 g_free(tmp);
620 iter = g_slist_next(iter);
624 if (!ourtag && !dialog) {
625 ourtag = gentag();
628 if (sipe_strequal(method, "REGISTER")) {
629 if (sip->regcallid) {
630 g_free(callid);
631 callid = g_strdup(sip->regcallid);
632 } else {
633 sip->regcallid = g_strdup(callid);
635 cseq = ++transport->cseq;
638 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
639 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
640 "From: <sip:%s>%s%s;epid=%s\r\n"
641 "To: <%s>%s%s%s%s\r\n"
642 "Max-Forwards: 70\r\n"
643 "CSeq: %d %s\r\n"
644 "User-Agent: %s\r\n"
645 "Call-ID: %s\r\n"
646 "%s%s"
647 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
648 method,
649 dialog && dialog->request ? dialog->request : url,
650 TRANSPORT_DESCRIPTOR,
651 sipe_backend_network_ip_address(),
652 transport->connection->client_port,
653 branch ? ";branch=" : "",
654 branch ? branch : "",
655 sipe_private->username,
656 ourtag ? ";tag=" : "",
657 ourtag ? ourtag : "",
658 epid,
660 theirtag ? ";tag=" : "",
661 theirtag ? theirtag : "",
662 theirepid ? ";epid=" : "",
663 theirepid ? theirepid : "",
664 cseq,
665 method,
666 sip_transport_user_agent(sipe_private),
667 callid,
668 route,
669 addheaders ? addheaders : "",
670 body ? (gsize) strlen(body) : 0,
671 body ? body : "");
674 //printf ("parsing msg buf:\n%s\n\n", buf);
675 msg = sipmsg_parse_msg(buf);
677 g_free(buf);
678 g_free(ourtag);
679 g_free(theirtag);
680 g_free(theirepid);
681 g_free(branch);
682 g_free(route);
683 g_free(epid);
685 sign_outgoing_message(msg, sipe_private, method);
687 buf = sipmsg_to_string(msg);
689 /* add to ongoing transactions */
690 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
691 if (!sipe_strequal(method, "ACK")) {
692 trans = g_new0(struct transaction, 1);
693 trans->callback = callback;
694 trans->msg = msg;
695 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
696 if (timeout_callback) {
697 trans->timeout_callback = timeout_callback;
698 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
699 sipe_schedule_seconds(sipe_private,
700 trans->timeout_key,
701 trans,
702 timeout,
703 transaction_timeout_cb,
704 NULL);
706 transport->transactions = g_slist_append(transport->transactions,
707 trans);
708 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
709 } else {
710 sipmsg_free(msg);
712 g_free(callid);
714 sipe_utils_message_debug("SIP", buf, NULL, TRUE);
715 sipe_backend_transport_message(transport->connection, buf);
716 g_free(buf);
718 return trans;
721 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
722 const gchar *method,
723 const gchar *url,
724 const gchar *to,
725 const gchar *addheaders,
726 const gchar *body,
727 struct sip_dialog *dialog,
728 TransCallback callback)
730 return sip_transport_request_timeout(sipe_private,
731 method,
732 url,
734 addheaders,
735 body,
736 dialog,
737 callback,
739 NULL);
742 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
743 const gchar *method,
744 struct sip_dialog *dialog)
746 sip_transport_request(sipe_private,
747 method,
748 dialog->with,
749 dialog->with,
750 NULL,
751 NULL,
752 dialog,
753 NULL);
756 void sip_transport_ack(struct sipe_core_private *sipe_private,
757 struct sip_dialog *dialog)
759 sip_transport_simple_request(sipe_private, "ACK", dialog);
762 void sip_transport_bye(struct sipe_core_private *sipe_private,
763 struct sip_dialog *dialog)
765 sip_transport_simple_request(sipe_private, "BYE", dialog);
768 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
769 const gchar *addheaders,
770 const gchar *body,
771 struct sip_dialog *dialog,
772 TransCallback callback)
774 return sip_transport_request(sipe_private,
775 "INFO",
776 dialog->with,
777 dialog->with,
778 addheaders,
779 body,
780 dialog,
781 callback);
784 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
785 const gchar *addheaders,
786 const gchar *body,
787 struct sip_dialog *dialog,
788 TransCallback callback)
790 return sip_transport_request(sipe_private,
791 "INVITE",
792 dialog->with,
793 dialog->with,
794 addheaders,
795 body,
796 dialog,
797 callback);
800 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
801 const gchar *uri,
802 const gchar *addheaders,
803 const gchar *body,
804 TransCallback callback)
806 return sip_transport_request(sipe_private,
807 "SERVICE",
808 uri,
809 uri,
810 addheaders,
811 body,
812 NULL,
813 callback);
816 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
817 const gchar *uri,
818 const gchar *addheaders,
819 const gchar *body,
820 struct sip_dialog *dialog,
821 TransCallback callback)
823 sip_transport_request(sipe_private,
824 "SUBSCRIBE",
825 uri,
826 uri,
827 addheaders,
828 body,
829 dialog,
830 callback);
833 static const char*
834 sipe_get_auth_scheme_name(struct sipe_core_private *sipe_private)
836 const char *res = "NTLM";
837 #ifdef HAVE_LIBKRB5
838 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5)) {
839 res = "Kerberos";
841 #else
842 (void) sipe_private; /* make compiler happy */
843 #endif
844 return res;
847 static void do_register(struct sipe_core_private *sipe_private,
848 gboolean deregister);
850 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
851 SIPE_UNUSED_PARAMETER gpointer unused)
853 struct sip_transport *transport = sipe_private->transport;
855 /* register again when security token expires */
856 /* we have to start a new authentication as the security token
857 * is almost expired by sending a not signed REGISTER message */
858 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
859 sipe_auth_free(&transport->registrar);
860 sipe_auth_free(&transport->proxy);
861 sipe_schedule_cancel(sipe_private, "<registration>");
862 transport->reregister_set = FALSE;
863 transport->register_attempt = 0;
864 do_register(sipe_private, FALSE);
865 transport->reauthenticate_set = FALSE;
868 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
870 struct sip_transport *transport = sipe_private->transport;
871 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
872 sipe_private->username,
873 transport->connection->client_port,
874 sipe_backend_network_ip_address(),
875 TRANSPORT_DESCRIPTOR);
878 static void do_register_cb(struct sipe_core_private *sipe_private,
879 SIPE_UNUSED_PARAMETER void *unused)
881 do_register(sipe_private, FALSE);
884 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
885 int expires)
887 sipe_schedule_seconds(sipe_private,
888 "<registration>",
889 NULL,
890 expires,
891 do_register_cb,
892 NULL);
895 static void sipe_server_register(struct sipe_core_private *sipe_private,
896 guint type,
897 gchar *server_name,
898 guint server_port);
900 static gboolean process_register_response(struct sipe_core_private *sipe_private,
901 struct sipmsg *msg,
902 SIPE_UNUSED_PARAMETER struct transaction *trans)
904 struct sip_transport *transport = sipe_private->transport;
905 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
906 gchar *tmp;
907 const gchar *expires_header;
908 int expires, i;
909 GSList *hdr = msg->headers;
910 struct sipnameval *elem;
912 expires_header = sipmsg_find_header(msg, "Expires");
913 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
914 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
916 switch (msg->response) {
917 case 200:
918 if (expires) {
919 const gchar *contact_hdr;
920 gchar *gruu = NULL;
921 gchar *epid;
922 gchar *uuid;
923 gchar *timeout;
924 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
925 const char *auth_scheme;
927 if (!transport->reregister_set) {
928 sip_transport_set_reregister(sipe_private,
929 expires);
930 transport->reregister_set = TRUE;
933 if (server_hdr && !transport->server_version) {
934 transport->server_version = g_strdup(server_hdr);
935 g_free(transport->user_agent);
936 transport->user_agent = NULL;
939 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
940 tmp = sipmsg_find_auth_header(msg, auth_scheme);
942 if (tmp) {
943 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp);
944 fill_auth(tmp, &transport->registrar);
947 if (!transport->reauthenticate_set) {
948 gchar *action_name = g_strdup_printf("<%s>", "+reauthentication");
949 guint reauth_timeout;
950 if (transport->registrar.type == AUTH_TYPE_KERBEROS && transport->registrar.expires > 0) {
951 /* assuming normal Kerberos ticket expiration of about 8-10 hours */
952 reauth_timeout = transport->registrar.expires - 300;
953 } else {
954 /* NTLM: we have to reauthenticate as our security token expires
955 after eight hours (be five minutes early) */
956 reauth_timeout = (8 * 3600) - 300;
958 sipe_schedule_seconds(sipe_private,
959 action_name,
960 NULL,
961 reauth_timeout,
962 do_reauthenticate_cb,
963 NULL);
964 g_free(action_name);
965 transport->reauthenticate_set = TRUE;
968 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
970 epid = get_epid(sipe_private);
971 uuid = generateUUIDfromEPID(epid);
972 g_free(epid);
974 // There can be multiple Contact headers (one per location where the user is logged in) so
975 // make sure to only get the one for this uuid
976 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
977 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
978 if (valid_contact) {
979 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
980 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
981 g_free(valid_contact);
982 break;
983 } else {
984 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
987 g_free(uuid);
989 g_free(sipe_private->contact);
990 if(gruu) {
991 sipe_private->contact = g_strdup_printf("<%s>", gruu);
992 g_free(gruu);
993 } else {
994 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
995 sip_transport_default_contact(sipe_private);
997 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
998 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
999 sip->batched_support = FALSE;
1001 while(hdr)
1003 elem = hdr->data;
1004 if (sipe_strcase_equal(elem->name, "Supported")) {
1005 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1006 /* We interpret this as OCS2007+ indicator */
1007 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1008 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem->value);
1010 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1011 sip->batched_support = TRUE;
1012 SIPE_DEBUG_INFO("Supported: %s", elem->value);
1015 if (sipe_strcase_equal(elem->name, "Allow-Events")){
1016 gchar **caps = g_strsplit(elem->value,",",0);
1017 i = 0;
1018 while (caps[i]) {
1019 sip->allow_events = g_slist_append(sip->allow_events, g_strdup(caps[i]));
1020 SIPE_DEBUG_INFO("Allow-Events: %s", caps[i]);
1021 i++;
1023 g_strfreev(caps);
1025 if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1026 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1027 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1028 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1029 "via Edge Server)");
1032 hdr = g_slist_next(hdr);
1035 /* rejoin open chats to be able to use them by continue to send messages */
1036 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1038 /* subscriptions */
1039 if (!transport->subscribed) { //do it just once, not every re-register
1041 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-contacts",
1042 (GCompareFunc)g_ascii_strcasecmp)) {
1043 sipe_subscribe_roaming_contacts(sipe_private);
1046 /* For 2007+ it does not make sence to subscribe to:
1047 * vnd-microsoft-roaming-ACL
1048 * vnd-microsoft-provisioning (not v2)
1049 * presence.wpending
1050 * These are for backward compatibility.
1052 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
1054 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-self",
1055 (GCompareFunc)g_ascii_strcasecmp)) {
1056 sipe_subscribe_roaming_self(sipe_private);
1058 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-provisioning-v2",
1059 (GCompareFunc)g_ascii_strcasecmp)) {
1060 sipe_subscribe_roaming_provisioning_v2(sipe_private);
1063 /* For 2005- servers */
1064 else
1066 //sipe_options_request(sip, sipe_private->public.sip_domain);
1068 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-ACL",
1069 (GCompareFunc)g_ascii_strcasecmp)) {
1070 sipe_subscribe_roaming_acl(sipe_private);
1072 if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-provisioning",
1073 (GCompareFunc)g_ascii_strcasecmp)) {
1074 sipe_subscribe_roaming_provisioning(sipe_private);
1076 if (g_slist_find_custom(sip->allow_events, "presence.wpending",
1077 (GCompareFunc)g_ascii_strcasecmp)) {
1078 sipe_subscribe_presence_wpending(sipe_private,
1079 NULL);
1082 /* For 2007+ we publish our initial statuses and calendar data only after
1083 * received our existing publications in sipe_process_roaming_self()
1084 * Only in this case we know versions of current publications made
1085 * on our behalf.
1087 /* For 2005- we publish our initial statuses only after
1088 * received our existing UserInfo data in response to
1089 * self subscription.
1090 * Only in this case we won't override existing UserInfo data
1091 * set earlier or by other client on our behalf.
1095 transport->subscribed = TRUE;
1098 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1099 "timeout=", ";", NULL);
1100 if (timeout != NULL) {
1101 sscanf(timeout, "%u", &sipe_private->public.keepalive_timeout);
1102 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1103 sipe_private->public.keepalive_timeout);
1104 g_free(timeout);
1107 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1109 break;
1110 case 301:
1112 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1114 if (redirect && (g_strncasecmp("sip:", redirect, 4) == 0)) {
1115 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1116 gchar **tmp;
1117 gchar *hostname;
1118 int port = 0;
1119 guint transport = SIPE_TRANSPORT_TLS;
1120 int i = 1;
1122 tmp = g_strsplit(parts[0], ":", 0);
1123 hostname = g_strdup(tmp[0]);
1124 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1125 g_strfreev(tmp);
1127 while (parts[i]) {
1128 tmp = g_strsplit(parts[i], "=", 0);
1129 if (tmp[1]) {
1130 if (g_strcasecmp("transport", tmp[0]) == 0) {
1131 if (g_strcasecmp("tcp", tmp[1]) == 0) {
1132 transport = SIPE_TRANSPORT_TCP;
1136 g_strfreev(tmp);
1137 i++;
1139 g_strfreev(parts);
1141 /* Close old connection */
1142 sipe_connection_cleanup(sipe_private);
1144 /* Create new connection */
1145 sipe_server_register(sipe_private, transport, hostname, port);
1146 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1147 hostname, port, transport);
1149 g_free(redirect);
1151 break;
1152 case 401:
1154 const char *auth_scheme;
1155 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1156 if (transport->registrar.retries > 2) {
1157 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: still not authenticated after 3 tries - giving up.");
1158 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1159 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1160 _("Authentication failed"));
1161 return TRUE;
1164 if (transport->reauthenticate_set) {
1165 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1166 do_reauthenticate_cb(sipe_private, NULL);
1167 return TRUE;
1170 auth_scheme = sipe_get_auth_scheme_name(sipe_private);
1171 tmp = sipmsg_find_auth_header(msg, auth_scheme);
1173 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp ? tmp : "");
1174 if (!tmp) {
1175 char *tmp2 = g_strconcat(_("Incompatible authentication scheme chosen"), ": ", auth_scheme, NULL);
1176 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1177 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1178 tmp2);
1179 g_free(tmp2);
1180 return TRUE;
1182 fill_auth(tmp, &transport->registrar);
1183 transport->reregister_set = FALSE;
1184 transport->register_attempt = 0;
1185 do_register(sipe_private,
1186 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1188 break;
1189 case 403:
1191 const gchar *diagnostics = sipmsg_find_header(msg, "Warning");
1192 gchar **reason = NULL;
1193 gchar *warning;
1194 if (diagnostics != NULL) {
1195 /* Example header:
1196 Warning: 310 lcs.microsoft.com "You are currently not using the recommended version of the client"
1198 reason = g_strsplit(diagnostics, "\"", 0);
1200 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1201 (reason && reason[1]) ? reason[1] : _("no reason given"));
1202 g_strfreev(reason);
1204 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1205 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1206 warning);
1207 g_free(warning);
1208 return TRUE;
1210 break;
1211 case 404:
1213 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1214 gchar *reason = NULL;
1215 gchar *warning;
1216 if (diagnostics != NULL) {
1217 reason = sipmsg_find_part_of_header(diagnostics, "reason=\"", "\"", NULL);
1219 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1220 diagnostics ? (reason ? reason : _("no reason given")) :
1221 _("SIP is either not enabled for the destination URI or it does not exist"));
1222 g_free(reason);
1224 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1225 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1226 warning);
1227 g_free(warning);
1228 return TRUE;
1230 break;
1231 case 504: /* Server time-out */
1232 /* first attempt + 5 retries */
1233 if (transport->register_attempt < 6) {
1234 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1235 transport->register_attempt);
1236 sip_transport_set_reregister(sipe_private, 60);
1237 return TRUE;
1239 /* FALLTHROUGH */
1240 case 503:
1242 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1243 gchar *reason = NULL;
1244 gchar *warning;
1245 if (diagnostics != NULL) {
1246 reason = sipmsg_find_part_of_header(diagnostics, "reason=\"", "\"", NULL);
1248 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1249 g_free(reason);
1251 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1252 SIPE_CONNECTION_ERROR_NETWORK,
1253 warning);
1254 g_free(warning);
1255 return TRUE;
1257 break;
1259 return TRUE;
1262 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1263 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1264 SIPE_UNUSED_PARAMETER struct transaction *trans)
1266 struct sip_transport *transport = sipe_private->transport;
1267 if (transport->register_attempt < 6) {
1268 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1269 transport->register_attempt);
1270 do_register(sipe_private, FALSE);
1271 } else {
1272 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1273 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1274 SIPE_CONNECTION_ERROR_NETWORK,
1275 warning);
1276 g_free(warning);
1278 return TRUE;
1281 static void do_register(struct sipe_core_private *sipe_private,
1282 gboolean deregister)
1284 struct sip_transport *transport = sipe_private->transport;
1285 char *uri;
1286 char *to;
1287 char *hdr;
1288 char *epid;
1289 char *uuid;
1291 if (!sipe_private->public.sip_domain) return;
1293 if (!deregister) {
1294 if (transport->reregister_set) {
1295 transport->reregister_set = FALSE;
1296 transport->register_attempt = 1;
1297 } else {
1298 transport->register_attempt++;
1302 epid = get_epid(sipe_private);
1303 uuid = generateUUIDfromEPID(epid);
1304 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"
1305 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1306 "Event: registration\r\n"
1307 "Allow-Events: presence\r\n"
1308 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1309 "%s",
1310 sipe_backend_network_ip_address(),
1311 transport->connection->client_port,
1312 TRANSPORT_DESCRIPTOR,
1313 uuid,
1314 deregister ? "Expires: 0\r\n" : "");
1315 g_free(uuid);
1316 g_free(epid);
1318 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1319 to = sip_uri_self(sipe_private);
1320 sip_transport_request_timeout(sipe_private,
1321 "REGISTER",
1322 uri,
1324 hdr,
1326 NULL,
1327 process_register_response,
1329 deregister ? NULL : register_response_timeout);
1330 g_free(to);
1331 g_free(uri);
1332 g_free(hdr);
1334 if (deregister) {
1335 /* Make sure that all messages are pushed to the server
1336 before the connection gets shut down */
1337 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1338 sipe_backend_transport_flush(transport->connection);
1342 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1344 do_register(sipe_private, TRUE);
1347 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1349 struct sip_transport *transport = sipe_private->transport;
1351 sipe_backend_transport_disconnect(transport->connection);
1353 sipe_auth_free(&transport->registrar);
1354 sipe_auth_free(&transport->proxy);
1356 g_free(transport->server_name);
1357 g_free(transport->server_version);
1358 g_free(transport->user_agent);
1360 while (transport->transactions)
1361 transactions_remove(sipe_private,
1362 transport->transactions->data);
1364 g_free(transport);
1366 sipe_private->transport = NULL;
1367 sipe_private->service_data = NULL;
1369 if (sipe_private->dns_query)
1370 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1374 guint sip_transport_port(struct sipe_core_private *sipe_private)
1376 return sipe_private->transport->server_port;
1379 static void process_input_message(struct sipe_core_private *sipe_private,
1380 struct sipmsg *msg)
1382 struct sip_transport *transport = sipe_private->transport;
1383 gboolean notfound = FALSE;
1384 const char *method = msg->method ? msg->method : "NOT FOUND";
1386 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1387 msg->response, method);
1389 if (msg->response == 0) { /* request */
1390 if (sipe_strequal(method, "MESSAGE")) {
1391 process_incoming_message(sipe_private, msg);
1392 } else if (sipe_strequal(method, "NOTIFY")) {
1393 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1394 process_incoming_notify(sipe_private, msg, TRUE, FALSE);
1395 } else if (sipe_strequal(method, "BENOTIFY")) {
1396 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1397 process_incoming_notify(sipe_private, msg, TRUE, TRUE);
1398 } else if (sipe_strequal(method, "INVITE")) {
1399 process_incoming_invite(sipe_private, msg);
1400 } else if (sipe_strequal(method, "REFER")) {
1401 process_incoming_refer(sipe_private, msg);
1402 } else if (sipe_strequal(method, "OPTIONS")) {
1403 process_incoming_options(sipe_private, msg);
1404 } else if (sipe_strequal(method, "INFO")) {
1405 process_incoming_info(sipe_private, msg);
1406 } else if (sipe_strequal(method, "ACK")) {
1407 /* ACK's don't need any response */
1408 } else if (sipe_strequal(method, "PRACK")) {
1409 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1410 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1411 /* LCS 2005 sends us these - just respond 200 OK */
1412 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1413 } else if (sipe_strequal(method, "CANCEL")) {
1414 process_incoming_cancel(sipe_private, msg);
1415 } else if (sipe_strequal(method, "BYE")) {
1416 process_incoming_bye(sipe_private, msg);
1417 } else {
1418 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1419 notfound = TRUE;
1422 } else { /* response */
1423 struct transaction *trans = transactions_find(transport, msg);
1424 if (trans) {
1425 if (msg->response < 200) {
1426 if (msg->bodylen != 0) {
1427 SIPE_DEBUG_INFO("got provisional (%d) response with body", msg->response);
1428 if (trans->callback) {
1429 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1430 (trans->callback)(sipe_private, msg, trans);
1432 } else {
1433 /* ignore provisional response */
1434 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1437 /* Transaction not yet completed */
1438 trans = NULL;
1440 } else if (msg->response == 401) { /* Unauthorized */
1442 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1443 /* Expected response during authentication handshake */
1444 transport->registrar.retries++;
1445 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1446 } else {
1447 gchar *resend;
1449 /* Are we registered? */
1450 if (transport->reregister_set) {
1451 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1452 sign_outgoing_message(trans->msg,
1453 sipe_private,
1454 trans->msg->method);
1455 } else {
1457 * We don't have a valid authentication at the moment.
1458 * Resend message unchanged. It will be rejected again
1459 * and hopefully by then we have a valid authentication.
1461 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1464 /* Resend request */
1465 resend = sipmsg_to_string(trans->msg);
1466 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1467 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1468 g_free(resend);
1470 /* Transaction not yet completed */
1471 trans = NULL;
1474 } else if (msg->response == 407) { /* Proxy Authentication Required */
1476 if (transport->proxy.retries > 30) {
1477 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1478 } else {
1479 gchar *resend, *auth;
1480 const gchar *ptmp;
1482 transport->proxy.retries++;
1484 /* do proxy authentication */
1485 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate");
1486 fill_auth(ptmp, &transport->proxy);
1487 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1488 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1489 sipmsg_add_header_now_pos(trans->msg, "Proxy-Authorization", auth, 5);
1490 g_free(auth);
1492 /* resend request */
1493 resend = sipmsg_to_string(trans->msg);
1494 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1495 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1496 g_free(resend);
1498 /* Transaction not yet completed */
1499 trans = NULL;
1502 } else {
1503 transport->registrar.retries = 0;
1504 transport->proxy.retries = 0;
1507 /* Is transaction completed? */
1508 if (trans) {
1509 if (trans->callback) {
1510 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1511 /* call the callback to process response */
1512 (trans->callback)(sipe_private, msg, trans);
1515 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1516 transactions_remove(sipe_private, trans);
1518 } else {
1519 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1520 notfound = TRUE;
1524 if (notfound) {
1525 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1529 static void sip_transport_input(struct sipe_transport_connection *conn)
1531 struct sipe_core_private *sipe_private = conn->user_data;
1532 struct sip_transport *transport = sipe_private->transport;
1533 gchar *cur = conn->buffer;
1535 /* according to the RFC remove CRLF at the beginning */
1536 while (*cur == '\r' || *cur == '\n') {
1537 cur++;
1539 if (cur != conn->buffer)
1540 sipe_utils_shrink_buffer(conn, cur);
1542 /* Received a full Header? */
1543 transport->processing_input = TRUE;
1544 while (transport->processing_input &&
1545 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1546 struct sipmsg *msg;
1547 guint remainder;
1549 cur += 2;
1550 cur[0] = '\0';
1551 msg = sipmsg_parse_header(conn->buffer);
1553 cur += 2;
1554 remainder = conn->buffer_used - (cur - conn->buffer);
1555 if (msg && remainder >= (guint) msg->bodylen) {
1556 char *dummy = g_malloc(msg->bodylen + 1);
1557 memcpy(dummy, cur, msg->bodylen);
1558 dummy[msg->bodylen] = '\0';
1559 msg->body = dummy;
1560 cur += msg->bodylen;
1561 sipe_utils_message_debug("SIP",
1562 conn->buffer,
1563 msg->body,
1564 FALSE);
1565 sipe_utils_shrink_buffer(conn, cur);
1566 } else {
1567 if (msg){
1568 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1569 sipmsg_free(msg);
1572 /* restore header for next try */
1573 cur[-2] = '\r';
1574 return;
1577 // Verify the signature before processing it
1578 if (transport->registrar.gssapi_context) {
1579 struct sipmsg_breakdown msgbd;
1580 gchar *signature_input_str;
1581 gchar *rspauth;
1582 msgbd.msg = msg;
1583 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target);
1584 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1586 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1588 if (rspauth != NULL) {
1589 if (!sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1590 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1591 process_input_message(sipe_private, msg);
1592 } else {
1593 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1594 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1595 SIPE_CONNECTION_ERROR_NETWORK,
1596 _("Invalid message signature received"));
1598 } else if ((msg->response == 401) ||
1599 sipe_strequal(msg->method, "REGISTER")) {
1600 /* a) Retry non-REGISTER requests with updated authentication */
1601 /* b) We must always process REGISTER responses */
1602 process_input_message(sipe_private, msg);
1603 } else {
1604 /* OCS sends provisional messages that are *not* signed */
1605 if (msg->response >= 200) {
1606 /* We are not calling process_input_message(),
1607 so we need to drop the transaction here. */
1608 struct transaction *trans = transactions_find(transport, msg);
1609 if (trans) transactions_remove(sipe_private, trans);
1611 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1613 g_free(signature_input_str);
1615 g_free(rspauth);
1616 sipmsg_breakdown_free(&msgbd);
1617 } else {
1618 process_input_message(sipe_private, msg);
1621 sipmsg_free(msg);
1623 /* Redirect: old content of "transport" is no longer valid */
1624 transport = sipe_private->transport;
1628 static void sip_transport_connected(struct sipe_transport_connection *conn)
1630 struct sipe_core_private *sipe_private = conn->user_data;
1631 sipe_private->service_data = NULL;
1632 do_register(sipe_private, FALSE);
1635 static void resolve_next_service(struct sipe_core_private *sipe_private,
1636 const struct sip_service_data *start);
1637 static void sip_transport_error(struct sipe_transport_connection *conn,
1638 const gchar *msg)
1640 struct sipe_core_private *sipe_private = conn->user_data;
1642 /* This failed attempt was based on a DNS SRV record */
1643 if (sipe_private->service_data) {
1644 resolve_next_service(sipe_private, NULL);
1645 } else {
1646 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1647 SIPE_CONNECTION_ERROR_NETWORK,
1648 msg);
1652 /* server_name must be g_alloc()'ed */
1653 static void sipe_server_register(struct sipe_core_private *sipe_private,
1654 guint type,
1655 gchar *server_name,
1656 guint server_port)
1658 sipe_connect_setup setup = {
1659 type,
1660 server_name,
1661 (server_port != 0) ? server_port :
1662 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1663 sipe_private,
1664 sip_transport_connected,
1665 sip_transport_input,
1666 sip_transport_error
1668 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1670 transport->server_name = server_name;
1671 transport->server_port = setup.server_port;
1672 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1673 &setup);
1674 sipe_private->transport = transport;
1677 struct sip_service_data {
1678 const char *protocol;
1679 const char *transport;
1680 guint type;
1683 /* Service list for autodection */
1684 static const struct sip_service_data service_autodetect[] = {
1685 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1686 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1687 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1688 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1689 { NULL, NULL, 0 }
1692 /* Service list for SSL/TLS */
1693 static const struct sip_service_data service_tls[] = {
1694 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1695 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1696 { NULL, NULL, 0 }
1699 /* Service list for TCP */
1700 static const struct sip_service_data service_tcp[] = {
1701 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1702 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1703 { NULL, NULL, 0 }
1706 static const struct sip_service_data *services[] = {
1707 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1708 service_tls, /* SIPE_TRANSPORT_TLS */
1709 service_tcp /* SIPE_TRANSPORT_TCP */
1712 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1713 const gchar *hostname, guint port)
1715 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1717 sipe_private->dns_query = NULL;
1719 if (hostname) {
1720 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1721 hostname, port);
1722 sipe_server_register(sipe_private,
1723 sipe_private->service_data->type,
1724 g_strdup(hostname), port);
1725 } else {
1726 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1730 static void resolve_next_service(struct sipe_core_private *sipe_private,
1731 const struct sip_service_data *start)
1733 if (start) {
1734 sipe_private->service_data = start;
1735 } else {
1736 sipe_private->service_data++;
1737 if (sipe_private->service_data->protocol == NULL) {
1738 guint type = sipe_private->transport_type;
1740 /* We tried all services */
1741 sipe_private->service_data = NULL;
1743 /* Try connecting to the SIP hostname directly */
1744 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1745 if (type == SIPE_TRANSPORT_AUTO)
1746 type = SIPE_TRANSPORT_TLS;
1748 sipe_server_register(sipe_private, type,
1749 g_strdup(sipe_private->public.sip_domain),
1751 return;
1755 /* Try to resolve next service */
1756 sipe_private->dns_query = sipe_backend_dns_query_srv(
1757 sipe_private->service_data->protocol,
1758 sipe_private->service_data->transport,
1759 sipe_private->public.sip_domain,
1760 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
1761 SIPE_CORE_PUBLIC);
1764 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
1765 guint transport,
1766 const gchar *server,
1767 const gchar *port)
1769 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1771 if (server) {
1772 /* Use user specified server[:port] */
1773 int port_number = 0;
1775 if (port)
1776 port_number = atoi(port);
1778 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1779 server, port_number);
1781 sipe_server_register(sipe_private, transport,
1782 g_strdup(server), port_number);
1783 } else {
1784 /* Server auto-discovery */
1786 /* Remember user specified transport type */
1787 sipe_private->transport_type = transport;
1788 resolve_next_service(sipe_private, services[transport]);
1792 void sipe_core_transport_sip_keepalive(struct sipe_core_public *sipe_public)
1794 SIPE_DEBUG_INFO("sending keep alive %d",
1795 sipe_public->keepalive_timeout);
1796 sipe_utils_message_debug("SIP", "", NULL, TRUE);
1797 sipe_backend_transport_message(SIPE_CORE_PRIVATE->transport->connection,
1798 "\r\n\r\n");
1802 Local Variables:
1803 mode: c
1804 c-file-style: "bsd"
1805 indent-tabs-mode: t
1806 tab-width: 8
1807 End: