Summary: Isode provides a number of APIs which allow integrators and product developers to build components that access the Isode Messaging server products or other products supporting the same protocols.
x400_mssend_msg_tok_sign.c
1 /* Copyright (c) 2009-2014, Isode Limited, London, England.
2  * All rights reserved.
3  *
4  * Acquisition and use of this software and related materials for any
5  * purpose requires a written licence agreement from Isode Limited,
6  * or a written licence from an organisation licenced by Isode Limited
7  * to grant such a licence.
8  *
9  */
10 
11 /*
12  *
13  * @VERSION@
14  *
15  *
16  * Simple example program for submitting a message via a message store.
17  * The security environment is set up so that messages are signed with
18  * a per recipient message token.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #ifndef _WIN32
26 #include <unistd.h>
27 #endif
28 #include <fcntl.h>
29 #include <errno.h>
30 
31 #include <x400_msapi.h>
32 #include <seclabel_api.h> /* For security labels */
33 #include "example.h"
34 #include "ms_example.h"
35 #include "time.h"
36 
37 /* uncomment this if you want a second recipient.
38  * NB as the recipient name is the same, M-Switch
39  * removes the duplicate envelope recips */
40 /*
41 #define tworecips 1
42 */
43 
44 /* uncomment this to cause the API to generate msg_seq_nums which
45  * increment by 1 per message per session */
46 #define FIRST_SEQ_NUM 2
47 
48 #ifdef FIRST_SEQ_NUM
49 int seq_num_val_1 = FIRST_SEQ_NUM;
50 int seq_num_val_2 = FIRST_SEQ_NUM + 100;
51 #endif
52 
53 /* set this to non zero to cause the IA5 body part to be an attachment */
54 int send_ia5_as_att = 0;
55 
56 /*
57 #define ADD_MOAC
58 */
59 
60 static char *optstr = "u37m:d:p:w:M:D:P:W:r:o:O:r:g:G:c:l:R:y:C:iaqsAve:x:b:f:Y:S:j:";
61 
62 /* These are the data items used to construct the message for submission */
63 static char *default_recip = "/CN=P7User1/OU=sales/O=attlee/PRMD=TestPRMD/ADMD=TestADMD/C=GB/";
64 char *recip;
65 char *recip2;
66 static char *content_id = "030924.140212";
67 static const char text[] = "First line\r\nSecond line\r\n";
68 
69 int adding_sec_label = 1;
70 
71 /* local functions */
72 
73 static void usage(void) ;
74 static int send_msg(
75  int contype,
76  char *orn,
77  char *def_dn,
78  char *pa,
79  char *password);
80 
81 static int submit_msg(
82  char *orn,
83  struct X400msSession *sp /* session object */
84 );
85 
86 static int setup_default_new_sec_env(
87  struct X400msSession *sp,
88  char *identity_filename,
89  char *pw
90 );
91 
92 
93 static int setup_default_old_sec_env(
94  struct X400msSession *sp,
95  char *id,
96  char *dn,
97  char *pw
98 );
99 
100 #ifdef notused
101 static int setup_msg_new_sec_env(
102  struct X400msMessage *mp, /* message object */
103  char *identity_filename,
104  char *pw
105 );
106 
107 
108 static int setup_msg_old_sec_env(
109  struct X400msMessage *mp, /* message object */
110  char *id,
111  char *dn,
112  char *pw
113 );
114 
115 static int setup_recip_new_sec_env(
116  struct X400Recipient *rp, /* recipient object */
117  char *identity_filename,
118  char *pw /* passphrase for private key in pkcs12 file */
119 );
120 
121 static int setup_recip_old_sec_env(
122  struct X400Recipient *rp, /* recipient object */
123  char *id, /* x509 identity (directory with x509 subdir) */
124  char *dn, /* DN to use as subject of the X.509 identity */
125  char *pw /* passphrase for private key in pkcs12 file */
126 );
127 
128 #endif
129 
130 
131 static int add_sec_label(
132  struct X400msMessage *mp /* message object */
133 );
134 
135 static int add_recip(
136  struct X400msMessage *mp, /* message object */
137  char *recip
138 );
139 
140 static int add_content(
141  struct X400msMessage *mp /* message object */
142 );
143 
144 static int add_binary_bp(
145  struct X400msMessage *mp
146 );
147 
148 static int add_ftbp(
149  struct X400msMessage *mp
150 );
151 
152 static int add_ia5_str(
153  struct X400msMessage *mp
154 );
155 
156 /* start here */
157 int main (
158  int argc,
159  char **argv
160 )
161 {
162  char pa[BUFSIZ];
163  char orn[BUFSIZ];
164  char *def_oraddr;
165  char *def_dn;
166  char *def_pa;
167  int contype;
168  int status;
169  char password[BUFSIZ];
170 
171  if (get_args(argc, argv, optstr)) {
172  usage();
173  exit(-1);
174  }
175 
176  printf("Connection type (0 = P7, 1 = P3 submit only, 2 = P3 both directions) [%d]: ", x400_contype);
177  contype = ic_fgetc(x400_contype, stdin);
178  if (contype != 10)
179  ic_fgetc(x400_contype, stdin);
180 
181  if ( contype < '0' || '2' < contype )
182  contype = x400_contype;
183  else
184  contype -= '0';
185 
186  if (contype == 0) {
187  def_oraddr = x400_ms_user_addr;
188  def_dn = x400_ms_user_dn;
189  def_pa = x400_ms_presentation_address;
190  } else {
191  def_oraddr = x400_mta_user_addr;
192  def_dn = x400_mta_user_dn;
193  def_pa = x400_mta_presentation_address;
194  }
195 
196  printf("Your ORAddress [%s] > ", def_oraddr);
197  ic_fgets (orn, sizeof orn, stdin);
198 
199  if ( orn[strlen(orn)-1] == '\n' )
200  orn[strlen(orn)-1] = '\0';
201 
202  if (orn[0] == '\0')
203  strcpy(orn, def_oraddr);
204 
205  /* Prompt for password; note: reflected. */
206  printf ("Password [%s]: ",
207  contype == 0 ? x400_p7_password : x400_p3_password);
208  if ( ic_fgets (password, sizeof password, stdin) == NULL )
209  exit (1);
210 
211  if (password[strlen(password)-1] == '\n' )
212  password[strlen(password)-1] = '\0';
213  if (password[0] == '\0')
214  strcpy(password, contype == 0 ? x400_p7_password : x400_p3_password);
215 
216  /* Presentation Address */
217  printf("Presentation Address [%s] > ", def_pa);
218  ic_fgets (pa, sizeof pa, stdin);
219 
220  if ( pa[strlen(pa)-1] == '\n' )
221  pa[strlen(pa)-1] = '\0';
222 
223  if (pa[0] == '\0')
224  strcpy(pa, def_pa);
225 
226  printf("sending message using session 1\n");
227  if ((status = send_msg(contype, orn, def_dn, pa, password))
228  != X400_E_NOERROR ) {
229  fprintf (stderr, "Error in sending message\n");
230  exit (status);
231  }
232 
233 #ifdef notdef
234  printf("sending message using session 2\n");
235  if ((status = send_msg(contype, orn, def_dn, pa, password))
236  != X400_E_NOERROR ) {
237  fprintf (stderr, "Error sending message\n");
238  exit (status);
239  }
240 #endif
241 
242  return (status);
243 }
244 
245 static int send_msg(
246  int contype,
247  char *orn,
248  char *def_dn,
249  char *pa,
250  char *password
251 )
252 {
253  struct X400msSession *sp; /* session object */
254 
255  int status;
256  int nummsg;
257 
258 
259  /* Open an API session */
260  status = X400msOpen (contype, orn, def_dn, password, pa, &nummsg, &sp);
261  if ( status != X400_E_NOERROR ) {
262  fprintf (stderr, "Error in Open: %s\n", X400msError (status));
263  fprintf (stderr, "%s %s %s\n", orn, def_dn, pa);
264  return (status);
265  }
266 
267  /* setup logging */
268  X400msSetStrDefault(sp, X400_S_LOG_CONFIGURATION_FILE, "x400api.xml", 0);
269 
270  /* Set up the security environment.
271  *
272  * In R15.0 this need only be the name of a trusted certificate directory.
273  *
274  * Prior to R15.0, the ID is specified as a pathname, in which the
275  * subdirectory "x509" is expected to contain one or more PKCS12
276  * files. The appropriate Digital Identity is determined from the
277  * DN of the subject, and the passphrase is used to decrypt the
278  * private key. NB even though we're not going to use our cert,
279  * (as we're going to use the cert in the message to check the MOAC
280  * we need to do this due to a limitation in the underlying X.509
281  * layer.
282  */
283 
284  if (use_new_sec_env) {
285  status = setup_default_new_sec_env(sp, identity_filename, passphrase);
286  } else {
287  status = setup_default_old_sec_env(sp, security_id,
288  identity_dn, passphrase);
289  }
290 
291  if ( status != X400_E_NOERROR ) {
292  fprintf (stderr, "Can't setup security environment\n");
293  return (status);
294  }
295 
296  printf("sending message 1\n");
297  status = submit_msg(orn, sp);
298  if ( status != X400_E_NOERROR ) {
299  fprintf (stderr, "Can't submit\n");
300  return (status);
301  }
302 
303 /*
304  printf("sending message 2\n");
305  status = submit_msg(orn, sp);
306  if ( status != X400_E_NOERROR ) {
307  fprintf (stderr, "Can't submit\n");
308  return (status);
309  }
310  printf("sending message 3\n");
311  status = submit_msg(orn, sp);
312  if ( status != X400_E_NOERROR ) {
313  fprintf (stderr, "Can't submit\n");
314  return (status);
315  }
316 */
317  status = X400msClose (sp);
318  if ( status != X400_E_NOERROR ) {
319  fprintf (stderr, "X400msClose returned error: %s\n", X400msError (status));
320  return (status);
321  }
322  return status;
323 }
324 
325 static int submit_msg(
326  char *orn,
327  struct X400msSession *sp /* session object */
328 )
329 {
330  struct X400msMessage *mp; /* message object */
331 #ifdef tworecips
332  struct X400Recipient *rp2; /* recipient object */
333 #endif
334  char tmp[BUFSIZ];
335  static int msg_num = 0;
336  int status;
337 
338  msg_num++;
339 
340  if (x400_default_recipient != NULL) {
341  recip = x400_default_recipient;
342  recip2 = x400_default_recipient;
343  } else {
344  recip = default_recip;
345  recip2 = default_recip;
346  }
347 
348  printf("Message recipient [%s]: ", recip);
349  ic_fgets (tmp, sizeof tmp, stdin);
350 
351  if ( tmp[strlen(tmp)-1] == '\n' )
352  tmp[strlen(tmp)-1] = '\0';
353  if (strlen(tmp) != 0) {
354  recip = strdup(tmp);
355  recip2 = strdup(tmp);
356  }
357 
358  printf("Subject [%s]: ", subject);
359  ic_fgets (tmp, sizeof tmp, stdin);
360 
361  if ( tmp[strlen(tmp)-1] == '\n' )
362  tmp[strlen(tmp)-1] = '\0';
363  if (strlen(tmp) != 0)
364  subject = strdup(tmp);
365 
366  printf("\n");
367  status = X400msMsgNew (sp, X400_MSG_MESSAGE, &mp);
368  if ( status != X400_E_NOERROR ) {
369  fprintf (stderr, "x400msMsgNew returned error: %s\n",
370  X400msError (status));
371  return (status);
372  }
373 
374 #ifdef use_diff_sec_env_second_msg
375  if (msg_num > 1) {
376  /* set up a security env for the message - this will be used in
377  * preference to the default security env */
378  status = setup_msg_sec_env(mp, "/root",
379  "cn=P7User1,o=Address Book,c=GB", "secret");
380  if ( status != X400_E_NOERROR ) {
381  fprintf (stderr, "setup_msg_sec_env returned error: %s\n",
382  X400msError (status));
383  /* ignore - let's see if the defaults work */
384  }
385  }
386 #endif
387 
388 #ifdef ADD_MOAC
389  /* Instruct the X400msMsgSend() function to generate a
390  * MOAC (signature) for
391  * the message Instruct the X400msMsgSend() function to generate a MOAC
392  * (signature) for the message
393  * The default attributes will be used unless the attributes are
394  * also included in the message eg by calling setup_msg_sec_env() above */
395  status = X400msMsgAddIntParam (mp, X400_B_SEC_GEN_MOAC, 1);
396  if ( status != X400_E_NOERROR ) {
397  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
398  X400msError (status));
399  return (status);
400  } else {
401  fprintf (stderr, "Adding MOAC\n");
402  }
403 #endif
404 
405 
406  /* originator */
407  status = X400msMsgAddStrParam (mp, X400_S_OR_ADDRESS, orn, -1);
408  if ( status != X400_E_NOERROR ) {
409  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
410  X400msError (status));
411  return (status);
412  }
413 
415  "CN=originator;c=gb", -1);
416  if ( status != X400_E_NOERROR ) {
417  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
418  X400msError (status));
419  return (status);
420  }
421 
422  if (adding_sec_label) {
423  status = add_sec_label (mp);
424  if ( status != X400_E_NOERROR ) {
425  fprintf (stderr, "Failed to add Security Label: %s\n",
426  X400msError (status));
427  return (status);
428  } else {
429  fprintf (stderr, "added Security Label\n");
430  }
431  }
433  content_id, -1);
434  if ( status != X400_E_NOERROR ) {
435  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
436  X400msError (status));
437  return (status);
438  }
439 
440  /*
441  status = X400msMsgAddStrParam (mp, X400_S_SUBJECT, subject, -1);
442  if ( status != X400_E_NOERROR ) {
443  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
444  X400msError (status));
445  return (status);
446  }
447 */
448 
449  /* Priority: X.400 0 - normal, 1 - non-urgent, 2 - urgent */
450  /* Military 0 - deferred, 1 - routine, 2 - priority \n"); */
451  /* 3 - immediate, 4 - flash, 5 - override \n"); */
452  printf("military message priority is %d (%s) \n",
453  x400_default_priority,
454  get_x400_pty_str_from_4406(x400_default_priority));
455  status = X400msMsgAddIntParam (mp, X400_N_PRIORITY,
456  get_x400_pty_from_4406(x400_default_priority));
457  if ( status != X400_E_NOERROR ) return (status);
458 
459  /* Priority qaulifier: 0 - low, 1 - high */
460  printf("military message priority qualifer is %d ( 0 - low, 1 - high)\n",
461  get_x400_pty_qual_from_4406(x400_default_priority));
463  get_x400_pty_qual_from_4406(x400_default_priority));
464  if ( status != X400_E_NOERROR ) return (status);
465 
466  /* subject */
467  {
468  time_t t;
469  time(&t);
470  char tmp_buffer[255];
471  // NB strip newline from ctime result
472  snprintf(tmp_buffer, 244, "%s '%s' '%.19s'",
473  subject, get_x400_pty_str_from_4406(x400_default_priority), ctime(&t));
474  printf("Subject is '%s'\n", tmp_buffer);
475  status = X400msMsgAddStrParam (mp, X400_S_SUBJECT, tmp_buffer, -1);
476  if ( status != X400_E_NOERROR ) {
477  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
478  X400msError (status));
479  exit (status);
480  }
481  }
482 
483  /* content type */
484  status = X400msMsgAddStrParam (mp, X400_S_EXTERNAL_CONTENT_TYPE, "1.3.26.0.4406.0.4.1", -1);
485  if ( status != X400_E_NOERROR ) {
486  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n", X400msError (status));
487  exit (status);
488  }
489 
490  if (add_recip(mp, recip) != X400_E_NOERROR) {
491  fprintf (stderr, "add_recip() returned error: %s\n",
492  X400msError (status));
493  return (status);
494  }
495 
496  /*
497  * Use this to add a second recip
498  *
499  if (add_recip(mp, "/G=P7/S=User2/ou=acp127/O=centos64-1/ADMD= /C=GB/") != X400_E_NOERROR) {
500  fprintf (stderr, "add_recip() returned error: %s\n",
501  X400msError (status));
502  return (status);
503  }
504  */
505 
506  if (add_content(mp) != X400_E_NOERROR) {
507  fprintf (stderr, "add_content() returned error: %s\n",
508  X400msError (status));
509  return (status);
510  }
511 
512  status = X400msMsgSend (mp);
513  if ( status != X400_E_NOERROR ) {
514  fprintf (stderr, "x400msMsgSend returned error: %s\n",
515  X400msError (status));
516  return (status);
517  } else {
518  printf("Message submitted successfully\n");
519  }
520 
521  status = X400msMsgDelete (mp, 0);
522  if ( status != X400_E_NOERROR ) {
523  fprintf (stderr, "x400msMsgDelete returned error: %s\n",
524  X400msError (status));
525  return (status);
526  }
527 
528  mp = NULL;
529  return (status);
530 }
531 
532 
533 static int add_recip(
534  struct X400msMessage *mp, /* message object */
535  char *local_recip
536 )
537 {
538  int status;
539  struct X400Recipient *rp; /* recipient object */
540 
541  /* first recip */
542  status = X400msRecipNew (mp, X400_RECIP_STANDARD, &rp);
543  if ( status != X400_E_NOERROR ) {
544  fprintf (stderr, "x400msRecipNew returned error: %s\n",
545  X400msError (status));
546  return (status);
547  }
548 
549  /* put precedence extension into primary recipient */
550  status = X400msRecipAddIntParam (rp, X400_N_PRECEDENCE, 2);
551  if ( status != X400_E_NOERROR ) {
552  fprintf (stderr, "x400msRecipAddIntParam returned error: %s\n",
553  X400msError (status));
554  return (status);
555  }
556 
557 
558  status = X400msRecipAddStrParam (rp, X400_S_OR_ADDRESS, local_recip, -1);
559  if ( status != X400_E_NOERROR ) {
560  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
561  X400msError (status));
562  return (status);
563  }
564 
566  "CN=recipient;c=gb", -1);
567  if ( status != X400_E_NOERROR ) {
568  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
569  X400msError (status));
570  return (status);
571  }
572 
573  /* cause a PODR to be added as a recip extension */
575  if ( status != X400_E_NOERROR ) {
576  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
577  X400msError (status));
578  return (status);
579  }
580 
581  /* cause a Content Integrity Check to be added as a recip extension */
583  if ( status != X400_E_NOERROR ) {
584  fprintf (stderr, "X400msRecipAddIntParam returned error: %s\n",
585  X400msError (status));
586  return (status);
587  }
588 
589  /* Ask for Message Token for this recip */
590  fprintf (stderr, "requesting token\n");
592  if ( status != X400_E_NOERROR ) {
593  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
594  X400msError (status));
595  return (status);
596  }
597 
598 #ifdef FIRST_SEQ_NUM
599  /* Add sequence num */
601  seq_num_val_1);
602  if ( status != X400_E_NOERROR ) {
603  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
604  X400msError (status));
605  return (status);
606  } else {
607  fprintf (stderr, "Added sequence number %d for token\n", seq_num_val_1);
608  }
609  seq_num_val_1++;
610 #endif
611 
612 
613  /* Ask for +ve and -ve delivery reports */
614  /* status = X400msRecipAddIntParam (rp, X400_N_REPORT_REQUEST, 2); */
615  /* Ask for no +ve and -ve delivery reports */
617  if ( status != X400_E_NOERROR ) {
618  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
619  X400msError (status));
620  return (status);
621  }
622 
623  /* Ask for +ve and -ve read receipts */
625  if ( status != X400_E_NOERROR ) {
626  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
627  X400msError (status));
628  return (status);
629  }
630  return X400_E_NOERROR;
631 }
632 
633 
634 static int setup_default_new_sec_env(
635  struct X400msSession *sp,
636  char *idf,
637  char *pw
638 )
639 {
640  int status;
641 
642  fprintf (stderr, "using new_sec_nv %s\n", idf);
643  /* Filename of the Digital Identity (PKCS12 file)
644  * This supersedes the obsolescent X400_S_SEC_IDENTITY,
645  * X400_S_SEC_IDENTITY_DN attributes */
647  idf, -1);
648  if ( status != X400_E_NOERROR ) {
649  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
650  X400msError (status));
651  return (status);
652  }
653 
654  /* passphrase used to open the Identity */
656  if ( status != X400_E_NOERROR ) {
657  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
658  X400msError (status));
659  return (status);
660  }
661 
662  /* test the sec env */
663  status = X400msTestSecurityEnv (sp);
664  if ( status != X400_E_NOERROR ) {
665  fprintf (stderr, "X400msTestSecurityEnv returned error: %s\n",
666  X400msError (status));
667  return (status);
668  }
669 
670  return status;
671 }
672 
673 
674 static int setup_default_old_sec_env(
675  struct X400msSession *sp,
676  char *id,
677  char *dn,
678  char *pw
679 )
680 {
681  int status;
682 
683  fprintf (stderr, "using old_sec_nv\n");
684  /* first set a default security identity. This passes in the name of a
685  * directory, which contains an x509 subdirectory in which all Identities
686  * are held */
688 
689  /* select by DN which Identity is to be used (if there are several)
690  * Currently these must be PKCS12 files */
691  status = X400msSetStrDefault (sp, X400_S_SEC_IDENTITY_DN, dn, -1);
692  if ( status != X400_E_NOERROR ) {
693  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
694  X400msError (status));
695  return (status);
696  }
697 
698  /* passphrase used to open the Identity */
700  if ( status != X400_E_NOERROR ) {
701  fprintf (stderr, "X400msSetStrDefault returned error: %s\n",
702  X400msError (status));
703  return (status);
704  }
705  return status;
706 }
707 
708 #ifdef notused
709 static int setup_msg_new_sec_env(
710  struct X400msMessage *mp, /* message object */
711  char *identity_filename,
712  char *pw /* passphrase for private key in pkcs12 file */
713 )
714 {
715  int status;
716 
717  /* Filename of the Digital Identity (PKCS12 file)
718  * This supersedes the obsolescent X400_S_SEC_IDENTITY,
719  * X400_S_SEC_IDENTITY_DN attributes */
721  identity_filename, -1);
722  if ( status != X400_E_NOERROR ) {
723  fprintf (stderr, "X400msMsgAddStrParam returned error: %s\n",
724  X400msError (status));
725  return (status);
726  }
727 
728  printf("setting up new message security env %s\n", identity_filename);
729 
730  /* security additions */
732  if ( status != X400_E_NOERROR ) {
733  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
734  X400msError (status));
735  return (status);
736  }
737  return (status);
738 }
739 
740 static int setup_msg_old_sec_env(
741  struct X400msMessage *mp, /* message object */
742  char *id, /* x509 identity (directory with x509 subdir) */
743  char *dn, /* DN to use as subject of the X.509 identity */
744  char *pw /* passphrase for private key in pkcs12 file */
745 )
746 {
747  int status;
748 
749  printf("setting up message security env %s\n", id);
750 
751  /* overide the default security environment by specifying a new set of
752  * attibutes, and put them into the message */
753  /* security additions */
754  status = X400msMsgAddStrParam (mp, X400_S_SEC_IDENTITY, id, -1);
755  if ( status != X400_E_NOERROR ) {
756  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
757  X400msError (status));
758  return (status);
759  }
760 
761  /* security additions */
762  status = X400msMsgAddStrParam (mp, X400_S_SEC_IDENTITY_DN, dn, -1);
763  if ( status != X400_E_NOERROR ) {
764  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
765  X400msError (status));
766  return (status);
767  }
768 
769  printf("setting up new message security env %s\n", identity_filename);
770 
771  /* security additions */
773  if ( status != X400_E_NOERROR ) {
774  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
775  X400msError (status));
776  return (status);
777  }
778  return (status);
779 }
780 
781 static int setup_recip_new_sec_env(
782  struct X400Recipient *rp, /* recipient object */
783  char *identity_filename,
784  char *pw /* passphrase for private key in pkcs12 file */
785 )
786 {
787  int status;
788 
789  printf("setting up recipient security env %s\n", identity_filename);
790 
791  /* Filename of the Digital Identity (PKCS12 file)
792  * This supersedes the obsolescent X400_S_SEC_IDENTITY,
793  * X400_S_SEC_IDENTITY_DN attributes */
795  identity_filename, -1);
796  if ( status != X400_E_NOERROR ) {
797  fprintf (stderr, "X400msRecipAddStrParam returned error: %s\n",
798  X400msError (status));
799  return (status);
800  }
801 
802  status = X400msRecipAddStrParam (rp,
804  if ( status != X400_E_NOERROR ) {
805  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
806  X400msError (status));
807  return (status);
808  }
809 
810  return (status);
811 }
812 
813 
814 static int setup_recip_old_sec_env(
815  struct X400Recipient *rp, /* recipient object */
816  char *id, /* x509 identity (directory with x509 subdir) */
817  char *dn, /* DN to use as subject of the X.509 identity */
818  char *pw /* passphrase for private key in pkcs12 file */
819 )
820 {
821  int status;
822 
823  printf("setting up recipient security env %s\n", id);
824 
825  /* overide the default and message security environment
826  * by specifying a new set of attibutes, and put them
827  * into the recipient security attributes */
828  status = X400msRecipAddStrParam (rp, X400_S_SEC_IDENTITY, id, -1);
829  if ( status != X400_E_NOERROR ) {
830  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
831  X400msError (status));
832  return (status);
833  }
834 
835  status = X400msRecipAddStrParam (rp, X400_S_SEC_IDENTITY_DN, dn, -1);
836  if ( status != X400_E_NOERROR ) {
837  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
838  X400msError (status));
839  return (status);
840  }
841 
842  status = X400msRecipAddStrParam (rp,
844  if ( status != X400_E_NOERROR ) {
845  fprintf (stderr, "x400msRecipAddStrParam returned error: %s\n",
846  X400msError (status));
847  return (status);
848  }
849 
850  return (status);
851 }
852 #endif
853 
854 static int add_sec_label(
855  struct X400msMessage *mp /* message object */
856 )
857 {
858 #define XML_BUFSIZE 1024
859 #define STRING_BUFSIZE 1024
860 
861  const char* xml_filename = "seclabel.xml";
862  char xml_content[XML_BUFSIZE];
863  char str_content[STRING_BUFSIZE];
864  int str_len = STRING_BUFSIZE;
865  FILE *fd = NULL;
866  int status;
867 
868  /* Read in the security label XML file */
869  fd = fopen(xml_filename,"r");
870  if(fd == NULL) {
871  fprintf(stderr,"Failed to open %s : %s\n",
872  xml_filename,strerror(errno));
873  return X400_E_INT_ERROR;
874  }
875 
876  fread(&xml_content,XML_BUFSIZE,1,fd);
877 
878  fclose(fd);
879 
880  status = SecLabelInit("Example program");
881  if (status != SECLABEL_E_NOERROR) {
882  fprintf(stderr, "SecLabelInit returned error %d\n", status);
883  return(X400_E_INT_ERROR);
884  }
885 
886  /* Use SecLabelParse to turn the XML into an octect string */
887  status = SecLabelParse(xml_content,
888  str_content,
889  STRING_BUFSIZE,
890  &str_len);
891 
892  if (status != SECLABEL_E_NOERROR) {
893  fprintf(stderr, "SecLabelParse returned error %d\n", status);
894  return(X400_E_INT_ERROR);
895  }
896 
897  /* Add the octect string to the message pointer */
899  str_content,str_len);
900  if ( status != X400_E_NOERROR ) {
901  fprintf (stderr, "x400msMsgAddStrParam returned error: %s\n",
902  X400msError (status));
903  return (status);
904  }
905  return X400_E_NOERROR;
906 }
907 
908 static int add_content(
909  struct X400msMessage *mp /* message object */
910 )
911 {
912  FILE *fp = NULL;
913  int fs = 0;
914  int status;
915  char *binary_data;
916 
917  /* add some attachments/body parts
918  * Strictly a message simply has a sequence of body parts.
919  * However in human terms, it can be useful to treat the Body Parts
920  * as
921  * - text, i.e. an IA5 or general text attachment
922  * - followed by 0 or more attachments (e.g. documents, images etc)
923  *
924  * The API allows for either style.
925  *
926  * Use the AddStrParam() function to add a text attachment
927  * Use the X400msMsgAddAttachment() function to add a Body Part
928  * Use the X400msMsgAddMessageBodyWType() function to add structured
929  * Body Part (e.g. message, FTBP)
930  */
931 
932  status = X400msMsgAddStrParam (mp, X400_T_ISO8859_1, text, -1);
933  if ( status != X400_E_NOERROR ) {
934  fprintf (stderr, "x400ms returned error: %s\n", X400msError (status));
935  return (status);
936  }
937  printf("Sent 8859 attachment as string:\n%s\n", text);
938 
939  if (send_ia5_as_att) {
940  /* now an IA5 body attachment using the attachment func */
941  status = X400msMsgAddAttachment (mp, X400_T_IA5TEXT,
942  text, strlen(text));
943  if ( status != X400_E_NOERROR ) {
944  printf("failed to add X400_T_IA5TEXT attachment\n");
945  return (status);
946  }
947  printf("Sent IA5 as first attachment:\n%s\n", text);
948  } else {
949  /* now an IA5 attachment using the str func */
950  if (num_of_ia5_bytes == 0) {
951  status = X400msMsgAddStrParam (mp, X400_T_IA5TEXT, text, -1);
952  if ( status != X400_E_NOERROR ){
953  printf("failed to add X400_T_IA5TEXT BP\n");
954  return (status);
955  }
956  printf("Sent IA5 as string in message \n%s\n", text);
957  } else {
958  status = add_ia5_str(mp);
959  if ( status != X400_E_NOERROR ) {
960  printf("failed to add IA5 str\n");
961  return (status);
962  }
963  }
964  }
965 
966  /* now an 8859-1 body attachment using the attachment func */
967  status = X400msMsgAddAttachment (mp, X400_T_ISO8859_1, text, strlen(text));
968  if ( status != X400_E_NOERROR ) {
969  printf("failed to add X400_T_ISO8859_1, attachment\n");
970  return (status);
971  }
972  printf("Sent 8859-1 as attachment:\n%s\n", text);
973 
974  /* or a Binary body part using the bodypart func */
975  status = add_binary_bp(mp);
976  if ( status != X400_E_NOERROR ) {
977  printf("failed to add X400_T_BINARY BP\n");
978  return (status);
979  }
980 
981  /* File Transfer Body Part using the bodypart func */
982  status = add_ftbp(mp);
983  if ( status != X400_E_NOERROR ) {
984  printf("failed to add X400_T_BINARY BP\n");
985  return (status);
986  }
987 
988  return status;
989 
990  if (filename_to_send != NULL) {
991  binary_data = (char *) malloc(100000);
992  if ( binary_data == NULL )
993  return X400_E_NOMEMORY;
994  fp = fopen(filename_to_send, "r");
995  if (fp == (FILE *)NULL) {
996  printf("Cannot open binary file\n");
997  return (X400_E_SYSERROR);
998  }
999  if ((fs = fread (binary_data, sizeof(char), 100000/sizeof(char), fp))
1000  == -1) {
1001  printf("Cannot read from binary file\n");
1002  return (X400_E_SYSERROR);
1003  }
1004  fclose(fp);
1005 
1006  status = X400msMsgAddAttachment (mp, X400_T_BINARY, binary_data, fs);
1007  if ( status != X400_E_NOERROR ) {
1008  printf("failed to add X400_T_BINARY BP\n");
1009  return (status);
1010  }
1011 
1012  status = X400msMsgAddStrParam (mp, X400_T_IA5TEXT, text, -1);
1013  if ( status != X400_E_NOERROR ){
1014  printf("failed to add X400_T_IA5TEXT BP\n");
1015  return (status);
1016  }
1017  printf("Sent IA5 as string in message \n%s\n", text);
1018 
1019  free (binary_data);
1020 
1021  } else {
1022  printf("no binary file set - not sending X400_T_BINARY\n");
1023  }
1024  return status;
1025 }
1026 
1027 
1028 static int add_ia5_str(
1029  struct X400msMessage *mp
1030 )
1031 {
1032  int status;
1033  char *tmp;
1034  int i;
1035  char *sample_ia5 = {"Here is some sample text to put into the IA5 attachment."};
1036 
1037  if ((tmp = malloc(num_of_ia5_bytes + 1)) == NULL) {
1038  printf("failed to malloc %d bytes\n", num_of_ia5_bytes);
1039  return (X400_E_SYSERROR);
1040  }
1041  strcpy(tmp, text);
1042  for (i = strlen(text) ; i < num_of_ia5_bytes ; i++)
1043  tmp[i] = sample_ia5[i%strlen(sample_ia5)];
1044  tmp[i] = '\0';
1045 
1046  status = X400msMsgAddStrParam (mp, X400_T_IA5TEXT, tmp, strlen(tmp));
1047  if ( status != X400_E_NOERROR ) {
1048  printf("failed to add X400_T_IA5TEXT BP\n");
1049  return (status);
1050  }
1051  printf("Sent %d bytes IA5 as string in message \n%s\n", i, tmp);
1052  return X400_E_NOERROR;
1053 }
1054 
1055 
1056 static int add_binary_bp(
1057  struct X400msMessage *mp
1058 )
1059 {
1060  FILE *fp = NULL;
1061  int fs=0;
1062  char *binary_data;
1063  int status;
1064 
1065  /* or a Binary body part using the bodypart func */
1066  if (filename_to_send != NULL) {
1067  fp = fopen(filename_to_send, "rb");
1068  if (fp == (FILE *)NULL) {
1069  printf("Cannot open binary file\n");
1070  return (X400_E_SYSERROR);
1071  }
1072  binary_data = (char *) malloc(bin_bp_size);
1073  if ( binary_data == NULL )
1074  return X400_E_NOMEMORY;
1075  if ((fs = fread (binary_data, sizeof(char),
1076  bin_bp_size/sizeof(char), fp) ) == -1) {
1077  printf("Cannot read from binary file\n");
1078  free (binary_data);
1079  fclose(fp);
1080  return (X400_E_SYSERROR);
1081  }
1082  fclose(fp);
1083  if (fs < bin_bp_size) {
1084  printf("Cannot read %d bytes from binary file (got %d)\n",
1085  bin_bp_size, fs);
1086  free (binary_data);
1087  return (X400_E_SYSERROR);
1088  }
1089 
1090  status = X400msMsgAddAttachment (mp, X400_T_BINARY, binary_data, fs);
1091  free (binary_data);
1092  if ( status != X400_E_NOERROR ) {
1093  printf("failed to add X400_T_BINARY BP\n");
1094  return (status);
1095  }
1096  printf("Sent %d bytes as X400_T_BINARY BP\n", fs);
1097  } else {
1098  printf("no binary file set - not sending X400_T_BINARY\n");
1099  }
1100  return X400_E_NOERROR;
1101 }
1102 
1103 
1104 static int add_ftbp(
1105  struct X400msMessage *mp
1106 )
1107 {
1108  FILE *fp = NULL;
1109  int fs=0;
1110  char *binary_data;
1111  int status;
1112  struct X400Bodypart *bp;
1113 
1114  /* or a Binary body part using the bodypart func */
1115  if (filename_to_send != NULL) {
1116  fp = fopen(filename_to_send, "rb");
1117  if (fp == (FILE *)NULL) {
1118  printf("Cannot open binary file\n");
1119  return (X400_E_SYSERROR);
1120  }
1121  binary_data = (char *) malloc(bin_bp_size);
1122  if ( binary_data == NULL )
1123  return X400_E_NOMEMORY;
1124  if ((fs = fread (binary_data, sizeof(char),
1125  bin_bp_size/sizeof(char), fp) ) == -1) {
1126  printf("Cannot read from binary file\n");
1127  free (binary_data);
1128  fclose(fp);
1129  return (X400_E_SYSERROR);
1130  }
1131  fclose(fp);
1132  if (fs < bin_bp_size) {
1133  printf("Cannot read %d bytes from binary file (got %d)\n",
1134  bin_bp_size, fs);
1135  free (binary_data);
1136  return (X400_E_SYSERROR);
1137  }
1138 
1140  X400BodypartAddStrParam(bp, X400_S_BODY_DATA, binary_data, fs);
1142  "Test FTBP File", -1);
1143  /* NB this value should have the filename, but not the full path */
1144  /* Ad on Windows backslashes must be escaped with a second backslash */
1145  X400BodypartAddStrParam(bp, X400_S_FTBP_FILENAME, filename_to_send, -1);
1147  "20160801060101.0Z", -1);
1149  "20160801060202.0Z", -1);
1151  status = X400msMsgAddBodypart(mp, bp);
1152  free (binary_data);
1153 
1154  if ( status != X400_E_NOERROR ) {
1155  printf("failed to add X400_T_FTBP BP\n");
1156  return (status);
1157  }
1158  printf("Sent %d bytes as X400_T_FTBP BP\n", fs);
1159  } else {
1160  printf("no binary file set - not sending X400_T_FTBP\n");
1161  }
1162  return X400_E_NOERROR;
1163 }
1164 
1165 
1166 static void usage(void) {
1167 printf("usage: %s\n", optstr);
1168  printf("\t where:\n");
1169  printf("\t -u : Don't prompt to override defaults \n");
1170  printf("\t -3 : Use P3 connection \n");
1171  printf("\t -7 : Use P7 connection \n");
1172  printf("\t -m : OR Address in P7 bind arg \n");
1173  printf("\t -d : DN in P7 bind arg \n");
1174  printf("\t -p : Presentation Address of P7 Store \n");
1175  printf("\t -w : P7 password of P7 user \n");
1176  printf("\t -M : OR Address in P3 bind arg \n");
1177  printf("\t -D : DN in P3 bind arg \n");
1178  printf("\t -P : Presentation Address of P3 server\n");
1179  printf("\t -W : P3 password of P3 user \n");
1180  printf("\t -o : Originator \n");
1181  printf("\t -O : Originator Return Address \n");
1182  printf("\t -r : Recipient\n");
1183  printf("\t -l : Logline\n");
1184  printf("\t -y : Military Priority \n");
1185  printf("\t\t 0 - deferred, 1 - routine, 2 - priority \n");
1186  printf("\t\t 3 - immediate, 4 - flash, 5 - override \n");
1187  printf("\t -C : Content Type (2/22/772/OID) \n");
1188  printf("\t -i : Implicit conversion prohibited = TRUE \n");
1189  printf("\t -a : Alternate Recipient Prohibited = TRUE \n");
1190  printf("\t -q : Content Return Request = TRUE \n");
1191  printf("\t -s : Disclosure of Recipient = FALSE \n");
1192  printf("\t -A : Recipient Reassignment Prohibited = FALSE \n");
1193  printf("\t -v : Conversion with Loss Prohibited = FALSE \n");
1194  printf("\t -e : Security Environment (dir with x509 subdir): obsolete, use -Y <p12file>\n");
1195  printf("\t -x : DN of X.509 Digital Identity\n");
1196  printf("\t -b : Passphrase for private key in PKCS12 file\n");
1197  printf("\t -f : Filename to transfer as binary bp\n");
1198  printf("\t -Y : Filename of PKCS12 file containing Digital Identity\n");
1199  printf("\t -S : Number of bytes to put into Binary BP and FTBP (default 100)\n");
1200  return;
1201 }
1202 
1203 
#define X400_S_DIRECTORY_NAME
Definition: x400_att.h:394
#define X400_MSG_MESSAGE
Definition: x400_att.h:29
#define X400_S_EXTERNAL_CONTENT_TYPE
Definition: x400_att.h:444
int X400BodypartNew(int type, struct X400Bodypart **bpp)
Create a new body part object.
#define X400_E_SYSERROR
Definition: x400_att.h:49
#define X400_S_LOG_CONFIGURATION_FILE
Definition: x400_att.h:1080
int X400msSetStrDefault(struct X400msSession *sp, int paramtype, const char *value, size_t length)
Set a default string parameter value in a session.
#define X400_S_FTBP_CONTENT_DESCRIPTION
Definition: x400_att.h:1188
#define X400_S_CONTENT_IDENTIFIER
Definition: x400_att.h:411
int X400msMsgAddStrParam(struct X400msMessage *mp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
#define X400_S_SEC_IDENTITY
Definition: x400_att.h:551
int X400BodypartAddStrParam(struct X400Bodypart *bp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the body part.
#define X400_S_BODY_DATA
Definition: x400_att.h:1158
int X400msTestSecurityEnv(struct X400msSession *sp)
Test the default Security Environment.
int X400msRecipAddIntParam(struct X400Recipient *rp, int paramtype, int value)
Add integer-valued parameter to the message.
int X400msMsgAddBodypart(struct X400msMessage *mp, struct X400Bodypart *bp)
#define X400_N_PRECEDENCE
Definition: x400_att.h:682
const char * X400msError(int error)
Obtain a string describing the meaning of the given error code.
#define X400_S_FTBP_FILENAME
Definition: x400_att.h:1191
int X400msMsgNew(struct X400msSession *sp, int type, struct X400msMessage **mpp)
Creates new message.
int X400msClose(struct X400msSession *sp)
Close a X400 Session.
#define X400_T_ISO8859_1
Definition: x400_att.h:805
#define X400_N_PROOF_OF_DEL_REQ
Definition: x400_att.h:974
#define X400_S_FTBP_CREATION_DATE
Definition: x400_att.h:1194
#define X400_N_NOTIFICATION_REQUEST
Definition: x400_att.h:672
#define X400_S_FTBP_MODIFICATION_DATE
Definition: x400_att.h:1197
int X400msMsgAddAttachment(struct X400msMessage *mp, int type, const char *string, size_t length)
Add attachment to the message.
int X400msRecipAddStrParam(struct X400Recipient *rp, int paramtype, const char *value, size_t length)
Add string-valued parameter to the message.
#define X400_T_IA5TEXT
Definition: x400_att.h:795
#define X400_E_NOERROR
Definition: x400_att.h:46
int X400msOpen(int type, const char *oraddr, const char *dirname, const char *credentials, const char *pa, int *messages, struct X400msSession **spp)
Open a session to a Message Store (P7) or MTA (P3) in synchronous mode.
#define X400_N_FTBP_OBJECT_SIZE
Definition: x400_att.h:1203
#define X400_S_OR_ADDRESS
Definition: x400_att.h:346
#define X400_S_SEC_IDENTITY_PASSPHRASE
Definition: x400_att.h:557
#define X400_B_SEC_GEN_MESSAGE_TOKEN
Definition: x400_att.h:1397
#define X400_RECIP_STANDARD
Definition: x400_att.h:338
#define X400_T_BINARY
Definition: x400_att.h:821
#define X400_S_SECURITY_LABEL
Definition: x400_att.h:1319
#define X400_S_SEC_IDENTITY_DN
Definition: x400_att.h:560
#define X400_N_REPORT_REQUEST
Definition: x400_att.h:650
int X400msMsgSend(struct X400msMessage *mp)
Send message object.
int X400BodypartAddIntParam(struct X400Bodypart *bp, int paramtype, int value)
Add integer-valued parameter to the body part.
#define X400_B_SEC_CONTENT_INTEGRITY_CHECK
Definition: x400_att.h:1403
X400 MA/MS (P3/P7) Interface.
#define X400_S_SEC_IDENTITY_FILE
Definition: x400_att.h:575
#define X400_N_PRIORITY
Definition: x400_att.h:419
int X400msRecipNew(struct X400msMessage *mp, int type, struct X400Recipient **rpp)
Add new recipient to a message.
#define X400_N_MSGTOK_SEQ_NUM
Definition: x400_att.h:1414
#define X400_E_NOMEMORY
Definition: x400_att.h:52
#define X400_S_SUBJECT
Definition: x400_att.h:719
#define X400_E_INT_ERROR
Definition: x400_att.h:58
#define X400_B_SEC_GEN_MOAC
Definition: x400_att.h:554
#define X400_N_MMTS_PRIORITY_QUALIFIER
Definition: x400_att.h:470
#define X400_T_FTBP
Definition: x400_att.h:830
int X400msMsgAddIntParam(struct X400msMessage *mp, int paramtype, int value)
Add integer-valued parameter to the message.
int X400msMsgDelete(struct X400msMessage *mp, int retain)
Delete message object.