core: move SIP transport auth type to public API
[siplcs.git] / src / core / sip-transport.c
blob26857147659e8c4c511d3d5ecc8684c5a874d28f
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010-12 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-certificate.h"
69 #include "sipe-dialog.h"
70 #include "sipe-incoming.h"
71 #include "sipe-nls.h"
72 #include "sipe-notify.h"
73 #include "sipe-schedule.h"
74 #include "sipe-sign.h"
75 #include "sipe-subscriptions.h"
76 #include "sipe-utils.h"
78 struct sip_auth {
79 guint type;
80 struct sip_sec_context *gssapi_context;
81 gchar *gssapi_data;
82 gchar *opaque;
83 const gchar *protocol;
84 gchar *realm;
85 gchar *sts_uri;
86 gchar *target;
87 int version;
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 auth_incomplete; /* whether authentication not completed */
113 gboolean reregister_set; /* whether reregister timer set */
114 gboolean reauthenticate_set; /* whether reauthenticate timer set */
115 gboolean subscribed; /* whether subscribed to events, except buddies presence */
116 gboolean deregister; /* whether in deregistration */
119 /* Keep in sync with sipe_transport_type! */
120 static const char *transport_descriptor[] = { "", "tls", "tcp"};
121 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
123 static char *genbranch()
125 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
126 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
127 rand() & 0xFFFF, rand() & 0xFFFF);
130 static void sipe_auth_free(struct sip_auth *auth)
132 g_free(auth->opaque);
133 auth->opaque = NULL;
134 auth->protocol = NULL;
135 g_free(auth->realm);
136 auth->realm = NULL;
137 g_free(auth->sts_uri);
138 auth->sts_uri = NULL;
139 g_free(auth->target);
140 auth->target = NULL;
141 auth->version = 0;
142 auth->type = SIPE_AUTHENTICATION_TYPE_UNSET;
143 auth->retries = 0;
144 auth->expires = 0;
145 g_free(auth->gssapi_data);
146 auth->gssapi_data = NULL;
147 sip_sec_destroy_context(auth->gssapi_context);
148 auth->gssapi_context = NULL;
151 static void sipe_make_signature(struct sipe_core_private *sipe_private,
152 struct sipmsg *msg)
154 struct sip_transport *transport = sipe_private->transport;
155 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
156 struct sipmsg_breakdown msgbd;
157 gchar *signature_input_str;
158 msgbd.msg = msg;
159 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
160 transport->registrar.protocol);
161 msgbd.rand = g_strdup_printf("%08x", g_random_int());
162 transport->registrar.ntlm_num++;
163 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
164 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
165 if (signature_input_str != NULL) {
166 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
167 msg->signature = signature_hex;
168 msg->rand = g_strdup(msgbd.rand);
169 msg->num = g_strdup(msgbd.num);
170 g_free(signature_input_str);
172 sipmsg_breakdown_free(&msgbd);
176 static gchar *auth_header_version(struct sip_auth *auth)
178 return(auth->version > 2 ?
179 g_strdup_printf(", version=%d", auth->version) :
180 g_strdup(""));
183 static const gchar *const auth_type_to_protocol[] = {
184 NULL, /* SIPE_AUTHENTICATION_TYPE_UNSET */
185 "NTLM", /* SIPE_AUTHENTICATION_TYPE_NTLM */
186 "Kerberos", /* SIPE_AUTHENTICATION_TYPE_KERBEROS */
187 NULL, /* SIPE_AUTHENTICATION_TYPE_NEGOTIATE */
188 "TLS-DSK", /* SIPE_AUTHENTICATION_TYPE_TLS_DSK */
190 #define AUTH_PROTOCOLS (sizeof(auth_type_to_protocol)/sizeof(gchar *))
192 static gchar *msg_signature_to_auth(struct sip_auth *auth,
193 struct sipmsg *msg)
195 return(g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
196 auth->protocol,
197 auth->opaque, auth->realm, auth->target,
198 msg->rand, msg->num, msg->signature));
201 static gchar *initialize_auth_context(struct sipe_core_private *sipe_private,
202 struct sip_auth *auth,
203 struct sipmsg *msg)
205 struct sip_transport *transport = sipe_private->transport;
206 gchar *ret;
207 gchar *gssapi_data = NULL;
208 gchar *sign_str;
209 gchar *gssapi_str;
210 gchar *opaque_str;
211 gchar *version_str;
214 * If transport is de-registering when we reach this point then we
215 * are in the middle of the previous authentication context setup
216 * attempt. So we shouldn't try another attempt.
218 if (transport->deregister)
219 return NULL;
221 /* Create security context or handshake continuation? */
222 if (auth->gssapi_context) {
223 /* Perform next step in authentication handshake */
224 int status = sip_sec_init_context_step(auth->gssapi_context,
225 auth->target,
226 auth->gssapi_data,
227 &gssapi_data,
228 &auth->expires);
230 /* If authentication is completed gssapi_data can be NULL */
231 if ((status < 0) ||
232 !(sip_sec_context_is_ready(auth->gssapi_context) || gssapi_data)) {
233 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context continuation failed");
234 g_free(gssapi_data);
235 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
236 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
237 _("Failed to authenticate to server"));
238 return NULL;
241 } else {
242 /* Create security context */
243 const gchar *authuser = sipe_private->authuser;
244 gpointer password = sipe_private->password;
246 if (is_empty(authuser)) {
247 authuser = sipe_private->username;
250 /* For TLS-DSK the "password" is a certificate */
251 if (auth->type == SIPE_AUTHENTICATION_TYPE_TLS_DSK) {
252 password = sipe_certificate_tls_dsk_find(sipe_private,
253 auth->target);
255 if (!password) {
256 if (auth->sts_uri) {
257 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK Certificate Provisioning URI %s",
258 auth->sts_uri);
259 if (!sipe_certificate_tls_dsk_generate(sipe_private,
260 auth->target,
261 auth->sts_uri)) {
262 gchar *tmp = g_strdup_printf(_("Can't request certificate from %s"),
263 auth->sts_uri);
264 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
265 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
266 tmp);
267 g_free(tmp);
269 } else {
270 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
271 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
272 _("No URI for certificate provisioning service provided"));
275 /* we can't authenticate the message yet */
276 transport->auth_incomplete = TRUE;
278 return(NULL);
279 } else {
280 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK certificate for target '%s' found.",
281 auth->target);
285 gssapi_data = sip_sec_init_context(&(auth->gssapi_context),
286 &(auth->expires),
287 auth->type,
288 SIPE_CORE_PUBLIC_FLAG_IS(SSO),
289 sipe_private->authdomain ? sipe_private->authdomain : "",
290 authuser,
291 password,
292 auth->target,
293 auth->gssapi_data);
294 if (!gssapi_data || !auth->gssapi_context) {
295 g_free(gssapi_data);
296 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
297 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
298 _("Failed to authenticate to server"));
299 return NULL;
303 if ((auth->version > 3) &&
304 sip_sec_context_is_ready(auth->gssapi_context)) {
305 sipe_make_signature(sipe_private, msg);
306 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
307 msg->rand, msg->num, msg->signature);
308 } else {
309 sign_str = g_strdup("");
312 if (gssapi_data) {
313 gssapi_str = g_strdup_printf(", gssapi-data=\"%s\"",
314 gssapi_data);
315 g_free(gssapi_data);
316 } else {
317 gssapi_str = g_strdup("");
320 opaque_str = auth->opaque ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup("");
321 version_str = auth_header_version(auth);
322 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\"%s%s%s",
323 auth->protocol, opaque_str,
324 auth->realm, auth->target,
325 gssapi_str, version_str, sign_str);
326 g_free(version_str);
327 g_free(opaque_str);
328 g_free(gssapi_str);
329 g_free(sign_str);
331 return(ret);
334 static gchar *start_auth_handshake(struct sip_auth *auth)
336 gchar *version_str = auth_header_version(auth);
337 gchar *ret = g_strdup_printf("%s qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"%s",
338 auth->protocol,
339 auth->realm, auth->target,
340 version_str);
341 g_free(version_str);
342 return(ret);
345 static gchar *auth_header(struct sipe_core_private *sipe_private,
346 struct sip_auth *auth,
347 struct sipmsg *msg)
349 gchar *ret = NULL;
352 * If the message is already signed then we have an authentication
353 * context, i.e. the authentication handshake is complete. Generate
354 * authentication header from message signature.
356 if (msg->signature) {
357 ret = msg_signature_to_auth(auth, msg);
360 * If the message isn't signed then we don't have a initialized
361 * authentication context yet.
363 * Start the authentication handshake if NTLM is selected.
365 } else if ((auth->type == SIPE_AUTHENTICATION_TYPE_NTLM) &&
366 !auth->gssapi_data) {
367 ret = start_auth_handshake(auth);
370 * We should reach this point only when the authentication context
371 * needs to be initialized.
373 } else {
374 ret = initialize_auth_context(sipe_private, auth, msg);
377 return(ret);
380 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
382 const gchar *param;
384 /* skip authentication identifier */
385 hdr = strchr(hdr, ' ');
386 if (!hdr) {
387 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: corrupted authentication header");
388 return;
390 while (*hdr == ' ')
391 hdr++;
393 /* start of next parameter value */
394 while ((param = strchr(hdr, '=')) != NULL) {
395 const gchar *end;
397 /* parameter value type */
398 param++;
399 if (*param == '"') {
400 /* string: xyz="..."(,) */
401 end = strchr(++param, '"');
402 if (!end) {
403 SIPE_DEBUG_ERROR("fill_auth: corrupted string parameter near '%s'", hdr);
404 break;
406 } else {
407 /* number: xyz=12345(,) */
408 end = strchr(param, ',');
409 if (!end) {
410 /* last parameter */
411 end = param + strlen(param);
415 #if 0
416 SIPE_DEBUG_INFO("fill_auth: hdr '%s'", hdr);
417 SIPE_DEBUG_INFO("fill_auth: param '%s'", param);
418 SIPE_DEBUG_INFO("fill_auth: end '%s'", end);
419 #endif
421 /* parameter type */
422 if (g_str_has_prefix(hdr, "gssapi-data=\"")) {
423 g_free(auth->gssapi_data);
424 auth->gssapi_data = g_strndup(param, end - param);
425 } else if (g_str_has_prefix(hdr, "opaque=\"")) {
426 g_free(auth->opaque);
427 auth->opaque = g_strndup(param, end - param);
428 } else if (g_str_has_prefix(hdr, "realm=\"")) {
429 g_free(auth->realm);
430 auth->realm = g_strndup(param, end - param);
431 } else if (g_str_has_prefix(hdr, "sts-uri=\"")) {
432 /* Only used with SIPE_AUTHENTICATION_TYPE_TLS_DSK */
433 g_free(auth->sts_uri);
434 auth->sts_uri = g_strndup(param, end - param);
435 } else if (g_str_has_prefix(hdr, "targetname=\"")) {
436 g_free(auth->target);
437 auth->target = g_strndup(param, end - param);
438 } else if (g_str_has_prefix(hdr, "version=")) {
439 auth->version = atoi(param);
442 /* skip to next parameter */
443 while ((*end == '"') || (*end == ',') || (*end == ' '))
444 end++;
445 hdr = end;
448 return;
451 static void sign_outgoing_message(struct sipe_core_private *sipe_private,
452 struct sipmsg *msg)
454 struct sip_transport *transport = sipe_private->transport;
455 gchar *buf;
457 if (transport->registrar.type == SIPE_AUTHENTICATION_TYPE_UNSET) {
458 return;
461 sipe_make_signature(sipe_private, msg);
463 buf = auth_header(sipe_private, &transport->registrar, msg);
464 if (buf) {
465 sipmsg_add_header_now_pos(msg, "Authorization", buf, 5);
466 g_free(buf);
470 static const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
472 struct sip_transport *transport = sipe_private->transport;
474 if (!transport->user_agent) {
475 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
476 SIPE_SETTING_USER_AGENT);
477 if (is_empty(useragent)) {
478 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
479 /* ref: lzodefs.h */
480 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
481 #define SIPE_TARGET_PLATFORM "linux"
482 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
483 #define SIPE_TARGET_PLATFORM "bsd"
484 #elif defined(__APPLE__) || defined(__MACOS__)
485 #define SIPE_TARGET_PLATFORM "macosx"
486 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
487 #define SIPE_TARGET_PLATFORM "aix"
488 #elif defined(__solaris__) || defined(__sun)
489 #define SIPE_TARGET_PLATFORM "sun"
490 #elif defined(_WIN32)
491 #define SIPE_TARGET_PLATFORM "win"
492 #elif defined(__CYGWIN__)
493 #define SIPE_TARGET_PLATFORM "cygwin"
494 #elif defined(__hpux__)
495 #define SIPE_TARGET_PLATFORM "hpux"
496 #elif defined(__sgi__)
497 #define SIPE_TARGET_PLATFORM "irix"
498 #else
499 #define SIPE_TARGET_PLATFORM "unknown"
500 #endif
502 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
503 #define SIPE_TARGET_ARCH "x86_64"
504 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
505 #define SIPE_TARGET_ARCH "i386"
506 #elif defined(__ppc64__)
507 #define SIPE_TARGET_ARCH "ppc64"
508 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
509 #define SIPE_TARGET_ARCH "ppc"
510 #elif defined(__hppa__) || defined(__hppa)
511 #define SIPE_TARGET_ARCH "hppa"
512 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
513 #define SIPE_TARGET_ARCH "mips"
514 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
515 #define SIPE_TARGET_ARCH "s390"
516 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
517 #define SIPE_TARGET_ARCH "sparc"
518 #elif defined(__arm__)
519 #define SIPE_TARGET_ARCH "arm"
520 #else
521 #define SIPE_TARGET_ARCH "other"
522 #endif
523 gchar *backend = sipe_backend_version();
524 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
525 backend,
526 transport->server_version ? transport->server_version : "");
527 g_free(backend);
528 } else {
529 transport->user_agent = g_strdup(useragent);
532 return(transport->user_agent);
535 void sip_transport_response(struct sipe_core_private *sipe_private,
536 struct sipmsg *msg,
537 guint code,
538 const char *text,
539 const char *body)
541 gchar *name;
542 gchar *value;
543 GString *outstr = g_string_new("");
544 gchar *contact;
545 GSList *tmp;
546 const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
548 /* Can return NULL! */
549 contact = get_contact(sipe_private);
550 if (contact) {
551 sipmsg_add_header(msg, "Contact", contact);
552 g_free(contact);
555 if (body) {
556 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
557 sipmsg_add_header(msg, "Content-Length", len);
558 g_free(len);
559 } else {
560 sipmsg_add_header(msg, "Content-Length", "0");
563 sipmsg_add_header(msg, "User-Agent", sip_transport_user_agent(sipe_private));
565 msg->response = code;
567 sipmsg_strip_headers(msg, keepers);
568 sipmsg_merge_new_headers(msg);
569 sign_outgoing_message(sipe_private, msg);
571 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
572 tmp = msg->headers;
573 while (tmp) {
574 name = ((struct sipnameval*) (tmp->data))->name;
575 value = ((struct sipnameval*) (tmp->data))->value;
577 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
578 tmp = g_slist_next(tmp);
580 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
581 sipe_utils_message_debug("SIP", outstr->str, NULL, TRUE);
582 sipe_backend_transport_message(sipe_private->transport->connection, outstr->str);
583 g_string_free(outstr, TRUE);
586 static void transactions_remove(struct sipe_core_private *sipe_private,
587 struct transaction *trans)
589 struct sip_transport *transport = sipe_private->transport;
590 if (transport->transactions) {
591 transport->transactions = g_slist_remove(transport->transactions,
592 trans);
593 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
595 if (trans->msg) sipmsg_free(trans->msg);
596 if (trans->payload) {
597 if (trans->payload->destroy)
598 (*trans->payload->destroy)(trans->payload->data);
599 g_free(trans->payload);
601 g_free(trans->key);
602 if (trans->timeout_key) {
603 sipe_schedule_cancel(sipe_private, trans->timeout_key);
604 g_free(trans->timeout_key);
606 g_free(trans);
610 static struct transaction *transactions_find(struct sip_transport *transport,
611 struct sipmsg *msg)
613 GSList *transactions = transport->transactions;
614 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
615 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
616 gchar *key;
618 if (!call_id || !cseq) {
619 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
620 return NULL;
623 key = g_strdup_printf("<%s><%s>", call_id, cseq);
624 while (transactions) {
625 struct transaction *trans = transactions->data;
626 if (!g_ascii_strcasecmp(trans->key, key)) {
627 g_free(key);
628 return trans;
630 transactions = transactions->next;
632 g_free(key);
634 return NULL;
637 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
638 gpointer data)
640 struct transaction *trans = data;
641 (trans->timeout_callback)(sipe_private, trans->msg, trans);
642 transactions_remove(sipe_private, trans);
645 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
646 const gchar *method,
647 const gchar *url,
648 const gchar *to,
649 const gchar *addheaders,
650 const gchar *body,
651 struct sip_dialog *dialog,
652 TransCallback callback,
653 guint timeout,
654 TransCallback timeout_callback)
656 struct sip_transport *transport = sipe_private->transport;
657 char *buf;
658 struct sipmsg *msg;
659 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
660 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
661 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
662 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
663 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
664 gchar *route = g_strdup("");
665 gchar *epid = get_epid(sipe_private);
666 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
667 struct transaction *trans = NULL;
669 if (dialog && dialog->routes)
671 GSList *iter = dialog->routes;
673 while(iter)
675 char *tmp = route;
676 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
677 g_free(tmp);
678 iter = g_slist_next(iter);
682 if (!ourtag && !dialog) {
683 ourtag = gentag();
686 if (sipe_strequal(method, "REGISTER")) {
687 if (sipe_private->register_callid) {
688 g_free(callid);
689 callid = g_strdup(sipe_private->register_callid);
690 } else {
691 sipe_private->register_callid = g_strdup(callid);
693 cseq = ++transport->cseq;
696 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
697 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
698 "From: <sip:%s>%s%s;epid=%s\r\n"
699 "To: <%s>%s%s%s%s\r\n"
700 "Max-Forwards: 70\r\n"
701 "CSeq: %d %s\r\n"
702 "User-Agent: %s\r\n"
703 "Call-ID: %s\r\n"
704 "%s%s"
705 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
706 method,
707 dialog && dialog->request ? dialog->request : url,
708 TRANSPORT_DESCRIPTOR,
709 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
710 transport->connection->client_port,
711 branch ? ";branch=" : "",
712 branch ? branch : "",
713 sipe_private->username,
714 ourtag ? ";tag=" : "",
715 ourtag ? ourtag : "",
716 epid,
718 theirtag ? ";tag=" : "",
719 theirtag ? theirtag : "",
720 theirepid ? ";epid=" : "",
721 theirepid ? theirepid : "",
722 cseq,
723 method,
724 sip_transport_user_agent(sipe_private),
725 callid,
726 route,
727 addheaders ? addheaders : "",
728 body ? (gsize) strlen(body) : 0,
729 body ? body : "");
732 //printf ("parsing msg buf:\n%s\n\n", buf);
733 msg = sipmsg_parse_msg(buf);
735 g_free(buf);
736 g_free(ourtag);
737 g_free(theirtag);
738 g_free(theirepid);
739 g_free(branch);
740 g_free(route);
741 g_free(epid);
743 sign_outgoing_message(sipe_private, msg);
745 /* The authentication scheme is not ready so we can't send the message.
746 This should only happen for REGISTER messages. */
747 if (!transport->auth_incomplete) {
748 buf = sipmsg_to_string(msg);
750 /* add to ongoing transactions */
751 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
752 if (!sipe_strequal(method, "ACK")) {
753 trans = g_new0(struct transaction, 1);
754 trans->callback = callback;
755 trans->msg = msg;
756 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
757 if (timeout_callback) {
758 trans->timeout_callback = timeout_callback;
759 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
760 sipe_schedule_seconds(sipe_private,
761 trans->timeout_key,
762 trans,
763 timeout,
764 transaction_timeout_cb,
765 NULL);
767 transport->transactions = g_slist_append(transport->transactions,
768 trans);
769 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
772 sipe_utils_message_debug("SIP", buf, NULL, TRUE);
773 sipe_backend_transport_message(transport->connection, buf);
774 g_free(buf);
777 if (!trans) sipmsg_free(msg);
778 g_free(callid);
779 return trans;
782 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
783 const gchar *method,
784 const gchar *url,
785 const gchar *to,
786 const gchar *addheaders,
787 const gchar *body,
788 struct sip_dialog *dialog,
789 TransCallback callback)
791 return sip_transport_request_timeout(sipe_private,
792 method,
793 url,
795 addheaders,
796 body,
797 dialog,
798 callback,
800 NULL);
803 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
804 const gchar *method,
805 struct sip_dialog *dialog)
807 sip_transport_request(sipe_private,
808 method,
809 dialog->with,
810 dialog->with,
811 NULL,
812 NULL,
813 dialog,
814 NULL);
817 void sip_transport_ack(struct sipe_core_private *sipe_private,
818 struct sip_dialog *dialog)
820 sip_transport_simple_request(sipe_private, "ACK", dialog);
823 void sip_transport_bye(struct sipe_core_private *sipe_private,
824 struct sip_dialog *dialog)
826 sip_transport_simple_request(sipe_private, "BYE", dialog);
829 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
830 const gchar *addheaders,
831 const gchar *body,
832 struct sip_dialog *dialog,
833 TransCallback callback)
835 return sip_transport_request(sipe_private,
836 "INFO",
837 dialog->with,
838 dialog->with,
839 addheaders,
840 body,
841 dialog,
842 callback);
845 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
846 const gchar *addheaders,
847 const gchar *body,
848 struct sip_dialog *dialog,
849 TransCallback callback)
851 return sip_transport_request(sipe_private,
852 "INVITE",
853 dialog->with,
854 dialog->with,
855 addheaders,
856 body,
857 dialog,
858 callback);
861 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
862 const gchar *uri,
863 const gchar *addheaders,
864 const gchar *body,
865 TransCallback callback)
867 return sip_transport_request(sipe_private,
868 "SERVICE",
869 uri,
870 uri,
871 addheaders,
872 body,
873 NULL,
874 callback);
877 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
878 const gchar *uri,
879 const gchar *addheaders,
880 const gchar *body,
881 struct sip_dialog *dialog,
882 TransCallback callback)
884 sip_transport_request(sipe_private,
885 "SUBSCRIBE",
886 uri,
887 uri,
888 addheaders,
889 body,
890 dialog,
891 callback);
894 static const gchar *get_auth_header(struct sipe_core_private *sipe_private,
895 struct sip_auth *auth,
896 struct sipmsg *msg)
898 auth->type = sipe_private->authentication_type;
899 auth->protocol = auth_type_to_protocol[auth->type];
901 return(sipmsg_find_auth_header(msg, auth->protocol));
904 static void do_register(struct sipe_core_private *sipe_private,
905 gboolean deregister);
907 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
908 SIPE_UNUSED_PARAMETER gpointer unused)
910 struct sip_transport *transport = sipe_private->transport;
912 /* register again when security token expires */
913 /* we have to start a new authentication as the security token
914 * is almost expired by sending a not signed REGISTER message */
915 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
916 sipe_auth_free(&transport->registrar);
917 sipe_auth_free(&transport->proxy);
918 sipe_schedule_cancel(sipe_private, "<registration>");
919 transport->reregister_set = FALSE;
920 transport->register_attempt = 0;
921 do_register(sipe_private, FALSE);
922 transport->reauthenticate_set = FALSE;
925 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
927 struct sip_transport *transport = sipe_private->transport;
928 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
929 sipe_private->username,
930 transport->connection->client_port,
931 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
932 TRANSPORT_DESCRIPTOR);
935 static void do_register_cb(struct sipe_core_private *sipe_private,
936 SIPE_UNUSED_PARAMETER void *unused)
938 do_register(sipe_private, FALSE);
941 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
942 int expires)
944 sipe_schedule_seconds(sipe_private,
945 "<registration>",
946 NULL,
947 expires,
948 do_register_cb,
949 NULL);
952 static void sipe_server_register(struct sipe_core_private *sipe_private,
953 guint type,
954 gchar *server_name,
955 guint server_port);
957 static gboolean process_register_response(struct sipe_core_private *sipe_private,
958 struct sipmsg *msg,
959 SIPE_UNUSED_PARAMETER struct transaction *trans)
961 struct sip_transport *transport = sipe_private->transport;
962 const gchar *expires_header;
963 int expires, i;
964 GSList *hdr = msg->headers;
965 struct sipnameval *elem;
967 expires_header = sipmsg_find_header(msg, "Expires");
968 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
969 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
971 switch (msg->response) {
972 case 200:
973 if (expires) {
974 const gchar *contact_hdr;
975 const gchar *auth_hdr;
976 gchar *gruu = NULL;
977 gchar *uuid;
978 gchar *timeout;
979 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
981 if (!transport->reregister_set) {
982 sip_transport_set_reregister(sipe_private,
983 expires);
984 transport->reregister_set = TRUE;
987 if (server_hdr && !transport->server_version) {
988 transport->server_version = g_strdup(server_hdr);
989 g_free(transport->user_agent);
990 transport->user_agent = NULL;
993 auth_hdr = get_auth_header(sipe_private, &transport->registrar, msg);
994 if (auth_hdr) {
995 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
996 fill_auth(auth_hdr, &transport->registrar);
999 if (!transport->reauthenticate_set) {
1000 gchar *action_name = g_strdup_printf("<%s>", "+reauthentication");
1001 guint reauth_timeout = transport->registrar.expires;
1003 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1005 /* Does authentication scheme provide valid expiration time? */
1006 if (reauth_timeout <= (5 * 60)) {
1007 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: no expiration time - using default of 8 hours");
1008 reauth_timeout = 8 * 60 * 60;
1011 /* schedule reauthentication 5 minutes before expiration */
1012 sipe_schedule_seconds(sipe_private,
1013 action_name,
1014 NULL,
1015 reauth_timeout - 5 * 60,
1016 do_reauthenticate_cb,
1017 NULL);
1018 g_free(action_name);
1019 transport->reauthenticate_set = TRUE;
1022 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
1024 uuid = get_uuid(sipe_private);
1026 // There can be multiple Contact headers (one per location where the user is logged in) so
1027 // make sure to only get the one for this uuid
1028 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
1029 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
1030 if (valid_contact) {
1031 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
1032 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
1033 g_free(valid_contact);
1034 break;
1035 } else {
1036 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
1039 g_free(uuid);
1041 g_free(sipe_private->contact);
1042 if(gruu) {
1043 sipe_private->contact = g_strdup_printf("<%s>", gruu);
1044 g_free(gruu);
1045 } else {
1046 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
1047 sip_transport_default_contact(sipe_private);
1049 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1050 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1051 SIPE_CORE_PRIVATE_FLAG_UNSET(BATCHED_SUPPORT);
1053 while(hdr)
1055 elem = hdr->data;
1056 if (sipe_strcase_equal(elem->name, "Supported")) {
1057 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1058 /* We interpret this as OCS2007+ indicator */
1059 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1060 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem->value);
1062 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1063 SIPE_CORE_PRIVATE_FLAG_SET(BATCHED_SUPPORT);
1064 SIPE_DEBUG_INFO("Supported: %s", elem->value);
1067 if (sipe_strcase_equal(elem->name, "Allow-Events")){
1068 gchar **caps = g_strsplit(elem->value,",",0);
1069 i = 0;
1070 while (caps[i]) {
1071 sipe_private->allowed_events = g_slist_append(sipe_private->allowed_events, g_strdup(caps[i]));
1072 SIPE_DEBUG_INFO("Allow-Events: %s", caps[i]);
1073 i++;
1075 g_strfreev(caps);
1077 if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1078 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1079 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1080 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1081 "via Edge Server)");
1084 hdr = g_slist_next(hdr);
1087 /* rejoin open chats to be able to use them by continue to send messages */
1088 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1090 /* subscriptions */
1091 if (!transport->subscribed) { //do it just once, not every re-register
1093 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-roaming-contacts",
1094 (GCompareFunc)g_ascii_strcasecmp)) {
1095 sipe_subscribe_roaming_contacts(sipe_private);
1098 /* For 2007+ it does not make sence to subscribe to:
1099 * vnd-microsoft-roaming-ACL
1100 * vnd-microsoft-provisioning (not v2)
1101 * presence.wpending
1102 * These are for backward compatibility.
1104 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
1106 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-roaming-self",
1107 (GCompareFunc)g_ascii_strcasecmp)) {
1108 sipe_subscribe_roaming_self(sipe_private);
1110 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-provisioning-v2",
1111 (GCompareFunc)g_ascii_strcasecmp)) {
1112 sipe_subscribe_roaming_provisioning_v2(sipe_private);
1115 /* For 2005- servers */
1116 else
1118 //sipe_options_request(sip, sipe_private->public.sip_domain);
1120 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-roaming-ACL",
1121 (GCompareFunc)g_ascii_strcasecmp)) {
1122 sipe_subscribe_roaming_acl(sipe_private);
1124 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-provisioning",
1125 (GCompareFunc)g_ascii_strcasecmp)) {
1126 sipe_subscribe_roaming_provisioning(sipe_private);
1128 if (g_slist_find_custom(sipe_private->allowed_events, "presence.wpending",
1129 (GCompareFunc)g_ascii_strcasecmp)) {
1130 sipe_subscribe_presence_wpending(sipe_private,
1131 NULL);
1134 /* For 2007+ we publish our initial statuses and calendar data only after
1135 * received our existing publications in sipe_process_roaming_self()
1136 * Only in this case we know versions of current publications made
1137 * on our behalf.
1139 /* For 2005- we publish our initial statuses only after
1140 * received our existing UserInfo data in response to
1141 * self subscription.
1142 * Only in this case we won't override existing UserInfo data
1143 * set earlier or by other client on our behalf.
1147 transport->subscribed = TRUE;
1150 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1151 "timeout=", ";", NULL);
1152 if (timeout != NULL) {
1153 sscanf(timeout, "%u", &sipe_private->public.keepalive_timeout);
1154 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1155 sipe_private->public.keepalive_timeout);
1156 g_free(timeout);
1159 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1161 break;
1162 case 301:
1164 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1166 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1168 if (redirect && (g_ascii_strncasecmp("sip:", redirect, 4) == 0)) {
1169 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1170 gchar **tmp;
1171 gchar *hostname;
1172 int port = 0;
1173 guint transport = SIPE_TRANSPORT_TLS;
1174 int i = 1;
1176 tmp = g_strsplit(parts[0], ":", 0);
1177 hostname = g_strdup(tmp[0]);
1178 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1179 g_strfreev(tmp);
1181 while (parts[i]) {
1182 tmp = g_strsplit(parts[i], "=", 0);
1183 if (tmp[1]) {
1184 if (g_ascii_strcasecmp("transport", tmp[0]) == 0) {
1185 if (g_ascii_strcasecmp("tcp", tmp[1]) == 0) {
1186 transport = SIPE_TRANSPORT_TCP;
1190 g_strfreev(tmp);
1191 i++;
1193 g_strfreev(parts);
1195 /* Close old connection */
1196 sipe_core_connection_cleanup(sipe_private);
1198 /* Create new connection */
1199 sipe_server_register(sipe_private, transport, hostname, port);
1200 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1201 hostname, port, transport);
1203 g_free(redirect);
1205 break;
1206 case 401:
1208 const char *auth_hdr;
1210 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1212 if (transport->reauthenticate_set) {
1213 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1214 do_reauthenticate_cb(sipe_private, NULL);
1215 return TRUE;
1218 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1219 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - giving up.");
1220 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1221 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1222 _("Authentication failed"));
1223 return TRUE;
1226 auth_hdr = get_auth_header(sipe_private, &transport->registrar, msg);
1227 if (!auth_hdr) {
1228 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1229 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1230 _("Incompatible authentication scheme chosen"));
1231 return TRUE;
1233 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1234 fill_auth(auth_hdr, &transport->registrar);
1235 transport->reregister_set = FALSE;
1236 transport->register_attempt = 0;
1237 do_register(sipe_private,
1238 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1240 break;
1241 case 403:
1243 gchar *reason;
1244 gchar *warning;
1245 sipmsg_parse_warning(msg, &reason);
1246 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1247 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1248 reason ? reason : _("no reason given"));
1249 g_free(reason);
1251 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1252 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1253 warning);
1254 g_free(warning);
1255 return TRUE;
1257 break;
1258 case 404:
1260 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1261 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1262 gchar *warning;
1263 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1264 diagnostics ? (reason ? reason : _("no reason given")) :
1265 _("SIP is either not enabled for the destination URI or it does not exist"));
1266 g_free(reason);
1268 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1269 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1270 warning);
1271 g_free(warning);
1272 return TRUE;
1274 break;
1275 case 504: /* Server time-out */
1276 /* first attempt + 5 retries */
1277 if (transport->register_attempt < 6) {
1278 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1279 transport->register_attempt);
1280 sip_transport_set_reregister(sipe_private, 60);
1281 return TRUE;
1283 /* FALLTHROUGH */
1284 case 503:
1286 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1287 gchar *warning;
1288 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1289 g_free(reason);
1291 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1292 SIPE_CONNECTION_ERROR_NETWORK,
1293 warning);
1294 g_free(warning);
1295 return TRUE;
1297 break;
1299 return TRUE;
1302 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1303 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1304 SIPE_UNUSED_PARAMETER struct transaction *trans)
1306 struct sip_transport *transport = sipe_private->transport;
1307 if (transport->register_attempt < 6) {
1308 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1309 transport->register_attempt);
1310 do_register(sipe_private, FALSE);
1311 } else {
1312 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1313 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1314 SIPE_CONNECTION_ERROR_NETWORK,
1315 warning);
1316 g_free(warning);
1318 return TRUE;
1321 static void do_register(struct sipe_core_private *sipe_private,
1322 gboolean deregister)
1324 struct sip_transport *transport = sipe_private->transport;
1325 char *uri;
1326 char *to;
1327 char *hdr;
1328 char *uuid;
1330 if (!sipe_private->public.sip_domain) return;
1332 if (!deregister) {
1333 if (transport->reregister_set) {
1334 transport->reregister_set = FALSE;
1335 transport->register_attempt = 1;
1336 } else {
1337 transport->register_attempt++;
1341 transport->deregister = deregister;
1342 transport->auth_incomplete = FALSE;
1344 uuid = get_uuid(sipe_private);
1345 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"
1346 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1347 "Event: registration\r\n"
1348 "Allow-Events: presence\r\n"
1349 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1350 "%s",
1351 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
1352 transport->connection->client_port,
1353 TRANSPORT_DESCRIPTOR,
1354 uuid,
1355 deregister ? "Expires: 0\r\n" : "");
1356 g_free(uuid);
1358 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1359 to = sip_uri_self(sipe_private);
1360 sip_transport_request_timeout(sipe_private,
1361 "REGISTER",
1362 uri,
1364 hdr,
1366 NULL,
1367 process_register_response,
1369 deregister ? NULL : register_response_timeout);
1370 g_free(to);
1371 g_free(uri);
1372 g_free(hdr);
1374 if (deregister) {
1375 /* Make sure that all messages are pushed to the server
1376 before the connection gets shut down */
1377 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1378 sipe_backend_transport_flush(transport->connection);
1382 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1384 do_register(sipe_private, TRUE);
1387 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1389 struct sip_transport *transport = sipe_private->transport;
1391 /* transport can be NULL during connection setup */
1392 if (transport) {
1393 sipe_backend_transport_disconnect(transport->connection);
1395 sipe_auth_free(&transport->registrar);
1396 sipe_auth_free(&transport->proxy);
1398 g_free(transport->server_name);
1399 g_free(transport->server_version);
1400 g_free(transport->user_agent);
1402 while (transport->transactions)
1403 transactions_remove(sipe_private,
1404 transport->transactions->data);
1406 g_free(transport);
1409 sipe_private->transport = NULL;
1410 sipe_private->service_data = NULL;
1412 if (sipe_private->dns_query)
1413 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1417 void sip_transport_authentication_completed(struct sipe_core_private *sipe_private)
1419 do_reauthenticate_cb(sipe_private, NULL);
1422 guint sip_transport_port(struct sipe_core_private *sipe_private)
1424 return sipe_private->transport->server_port;
1427 static void process_input_message(struct sipe_core_private *sipe_private,
1428 struct sipmsg *msg)
1430 struct sip_transport *transport = sipe_private->transport;
1431 gboolean notfound = FALSE;
1432 const char *method = msg->method ? msg->method : "NOT FOUND";
1434 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1435 msg->response, method);
1437 if (msg->response == 0) { /* request */
1438 if (sipe_strequal(method, "MESSAGE")) {
1439 process_incoming_message(sipe_private, msg);
1440 } else if (sipe_strequal(method, "NOTIFY")) {
1441 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1442 process_incoming_notify(sipe_private, msg, TRUE, FALSE);
1443 } else if (sipe_strequal(method, "BENOTIFY")) {
1444 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1445 process_incoming_notify(sipe_private, msg, TRUE, TRUE);
1446 } else if (sipe_strequal(method, "INVITE")) {
1447 process_incoming_invite(sipe_private, msg);
1448 } else if (sipe_strequal(method, "REFER")) {
1449 process_incoming_refer(sipe_private, msg);
1450 } else if (sipe_strequal(method, "OPTIONS")) {
1451 process_incoming_options(sipe_private, msg);
1452 } else if (sipe_strequal(method, "INFO")) {
1453 process_incoming_info(sipe_private, msg);
1454 } else if (sipe_strequal(method, "ACK")) {
1455 /* ACK's don't need any response */
1456 } else if (sipe_strequal(method, "PRACK")) {
1457 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1458 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1459 /* LCS 2005 sends us these - just respond 200 OK */
1460 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1461 } else if (sipe_strequal(method, "CANCEL")) {
1462 process_incoming_cancel(sipe_private, msg);
1463 } else if (sipe_strequal(method, "BYE")) {
1464 process_incoming_bye(sipe_private, msg);
1465 } else {
1466 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1467 notfound = TRUE;
1470 } else { /* response */
1471 struct transaction *trans = transactions_find(transport, msg);
1472 if (trans) {
1473 if (msg->response < 200) {
1474 /* ignore provisional response */
1475 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1477 /* Transaction not yet completed */
1478 trans = NULL;
1480 } else if (msg->response == 401) { /* Unauthorized */
1482 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1483 /* Expected response during authentication handshake */
1484 transport->registrar.retries++;
1485 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1486 } else {
1487 gchar *resend;
1489 /* Are we registered? */
1490 if (transport->reregister_set) {
1491 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1492 sign_outgoing_message(sipe_private,
1493 trans->msg);
1494 } else {
1496 * We don't have a valid authentication at the moment.
1497 * Resend message unchanged. It will be rejected again
1498 * and hopefully by then we have a valid authentication.
1500 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1503 /* Resend request */
1504 resend = sipmsg_to_string(trans->msg);
1505 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1506 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1507 g_free(resend);
1509 /* Transaction not yet completed */
1510 trans = NULL;
1513 } else if (msg->response == 407) { /* Proxy Authentication Required */
1515 if (transport->proxy.retries > 30) {
1516 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1517 } else {
1518 gchar *resend, *auth;
1519 const gchar *auth_hdr;
1521 transport->proxy.retries++;
1523 /* do proxy authentication */
1524 auth_hdr = sipmsg_find_header(msg, "Proxy-Authenticate");
1525 if (auth_hdr) {
1526 guint i;
1527 transport->proxy.type = SIPE_AUTHENTICATION_TYPE_UNSET;
1528 for (i = 0; i < AUTH_PROTOCOLS; i++) {
1529 const gchar *protocol = auth_type_to_protocol[i];
1530 if (protocol &&
1531 !g_ascii_strncasecmp(auth_hdr, protocol, strlen(protocol))) {
1532 SIPE_DEBUG_INFO("proxy auth: type %s", protocol);
1533 transport->proxy.type = i;
1534 transport->proxy.protocol = protocol;
1535 break;
1538 if (transport->proxy.type == SIPE_AUTHENTICATION_TYPE_UNSET)
1539 SIPE_DEBUG_ERROR("Unknown proxy authentication: %s", auth_hdr);
1540 fill_auth(auth_hdr, &transport->proxy);
1542 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1543 if (auth) {
1544 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1545 sipmsg_add_header_now_pos(trans->msg, "Proxy-Authorization", auth, 5);
1546 g_free(auth);
1549 /* resend request */
1550 resend = sipmsg_to_string(trans->msg);
1551 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1552 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1553 g_free(resend);
1555 /* Transaction not yet completed */
1556 trans = NULL;
1559 } else {
1560 transport->registrar.retries = 0;
1561 transport->proxy.retries = 0;
1564 /* Is transaction completed? */
1565 if (trans) {
1566 if (trans->callback) {
1567 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1568 /* call the callback to process response */
1569 (trans->callback)(sipe_private, msg, trans);
1572 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1573 transactions_remove(sipe_private, trans);
1575 } else {
1576 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1577 notfound = TRUE;
1581 if (notfound) {
1582 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1586 static void sip_transport_input(struct sipe_transport_connection *conn)
1588 struct sipe_core_private *sipe_private = conn->user_data;
1589 struct sip_transport *transport = sipe_private->transport;
1590 gchar *cur = conn->buffer;
1592 /* according to the RFC remove CRLF at the beginning */
1593 while (*cur == '\r' || *cur == '\n') {
1594 cur++;
1596 if (cur != conn->buffer)
1597 sipe_utils_shrink_buffer(conn, cur);
1599 /* Received a full Header? */
1600 transport->processing_input = TRUE;
1601 while (transport->processing_input &&
1602 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1603 struct sipmsg *msg;
1604 guint remainder;
1606 cur += 2;
1607 cur[0] = '\0';
1608 msg = sipmsg_parse_header(conn->buffer);
1610 cur += 2;
1611 remainder = conn->buffer_used - (cur - conn->buffer);
1612 if (msg && remainder >= (guint) msg->bodylen) {
1613 char *dummy = g_malloc(msg->bodylen + 1);
1614 memcpy(dummy, cur, msg->bodylen);
1615 dummy[msg->bodylen] = '\0';
1616 msg->body = dummy;
1617 cur += msg->bodylen;
1618 sipe_utils_message_debug("SIP",
1619 conn->buffer,
1620 msg->body,
1621 FALSE);
1622 sipe_utils_shrink_buffer(conn, cur);
1623 } else {
1624 if (msg){
1625 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1626 sipmsg_free(msg);
1629 /* restore header for next try */
1630 cur[-2] = '\r';
1631 return;
1634 // Verify the signature before processing it
1635 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1636 struct sipmsg_breakdown msgbd;
1637 gchar *signature_input_str;
1638 gchar *rspauth;
1639 msgbd.msg = msg;
1640 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
1641 transport->registrar.protocol);
1642 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1644 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1646 if (rspauth != NULL) {
1647 if (!sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1648 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1649 process_input_message(sipe_private, msg);
1650 } else {
1651 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1652 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1653 SIPE_CONNECTION_ERROR_NETWORK,
1654 _("Invalid message signature received"));
1656 } else if ((msg->response == 401) ||
1657 sipe_strequal(msg->method, "REGISTER")) {
1658 /* a) Retry non-REGISTER requests with updated authentication */
1659 /* b) We must always process REGISTER responses */
1660 process_input_message(sipe_private, msg);
1661 } else {
1662 /* OCS sends provisional messages that are *not* signed */
1663 if (msg->response >= 200) {
1664 /* We are not calling process_input_message(),
1665 so we need to drop the transaction here. */
1666 struct transaction *trans = transactions_find(transport, msg);
1667 if (trans) transactions_remove(sipe_private, trans);
1669 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1671 g_free(signature_input_str);
1673 g_free(rspauth);
1674 sipmsg_breakdown_free(&msgbd);
1675 } else {
1676 process_input_message(sipe_private, msg);
1679 sipmsg_free(msg);
1681 /* Redirect: old content of "transport" is no longer valid */
1682 transport = sipe_private->transport;
1686 static void sip_transport_connected(struct sipe_transport_connection *conn)
1688 struct sipe_core_private *sipe_private = conn->user_data;
1689 sipe_private->service_data = NULL;
1690 do_register(sipe_private, FALSE);
1693 static void resolve_next_service(struct sipe_core_private *sipe_private,
1694 const struct sip_service_data *start);
1695 static void sip_transport_error(struct sipe_transport_connection *conn,
1696 const gchar *msg)
1698 struct sipe_core_private *sipe_private = conn->user_data;
1700 /* This failed attempt was based on a DNS SRV record */
1701 if (sipe_private->service_data) {
1702 resolve_next_service(sipe_private, NULL);
1703 } else {
1704 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1705 SIPE_CONNECTION_ERROR_NETWORK,
1706 msg);
1710 /* server_name must be g_alloc()'ed */
1711 static void sipe_server_register(struct sipe_core_private *sipe_private,
1712 guint type,
1713 gchar *server_name,
1714 guint server_port)
1716 sipe_connect_setup setup = {
1717 type,
1718 server_name,
1719 (server_port != 0) ? server_port :
1720 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1721 sipe_private,
1722 sip_transport_connected,
1723 sip_transport_input,
1724 sip_transport_error
1726 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1728 transport->server_name = server_name;
1729 transport->server_port = setup.server_port;
1730 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1731 &setup);
1732 sipe_private->transport = transport;
1735 struct sip_service_data {
1736 const char *protocol;
1737 const char *transport;
1738 guint type;
1741 /* Service list for autodection */
1742 static const struct sip_service_data service_autodetect[] = {
1743 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1744 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1745 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1746 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1747 { NULL, NULL, 0 }
1750 /* Service list for SSL/TLS */
1751 static const struct sip_service_data service_tls[] = {
1752 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1753 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1754 { NULL, NULL, 0 }
1757 /* Service list for TCP */
1758 static const struct sip_service_data service_tcp[] = {
1759 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1760 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1761 { NULL, NULL, 0 }
1764 static const struct sip_service_data *services[] = {
1765 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1766 service_tls, /* SIPE_TRANSPORT_TLS */
1767 service_tcp /* SIPE_TRANSPORT_TCP */
1770 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1771 const gchar *hostname, guint port)
1773 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1775 sipe_private->dns_query = NULL;
1777 if (hostname) {
1778 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1779 hostname, port);
1780 sipe_server_register(sipe_private,
1781 sipe_private->service_data->type,
1782 g_strdup(hostname), port);
1783 } else {
1784 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1788 static void resolve_next_service(struct sipe_core_private *sipe_private,
1789 const struct sip_service_data *start)
1791 if (start) {
1792 sipe_private->service_data = start;
1793 } else {
1794 sipe_private->service_data++;
1795 if (sipe_private->service_data->protocol == NULL) {
1796 guint type = sipe_private->transport_type;
1798 /* We tried all services */
1799 sipe_private->service_data = NULL;
1801 /* Try connecting to the SIP hostname directly */
1802 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1803 if (type == SIPE_TRANSPORT_AUTO)
1804 type = SIPE_TRANSPORT_TLS;
1806 sipe_server_register(sipe_private, type,
1807 g_strdup(sipe_private->public.sip_domain),
1809 return;
1813 /* Try to resolve next service */
1814 sipe_private->dns_query = sipe_backend_dns_query_srv(
1815 SIPE_CORE_PUBLIC,
1816 sipe_private->service_data->protocol,
1817 sipe_private->service_data->transport,
1818 sipe_private->public.sip_domain,
1819 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
1820 SIPE_CORE_PUBLIC);
1823 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
1824 guint transport,
1825 guint authentication,
1826 const gchar *server,
1827 const gchar *port)
1829 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1831 sipe_private->authentication_type = authentication;
1834 * Initializing the certificate sub-system will trigger the generation
1835 * of a cryptographic key pair which takes time. If we do this after we
1836 * have connected to the server then there is a risk that we run into a
1837 * SIP connection timeout. So let's get this out of the way now...
1839 * This is currently only needed if the user has selected TLS-DSK.
1841 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_TLS_DSK)
1842 sipe_certificate_init(sipe_private);
1844 if (server) {
1845 /* Use user specified server[:port] */
1846 int port_number = 0;
1848 if (port)
1849 port_number = atoi(port);
1851 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1852 server, port_number);
1854 sipe_server_register(sipe_private, transport,
1855 g_strdup(server), port_number);
1856 } else {
1857 /* Server auto-discovery */
1859 /* Remember user specified transport type */
1860 sipe_private->transport_type = transport;
1861 resolve_next_service(sipe_private, services[transport]);
1865 void sipe_core_transport_sip_keepalive(struct sipe_core_public *sipe_public)
1867 SIPE_DEBUG_INFO("sending keep alive %d",
1868 sipe_public->keepalive_timeout);
1869 sipe_utils_message_debug("SIP", "", NULL, TRUE);
1870 sipe_backend_transport_message(SIPE_CORE_PRIVATE->transport->connection,
1871 "\r\n\r\n");
1874 int sip_transaction_cseq(struct transaction *trans)
1876 int cseq;
1878 g_return_val_if_fail(trans && trans->key, 0);
1880 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
1881 return cseq;
1885 Local Variables:
1886 mode: c
1887 c-file-style: "bsd"
1888 indent-tabs-mode: t
1889 tab-width: 8
1890 End: