[client] Fixed several minor memory leaks caught by valgrind
[fwknop.git] / client / fwknop.c
1 /*
2  *****************************************************************************
3  *
4  * File:    fwknop.c
5  *
6  * Author:  Damien S. Stuart
7  *
8  * Purpose: An implementation of an fwknop client.
9  *
10  * Copyright 2009-2010 Damien Stuart (dstuart@dstuart.org)
11  *
12  *  License (GNU Public License):
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
27  *  USA
28  *
29  *****************************************************************************
30 */
31 #include "fwknop.h"
32 #include "config_init.h"
33 #include "spa_comm.h"
34 #include "utils.h"
35 #include "getpasswd.h"
36
37 /* prototypes
38 */
39 static char * get_user_pw(fko_cli_options_t *options, const int crypt_op);
40 static void display_ctx(fko_ctx_t ctx);
41 static void errmsg(const char *msg, const int err);
42 static void show_last_command(void);
43 static void save_args(int argc, char **argv);
44 static void run_last_args(fko_cli_options_t *options);
45 static int set_message_type(fko_ctx_t ctx, fko_cli_options_t *options);
46 static int set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options);
47 static int get_rand_port(fko_ctx_t ctx);
48 int resolve_ip_http(fko_cli_options_t *options);
49
50 int
51 main(int argc, char **argv)
52 {
53     fko_ctx_t           ctx, ctx2;
54     int                 res;
55     char               *spa_data, *version;
56     char                access_buf[MAX_LINE_LEN];
57
58     fko_cli_options_t   options;
59
60     /* Handle command line
61     */
62     config_init(&options, argc, argv);
63
64     /* Handle options that don't require a libfko context
65     */
66     if(options.run_last_command)
67         run_last_args(&options);
68     else if(options.show_last_command)
69         show_last_command();
70     else if (!options.no_save_args)
71         save_args(argc, argv);
72
73     /* Intialize the context
74     */
75     res = fko_new(&ctx);
76     if(res != FKO_SUCCESS)
77     {
78         errmsg("fko_new", res);
79         return(EXIT_FAILURE);
80     }
81
82     /* Display version info and exit.
83     */
84     if (options.version) {
85         fko_get_version(ctx, &version);
86
87         fprintf(stdout, "fwknop client %s, FKO protocol version %s\n",
88             MY_VERSION, version);
89
90         fko_destroy(ctx);
91         return(EXIT_SUCCESS);
92     }
93
94     /* Set client timeout
95     */
96     if(options.fw_timeout >= 0)
97     {
98         res = fko_set_spa_client_timeout(ctx, options.fw_timeout);
99         if(res != FKO_SUCCESS)
100         {
101             errmsg("fko_set_spa_client_timeout", res);
102             fko_destroy(ctx);
103             return(EXIT_FAILURE);
104         }
105     }
106
107     /* Set the SPA packet message type based on command line options
108     */
109     res = set_message_type(ctx, &options);
110     if(res != FKO_SUCCESS)
111     {
112         errmsg("fko_set_spa_message_type", res);
113         fko_destroy(ctx);
114         return(EXIT_FAILURE);
115     }
116
117     /* Adjust the SPA timestamp if necessary
118     */
119     if(options.time_offset_plus > 0)
120     {
121         res = fko_set_timestamp(ctx, options.time_offset_plus);
122         if(res != FKO_SUCCESS)
123         {
124             errmsg("fko_set_timestamp", res);
125             fko_destroy(ctx);
126             return(EXIT_FAILURE);
127         }
128     }
129     if(options.time_offset_minus > 0)
130     {
131         res = fko_set_timestamp(ctx, -options.time_offset_minus);
132         if(res != FKO_SUCCESS)
133         {
134             errmsg("fko_set_timestamp", res);
135             fko_destroy(ctx);
136             return(EXIT_FAILURE);
137         }
138     }
139
140     if(options.server_command[0] != 0x0)
141     {
142         /* Set the access message to a command that the server will
143          * execute
144         */
145         snprintf(access_buf, MAX_LINE_LEN, "%s%s%s",
146                 options.allow_ip_str, ",", options.server_command);
147     }
148     else
149     {
150         /* Resolve the client's public facing IP address if requestesd.
151          * if this fails, consider it fatal.
152         */
153         if (options.resolve_ip_http)
154             if(resolve_ip_http(&options) < 0)
155             {
156                 fko_destroy(ctx);
157                 return(EXIT_FAILURE);
158             }
159
160         /* Set a message string by combining the allow IP and the
161          * port/protocol.  The fwknopd server allows no port/protocol
162          * to be specified as well, so in this case append the string
163          * "none/0" to the allow IP.
164         */
165         if(options.access_str[0] != 0x0)
166         {
167             snprintf(access_buf, MAX_LINE_LEN, "%s%s%s",
168                     options.allow_ip_str, ",", options.access_str);
169         }
170         else
171         {
172             snprintf(access_buf, MAX_LINE_LEN, "%s%s%s",
173                     options.allow_ip_str, ",", "none/0");
174         }
175     }
176     res = fko_set_spa_message(ctx, access_buf);
177     if(res != FKO_SUCCESS)
178     {
179         errmsg("fko_set_spa_message", res);
180         fko_destroy(ctx);
181         return(EXIT_FAILURE);
182     }
183
184     /* Set NAT access string
185     */
186     if (options.nat_local || options.nat_access_str[0] != 0x0)
187     {
188         res = set_nat_access(ctx, &options);
189         if(res != FKO_SUCCESS)
190         {
191             errmsg("fko_set_nat_access_str", res);
192             fko_destroy(ctx);
193             return(EXIT_FAILURE);
194         }
195     }
196
197     /* Set username
198     */
199     if(options.spoof_user[0] != 0x0)
200     {
201         res = fko_set_username(ctx, options.spoof_user);
202         if(res != FKO_SUCCESS)
203         {
204             errmsg("fko_set_username", res);
205             fko_destroy(ctx);
206             return(EXIT_FAILURE);
207         }
208     }
209
210     /* Set up for using GPG if specified.
211     */
212     if(options.use_gpg)
213     {
214         /* If use-gpg-agent was not specified, then remove the GPG_AGENT_INFO
215          * ENV variable if it exists.
216         */
217 #ifndef WIN32
218         if(!options.use_gpg_agent)
219             unsetenv("GPG_AGENT_INFO");
220 #endif
221
222         res = fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG);
223         if(res != FKO_SUCCESS)
224         {
225             errmsg("fko_set_spa_encryption_type", res);
226             fko_destroy(ctx);
227             return(EXIT_FAILURE);
228         }
229
230         /* If a GPG home dir was specified, set it here.  Note: Setting
231          * this has to occur before calling any of the other GPG-related
232          * functions.
233         */
234         if(options.gpg_home_dir != NULL && strlen(options.gpg_home_dir) > 0)
235         {
236             res = fko_set_gpg_home_dir(ctx, options.gpg_home_dir);
237             if(res != FKO_SUCCESS)
238             {
239                 errmsg("fko_set_gpg_home_dir", res);
240                 fko_destroy(ctx);
241                 return(EXIT_FAILURE);
242             }
243         }
244
245         res = fko_set_gpg_recipient(ctx, options.gpg_recipient_key);
246         if(res != FKO_SUCCESS)
247         {
248             errmsg("fko_set_gpg_recipient", res);
249
250             if(IS_GPG_ERROR(res))
251                 fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errstr(ctx));
252             fko_destroy(ctx);
253             return(EXIT_FAILURE);
254         }
255
256         if(options.gpg_signer_key != NULL && strlen(options.gpg_signer_key))
257         {
258             res = fko_set_gpg_signer(ctx, options.gpg_signer_key);
259             if(res != FKO_SUCCESS)
260             {
261                 errmsg("fko_set_gpg_signer", res);
262
263                 if(IS_GPG_ERROR(res))
264                     fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errstr(ctx));
265
266                 fko_destroy(ctx);
267                 return(EXIT_FAILURE);
268             }
269         }
270     }
271
272     /* Set Digest type.
273     */
274     if(options.digest_type)
275     {
276         fko_set_spa_digest_type(ctx, options.digest_type);
277         if(res != FKO_SUCCESS)
278         {
279             errmsg("fko_set_spa_digest_type", res);
280             fko_destroy(ctx);
281             return(EXIT_FAILURE);
282         }
283     }
284
285     /* Finalize the context data (encrypt and encode the SPA data)
286     */
287     res = fko_spa_data_final(ctx, get_user_pw(&options, CRYPT_OP_ENCRYPT));
288     if(res != FKO_SUCCESS)
289     {
290         errmsg("fko_spa_data_final", res);
291
292         if(IS_GPG_ERROR(res))
293             fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errstr(ctx));
294
295         fko_destroy(ctx);
296         return(EXIT_FAILURE);
297     }
298
299     /* Display the context data.
300     */
301     if (options.verbose || options.test)
302         display_ctx(ctx);
303
304     /* Save packet data payload if requested.
305     */
306     if (options.save_packet_file[0] != 0x0)
307         write_spa_packet_data(ctx, &options);
308
309     if (options.rand_port)
310         options.spa_dst_port = get_rand_port(ctx);
311
312     res = send_spa_packet(ctx, &options);
313     if(res < 0)
314     {
315         fprintf(stderr, "send_spa_packet: packet not sent.\n");
316         fko_destroy(ctx);
317         return(EXIT_FAILURE);
318     }
319     else
320     {
321         if(options.verbose)
322             fprintf(stderr, "send_spa_packet: bytes sent: %i\n", res);
323     }
324
325     /* Run through a decode cycle in test mode (--DSS XXX: This test/decode
326      * portion should be moved elsewhere).
327     */
328     if (options.test)
329     {
330         /************** Decoding now *****************/
331
332         /* Now we create a new context based on data from the first one.
333         */
334         res = fko_get_spa_data(ctx, &spa_data);
335         if(res != FKO_SUCCESS)
336         {
337             errmsg("fko_get_spa_data", res);
338             fko_destroy(ctx);
339             return(EXIT_FAILURE);
340         }
341
342         /* If gpg-home-dir is specified, we have to defer decrypting if we
343          * use the fko_new_with_data() function because we need to set the
344          * gpg home dir after the context is created, but before we attempt
345          * to decrypt the data.  Therefore we either pass NULL for the
346          * decryption key to fko_new_with_data() or use fko_new() to create
347          * an empty context, populate it with the encrypted data, set our
348          * options, then decode it.
349         */
350         res = fko_new_with_data(&ctx2, spa_data, NULL);
351         if(res != FKO_SUCCESS)
352         {
353             errmsg("fko_new_with_data", res);
354             fko_destroy(ctx);
355             fko_destroy(ctx2);
356             return(EXIT_FAILURE);
357         }
358
359         /* See if we are using gpg and if we need to set the GPG home dir.
360         */
361         if(options.use_gpg)
362         {
363             if(options.gpg_home_dir != NULL && strlen(options.gpg_home_dir) > 0)
364             {
365                 res = fko_set_gpg_home_dir(ctx2, options.gpg_home_dir);
366                 if(res != FKO_SUCCESS)
367                 {
368                     errmsg("fko_set_gpg_home_dir", res);
369                     fko_destroy(ctx);
370                     fko_destroy(ctx2);
371                     return(EXIT_FAILURE);
372                 }
373             }
374         }
375
376         res = fko_decrypt_spa_data(
377             ctx2, get_user_pw(&options, CRYPT_OP_DECRYPT)
378         );
379
380         if(res != FKO_SUCCESS)
381         {
382             errmsg("fko_decrypt_spa_data", res);
383
384             if(IS_GPG_ERROR(res)) {
385                 /* we most likely could not decrypt the gpg-encrypted data
386                  * because we don't have access to the private key associated
387                  * with the public key we used for encryption.  Since this is
388                  * expected, return 0 instead of an error condition (so calling
389                  * programs like the fwknop test suite don't interpret this as
390                  * an unrecoverable error), but print the error string for
391                  debugging purposes. */
392                 fprintf(stderr, "GPG ERR: %s\n%s\n", fko_gpg_errstr(ctx2),
393                     "No access to recipient private key?\n");
394                 fko_destroy(ctx);
395                 fko_destroy(ctx2);
396                 return(EXIT_SUCCESS);
397             }
398
399             fko_destroy(ctx);
400             fko_destroy(ctx2);
401             return(EXIT_FAILURE);
402         }
403
404         printf("\nDump of the Decoded Data\n");
405         display_ctx(ctx2);
406
407         fko_destroy(ctx2);
408     }
409
410     fko_destroy(ctx);
411
412     free_configs(&options);
413
414     return(EXIT_SUCCESS);
415 }
416
417 void
418 free_configs(fko_cli_options_t *opts)
419 {
420     if (opts->resolve_url != NULL)
421         free(opts->resolve_url);
422 }
423
424 static int
425 get_rand_port(fko_ctx_t ctx)
426 {
427     char *rand_val = NULL;
428     int   port     = 0;
429     int   res      = 0;
430
431     res = fko_get_rand_value(ctx, &rand_val);
432     if(res != FKO_SUCCESS)
433     {
434         errmsg("get_rand_port(), fko_get_rand_value", res);
435         exit(EXIT_FAILURE);
436     }
437
438     /* Convert to a random value between 1024 and 65535
439     */
440     port = (MIN_HIGH_PORT + (abs(atoi(rand_val)) % (MAX_PORT - MIN_HIGH_PORT)));
441
442     /* Force libfko to calculate a new random value since we don't want to
443      * given anyone a hint (via the port value) about the contents of the
444      * encrypted SPA data.
445     */
446     res = fko_set_rand_value(ctx, NULL);
447     if(res != FKO_SUCCESS)
448     {
449         errmsg("get_rand_port(), fko_get_rand_value", res);
450         exit(EXIT_FAILURE);
451     }
452
453     return port;
454 }
455
456 /* See if the string is of the format "<ipv4 addr>:<port>",
457  */
458 static int
459 ipv4_str_has_port(char *str)
460 {
461     int o1, o2, o3, o4, p;
462
463     /* Force the ':' (if any) to a ','
464     */
465     char *ndx = strchr(str, ':');
466     if(ndx != NULL)
467         *ndx = ',';
468
469     /* Check format and values.
470     */
471     if((sscanf(str, "%u.%u.%u.%u,%u", &o1, &o2, &o3, &o4, &p)) == 5
472         && o1 >= 0 && o1 <= 255
473         && o2 >= 0 && o2 <= 255
474         && o3 >= 0 && o3 <= 255
475         && o4 >= 0 && o4 <= 255
476         && p  >  0 && p  <  65536)
477     {
478         return 1;
479     }
480
481     return 0;
482 }
483
484 /* Set NAT access string
485 */
486 static int
487 set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options)
488 {
489     char nat_access_buf[MAX_LINE_LEN] = "";
490     int nat_port = 0;
491
492     if (options->nat_rand_port)
493         nat_port = get_rand_port(ctx);
494     else if (options->nat_port)
495         nat_port = options->nat_port;
496     else
497         nat_port = DEFAULT_NAT_PORT;
498
499     if (options->nat_local && options->nat_access_str[0] == 0x0)
500     {
501         snprintf(nat_access_buf, MAX_LINE_LEN, "%s,%d",
502             options->spa_server_str, nat_port);
503     }
504
505     if (nat_access_buf[0] == 0x0 && options->nat_access_str[0] != 0x0)
506     {
507         if (ipv4_str_has_port(options->nat_access_str))
508         {
509             snprintf(nat_access_buf, MAX_LINE_LEN, "%s",
510                 options->nat_access_str);
511         }
512         else
513         {
514             snprintf(nat_access_buf, MAX_LINE_LEN, "%s,%d",
515                 options->nat_access_str, nat_port);
516         }
517     }
518
519     return fko_set_spa_nat_access(ctx, nat_access_buf);
520 }
521
522 static int
523 get_save_file(char *args_save_file)
524 {
525     char *homedir = NULL;
526     int rv = 0;
527
528     homedir = getenv("HOME");
529
530     if (homedir != NULL) {
531         snprintf(args_save_file, MAX_PATH_LEN, "%s%s%s",
532             homedir, "/", ".fwknop.run");
533         rv = 1;
534     }
535
536     return rv;
537 }
538
539 /* Show the last command that was executed
540 */
541 static void
542 show_last_command(void)
543 {
544     char args_save_file[MAX_PATH_LEN];
545     char args_str[MAX_LINE_LEN] = "";
546     FILE *args_file_ptr = NULL;
547
548 #ifdef WIN32
549     /* Not sure what the right thing is here on Win32, just exit
550      * for now.
551     */
552     fprintf(stderr, "--show-last not implemented on Win32 yet.");
553     exit(EXIT_FAILURE);
554 #endif
555
556     if (get_save_file(args_save_file)) {
557         if ((args_file_ptr = fopen(args_save_file, "r")) == NULL) {
558             fprintf(stderr, "Could not open args file: %s\n",
559                 args_save_file);
560             exit(EXIT_FAILURE);
561         }
562         if ((fgets(args_str, MAX_LINE_LEN, args_file_ptr)) != NULL) {
563             printf("Last fwknop client command line: %s", args_str);
564         } else {
565             printf("Could not read line from file: %s\n", args_save_file);
566         }
567         fclose(args_file_ptr);
568     }
569
570     exit(EXIT_SUCCESS);
571 }
572
573 /* Get the command line arguments from the previous invocation
574 */
575 static void
576 run_last_args(fko_cli_options_t *options)
577 {
578     FILE           *args_file_ptr = NULL;
579
580     int             current_arg_ctr = 0;
581     int             argc_new = 0;
582     int             i = 0;
583
584     char            args_save_file[MAX_PATH_LEN] = {0};
585     char            args_str[MAX_LINE_LEN] = {0};
586     char            arg_tmp[MAX_LINE_LEN]  = {0};
587     char           *argv_new[200];  /* should be way more than enough */
588
589
590 #ifdef WIN32
591     /* Not sure what the right thing is here on Win32, just return
592      * for now.
593     */
594     return;
595 #endif
596
597     if (get_save_file(args_save_file))
598     {
599         if ((args_file_ptr = fopen(args_save_file, "r")) == NULL)
600         {
601             fprintf(stderr, "Could not open args file: %s\n",
602                 args_save_file);
603             exit(EXIT_FAILURE);
604         }
605         if ((fgets(args_str, MAX_LINE_LEN, args_file_ptr)) != NULL)
606         {
607             args_str[MAX_LINE_LEN-1] = '\0';
608             if (options->verbose)
609                 printf("Executing: %s\n", args_str);
610             for (i=0; i < (int)strlen(args_str); i++)
611             {
612                 if (!isspace(args_str[i]))
613                 {
614                     arg_tmp[current_arg_ctr] = args_str[i];
615                     current_arg_ctr++;
616                 }
617                 else
618                 {
619                     arg_tmp[current_arg_ctr] = '\0';
620                     argv_new[argc_new] = malloc(strlen(arg_tmp)+1);
621                     if (argv_new[argc_new] == NULL)
622                     {
623                         fprintf(stderr, "malloc failure for cmd line arg.\n");
624                         exit(EXIT_FAILURE);
625                     }
626                     strlcpy(argv_new[argc_new], arg_tmp, strlen(arg_tmp)+1);
627                     current_arg_ctr = 0;
628                     argc_new++;
629                 }
630             }
631         }
632         fclose(args_file_ptr);
633
634         /* Reset the options index so we can run through them again.
635         */
636         optind = 0;
637
638         config_init(options, argc_new, argv_new);
639     }
640
641     return;
642 }
643
644 /* Save our command line arguments
645 */
646 static void
647 save_args(int argc, char **argv)
648 {
649     char args_save_file[MAX_PATH_LEN];
650     char args_str[MAX_LINE_LEN] = "";
651     FILE *args_file_ptr = NULL;
652     int i = 0, args_str_len = 0;
653
654 #ifdef WIN32
655     /* Not sure what the right thing is here on Win32, just return
656      * for now.
657     */
658     return;
659 #endif
660
661
662     if (get_save_file(args_save_file)) {
663         if ((args_file_ptr = fopen(args_save_file, "w")) == NULL) {
664             fprintf(stderr, "Could not open args file: %s\n",
665                 args_save_file);
666             exit(EXIT_FAILURE);
667         }
668         for (i=0; i < argc; i++) {
669             args_str_len += strlen(argv[i]);
670             if (args_str_len >= MAX_PATH_LEN) {
671                 fprintf(stderr, "argument string too long, exiting.\n");
672                 exit(EXIT_FAILURE);
673             }
674             strlcat(args_str, argv[i], MAX_PATH_LEN);
675             strlcat(args_str, " ", MAX_PATH_LEN);
676         }
677         fprintf(args_file_ptr, "%s\n", args_str);
678         fclose(args_file_ptr);
679     }
680     return;
681 }
682
683 /* Set the SPA packet message type
684 */
685 static int
686 set_message_type(fko_ctx_t ctx, fko_cli_options_t *options)
687 {
688     short message_type;
689
690     if(options->server_command[0] != 0x0)
691     {
692         message_type = FKO_COMMAND_MSG;
693     }
694     else if(options->nat_local)
695     {
696         if (options->fw_timeout >= 0)
697             message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG;
698         else
699             message_type = FKO_LOCAL_NAT_ACCESS_MSG;
700     }
701     else if(options->nat_access_str[0] != 0x0)
702     {
703         if (options->fw_timeout >= 0)
704             message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG;
705         else
706             message_type = FKO_NAT_ACCESS_MSG;
707     }
708     else
709     {
710         if (options->fw_timeout >= 0)
711             message_type = FKO_CLIENT_TIMEOUT_ACCESS_MSG;
712         else
713             message_type = FKO_ACCESS_MSG;
714     }
715
716     return fko_set_spa_message_type(ctx, message_type);
717 }
718
719 /* Prompt for and receive a user password.
720 */
721 static char*
722 get_user_pw(fko_cli_options_t *options, const int crypt_op)
723 {
724     char        *pw_ptr = NULL;
725     static char *no_pw  = "";
726
727     /* First of all if we are using GPG and GPG_AGENT
728      * then there is no password to return.
729     */
730     if(options->use_gpg
731       && (options->use_gpg_agent
732            || (crypt_op == CRYPT_OP_ENCRYPT && options->gpg_signer_key == NULL)))
733         return(no_pw);
734
735     /* If --get-key file was specified grab the key/password from it.
736     */
737     if (options->get_key_file[0] != 0x0)
738     {
739         pw_ptr = getpasswd_file(options->get_key_file, options->spa_server_str);
740     }
741     else if (options->use_gpg)
742     {
743         if(crypt_op == CRYPT_OP_DECRYPT)
744             pw_ptr = getpasswd("Enter passphrase for secret key: ");
745         else if(options->gpg_signer_key && strlen(options->gpg_signer_key))
746             pw_ptr = getpasswd("Enter passphrase for signing: ");
747         else
748             pw_ptr = no_pw;
749     }
750     else
751     {
752         if(crypt_op == CRYPT_OP_ENCRYPT)
753             pw_ptr = getpasswd("Enter encryption password: ");
754         else if(crypt_op == CRYPT_OP_DECRYPT)
755             pw_ptr = getpasswd("Enter decryption password: ");
756         else
757             pw_ptr = getpasswd("Enter password: ");
758     }
759
760     /* Empty password is allowed, NULL password is not.
761     */
762     if (pw_ptr == NULL)
763     {
764         fprintf(stderr, "Received no password data, exiting.\n");
765         exit(EXIT_FAILURE);
766     }
767
768     return pw_ptr;
769 }
770
771 /* Display an FKO error message.
772 */
773 void
774 errmsg(const char *msg, const int err) {
775     fprintf(stderr, "%s: %s: Error %i - %s\n",
776         MY_NAME, msg, err, fko_errstr(err));
777 }
778
779 /* Show the fields of the FKO context.
780 */
781 static void
782 display_ctx(fko_ctx_t ctx)
783 {
784     char       *rand_val        = NULL;
785     char       *username        = NULL;
786     char       *version         = NULL;
787     char       *spa_message     = NULL;
788     char       *nat_access      = NULL;
789     char       *server_auth     = NULL;
790     char       *enc_data        = NULL;
791     char       *spa_digest      = NULL;
792     char       *spa_data        = NULL;
793
794     time_t      timestamp       = 0;
795     short       msg_type        = -1;
796     short       digest_type     = -1;
797     int         client_timeout  = -1;
798
799     /* Should be checking return values, but this is temp code. --DSS
800     */
801     fko_get_rand_value(ctx, &rand_val);
802     fko_get_username(ctx, &username);
803     fko_get_timestamp(ctx, &timestamp);
804     fko_get_version(ctx, &version);
805     fko_get_spa_message_type(ctx, &msg_type);
806     fko_get_spa_message(ctx, &spa_message);
807     fko_get_spa_nat_access(ctx, &nat_access);
808     fko_get_spa_server_auth(ctx, &server_auth);
809     fko_get_spa_client_timeout(ctx, &client_timeout);
810     fko_get_spa_digest_type(ctx, &digest_type);
811     fko_get_encoded_data(ctx, &enc_data);
812     fko_get_spa_digest(ctx, &spa_digest);
813     fko_get_spa_data(ctx, &spa_data);
814
815     printf("\nFKO Field Values:\n=================\n\n");
816     printf("   Random Value: %s\n", rand_val == NULL ? "<NULL>" : rand_val);
817     printf("       Username: %s\n", username == NULL ? "<NULL>" : username);
818     printf("      Timestamp: %u\n", (unsigned int) timestamp);
819     printf("    FKO Version: %s\n", version == NULL ? "<NULL>" : version);
820     printf("   Message Type: %i\n", msg_type);
821     printf(" Message String: %s\n", spa_message == NULL ? "<NULL>" : spa_message);
822     printf("     Nat Access: %s\n", nat_access == NULL ? "<NULL>" : nat_access);
823     printf("    Server Auth: %s\n", server_auth == NULL ? "<NULL>" : server_auth);
824     printf(" Client Timeout: %u\n", client_timeout);
825     printf("    Digest Type: %u\n", digest_type);
826     printf("\n   Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data);
827     printf("\nSPA Data Digest: %s\n", spa_digest == NULL ? "<NULL>" : spa_digest);
828     printf("\nFinal Packed/Encrypted/Encoded Data:\n\n%s\n\n", spa_data);
829 }
830
831 /***EOF***/