e9fce708349ef457368930aa0e2eca5d89d1d3f1
[platform/upstream/syncevolution.git] / src / synthesis / src / sysync_SDK / Sources / san.cpp
1 /*
2  *  File:         san.cpp
3  *
4  *  Author:                       Beat Forster (bfo@synthesis.ch)
5  *
6  *  Server Alerted Notification
7  *    for OMA DS 1.2
8  *
9  *  Copyright (c) 2005-2009 by Synthesis AG (www.synthesis.ch)
10  *
11  *
12  */
13
14 /*
15                       128 bit     64 bit + n char
16                   +------------+--------------------+--------------------+
17                   |            |                    |                    |
18                   |  digest    |  notification-hdr  |  notification-body |
19                   |            |                    |                    |
20                   +------------+--------------------+--------------------+
21                               /                      \                    \
22                             /                          \ ---------          \
23                           /                              \         \          \
24      --------------------                                  ------    \          \
25    /                                                              \    \          \
26  /                                                                  \    \          \
27 +---------+---------+-----------+--------+---------+--------+--------+    +----------+
28 | version | ui-mode | initiator | future | session | server | server |    |  usage   |
29 |         |         |           |   use  |   id    | ident  | ident  |    | specific |
30 |         |         |           |        |         | length |        |    |          |
31 +---------+---------+-----------+--------+---------+--------+--------+    +----------+
32   10 bit     2 bit      1 bit     27 bit   16 bit     8 bit   n char
33
34
35 H     = MD5 hashing function
36 B64   = Base64 encoding
37 digest= H(B64(H(server-identifier:password)):nonce:B64(H(notification)))
38
39
40
41                 notification body:
42   +-------+--------+--------+--------+----------+
43   |  num  | future | sync 1 | sync N | vendor   |
44   | syncs |   use  |        |        | specific |
45   |       |        |        |        |          |
46   +-------+--------+--------+--------+----------+
47     4 bit  4 bit  /          \          n char
48                 /              \
49      ----------                  -------
50    /                                     \
51  /                                         \
52 +------+--------+---------+--------+--------+
53 | sync | future | content | server | server |
54 | type | use    | type    | URI    | URI    |
55 |      |        |         | length |        |
56 +------+--------+---------+--------+--------+
57  4 bit   4 bit    24 bit    8 bit    n char
58
59 */
60
61
62 #ifdef HAVE_CONFIG_H
63 # include <config.h>
64 #endif
65
66 #include "prefix_file.h"
67 #include "sync_include.h"
68 #include "san.h"
69 #include "sysync_md5.h"
70 #include "sysync_b64.h"
71
72 #ifndef WITHOUT_SAN_1_1
73 #include "sysync_utils.h"
74 #endif
75
76
77 const uInt16 SyncML12 = 12;   // currently supported SyncML version
78
79 #pragma options align= packed // allow direct mapping of the structure
80
81
82 using namespace sysync;
83
84 namespace sysync {
85
86 // ---- structure definition ---------------------------------------------
87 #define BpB        8 // bits per byte
88 #define NBits      7 // bytes of the notification-hdr  bits
89 #define BBits      4 // bytes of the notification-body bits
90
91 #define DB_Full  420 // memory full error
92 #define DB_Error 510 // general DB error
93
94 struct TPackage {
95   TDigestField digest;
96
97   uInt8  bitField[ NBits ]; // version, ui-mode, initiator, future use, sesion id
98   uInt8  serverID_len;
99 }; // TPackage
100
101
102 struct TBody {
103   uInt8  bitField[ BBits ]; // sync type, future use, content type
104   uInt8  serverURI_len;
105 }; // TBody
106
107
108
109 // ---- defined locally for the moment to avoid dependencies ----
110 // - sysync_free replaced by free
111 //
112 // MD5 and B64 given string
113 static void MD5B64_Local(const char *aString, sInt32 aLen, string &aMD5B64)
114 {
115   // determine input length
116   if (aLen<=0) aLen=strlen(aString);
117   // calc MD5
118   md5::SYSYNC_MD5_CTX context;
119   uInt8 digest[16];
120   md5::Init (&context);
121   md5::Update (&context, (const uInt8 *)aString,aLen);
122   md5::Final (digest, &context);
123   // b64 encode the MD5 digest
124   uInt32 b64md5len;
125   char *b64md5=b64::encode(digest,16,&b64md5len);
126   // assign result
127   aMD5B64.assign(b64md5,b64md5len);
128   // done
129   /*sysync_*/free(b64md5); // return buffer allocated by b64::encode
130 } // MD5B64_Local
131
132
133
134 // ---- constructor/destructor -------------------------------------------
135 SanPackage::SanPackage() // constructor
136 {
137   fBody= NULL;
138   CreateEmptyNotificationBody();
139
140   memset( &fDigest, 0, DigestSize );
141   fProtocolVersion= 0;
142   fUI_Mode        = UI_not_specified;
143   fInitiator      = Initiator_Server;
144   fSessionID      = 0;
145
146   fSan            = NULL;
147   fSanSize        = 0;
148 } // constructor
149
150
151 SanPackage::~SanPackage() // destructor
152 {
153   ReleasePackage();
154   ReleaseNotificationBody();
155 } // destructor
156
157
158
159 // ---- digest creation --------------------------------------------------
160 TDigestField SanPackage::H( string s )
161 {
162   TDigestField df;
163
164   // calc MD5
165   md5::SYSYNC_MD5_CTX context;
166   md5::Init        ( &context );
167   md5::Update      ( &context, (const uInt8 *)s.c_str(), s.length() );
168   md5::Final( df.b,  &context );
169   return      df;
170 } // DigestField
171
172
173 string SanPackage::B64_H( string s1, string s2 )
174 {
175   if          (!s2.empty()) s1+= ":" + s2;
176   MD5B64_Local( s1.c_str(), s1.size(), s1 );
177   return        s1;
178 } // B64_H
179
180
181 string SanPackage::B64_H_Notification( void* san, size_t sanSize )
182 {
183   string                    s;
184   const char*   v= (const char*)san + DigestSize;
185   size_t           nfySize= sanSize - DigestSize;
186   MD5B64_Local( v, nfySize, s );
187   return                    s;
188 } // B64_H
189
190
191
192 /*! Prepare the SAN record */
193 void SanPackage::PreparePackage( string    aB64_H_srvID_pwd,
194                                  string    aNonce,
195                                  uInt16    aProtocolVersion,
196                                  UI_Mode   aUI_Mode,
197                                  Initiator aInitiator,
198                                  uInt16    aSessionID,
199                                  string    aSrvID )
200 {
201   fB64_H_srvID_pwd= aB64_H_srvID_pwd;
202   fNonce          = aNonce;
203   fProtocolVersion= aProtocolVersion;
204   fUI_Mode        = aUI_Mode;
205   fInitiator      = aInitiator;
206   fSessionID      = aSessionID;
207   fServerID       = aSrvID;
208 } // PreparePackage
209
210
211 // if only hashes are available
212 TSyError SanPackage::CreateDigest( const char* b64_h_serverID_password,
213                                    const char* aNonce,
214                                    void* san, size_t sanSize )
215 {
216   string s= b64_h_serverID_password;
217   if   ( s.empty()) {
218     for (int i= 0; i<DigestSize; i++) { // special case for empty digest
219       fDigest.b[ i ]= 0x00;
220     } // for
221   }
222   else {                    s+= ":";
223                 s+= aNonce; s+= ":";
224                 s+= B64_H_Notification( san,sanSize );
225     fDigest= H( s );
226   } // if
227
228   return LOCERR_OK;
229 } // CreateDigest
230
231
232 TSyError SanPackage::CreateDigest( const char* aServerID,
233                                    const char* aPassword,
234                                    const char* aNonce,
235                                    void* san, size_t sanSize )
236 {
237   return CreateDigest( B64_H( aServerID,aPassword ).c_str(),
238                        aNonce,
239                        san,sanSize );
240 } // CreateDigest
241
242
243
244 bool SanPackage::DigestOK( void* san )
245 {
246   TDigestField* sanD= (TDigestField*)san;
247
248   for (int i= 0; i<DigestSize; i++) {
249     if (fDigest.b[ i ]!=sanD->b[ i ]) return false;
250   } // for
251
252   return true;
253 } // DigestOK
254
255
256
257 // ---- bit operations ---------------------------------------------------
258 void SanPackage::AddBits( void* ptr, int pos, int n, uInt32 value )
259 {
260   byte* b= (byte*)ptr;
261   int    lim= pos+n;
262   if    (lim>BpB*NBits) return; // check if within the field
263   while (lim>BpB) { b++; lim-= BpB; }
264
265   int  i;
266   for (i=0; i<n; i++) {
267     uInt8 db= 1<<(BpB-lim);
268
269     if   ((value % 2)==1) *b|=  db; // add    bit
270     else                  *b&= ~db; // remove bit
271     value= value / 2;
272
273         lim--;
274     if (lim==0) { lim= BpB; b--; }
275   } // for
276 } // AddBits
277
278
279 uInt32 SanPackage::GetBits( void* ptr, int pos, int n )
280 {
281   uInt32 value= 0;
282
283   byte* b= (byte*)ptr;
284   int    lim= pos+n;
285   if    (lim>BpB*NBits) return 0; // check if within the field
286   while (lim>BpB) { b++; lim-= BpB; }
287
288   int  i;
289   for (i=0; i<n; i++) {
290     uInt8 db= 1<<(BpB-lim);
291
292     if ((*b & db)!=0) value|= (1<<n); // check bit and add it to <value>
293     value= value / 2;
294
295         lim--;
296     if (lim==0) { lim= BpB; b--; }
297   } // for
298
299   return value;
300 } // GetBits
301
302
303
304 // ---- notification body generation -------------------------------------
305 void SanPackage::CreateEmptyNotificationBody()
306 {
307   ReleaseNotificationBody();
308
309                     fEmpty= 0x00; // no sync fields = ALL data stores concerned
310   fBody=           &fEmpty;
311   fBodySize= sizeof(fEmpty);
312   fNSync= 0;
313 } // CreateEmptyNotificationBody
314
315
316
317 TSyError SanPackage::AddSync( int syncType, uInt32 contentType,
318                               const char* serverURI )
319 {
320   int    len= strlen(serverURI);
321   int   nLen= BBits + 1 +  len;  // length of the new part
322   int newLen= fBodySize + nLen;  // total length of the new block
323
324   void*   fb=  malloc( newLen ); // allocate it
325   memcpy( fb, fBody,fBodySize ); // copy existing structure to beginning
326
327   byte*   b = (byte*)fb;
328           b+= fBodySize;         // get a pointer to the new part
329
330   ReleaseNotificationBody();     // release the old structure
331   fNSync++;                      // adapt number of available parts
332   fBody    = fb;                 // now the new bigger structure is assigned
333   fBodySize= newLen;
334
335   // fill in new counter value
336   AddBits( fBody,         0, 4, fNSync       ); // number of sync datastores
337   AddBits( fBody,         4, 4, 0            ); // future use
338
339   // fill in contents of the nth structure
340   TBody*   tb= (TBody*)b;
341   AddBits( tb->bitField,  0, 4, syncType-200 ); // the sync type 206..210
342   AddBits( tb->bitField,  4, 4, 0            ); // future use
343   AddBits( tb->bitField,  8,24, contentType  ); // the content tye
344            tb->serverURI_len=   len;
345
346   byte*           pp= (byte*)(tb+1); // = right after TBody
347   memcpy( (void*) pp, (void*)serverURI, len );
348   return LOCERR_OK;
349 } // AddSync
350
351
352
353 void SanPackage::ReleaseNotificationBody()
354 {
355   if (fBody!=NULL &&
356       fBody!=&fEmpty) { free( fBody ); fBody= NULL; }
357 } // ReleaseNotificationBody
358
359
360 #ifndef WITHOUT_SAN_1_1
361 // general callback entry for all others
362 static Ret_t univ( ... )
363 {
364 //printf( "callback\n" );
365   return 0;
366 } // univ
367
368
369 static Ret_t startM( InstanceID_t id, VoidPtr_t userData, SmlSyncHdrPtr_t pContent )
370 {
371   cAppCharP Sy= "SyncML/";
372   size_t n = strlen(Sy);
373
374   SanPackage* a= (SanPackage*)userData;
375   string mup  = "";
376   string nonce= "";
377
378   uInt16 major=0,minor=0;
379
380   cAppCharP verP = smlPCDataToCharP(pContent->proto);
381   if (strucmp(verP,Sy,n)==0) {
382     n+=StrToUShort(verP+n,major);
383     if (verP[n]=='.') {
384       n++;
385       StrToUShort(verP+n,minor);
386     }
387   }
388
389   sInt32                                sessionID;
390   smlPCDataToLong( pContent->sessionID, sessionID );
391
392   string srvID= smlSrcTargLocURIToCharP(pContent->source);
393
394   a->PreparePackage( mup, nonce, 10*major+minor, UI_not_specified, Initiator_Server, sessionID, srvID );
395   a->CreateEmptyNotificationBody();
396   return 0;
397 } // startM
398
399
400 static Ret_t alertM( InstanceID_t id, VoidPtr_t userData, SmlAlertPtr_t pContent )
401 {
402   SanPackage* a= (SanPackage*)userData;
403
404   sInt32                           syncType;
405   smlPCDataToLong( pContent->data, syncType );
406   uInt32 contentType= 0; // always 0
407
408   SmlItemListPtr_t el= pContent->itemList;
409
410   while (true) { // can be a chained list of elements
411     string locURI= smlSrcTargLocURIToCharP(el->item->source);
412     a->AddSync( syncType, contentType, locURI.c_str() ); // for each element add one
413
414     if (el->next==NULL) break;
415     el= el->next;
416   } // while
417
418 //printf( "alert\n" );
419   return 0;
420 } // alert
421
422
423 static Ret_t endM( InstanceID_t id, VoidPtr_t userData, Boolean_t final )
424 {
425 //printf( "end\n" );
426   return 0;
427 } // endM
428
429
430 // Callback record, most of the routines are not used
431 static const SmlCallbacks_t mySmlCallbacks = {
432   /* message callbacks */
433   startM,                    // smlStartMessageCallback,
434   endM,                      // smlEndMessageCallback,
435   /* grouping commands */
436   (smlStartSyncFunc)   univ, // smlStartSyncCallback,
437   (smlEndSyncFunc)     univ, // smlEndSyncCallback,
438   #ifdef ATOMIC_RECEIVE  /* these callbacks are NOT included in the Toolkit lite version */
439     univ, // smlStartAtomicCallback,
440     univ, // smlEndAtomicCallback,
441   #endif
442   #ifdef SEQUENCE_RECEIVE
443     univ, // smlStartSequenceCallback,
444     univ, // smlEndSequenceCallback,
445   #endif
446   /* Sync Commands */
447   (smlAddCmdFunc)   univ, // smlAddCmdCallback,
448   alertM,                 // smlAlertCmdCallback,
449   (smlDeleteCmdFunc)univ, // smlDeleteCmdCallback,
450   (smlGetCmdFunc)   univ, // smlGetCmdCallback,
451   (smlPutCmdFunc)   univ, // smlPutCmdCallback,
452   #ifdef MAP_RECEIVE
453     (smlMapCmdFunc) univ, // smlMapCmdCallback,
454   #endif
455   #ifdef RESULT_RECEIVE
456     (smlResultsCmdFunc)univ, // smlResultsCmdCallback,
457   #endif
458   (smlStatusCmdFunc) univ, // smlStatusCmdCallback,
459   (smlReplaceCmdFunc)univ, // smlReplaceCmdCallback,
460   /* other commands */
461   #ifdef COPY_RECEIVE  /* these callbacks are NOT included in the Toolkit lite version */
462     univ, // smlCopyCmdCallback,
463   #endif
464   #ifdef EXEC_RECEIVE
465     univ, // smlExecCmdCallback,
466   #endif
467   #ifdef SEARCH_RECEIVE
468     univ, // smlSearchCmdCallback,
469   #endif
470   smlMoveCmdFunc(univ), // smlMoveCmdCallback,
471   /* Other Callbacks */
472   smlHandleErrorFunc  (univ), // smlHandleErrorCallback,
473   smlTransmitChunkFunc(univ)  // smlTransmitChunkCallback
474 }; /* sml_callbacks struct */
475
476
477
478 // Try to convert a 1.1 message
479 // - if successful, fill in values into 1.2 fields
480 // - if not successful, interpret it as 1.2 structure
481 TSyError SanPackage::Check_11( void* san, size_t sanSize )
482 {
483   TSyError             err;
484   SmlCallbacks_t       scb= mySmlCallbacks;
485   SmlInstanceOptions_t sIOpts;
486   InstanceID_t         id;
487   Ret_t                cer;
488   MemPtr_t             wPos;
489   MemSize_t            freeSize;
490
491   // struct assignment / 1k buffer
492   sIOpts.encoding       = SML_WBXML; // it is always WBXML
493   sIOpts.workspaceSize  = 1024;      // should be always sufficient
494   sIOpts.maxOutgoingSize=    0;      // disabled for now
495
496   err=   smlInitInstance( &scb, &sIOpts, this, &id );  if (err) return err;
497
498   do {
499     err= smlLockWriteBuffer  ( id, &wPos, &freeSize ); if (err) break;
500
501     memcpy( wPos, san,sanSize ); // now we have a new internal copy
502     err= smlUnlockWriteBuffer( id, sanSize );          if (err) break;
503     err= smlProcessData      ( id, SML_ALL_COMMANDS ); if (err) break;
504   } while (false);
505
506   cer= smlTerminateInstance( id ); if (!err) err= cer;
507
508   return err;
509 } // Check_11
510 #endif // WITHOUT_SAN_1_1
511
512
513 TSyError SanPackage::PassSan( void* san, size_t sanSize )
514 {
515   TSyError err;
516   bool     use_as_12= true;
517
518   ReleasePackage();
519 //printf( "here we will have the potential 1.1 -> 1.2 conversion\n" );
520
521   #ifndef WITHOUT_SAN_1_1
522                err= Check_11  ( san,sanSize );
523     if (!err)  err= GetPackage( san,sanSize );
524   //use_as_12= err==SML_ERR_XLT_INCOMP_WBXML_VERS;
525     use_as_12= err!=0;
526   //printf( "err=%d\n", err );
527   #endif
528
529   if (use_as_12) {
530     err= DB_Full;
531
532         fSan=   malloc( sanSize );
533     if (fSan) {
534       fSanSize=         sanSize;
535       memcpy( fSan, san,sanSize ); // now we have a new internal copy
536       err= LOCERR_OK;
537     } // if
538   } // if
539
540   return err;
541 } // PassSan
542
543
544 TSyError SanPackage::GetSanSize( void* san, size_t &sanSize )
545 {
546   TPackage* tp= (TPackage*)san;
547   TBody*    tb = NULL;
548
549   byte* b= (byte*)(tp+1);
550   byte* v;
551
552   b+= tp->serverID_len;
553
554   int nth= GetBits( b, 0,4 ); // first not valid = the end
555
556   b++; // start of 1st element
557   int    n= nth;
558   while (n>0) {
559     n--;
560     tb= (TBody*)b;
561     b = (byte*)(tb+1);
562
563     if (b > (byte*)san+sanSize && sanSize>0) return DB_Forbidden;
564     v=  b + tb->serverURI_len;
565     if (b > (byte*)san+sanSize && sanSize>0) return DB_Forbidden;
566
567     if (n==0) break;
568     b=  v;
569   } // while
570
571   b+= tb->serverURI_len; // finally the serverURI length
572
573   size_t   rslt= b - (byte*)san;
574   if (sanSize>0 && sanSize<rslt) return DB_Forbidden;
575
576   sanSize= rslt;
577   return LOCERR_OK;
578 } // GetSanSize
579
580
581 // ---- notification body parsing ----------------------------------------
582 TSyError SanPackage::GetNthSync( int    nth,
583                                  int    &syncType,
584                                  uInt32 &contentType,
585                                  string &serverURI )
586 {
587   syncType   =  0; // set default values
588   contentType=  0;
589   serverURI  = "";
590
591   TPackage* tp= (TPackage*)fSan;
592   TBody*    tb;
593
594   fDigest         =                     tp->digest;
595   fProtocolVersion=            GetBits( tp->bitField,  0,10 );
596   fUI_Mode        =   (UI_Mode)GetBits( tp->bitField, 10, 2 );
597   fInitiator      = (Initiator)GetBits( tp->bitField, 12, 1 );
598   fSessionID      =            GetBits( tp->bitField, 40,16 );
599
600   // that's the joke, it's no longer forbidden !
601 //if (fProtocolVersion!=SyncML12) return DB_Forbidden;
602
603   byte* b= (byte*)(tp+1);
604   byte* v;
605
606   fServerID.assign( (const char*)b,(unsigned int)tp->serverID_len );
607   b+= tp->serverID_len;
608
609   fNSync= GetBits( b, 0,4 );
610
611   if (nth==0)               return LOCERR_OK;
612   if (nth<1 || nth>fNSync ) return DB_NotFound;
613
614   b++; // start of 1st element
615   int    n= nth;
616   while (n>0) {
617     n--;
618     tb= (TBody*)b;
619     b = (byte*)(tb+1);
620
621     if (b > (byte*)fSan+fSanSize) return DB_Forbidden; // no access behind the message
622     v=  b + tb->serverURI_len;
623     if (v > (byte*)fSan+fSanSize) return DB_Forbidden; // no access behind the message
624
625     if (n==0) break;
626     b=  v;
627   } // while
628
629   syncType   = 200 + GetBits( tb->bitField,  0, 4 );
630   contentType=       GetBits( tb->bitField,  8,24 );
631
632   serverURI.assign( (const char*)b,(unsigned int)tb->serverURI_len );
633
634   return LOCERR_OK;
635 } // GetNthSync
636
637
638 TSyError SanPackage::GetHeader()
639 {
640   int    syncType; // these 3 variables are not really used
641   uInt32 contentType;
642   string serverURI;
643
644   return GetNthSync( 0, syncType,contentType,serverURI );
645 } // GetHeader
646
647
648
649 // ---- package generation -----------------------------------------------
650 TSyError SanPackage::GetPackage( void* &san, size_t &sanSize,
651                                  void*  vendorSpecific,
652                                  size_t vendorSpecificSize )
653 {
654   ReleasePackage(); // remove a previous one
655
656   byte   len    = (byte)fServerID.length();     // calulate the full size
657          sanSize= sizeof(TPackage) + len + fBodySize + vendorSpecificSize;
658   //size_t nfySize= sanSize - DigestSize;
659   fSan          = malloc( sanSize );
660   san           =            fSan;
661   TPackage*   tp= (TPackage*)fSan;
662
663   // -------------------
664   AddBits( tp->bitField,  0,10, fProtocolVersion );
665   AddBits( tp->bitField, 10, 2, fUI_Mode         );
666   AddBits( tp->bitField, 12, 1, fInitiator       );
667   AddBits( tp->bitField, 13,27, 0                ); // future use, must be "0"
668   AddBits( tp->bitField, 40,16, fSessionID       );
669            tp->serverID_len=    len;
670
671   // copy <fServerID> string at the end of TPackage struct
672   byte*           pp= (byte*)(tp+1); // = right after TPackage
673   memcpy( (void*) pp,      (void*)fServerID.c_str(), len );
674   memcpy( (void*)(pp+len),        fBody,       fBodySize );
675
676   if (vendorSpecific!=NULL &&
677       vendorSpecificSize>0)
678     memcpy( (void*)(pp+len+fBodySize), vendorSpecific,vendorSpecificSize );
679
680   CreateDigest( fB64_H_srvID_pwd.c_str(), fNonce.c_str(), san,sanSize );
681   tp->digest= fDigest;
682
683   fSanSize= sanSize;
684   return LOCERR_OK;
685 } // GetPackage
686
687
688 void SanPackage::ReleasePackage() {
689   if (fSan!=NULL) { free( fSan ); fSan= NULL; }
690 } // ReleasePackage
691
692
693 } // namespace sysync
694
695 // eof