Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / src / danetool.c
1 /*
2  * Copyright (C) 2012 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuTLS.
5  *
6  * GnuTLS is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuTLS is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  * In addition, as a special exception, the copyright holders give
21  * permission to link the code of portions of this program with the
22  * OpenSSL library under certain conditions as described in each
23  * individual source file, and distribute linked combinations including
24  * the two.
25  * 
26  * You must obey the GNU General Public License in all respects for all
27  * of the code used other than OpenSSL. If you modify file(s) with this
28  * exception, you may extend this exception to your version of the
29  * file(s), but you are not obligated to do so. If you do not wish to do
30  * so, delete this exception statement from your version. If you delete
31  * this exception statement from all source files in the program, then
32  * also delete it here.
33  */
34
35 #include <config.h>
36
37 #include <gnutls/gnutls.h>
38 #include <gnutls/x509.h>
39 #include <gnutls/openpgp.h>
40 #include <gnutls/pkcs12.h>
41 #include <gnutls/pkcs11.h>
42 #include <gnutls/abstract.h>
43 #include <gnutls/crypto.h>
44
45 #ifdef HAVE_DANE
46 #include <gnutls/dane.h>
47 #endif
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <ctype.h>
53 #include <time.h>
54 #include <unistd.h>
55 #include <errno.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59
60 /* Gnulib portability files. */
61 #include <read-file.h>
62 #include <minmax.h>
63
64 #include <common.h>
65 #include "danetool-args.h"
66 #include "certtool-common.h"
67 #include "socket.h"
68
69 static const char* obtain_cert(const char *hostname, const char *proto, unsigned int port,
70                                 const char *app_proto, unsigned quiet);
71 static void cmd_parser(int argc, char **argv);
72 static void dane_info(const char *host, const char *proto,
73                       unsigned int port, unsigned int ca,
74                       unsigned int domain, common_info_st * cinfo);
75
76 static void dane_check(const char *host, const char *proto,
77                        unsigned int port, common_info_st * cinfo);
78
79 FILE *outfile;
80 static gnutls_digest_algorithm_t default_dig;
81
82 /* non interactive operation if set
83  */
84 int batch = 0;
85 int ask_pass = 0;
86
87
88 static void tls_log_func(int level, const char *str)
89 {
90         fprintf(stderr, "|<%d>| %s", level, str);
91 }
92
93 int main(int argc, char **argv)
94 {
95         fix_lbuffer(0);
96         cmd_parser(argc, argv);
97
98         return 0;
99 }
100
101
102 static void cmd_parser(int argc, char **argv)
103 {
104         int ret, privkey_op = 0;
105         common_info_st cinfo;
106         const char *proto = "tcp";
107         unsigned int port = 443;
108
109         optionProcess(&danetoolOptions, argc, argv);
110
111         if (HAVE_OPT(OUTFILE)) {
112                 outfile = safe_open_rw(OPT_ARG(OUTFILE), privkey_op);
113                 if (outfile == NULL) {
114                         fprintf(stderr, "%s", OPT_ARG(OUTFILE));
115                         exit(1);
116                 }
117         } else
118                 outfile = stdout;
119
120         default_dig = GNUTLS_DIG_UNKNOWN;
121         if (HAVE_OPT(HASH)) {
122                 if (strcasecmp(OPT_ARG(HASH), "md5") == 0) {
123                         fprintf(stderr,
124                                 "Warning: MD5 is broken, and should not be used any more for digital signatures.\n");
125                         default_dig = GNUTLS_DIG_MD5;
126                 } else if (strcasecmp(OPT_ARG(HASH), "sha1") == 0)
127                         default_dig = GNUTLS_DIG_SHA1;
128                 else if (strcasecmp(OPT_ARG(HASH), "sha256") == 0)
129                         default_dig = GNUTLS_DIG_SHA256;
130                 else if (strcasecmp(OPT_ARG(HASH), "sha224") == 0)
131                         default_dig = GNUTLS_DIG_SHA224;
132                 else if (strcasecmp(OPT_ARG(HASH), "sha384") == 0)
133                         default_dig = GNUTLS_DIG_SHA384;
134                 else if (strcasecmp(OPT_ARG(HASH), "sha512") == 0)
135                         default_dig = GNUTLS_DIG_SHA512;
136                 else if (strcasecmp(OPT_ARG(HASH), "rmd160") == 0)
137                         default_dig = GNUTLS_DIG_RMD160;
138                 else {
139                         fprintf(stderr, "invalid hash: %s", OPT_ARG(HASH));
140                         exit(1);
141                 }
142         }
143
144         gnutls_global_set_log_function(tls_log_func);
145
146         if (HAVE_OPT(DEBUG)) {
147                 gnutls_global_set_log_level(OPT_VALUE_DEBUG);
148                 printf("Setting log level to %d\n", (int) OPT_VALUE_DEBUG);
149         }
150
151         if ((ret = gnutls_global_init()) < 0) {
152                 fprintf(stderr, "global_init: %s", gnutls_strerror(ret));
153                 exit(1);
154         }
155 #ifdef ENABLE_PKCS11
156         pkcs11_common(NULL);
157 #endif
158
159         memset(&cinfo, 0, sizeof(cinfo));
160
161         if (HAVE_OPT(INDER) || HAVE_OPT(INRAW))
162                 cinfo.incert_format = GNUTLS_X509_FMT_DER;
163         else
164                 cinfo.incert_format = GNUTLS_X509_FMT_PEM;
165
166         if (HAVE_OPT(VERBOSE))
167                 cinfo.verbose = 1;
168
169         if (HAVE_OPT(LOAD_PUBKEY))
170                 cinfo.pubkey = OPT_ARG(LOAD_PUBKEY);
171
172         if (HAVE_OPT(LOAD_CERTIFICATE))
173                 cinfo.cert = OPT_ARG(LOAD_CERTIFICATE);
174
175         if (HAVE_OPT(PORT))
176                 port = OPT_VALUE_PORT;
177         if (HAVE_OPT(PROTO))
178                 proto = OPT_ARG(PROTO);
179
180         if (HAVE_OPT(TLSA_RR))
181                 dane_info(OPT_ARG(HOST), proto, port,
182                           HAVE_OPT(CA), ENABLED_OPT(DOMAIN), &cinfo);
183         else if (HAVE_OPT(CHECK))
184                 dane_check(OPT_ARG(CHECK), proto, port, &cinfo);
185         else
186                 USAGE(1);
187
188         fclose(outfile);
189
190 #ifdef ENABLE_PKCS11
191         gnutls_pkcs11_deinit();
192 #endif
193         gnutls_global_deinit();
194 }
195
196 #define MAX_CLIST_SIZE 32
197 static void dane_check(const char *host, const char *proto,
198                        unsigned int port, common_info_st * cinfo)
199 {
200 #ifdef HAVE_DANE
201         dane_state_t s;
202         dane_query_t q;
203         int ret, retcode = 1;
204         unsigned entries;
205         unsigned int flags = DANE_F_IGNORE_LOCAL_RESOLVER, i;
206         unsigned int usage, type, match;
207         gnutls_datum_t data, file;
208         size_t size;
209         unsigned del = 0;
210         unsigned vflags = DANE_VFLAG_FAIL_IF_NOT_CHECKED;
211         const char *str;
212         gnutls_x509_crt_t *clist = NULL;
213         unsigned int clist_size = 0;
214         gnutls_datum_t certs[MAX_CLIST_SIZE];
215
216         if (ENABLED_OPT(LOCAL_DNS))
217                 flags = 0;
218
219         if (HAVE_OPT(INSECURE))
220                 flags |= DANE_F_INSECURE;
221
222         if (HAVE_OPT(CHECK_EE))
223                 vflags |= DANE_VFLAG_ONLY_CHECK_EE_USAGE;
224
225         if (HAVE_OPT(CHECK_CA))
226                 vflags |= DANE_VFLAG_ONLY_CHECK_CA_USAGE;
227
228         if (!cinfo->cert) {
229                 const char *app_proto = NULL;
230                 if (HAVE_OPT(APP_PROTO))
231                         app_proto = OPT_ARG(APP_PROTO);
232
233                 cinfo->cert = obtain_cert(host, proto, port, app_proto, HAVE_OPT(QUIET));
234                 del = 1;
235         }
236
237         if (!HAVE_OPT(QUIET))
238                 fprintf(stderr, "Querying DNS for %s (%s:%d)...\n", host, proto, port);
239         ret = dane_state_init(&s, flags);
240         if (ret < 0) {
241                 fprintf(stderr, "dane_state_init: %s\n",
242                         dane_strerror(ret));
243                 retcode = 1;
244                 goto error;
245         }
246
247         if (HAVE_OPT(DLV)) {
248                 ret = dane_state_set_dlv_file(s, OPT_ARG(DLV));
249                 if (ret < 0) {
250                         fprintf(stderr, "dane_state_set_dlv_file: %s\n",
251                                 dane_strerror(ret));
252                         retcode = 1;
253                         goto error;
254                 }
255         }
256
257         ret = dane_query_tlsa(s, &q, host, proto, port);
258         if (ret < 0) {
259                 fprintf(stderr, "dane_query_tlsa: %s\n",
260                         dane_strerror(ret));
261                 retcode = 1;
262                 goto error;
263         }
264
265         if (ENABLED_OPT(PRINT_RAW)) {
266                 unsigned entries;
267                 gnutls_datum_t t;
268                 char **dane_data;
269                 int *dane_data_len;
270                 int secure;
271                 int bogus;
272
273                 ret = dane_query_to_raw_tlsa(q, &entries, &dane_data,
274                         &dane_data_len, &secure, &bogus);
275                 if (ret < 0) {
276                         fprintf(stderr, "dane_query_to_raw_tlsa: %s\n",
277                                 dane_strerror(ret));
278                         retcode = 1;
279                         goto error;
280                 }
281
282                 for (i=0;i<entries;i++) {
283                         char *str;
284                         size_t str_size;
285                         t.data = (void*)dane_data[i];
286                         t.size = dane_data_len[i];
287
288                         str_size = t.size * 2 + 1;
289                         str = gnutls_malloc(str_size);
290
291                         ret = gnutls_hex_encode(&t, str, &str_size);
292                         if (ret < 0) {
293                                 fprintf(stderr, "gnutls_hex_encode: %s\n",
294                                         dane_strerror(ret));
295                                 retcode = 1;
296                                 goto error;
297                         }
298                         fprintf(outfile, "[%u]: %s\n", i, str);
299                         gnutls_free(str);
300                 }
301                 fprintf(outfile, "\n");
302         }
303
304         if (cinfo->cert) {
305                 ret = gnutls_load_file(cinfo->cert, &file);
306                 if (ret < 0) {
307                         fprintf(stderr, "gnutls_load_file: %s\n",
308                                 gnutls_strerror(ret));
309                         retcode = 1;
310                         goto error;
311                 }
312
313                 ret =
314                     gnutls_x509_crt_list_import2(&clist,
315                                                  &clist_size,
316                                                  &file,
317                                                  cinfo->
318                                                  incert_format, 0);
319                 if (ret < 0) {
320                         fprintf(stderr,
321                                 "gnutls_x509_crt_list_import2: %s\n",
322                                 gnutls_strerror(ret));
323                         retcode = 1;
324                         goto error;
325                 }
326
327                 if (clist_size > 0) {
328                         for (i = 0; i < MIN(MAX_CLIST_SIZE,clist_size); i++) {
329                                 ret =
330                                     gnutls_x509_crt_export2(clist
331                                                             [i],
332                                                             GNUTLS_X509_FMT_DER,
333                                                             &certs
334                                                             [i]);
335                                 if (ret < 0) {
336                                         fprintf(stderr,
337                                                 "gnutls_x509_crt_export2: %s\n",
338                                                 gnutls_strerror
339                                                 (ret));
340                                         retcode = 1;
341                                         goto error;
342                                 }
343                         }
344                 }
345         }
346
347         entries = dane_query_entries(q);
348         for (i = 0; i < entries; i++) {
349                 ret = dane_query_data(q, i, &usage, &type, &match, &data);
350                 if (ret < 0) {
351                         fprintf(stderr, "dane_query_data: %s\n",
352                                 dane_strerror(ret));
353                         retcode = 1;
354                         goto error;
355                 }
356
357                 size = lbuffer_size;
358                 ret = gnutls_hex_encode(&data, (void *) lbuffer, &size);
359                 if (ret < 0) {
360                         fprintf(stderr, "gnutls_hex_encode: %s\n",
361                                 dane_strerror(ret));
362                         retcode = 1;
363                         goto error;
364                 }
365
366                 if (entries > 1 && !HAVE_OPT(QUIET))
367                         fprintf(outfile, "\n==== Entry %d ====\n", i + 1);
368
369                 fprintf(outfile,
370                         "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n",
371                         port, proto, host, usage, type, match, lbuffer);
372
373                 if (!HAVE_OPT(QUIET)) {
374                         str = dane_cert_usage_name(usage);
375                         if (str == NULL) str= "Unknown";
376                         fprintf(outfile, "Certificate usage: %s (%.2x)\n", str, usage);
377
378                         str = dane_cert_type_name(type);
379                         if (str == NULL) str= "Unknown";
380                         fprintf(outfile, "Certificate type:  %s (%.2x)\n", str, type);
381
382                         str = dane_match_type_name(match);
383                         if (str == NULL) str= "Unknown";
384                         fprintf(outfile, "Contents:          %s (%.2x)\n", str, match);
385                         fprintf(outfile, "Data:              %s\n", lbuffer);
386                 }
387
388                 /* Verify the DANE data */
389                 if (cinfo->cert) {
390                         unsigned int status;
391                         gnutls_datum_t out;
392
393                         ret =
394                             dane_verify_crt(s, certs, clist_size,
395                                             GNUTLS_CRT_X509, host,
396                                             proto, port, 0, vflags,
397                                             &status);
398                         if (ret < 0) {
399                                 fprintf(stderr,
400                                         "dane_verify_crt: %s\n",
401                                         dane_strerror(ret));
402                                 retcode = 1;
403                                 goto error;
404                         }
405
406                         ret =
407                             dane_verification_status_print(status,
408                                                            &out,
409                                                            0);
410                         if (ret < 0) {
411                                 fprintf(stderr,
412                                         "dane_verification_status_print: %s\n",
413                                         dane_strerror(ret));
414                                 retcode = 1;
415                                 goto error;
416                         }
417
418                         if (!HAVE_OPT(QUIET))
419                                 fprintf(outfile, "\nVerification: %s\n", out.data);
420                         gnutls_free(out.data);
421
422                         /* if there is at least one correct accept */
423                         if (status == 0)
424                                 retcode = 0;
425                 } else {
426                         fprintf(stderr,
427                                 "\nCertificate could not be obtained. You can explicitly load the certificate using --load-certificate.\n");
428                 }
429         }
430
431         if (clist_size > 0) {
432                 for (i = 0; i < clist_size; i++) {
433                         gnutls_free(certs[i].data);
434                         gnutls_x509_crt_deinit(clist[i]);
435                 }
436                 gnutls_free(clist);
437         }
438
439
440
441         dane_query_deinit(q);
442         dane_state_deinit(s);
443
444  error:
445         if (del != 0 && cinfo->cert) {
446                 remove(cinfo->cert);
447         }
448
449         exit(retcode);
450 #else
451         fprintf(stderr,
452                 "This functionality is disabled (GnuTLS was not compiled with support for DANE).\n");
453         return;
454 #endif
455 }
456
457 static void dane_info(const char *host, const char *proto,
458                       unsigned int port, unsigned int ca,
459                       unsigned int domain, common_info_st * cinfo)
460 {
461         gnutls_pubkey_t pubkey;
462         gnutls_x509_crt_t crt;
463         unsigned char digest[64];
464         gnutls_datum_t t;
465         int ret;
466         unsigned int usage, selector, type;
467         size_t size;
468
469         if (proto == NULL)
470                 proto = "tcp";
471         if (port == 0)
472                 port = 443;
473
474         crt = load_cert(0, cinfo);
475         if (crt != NULL && HAVE_OPT(X509)) {
476                 selector = 0;   /* X.509 */
477
478                 size = lbuffer_size;
479                 ret =
480                     gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER,
481                                            lbuffer, &size);
482                 if (ret < 0) {
483                         fprintf(stderr, "export error: %s\n",
484                                 gnutls_strerror(ret));
485                         exit(1);
486                 }
487
488                 gnutls_x509_crt_deinit(crt);
489         } else {                /* use public key only */
490
491                 selector = 1;
492
493                 ret = gnutls_pubkey_init(&pubkey);
494                 if (ret < 0) {
495                         fprintf(stderr, "pubkey_init: %s\n",
496                                 gnutls_strerror(ret));
497                         exit(1);
498                 }
499
500                 if (crt != NULL) {
501
502                         ret = gnutls_pubkey_import_x509(pubkey, crt, 0);
503                         if (ret < 0) {
504                                 fprintf(stderr, "pubkey_import_x509: %s\n",
505                                         gnutls_strerror(ret));
506                                 exit(1);
507                         }
508
509                         size = lbuffer_size;
510                         ret =
511                             gnutls_pubkey_export(pubkey,
512                                                  GNUTLS_X509_FMT_DER,
513                                                  lbuffer, &size);
514                         if (ret < 0) {
515                                 fprintf(stderr, "pubkey_export: %s\n",
516                                         gnutls_strerror(ret));
517                                 exit(1);
518                         }
519
520                         gnutls_x509_crt_deinit(crt);
521                 } else {
522                         pubkey = load_pubkey(1, cinfo);
523
524                         size = lbuffer_size;
525                         ret =
526                             gnutls_pubkey_export(pubkey,
527                                                  GNUTLS_X509_FMT_DER,
528                                                  lbuffer, &size);
529                         if (ret < 0) {
530                                 fprintf(stderr, "export error: %s\n",
531                                         gnutls_strerror(ret));
532                                 exit(1);
533                         }
534                 }
535
536                 gnutls_pubkey_deinit(pubkey);
537         }
538
539         if (default_dig != GNUTLS_DIG_SHA256
540             && default_dig != GNUTLS_DIG_SHA512) {
541                 if (default_dig != GNUTLS_DIG_UNKNOWN)
542                         fprintf(stderr,
543                                 "Unsupported digest. Assuming SHA256.\n");
544                 default_dig = GNUTLS_DIG_SHA256;
545         }
546
547         ret = gnutls_hash_fast(default_dig, lbuffer, size, digest);
548         if (ret < 0) {
549                 fprintf(stderr, "hash error: %s\n", gnutls_strerror(ret));
550                 exit(1);
551         }
552
553         if (default_dig == GNUTLS_DIG_SHA256)
554                 type = 1;
555         else
556                 type = 2;
557
558         /* DANE certificate classification crap */
559         if (domain == 0) {
560                 if (ca)
561                         usage = 0;
562                 else
563                         usage = 1;
564         } else {
565                 if (ca)
566                         usage = 2;
567                 else
568                         usage = 3;
569         }
570
571         t.data = digest;
572         t.size = gnutls_hash_get_len(default_dig);
573
574         size = lbuffer_size;
575         ret = gnutls_hex_encode(&t, (void *) lbuffer, &size);
576         if (ret < 0) {
577                 fprintf(stderr, "hex encode error: %s\n",
578                         gnutls_strerror(ret));
579                 exit(1);
580         }
581
582         fprintf(outfile, "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n",
583                 port, proto, host, usage, selector, type, lbuffer);
584
585 }
586
587
588 struct priv_st {
589         int fd;
590         int found;
591 };
592
593 #ifdef HAVE_DANE
594 static int cert_callback(gnutls_session_t session)
595 {
596         const gnutls_datum_t *cert_list;
597         unsigned int cert_list_size = 0;
598         int ret;
599         unsigned i;
600         gnutls_datum_t t;
601         struct priv_st *priv;
602
603         cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
604         if (cert_list_size == 0) {
605                 fprintf(stderr, "no certificates sent by server!\n");
606                 return -1;
607         }
608
609         priv = gnutls_session_get_ptr(session);
610
611         for (i=0;i<cert_list_size;i++) {
612                 ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &cert_list[i], &t);
613                 if (ret < 0) {
614                         fprintf(stderr, "error[%d]: %s\n", __LINE__,
615                                 gnutls_strerror(ret));
616                         exit(1);
617                 }
618
619                 write(priv->fd, t.data, t.size);
620                 gnutls_free(t.data);
621         }
622         priv->found = 1;
623
624         return -1;
625 }
626
627 static int get_cert(socket_st *hd, const char *hostname, unsigned udp, int fd)
628 {
629         gnutls_certificate_credentials_t xcred;
630         gnutls_session_t session;
631         int ret;
632         struct priv_st priv;
633
634         priv.found = 0;
635         priv.fd = fd;
636
637         ret = gnutls_certificate_allocate_credentials(&xcred);
638         if (ret < 0) {
639                 fprintf(stderr, "error[%d]: %s\n", __LINE__,
640                         gnutls_strerror(ret));
641                 exit(1);
642         }
643         gnutls_certificate_set_verify_function(xcred, cert_callback);
644
645         ret = gnutls_init(&session, (udp?GNUTLS_DATAGRAM:0)|GNUTLS_CLIENT);
646         if (ret < 0) {
647                 fprintf(stderr, "error[%d]: %s\n", __LINE__,
648                         gnutls_strerror(ret));
649                 exit(1);
650         }
651         gnutls_session_set_ptr(session, &priv);
652         gnutls_transport_set_int(session, hd->fd);
653
654         gnutls_set_default_priority(session);
655         if (hostname && is_ip(hostname)==0) {
656                 gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
657         }
658         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
659
660         do {
661                 ret = gnutls_handshake(session);
662         } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_WARNING_ALERT_RECEIVED);
663         /* we don't care on the result */
664
665         gnutls_deinit(session);
666         gnutls_certificate_free_credentials(xcred);
667
668         if (priv.found == 0)
669                 return -1;
670
671         return 0;
672 }
673
674 static const char *obtain_cert(const char *hostname, const char *proto, unsigned port,
675                                 const char *app_proto, unsigned quiet)
676 {
677         socket_st hd;
678         char txt_port[16];
679         unsigned udp = 0;
680         static char tmpfile[32];
681         int fd, ret;
682         const char *str = "Obtaining certificate from";
683         const char *service;
684
685         if (strcmp(proto, "udp") == 0)
686                 udp = 1;
687         else if (strcmp(proto, "tcp") != 0) {
688                 /* we cannot handle this protocol */
689                 return NULL;
690         }
691
692         strcpy(tmpfile, "danetool-certXXXXXX");
693
694         sockets_init();
695         snprintf(txt_port, sizeof(txt_port), "%u", port);
696
697         if (quiet)
698                 str = NULL;
699         service = port_to_service(txt_port, proto);
700         socket_open(&hd, hostname, service, udp, str);
701
702         if (app_proto == NULL) app_proto = service;
703         socket_starttls(&hd, app_proto);
704
705         umask(066);
706         fd = mkstemp(tmpfile);
707         if (fd == -1) {
708                 int e = errno;
709                 fprintf(stderr, "error[%d]: %s\n", __LINE__,
710                         strerror(e));
711                 exit(1);
712         }
713
714         ret = get_cert(&hd, hostname, udp, fd);
715         close(fd);
716
717         socket_bye(&hd);
718
719         if (ret == -1)
720                 return NULL;
721         else
722                 return tmpfile;
723 }
724 #endif