Merge branch 'mob' of git+ssh://localhost/srv/git/siplcs into mob
[siplcs.git] / src / core / sip-sec.c
blobfc4e537b324c8584fbb5c4537b469f18feee4d76
1 /**
2 * @file sip-sec.c
4 * pidgin-sipe
6 * Copyright (C) 2009 pier11 <pier11@operamail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <glib.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include "debug.h"
29 /* #include "util.h" */
30 #include "sip-sec.h"
31 #include "sip-sec-mech.h"
33 #include "sip-sec-ntlm.h"
34 #ifndef _WIN32
35 #define sip_sec_create_context__NTLM sip_sec_create_context__ntlm
36 #define sip_sec_create_context__Negotiate sip_sec_create_context__NONE
38 #ifdef USE_KERBEROS
39 #include "sip-sec-krb5.h"
40 #define sip_sec_create_context__Kerberos sip_sec_create_context__krb5
41 #else
42 #define sip_sec_create_context__Kerberos sip_sec_create_context__NONE
43 #endif
45 #else /* _WIN32 */
46 #ifdef USE_KERBEROS
47 #include "sip-sec-sspi.h"
48 #define sip_sec_create_context__NTLM sip_sec_create_context__sspi
49 #define sip_sec_create_context__Negotiate sip_sec_create_context__sspi
50 #define sip_sec_create_context__Kerberos sip_sec_create_context__sspi
51 #else /* USE_KERBEROS */
52 #define sip_sec_create_context__NTLM sip_sec_create_context__ntlm
53 #define sip_sec_create_context__Negotiate sip_sec_create_context__NONE
54 #define sip_sec_create_context__Kerberos sip_sec_create_context__NONE
55 #endif /* USE_KERBEROS */
57 #endif /* _WIN32 */
59 gchar *purple_base64_encode(const guchar *data, gsize len);
60 guchar *purple_base64_decode(const char *str, gsize *ret_len);
62 /* Dummy initialization hook */
63 static SipSecContext
64 sip_sec_create_context__NONE(SIPE_UNUSED_PARAMETER SipSecAuthType type)
66 return(NULL);
69 /* sip_sec API methods */
70 void
71 sip_sec_create_context(SipSecContext *context,
72 SipSecAuthType type,
73 const int sso,
74 int is_connection_based,
75 const char *domain,
76 const char *username,
77 const char *password)
79 sip_uint32 ret;
81 /* Map authentication type to module initialization hook & name */
82 static sip_sec_create_context_func const auth_to_hook[] = {
83 sip_sec_create_context__NONE, /* AUTH_TYPE_UNSET */
84 sip_sec_create_context__NONE, /* AUTH_TYPE_DIGEST */
85 sip_sec_create_context__NTLM, /* AUTH_TYPE_NTLM */
86 sip_sec_create_context__Kerberos, /* AUTH_TYPE_KERBEROS */
87 sip_sec_create_context__Negotiate, /* AUTH_TYPE_NEGOTIATE */
90 /* @TODO: Can *context != NULL actually happen? */
91 sip_sec_destroy_context(*context);
93 *context = (*(auth_to_hook[type]))(type);
94 if (!*context) return;
96 (*context)->sso = sso;
97 (*context)->is_connection_based = is_connection_based;
99 ret = (*(*context)->acquire_cred_func)(*context, domain, username, password);
100 if (ret != SIP_SEC_E_OK) {
101 purple_debug_info("sipe", "ERROR: sip_sec_init_context failed to acquire credentials.\n");
102 return;
106 unsigned long
107 sip_sec_init_context_step(SipSecContext context,
108 const char *target,
109 const char *input_toked_base64,
110 char **output_toked_base64,
111 int *expires)
113 SipSecBuffer in_buff = {0, NULL};
114 SipSecBuffer out_buff = {0, NULL};
115 sip_uint32 ret;
116 char *tmp;
118 /* Not NULL for NTLM Type 2 */
119 if (input_toked_base64) {
120 in_buff.value = purple_base64_decode(input_toked_base64, &(in_buff.length));
122 tmp = sip_sec_ntlm_message_describe(in_buff);
123 if (tmp) {
124 purple_debug_info("sipe", "sip_sec_init_context_step: Chalenge message is:\n%s", tmp);
126 g_free(tmp);
129 ret = (*context->init_context_func)(context, in_buff, &out_buff, target);
131 if (input_toked_base64)
132 free_bytes_buffer(&in_buff);
134 if (ret == SIP_SEC_E_OK || ret == SIP_SEC_I_CONTINUE_NEEDED) {
135 *output_toked_base64 = purple_base64_encode(out_buff.value, out_buff.length);
137 if (out_buff.length > 0 && out_buff.value) {
138 tmp = sip_sec_ntlm_message_describe(out_buff);
139 if (tmp) {
140 purple_debug_info("sipe", "sip_sec_init_context_step: Negotiate or Authenticate message is:\n%s", tmp);
142 g_free(tmp);
145 free_bytes_buffer(&out_buff);
148 if (expires) {
149 *expires = context->expires;
152 return ret;
155 char *
156 sip_sec_init_context(SipSecContext *context,
157 int *expires,
158 SipSecAuthType type,
159 const int sso,
160 const char *domain,
161 const char *username,
162 const char *password,
163 const char *target,
164 const char *input_toked_base64)
166 sip_uint32 ret;
167 char *output_toked_base64 = NULL;
168 int exp;
170 sip_sec_create_context(context,
171 type,
172 sso,
173 0, /* Connectionless for SIP */
174 domain,
175 username,
176 password);
178 if (!*context) return NULL;
180 ret = sip_sec_init_context_step(*context,
181 target,
182 NULL,
183 &output_toked_base64,
184 &exp);
186 /* for NTLM type 3 */
187 if (ret == SIP_SEC_I_CONTINUE_NEEDED) {
188 g_free(output_toked_base64);
189 ret = sip_sec_init_context_step(*context,
190 target,
191 input_toked_base64,
192 &output_toked_base64,
193 &exp);
196 if (expires) {
197 *expires = exp;
200 return output_toked_base64;
203 void
204 sip_sec_destroy_context(SipSecContext context)
206 if (context) (*context->destroy_context_func)(context);
209 char * sip_sec_make_signature(SipSecContext context, const char *message)
211 SipSecBuffer signature;
212 char *signature_hex;
214 if(((*context->make_signature_func)(context, message, &signature)) != SIP_SEC_E_OK) {
215 purple_debug_info("sipe", "ERROR: sip_sec_make_signature failed. Unable to sign message!\n");
216 return NULL;
218 signature_hex = bytes_to_hex_str(&signature);
219 free_bytes_buffer(&signature);
220 return signature_hex;
223 int sip_sec_verify_signature(SipSecContext context, const char *message, const char *signature_hex)
225 SipSecBuffer signature;
226 sip_uint32 res;
228 purple_debug_info("sipe", "sip_sec_verify_signature: message is:%s signature to verify is:%s\n",
229 message ? message : "", signature_hex ? signature_hex : "");
231 if (!message || !signature_hex) return SIP_SEC_E_INTERNAL_ERROR;
233 hex_str_to_bytes(signature_hex, &signature);
234 res = (*context->verify_signature_func)(context, message, signature);
235 free_bytes_buffer(&signature);
236 return res;
240 /* Utility Methods */
242 void hex_str_to_bytes(const char *hex_str, SipSecBuffer *bytes)
244 guint8 *buff;
245 char two_digits[3];
246 size_t i;
248 bytes->length = strlen(hex_str)/2;
249 bytes->value = g_malloc(bytes->length);
251 buff = (guint8 *)bytes->value;
252 for (i = 0; i < bytes->length; i++) {
253 two_digits[0] = hex_str[i * 2];
254 two_digits[1] = hex_str[i * 2 + 1];
255 two_digits[2] = '\0';
256 buff[i] = (guint8)strtoul(two_digits, NULL, 16);
260 void free_bytes_buffer(SipSecBuffer *bytes)
262 g_free(bytes->value);
263 bytes->length = 0;
264 bytes->value = NULL;
267 char *bytes_to_hex_str(SipSecBuffer *bytes)
269 guint8 *buff = (guint8 *)bytes->value;
270 char *res = g_malloc(bytes->length * 2 + 1);
271 size_t i, j;
272 for (i = 0, j = 0; i < bytes->length; i++, j+=2) {
273 sprintf(&res[j], "%02X", buff[i]);
275 res[j] = '\0';
276 return res;
280 Local Variables:
281 mode: c
282 c-file-style: "bsd"
283 indent-tabs-mode: t
284 tab-width: 8
285 End: