Fix #293: Mandatory wsa:MessageID node missing
[siplcs.git] / src / core / uuid.c
blob51cd5c7091c8a3e04bf809ac021c68528e81463d
1 /**
2 * @file uuid.c
4 * pidgin-sipe
6 * Copyright (C) 2008-2015 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 #include <stdio.h>
24 #include <string.h>
26 #include <glib.h>
27 #include <glib/gprintf.h>
29 #include "sipe-digest.h"
30 #include "uuid.h"
32 #define UUID_STRING_LENGTH 36
33 static const char *epid_ns_uuid = "fcacfb03-8a73-46ef-91b1-e5ebeeaba4fe";
36 * This assumes that the structure is correctly packed on all target
37 * platforms, i.e. sizeof(uuid_t) == 16
39 * See also the test added to "configure". On Windows platform we know
40 * that #pragma pack() exists and therefore can use it in the code.
43 #ifdef _WIN32
44 #pragma pack(push, 1)
45 #endif
46 typedef struct {
47 guint32 time_low;
48 guint16 time_mid;
49 guint16 time_hi_and_version;
50 guint8 clock_seq_hi_and_reserved;
51 guint8 clock_seq_low;
52 guint8 node[6];
53 } uuid_t;
54 #ifdef _WIN32
55 #pragma pack(pop)
56 #endif
58 #define UUID_OFFSET_TO_LAST_SEGMENT 24
60 static void readUUID(const char *string, uuid_t *uuid)
62 int i;
63 /* Some platforms don't allow scanning to char using %02hhx */
64 short tmp1, tmp2;
66 sscanf(string, "%08x-%04hx-%04hx-%02hx%02hx-", &uuid->time_low
67 , &uuid->time_mid, &uuid->time_hi_and_version
68 , &tmp1, &tmp2);
69 uuid->clock_seq_hi_and_reserved = tmp1;
70 uuid->clock_seq_low = tmp2;
72 for(i=0;i<6;i++)
74 sscanf(&string[UUID_OFFSET_TO_LAST_SEGMENT+i*2], "%02hx", &tmp1);
75 uuid->node[i] = tmp1;
79 static void printUUID(uuid_t *uuid, char *string)
81 int i;
82 size_t pos;
83 sprintf(string, "%08x-%04x-%04x-%02x%02x-", uuid->time_low
84 , uuid->time_mid, uuid->time_hi_and_version
85 , uuid->clock_seq_hi_and_reserved
86 , uuid->clock_seq_low
88 pos = strlen(string);
89 for(i=0;i<6;i++)
91 pos += sprintf(&string[pos], "%02x", uuid->node[i]);
95 static void createUUIDfromHash(uuid_t *uuid, const unsigned char *hash)
97 memcpy(uuid, hash, sizeof(uuid_t));
98 uuid->time_hi_and_version &= GUINT16_TO_LE(0x0FFF);
99 uuid->time_hi_and_version |= GUINT16_TO_LE(0x5000);
100 uuid->clock_seq_hi_and_reserved &= 0x3F;
101 uuid->clock_seq_hi_and_reserved |= 0x80;
104 char *generateUUIDfromEPID(const gchar *epid)
106 uuid_t result;
107 gchar *buf;
108 guchar digest[SIPE_DIGEST_SHA1_LENGTH];
109 uint digest_length = sizeof(uuid_t) + strlen(epid);
110 uint buf_length = digest_length;
112 readUUID(epid_ns_uuid, &result);
114 result.time_low = GUINT32_FROM_LE(result.time_low);
115 result.time_mid = GUINT16_FROM_LE(result.time_mid);
116 result.time_hi_and_version = GUINT16_FROM_LE(result.time_hi_and_version);
118 /* buffer must be able to hold at least the UUID string */
119 if (buf_length < UUID_STRING_LENGTH)
120 buf_length = UUID_STRING_LENGTH;
121 buf = g_malloc(buf_length + 1);
123 memcpy(buf, &result, sizeof(uuid_t));
124 strcpy(buf + sizeof(uuid_t), epid);
126 sipe_digest_sha1((guchar *)buf, digest_length, digest);
127 createUUIDfromHash(&result, digest);
129 result.time_low = GUINT32_TO_LE(result.time_low);
130 result.time_mid = GUINT16_TO_LE(result.time_mid);
131 result.time_hi_and_version = GUINT16_TO_LE(result.time_hi_and_version);
133 printUUID(&result, buf);
134 return(buf);
138 * Generates epid from user SIP URI, hostname and IP address.
139 * Thus epid will be the same each start and
140 * not needed to be persistent.
142 * Using MAC address proved to be poorly portable solution.
144 * Must be g_free()'d
146 char *sipe_get_epid(const char *self_sip_uri,
147 const char *hostname,
148 const char *ip_address)
150 /* 6 last digits of hash */
151 #define SIPE_EPID_HASH_START 14
152 #define SIPE_EPID_HASH_END SIPE_DIGEST_SHA1_LENGTH
153 #define SIPE_EPID_LENGTH (2 * (SIPE_EPID_HASH_END - SIPE_EPID_HASH_START + 1))
155 int i,j;
156 char out[SIPE_EPID_LENGTH + 1];
157 char *buf = g_strdup_printf("%s:%s:%s", self_sip_uri, hostname, ip_address);
158 guchar hash[SIPE_DIGEST_SHA1_LENGTH];
160 sipe_digest_sha1((guchar *) buf, strlen(buf), hash);
161 for (i = SIPE_EPID_HASH_START, j = 0;
162 i < SIPE_EPID_HASH_END;
163 i++, j += 2) {
164 g_sprintf(&out[j], "%02x", hash[i]);
166 out[SIPE_EPID_LENGTH] = 0;
168 g_free(buf);
169 return g_strdup(out);
173 Local Variables:
174 mode: c
175 c-file-style: "bsd"
176 indent-tabs-mode: t
177 tab-width: 8
178 End: