• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  *
24  ***************************************************************************/
25 
26 /* CCSID API wrappers for OS/400. */
27 
28 #include <iconv.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <errno.h>
33 #include <stdarg.h>
34 
35 #pragma enum(int)
36 
37 #include "curl.h"
38 #include "mprintf.h"
39 #include "slist.h"
40 #include "urldata.h"
41 #include "url.h"
42 #include "setopt.h"
43 #include "getinfo.h"
44 #include "ccsidcurl.h"
45 
46 #include "os400sys.h"
47 
48 #ifndef SIZE_MAX
49 #define SIZE_MAX        ((size_t) ~0)   /* Is unsigned on OS/400. */
50 #endif
51 
52 
53 #define ASCII_CCSID     819     /* Use ISO-8859-1 as ASCII. */
54 #define NOCONV_CCSID    65535   /* No conversion. */
55 #define ICONV_ID_SIZE   32      /* Size of iconv_open() code identifier. */
56 #define ICONV_OPEN_ERROR(t)     ((t).return_value == -1)
57 
58 #define ALLOC_GRANULE   8       /* Alloc. granule for curl_formadd_ccsid(). */
59 
60 
61 static void
makeOS400IconvCode(char buf[ICONV_ID_SIZE],unsigned int ccsid)62 makeOS400IconvCode(char buf[ICONV_ID_SIZE], unsigned int ccsid)
63 {
64   /**
65   *** Convert a CCSID to the corresponding IBM iconv_open() character
66   ***  code identifier.
67   ***  This code is specific to the OS400 implementation of the iconv library.
68   ***  CCSID 65535 (no conversion) is replaced by the ASCII CCSID.
69   ***  CCSID 0 is interpreted by the OS400 as the job's CCSID.
70   **/
71 
72   ccsid &= 0xFFFF;
73 
74   if(ccsid == NOCONV_CCSID)
75     ccsid = ASCII_CCSID;
76 
77   memset(buf, 0, ICONV_ID_SIZE);
78   curl_msprintf(buf, "IBMCCSID%05u0000000", ccsid);
79 }
80 
81 
82 static iconv_t
iconv_open_CCSID(unsigned int ccsidout,unsigned int ccsidin,unsigned int cstr)83 iconv_open_CCSID(unsigned int ccsidout, unsigned int ccsidin,
84                  unsigned int cstr)
85 {
86   char fromcode[ICONV_ID_SIZE];
87   char tocode[ICONV_ID_SIZE];
88 
89   /**
90   ***  Like iconv_open(), but character codes are given as CCSIDs.
91   ***  If `cstr' is non-zero, conversion is set up to stop whenever a
92   ***   null character is encountered.
93   ***  See iconv_open() IBM description in "National Language Support API".
94   **/
95 
96   makeOS400IconvCode(fromcode, ccsidin);
97   makeOS400IconvCode(tocode, ccsidout);
98   memset(tocode + 13, 0, sizeof(tocode) - 13);   /* Dest. code id format. */
99 
100   if(cstr)
101     fromcode[18] = '1';                         /* Set null-terminator flag. */
102 
103   return iconv_open(tocode, fromcode);
104 }
105 
106 
107 static int
convert(char * d,size_t dlen,int dccsid,const char * s,int slen,int sccsid)108 convert(char *d, size_t dlen, int dccsid,
109         const char *s, int slen, int sccsid)
110 {
111   int i;
112   iconv_t cd;
113   size_t lslen;
114 
115   /**
116   ***  Convert `sccsid'-coded `slen'-data bytes at `s' into `dccsid'-coded
117   ***   data stored in the `dlen'-byte buffer at `d'.
118   ***  If `slen' < 0, source string is null-terminated.
119   ***  CCSID 65535 (no conversion) is replaced by the ASCII CCSID.
120   ***  Return the converted destination byte count, or -1 if error.
121   **/
122 
123   if(sccsid == 65535)
124     sccsid = ASCII_CCSID;
125 
126   if(dccsid == 65535)
127     dccsid = ASCII_CCSID;
128 
129   if(sccsid == dccsid) {
130     lslen = slen >= 0? slen: strlen(s) + 1;
131     i = lslen < dlen? lslen: dlen;
132 
133     if(s != d && i > 0)
134       memcpy(d, s, i);
135 
136     return i;
137     }
138 
139   if(slen < 0) {
140     lslen = 0;
141     cd = iconv_open_CCSID(dccsid, sccsid, 1);
142     }
143   else {
144     lslen = (size_t) slen;
145     cd = iconv_open_CCSID(dccsid, sccsid, 0);
146     }
147 
148   if(ICONV_OPEN_ERROR(cd))
149     return -1;
150 
151   i = dlen;
152 
153   if((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0)
154     i = -1;
155   else
156     i -= dlen;
157 
158   iconv_close(cd);
159   return i;
160 }
161 
162 
dynconvert(int dccsid,const char * s,int slen,int sccsid)163 static char *dynconvert(int dccsid, const char *s, int slen, int sccsid)
164 {
165   char *d;
166   char *cp;
167   size_t dlen;
168   int l;
169   static const char nullbyte = 0;
170 
171   /* Like convert, but the destination is allocated and returned. */
172 
173   dlen = (size_t) (slen < 0? strlen(s): slen) + 1;
174   dlen *= MAX_CONV_EXPANSION;           /* Allow some expansion. */
175   d = malloc(dlen);
176 
177   if(!d)
178     return (char *) NULL;
179 
180   l = convert(d, dlen, dccsid, s, slen, sccsid);
181 
182   if(l < 0) {
183     free(d);
184     return (char *) NULL;
185     }
186 
187   if(slen < 0) {
188     /* Need to null-terminate even when source length is given.
189        Since destination code size is unknown, use a conversion to generate
190        terminator. */
191 
192     int l2 = convert(d + l, dlen - l, dccsid, &nullbyte, -1, ASCII_CCSID);
193 
194     if(l2 < 0) {
195       free(d);
196       return (char *) NULL;
197       }
198 
199     l += l2;
200     }
201 
202   if((size_t) l < dlen) {
203     cp = realloc(d, l);         /* Shorten to minimum needed. */
204 
205     if(cp)
206       d = cp;
207     }
208 
209   return d;
210 }
211 
212 
213 static struct curl_slist *
slist_convert(int dccsid,struct curl_slist * from,int sccsid)214 slist_convert(int dccsid, struct curl_slist *from, int sccsid)
215 {
216   struct curl_slist *to = (struct curl_slist *) NULL;
217 
218   for(; from; from = from->next) {
219     struct curl_slist *nl;
220     char *cp = dynconvert(dccsid, from->data, -1, sccsid);
221 
222     if(!cp) {
223       curl_slist_free_all(to);
224       return (struct curl_slist *) NULL;
225     }
226     nl = Curl_slist_append_nodup(to, cp);
227     if(!nl) {
228       curl_slist_free_all(to);
229       free(cp);
230       return NULL;
231     }
232     to = nl;
233   }
234   return to;
235 }
236 
237 
curl_version_ccsid(unsigned int ccsid)238 char *curl_version_ccsid(unsigned int ccsid)
239 {
240   int i;
241   char *aversion;
242   char *eversion;
243 
244   aversion = curl_version();
245 
246   if(!aversion)
247     return aversion;
248 
249   i = strlen(aversion) + 1;
250   i *= MAX_CONV_EXPANSION;
251 
252   eversion = Curl_thread_buffer(LK_CURL_VERSION, i);
253   if(!eversion)
254     return (char *) NULL;
255 
256   if(convert(eversion, i, ccsid, aversion, -1, ASCII_CCSID) < 0)
257     return (char *) NULL;
258 
259   return eversion;
260 }
261 
262 
263 char *
curl_easy_escape_ccsid(CURL * handle,const char * string,int length,unsigned int sccsid,unsigned int dccsid)264 curl_easy_escape_ccsid(CURL *handle, const char *string, int length,
265                        unsigned int sccsid, unsigned int dccsid)
266 {
267   char *s;
268   char *d;
269 
270   if(!string) {
271     errno = EINVAL;
272     return (char *) NULL;
273     }
274 
275   s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid);
276 
277   if(!s)
278     return (char *) NULL;
279 
280   d = curl_easy_escape(handle, s, 0);
281   free(s);
282 
283   if(!d)
284     return (char *) NULL;
285 
286   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
287   free(d);
288   return s;
289 }
290 
291 
292 char *
curl_easy_unescape_ccsid(CURL * handle,const char * string,int length,int * outlength,unsigned int sccsid,unsigned int dccsid)293 curl_easy_unescape_ccsid(CURL *handle, const char *string, int length,
294                          int *outlength,
295                          unsigned int sccsid, unsigned int dccsid)
296 {
297   char *s;
298   char *d;
299 
300   if(!string) {
301     errno = EINVAL;
302     return (char *) NULL;
303     }
304 
305   s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid);
306 
307   if(!s)
308     return (char *) NULL;
309 
310   d = curl_easy_unescape(handle, s, 0, outlength);
311   free(s);
312 
313   if(!d)
314     return (char *) NULL;
315 
316   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
317   free(d);
318 
319   if(s && outlength)
320     *outlength = strlen(s);
321 
322   return s;
323 }
324 
325 
326 struct curl_slist *
curl_slist_append_ccsid(struct curl_slist * list,const char * data,unsigned int ccsid)327 curl_slist_append_ccsid(struct curl_slist *list,
328                         const char *data, unsigned int ccsid)
329 {
330   char *s;
331 
332   s = (char *) NULL;
333 
334   if(!data)
335     return curl_slist_append(list, data);
336 
337   s = dynconvert(ASCII_CCSID, data, -1, ccsid);
338 
339   if(!s)
340     return (struct curl_slist *) NULL;
341 
342   list = curl_slist_append(list, s);
343   free(s);
344   return list;
345 }
346 
347 
348 time_t
curl_getdate_ccsid(const char * p,const time_t * unused,unsigned int ccsid)349 curl_getdate_ccsid(const char *p, const time_t *unused, unsigned int ccsid)
350 {
351   char *s;
352   time_t t;
353 
354   if(!p)
355     return curl_getdate(p, unused);
356 
357   s = dynconvert(ASCII_CCSID, p, -1, ccsid);
358 
359   if(!s)
360     return (time_t) -1;
361 
362   t = curl_getdate(s, unused);
363   free(s);
364   return t;
365 }
366 
367 
368 static int
convert_version_info_string(const char ** stringp,char ** bufp,int * left,unsigned int ccsid)369 convert_version_info_string(const char **stringp,
370                             char **bufp, int *left, unsigned int ccsid)
371 {
372   /* Helper for curl_version_info_ccsid(): convert a string if defined.
373      Result is stored in the `*left'-byte buffer at `*bufp'.
374      `*bufp' and `*left' are updated accordingly.
375      Return 0 if ok, else -1. */
376 
377   if(*stringp) {
378     int l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID);
379 
380     if(l <= 0)
381       return -1;
382 
383     *stringp = *bufp;
384     *bufp += l;
385     *left -= l;
386     }
387 
388   return 0;
389 }
390 
391 
392 curl_version_info_data *
curl_version_info_ccsid(CURLversion stamp,unsigned int ccsid)393 curl_version_info_ccsid(CURLversion stamp, unsigned int ccsid)
394 {
395   curl_version_info_data *p;
396   char *cp;
397   int n;
398   int nproto;
399   curl_version_info_data *id;
400   int i;
401   const char **cpp;
402   static const size_t charfields[] = {
403     offsetof(curl_version_info_data, version),
404     offsetof(curl_version_info_data, host),
405     offsetof(curl_version_info_data, ssl_version),
406     offsetof(curl_version_info_data, libz_version),
407     offsetof(curl_version_info_data, ares),
408     offsetof(curl_version_info_data, libidn),
409     offsetof(curl_version_info_data, libssh_version),
410     offsetof(curl_version_info_data, brotli_version),
411     offsetof(curl_version_info_data, nghttp2_version),
412     offsetof(curl_version_info_data, quic_version),
413     offsetof(curl_version_info_data, cainfo),
414     offsetof(curl_version_info_data, capath),
415     offsetof(curl_version_info_data, zstd_version),
416     offsetof(curl_version_info_data, hyper_version),
417     offsetof(curl_version_info_data, gsasl_version)
418   };
419 
420   /* The assertion below is possible, because although the second operand
421      is an enum member, the first is a #define. In that case, the OS/400 C
422      compiler seems to compare string values after substitution. */
423 
424 #if CURLVERSION_NOW != CURLVERSION_TENTH
425 #error curl_version_info_data structure has changed: upgrade this procedure.
426 #endif
427 
428   /* If caller has been compiled with a new version, error. */
429 
430   if(stamp > CURLVERSION_NOW)
431     return (curl_version_info_data *) NULL;
432 
433   p = curl_version_info(stamp);
434 
435   if(!p)
436     return p;
437 
438   /* Measure thread space needed. */
439 
440   n = 0;
441   nproto = 0;
442 
443   if(p->protocols) {
444     while(p->protocols[nproto])
445       n += strlen(p->protocols[nproto++]);
446 
447     n += nproto++;
448     }
449 
450   for(i = 0; i < sizeof(charfields) / sizeof(charfields[0]); i++) {
451     cpp = (const char **) ((char *) p + charfields[i]);
452     if(*cpp)
453       n += strlen(*cpp) + 1;
454   }
455 
456   /* Allocate thread space. */
457 
458   n *= MAX_CONV_EXPANSION;
459 
460   if(nproto)
461     n += nproto * sizeof(const char *);
462 
463   cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n);
464   id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO,
465                                                      sizeof(*id));
466 
467   if(!id || !cp)
468     return (curl_version_info_data *) NULL;
469 
470   /* Copy data and convert strings. */
471 
472   memcpy((char *) id, (char *) p, sizeof(*p));
473 
474   if(id->protocols) {
475     i = nproto * sizeof(id->protocols[0]);
476 
477     id->protocols = (const char * const *) cp;
478     memcpy(cp, (char *) p->protocols, i);
479     cp += i;
480     n -= i;
481 
482     for(i = 0; id->protocols[i]; i++)
483       if(convert_version_info_string(((const char * *) id->protocols) + i,
484                                       &cp, &n, ccsid))
485         return (curl_version_info_data *) NULL;
486   }
487 
488   for(i = 0; i < sizeof(charfields) / sizeof(charfields[0]); i++) {
489     cpp = (const char **) ((char *) p + charfields[i]);
490     if(*cpp && convert_version_info_string(cpp, &cp, &n, ccsid))
491       return (curl_version_info_data *) NULL;
492   }
493 
494   return id;
495 }
496 
497 
498 const char *
curl_easy_strerror_ccsid(CURLcode error,unsigned int ccsid)499 curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid)
500 {
501   int i;
502   const char *s;
503   char *buf;
504 
505   s = curl_easy_strerror(error);
506 
507   if(!s)
508     return s;
509 
510   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
511 
512   buf = Curl_thread_buffer(LK_EASY_STRERROR, i);
513   if(!buf)
514     return (const char *) NULL;
515 
516   if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
517     return (const char *) NULL;
518 
519   return (const char *) buf;
520 }
521 
522 
523 const char *
curl_share_strerror_ccsid(CURLSHcode error,unsigned int ccsid)524 curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid)
525 {
526   int i;
527   const char *s;
528   char *buf;
529 
530   s = curl_share_strerror(error);
531 
532   if(!s)
533     return s;
534 
535   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
536 
537   buf = Curl_thread_buffer(LK_SHARE_STRERROR, i);
538   if(!buf)
539     return (const char *) NULL;
540 
541   if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
542     return (const char *) NULL;
543 
544   return (const char *) buf;
545 }
546 
547 
548 const char *
curl_multi_strerror_ccsid(CURLMcode error,unsigned int ccsid)549 curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid)
550 {
551   int i;
552   const char *s;
553   char *buf;
554 
555   s = curl_multi_strerror(error);
556 
557   if(!s)
558     return s;
559 
560   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
561 
562   buf = Curl_thread_buffer(LK_MULTI_STRERROR, i);
563   if(!buf)
564     return (const char *) NULL;
565 
566   if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
567     return (const char *) NULL;
568 
569   return (const char *) buf;
570 }
571 
572 
573 void
curl_certinfo_free_all(struct curl_certinfo * info)574 curl_certinfo_free_all(struct curl_certinfo *info)
575 {
576   /* Free all memory used by certificate info. */
577   if(info) {
578     if(info->certinfo) {
579       int i;
580 
581       for(i = 0; i < info->num_of_certs; i++)
582         curl_slist_free_all(info->certinfo[i]);
583       free((char *) info->certinfo);
584     }
585     free((char *) info);
586   }
587 }
588 
589 
590 CURLcode
curl_easy_getinfo_ccsid(CURL * curl,CURLINFO info,...)591 curl_easy_getinfo_ccsid(CURL *curl, CURLINFO info, ...)
592 {
593   va_list arg;
594   void *paramp;
595   CURLcode ret;
596   struct Curl_easy *data;
597 
598   /* WARNING: unlike curl_easy_getinfo(), the strings returned by this
599      procedure have to be free'ed. */
600 
601   data = (struct Curl_easy *) curl;
602   va_start(arg, info);
603   paramp = va_arg(arg, void *);
604   ret = Curl_getinfo(data, info, paramp);
605 
606   if(ret == CURLE_OK) {
607     unsigned int ccsid;
608     char **cpp;
609     struct curl_slist **slp;
610     struct curl_certinfo *cipf;
611     struct curl_certinfo *cipt;
612 
613     switch((int) info & CURLINFO_TYPEMASK) {
614 
615     case CURLINFO_STRING:
616       ccsid = va_arg(arg, unsigned int);
617       cpp = (char * *) paramp;
618 
619       if(*cpp) {
620         *cpp = dynconvert(ccsid, *cpp, -1, ASCII_CCSID);
621 
622         if(!*cpp)
623           ret = CURLE_OUT_OF_MEMORY;
624       }
625 
626       break;
627 
628     case CURLINFO_SLIST:
629       ccsid = va_arg(arg, unsigned int);
630       switch(info) {
631       case CURLINFO_CERTINFO:
632         cipf = *(struct curl_certinfo * *) paramp;
633         if(cipf) {
634           cipt = (struct curl_certinfo *) malloc(sizeof(*cipt));
635           if(!cipt)
636             ret = CURLE_OUT_OF_MEMORY;
637           else {
638             cipt->certinfo = (struct curl_slist **)
639               calloc(cipf->num_of_certs +
640                      1, sizeof(struct curl_slist *));
641             if(!cipt->certinfo)
642               ret = CURLE_OUT_OF_MEMORY;
643             else {
644               int i;
645 
646               cipt->num_of_certs = cipf->num_of_certs;
647               for(i = 0; i < cipf->num_of_certs; i++)
648                 if(cipf->certinfo[i])
649                   if(!(cipt->certinfo[i] = slist_convert(ccsid,
650                                                           cipf->certinfo[i],
651                                                           ASCII_CCSID))) {
652                     ret = CURLE_OUT_OF_MEMORY;
653                     break;
654                   }
655               }
656             }
657 
658           if(ret != CURLE_OK) {
659             curl_certinfo_free_all(cipt);
660             cipt = (struct curl_certinfo *) NULL;
661           }
662 
663           *(struct curl_certinfo * *) paramp = cipt;
664         }
665 
666         break;
667 
668       case CURLINFO_TLS_SESSION:
669       case CURLINFO_TLS_SSL_PTR:
670       case CURLINFO_SOCKET:
671         break;
672 
673       default:
674         slp = (struct curl_slist **) paramp;
675         if(*slp) {
676           *slp = slist_convert(ccsid, *slp, ASCII_CCSID);
677           if(!*slp)
678             ret = CURLE_OUT_OF_MEMORY;
679         }
680         break;
681       }
682     }
683   }
684 
685   va_end(arg);
686   return ret;
687 }
688 
689 
690 static int
Curl_is_formadd_string(CURLformoption option)691 Curl_is_formadd_string(CURLformoption option)
692 {
693   switch(option) {
694 
695   case CURLFORM_FILENAME:
696   case CURLFORM_CONTENTTYPE:
697   case CURLFORM_BUFFER:
698   case CURLFORM_FILE:
699   case CURLFORM_FILECONTENT:
700   case CURLFORM_COPYCONTENTS:
701   case CURLFORM_COPYNAME:
702     return 1;
703   }
704 
705   return 0;
706 }
707 
708 
709 static void
Curl_formadd_release_local(struct curl_forms * forms,int nargs,int skip)710 Curl_formadd_release_local(struct curl_forms *forms, int nargs, int skip)
711 {
712   while(nargs--)
713     if(nargs != skip)
714       if(Curl_is_formadd_string(forms[nargs].option))
715         if(forms[nargs].value)
716           free((char *) forms[nargs].value);
717 
718   free((char *) forms);
719 }
720 
721 
722 static int
Curl_formadd_convert(struct curl_forms * forms,int formx,int lengthx,unsigned int ccsid)723 Curl_formadd_convert(struct curl_forms *forms,
724                      int formx, int lengthx, unsigned int ccsid)
725 {
726   int l;
727   char *cp;
728   char *cp2;
729 
730   if(formx < 0 || !forms[formx].value)
731     return 0;
732 
733   if(lengthx >= 0)
734     l = (int) forms[lengthx].value;
735   else
736     l = strlen(forms[formx].value) + 1;
737 
738   cp = malloc(MAX_CONV_EXPANSION * l);
739 
740   if(!cp)
741     return -1;
742 
743   l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID,
744               forms[formx].value, l, ccsid);
745 
746   if(l < 0) {
747     free(cp);
748     return -1;
749     }
750 
751   cp2 = realloc(cp, l);         /* Shorten buffer to the string size. */
752 
753   if(cp2)
754     cp = cp2;
755 
756   forms[formx].value = cp;
757 
758   if(lengthx >= 0)
759     forms[lengthx].value = (char *) l;  /* Update length after conversion. */
760 
761   return l;
762 }
763 
764 
765 CURLFORMcode
curl_formadd_ccsid(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)766 curl_formadd_ccsid(struct curl_httppost **httppost,
767                    struct curl_httppost **last_post, ...)
768 {
769   va_list arg;
770   CURLformoption option;
771   CURLFORMcode result;
772   struct curl_forms *forms;
773   struct curl_forms *lforms;
774   struct curl_forms *tforms;
775   unsigned int lformlen;
776   const char *value;
777   unsigned int ccsid;
778   int nargs;
779   int namex;
780   int namelengthx;
781   int contentx;
782   int lengthx;
783   unsigned int contentccsid;
784   unsigned int nameccsid;
785 
786   /* A single curl_formadd() call cannot be split in several calls to deal
787      with all parameters: the original parameters are thus copied to a local
788      curl_forms array and converted to ASCII when needed.
789      CURLFORM_PTRNAME is processed as if it were CURLFORM_COPYNAME.
790      CURLFORM_COPYNAME and CURLFORM_NAMELENGTH occurrence order in
791      parameters is not defined; for this reason, the actual conversion is
792      delayed to the end of parameter processing. The same applies to
793      CURLFORM_COPYCONTENTS/CURLFORM_CONTENTSLENGTH, but these may appear
794      several times in the parameter list; the problem resides here in knowing
795      which CURLFORM_CONTENTSLENGTH applies to which CURLFORM_COPYCONTENTS and
796      when we can be sure to have both info for conversion: end of parameter
797      list is such a point, but CURLFORM_CONTENTTYPE is also used here as a
798      natural separator between content data definitions; this seems to be
799      in accordance with FormAdd() behavior. */
800 
801   /* Allocate the local curl_forms array. */
802 
803   lformlen = ALLOC_GRANULE;
804   lforms = malloc(lformlen * sizeof(*lforms));
805 
806   if(!lforms)
807     return CURL_FORMADD_MEMORY;
808 
809   /* Process the arguments, copying them into local array, latching conversion
810      indexes and converting when needed. */
811 
812   result = CURL_FORMADD_OK;
813   nargs = 0;
814   contentx = -1;
815   lengthx = -1;
816   namex = -1;
817   namelengthx = -1;
818   forms = (struct curl_forms *) NULL;
819   va_start(arg, last_post);
820 
821   for(;;) {
822     /* Make sure there is still room for an item in local array. */
823 
824     if(nargs >= lformlen) {
825       lformlen += ALLOC_GRANULE;
826       tforms = realloc(lforms, lformlen * sizeof(*lforms));
827 
828       if(!tforms) {
829         result = CURL_FORMADD_MEMORY;
830         break;
831         }
832 
833       lforms = tforms;
834       }
835 
836     /* Get next option. */
837 
838     if(forms) {
839       /* Get option from array. */
840 
841       option = forms->option;
842       value = forms->value;
843       forms++;
844       }
845     else {
846       /* Get option from arguments. */
847 
848       option = va_arg(arg, CURLformoption);
849 
850       if(option == CURLFORM_END)
851         break;
852       }
853 
854     /* Dispatch by option. */
855 
856     switch(option) {
857 
858     case CURLFORM_END:
859       forms = (struct curl_forms *) NULL;       /* Leave array mode. */
860       continue;
861 
862     case CURLFORM_ARRAY:
863       if(!forms) {
864         forms = va_arg(arg, struct curl_forms *);
865         continue;
866         }
867 
868       result = CURL_FORMADD_ILLEGAL_ARRAY;
869       break;
870 
871     case CURLFORM_COPYNAME:
872       option = CURLFORM_PTRNAME;                /* Static for now. */
873 
874     case CURLFORM_PTRNAME:
875       if(namex >= 0)
876         result = CURL_FORMADD_OPTION_TWICE;
877 
878       namex = nargs;
879 
880       if(!forms) {
881         value = va_arg(arg, char *);
882         nameccsid = (unsigned int) va_arg(arg, long);
883         }
884       else {
885         nameccsid = (unsigned int) forms->value;
886         forms++;
887         }
888 
889       break;
890 
891     case CURLFORM_COPYCONTENTS:
892       if(contentx >= 0)
893         result = CURL_FORMADD_OPTION_TWICE;
894 
895       contentx = nargs;
896 
897       if(!forms) {
898         value = va_arg(arg, char *);
899         contentccsid = (unsigned int) va_arg(arg, long);
900         }
901       else {
902         contentccsid = (unsigned int) forms->value;
903         forms++;
904         }
905 
906       break;
907 
908     case CURLFORM_PTRCONTENTS:
909     case CURLFORM_BUFFERPTR:
910       if(!forms)
911         value = va_arg(arg, char *);            /* No conversion. */
912 
913       break;
914 
915     case CURLFORM_CONTENTSLENGTH:
916       lengthx = nargs;
917 
918       if(!forms)
919         value = (char *) va_arg(arg, long);
920 
921       break;
922 
923     case CURLFORM_CONTENTLEN:
924       lengthx = nargs;
925 
926       if(!forms)
927         value = (char *) va_arg(arg, curl_off_t);
928 
929       break;
930 
931     case CURLFORM_NAMELENGTH:
932       namelengthx = nargs;
933 
934       if(!forms)
935         value = (char *) va_arg(arg, long);
936 
937       break;
938 
939     case CURLFORM_BUFFERLENGTH:
940       if(!forms)
941         value = (char *) va_arg(arg, long);
942 
943       break;
944 
945     case CURLFORM_CONTENTHEADER:
946       if(!forms)
947         value = (char *) va_arg(arg, struct curl_slist *);
948 
949       break;
950 
951     case CURLFORM_STREAM:
952       if(!forms)
953         value = (char *) va_arg(arg, void *);
954 
955       break;
956 
957     case CURLFORM_CONTENTTYPE:
958       /* If a previous content has been encountered, convert it now. */
959 
960       if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) {
961         result = CURL_FORMADD_MEMORY;
962         break;
963         }
964 
965       contentx = -1;
966       lengthx = -1;
967       /* Fall into default. */
968 
969     default:
970       /* Must be a convertible string. */
971 
972       if(!Curl_is_formadd_string(option)) {
973         result = CURL_FORMADD_UNKNOWN_OPTION;
974         break;
975         }
976 
977       if(!forms) {
978         value = va_arg(arg, char *);
979         ccsid = (unsigned int) va_arg(arg, long);
980         }
981       else {
982         ccsid = (unsigned int) forms->value;
983         forms++;
984         }
985 
986       /* Do the conversion. */
987 
988       lforms[nargs].value = value;
989 
990       if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) {
991         result = CURL_FORMADD_MEMORY;
992         break;
993         }
994 
995       value = lforms[nargs].value;
996       }
997 
998     if(result != CURL_FORMADD_OK)
999       break;
1000 
1001     lforms[nargs].value = value;
1002     lforms[nargs++].option = option;
1003     }
1004 
1005   va_end(arg);
1006 
1007   /* Convert the name and the last content, now that we know their lengths. */
1008 
1009   if(result == CURL_FORMADD_OK && namex >= 0) {
1010     if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0)
1011       result = CURL_FORMADD_MEMORY;
1012     else
1013       lforms[namex].option = CURLFORM_COPYNAME;         /* Force copy. */
1014     }
1015 
1016   if(result == CURL_FORMADD_OK) {
1017     if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0)
1018       result = CURL_FORMADD_MEMORY;
1019     else
1020       contentx = -1;
1021     }
1022 
1023   /* Do the formadd with our converted parameters. */
1024 
1025   if(result == CURL_FORMADD_OK) {
1026     lforms[nargs].option = CURLFORM_END;
1027     result = curl_formadd(httppost, last_post,
1028                           CURLFORM_ARRAY, lforms, CURLFORM_END);
1029     }
1030 
1031   /* Terminate. */
1032 
1033   Curl_formadd_release_local(lforms, nargs, contentx);
1034   return result;
1035 }
1036 
1037 
1038 struct cfcdata {
1039   curl_formget_callback append;
1040   void *                arg;
1041   unsigned int          ccsid;
1042 };
1043 
1044 
1045 static size_t
Curl_formget_callback_ccsid(void * arg,const char * buf,size_t len)1046 Curl_formget_callback_ccsid(void *arg, const char *buf, size_t len)
1047 {
1048   struct cfcdata *p;
1049   char *b;
1050   int l;
1051   size_t ret;
1052 
1053   p = (struct cfcdata *) arg;
1054 
1055   if((long) len <= 0)
1056     return (*p->append)(p->arg, buf, len);
1057 
1058   b = malloc(MAX_CONV_EXPANSION * len);
1059 
1060   if(!b)
1061     return (size_t) -1;
1062 
1063   l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID);
1064 
1065   if(l < 0) {
1066     free(b);
1067     return (size_t) -1;
1068     }
1069 
1070   ret = (*p->append)(p->arg, b, l);
1071   free(b);
1072   return ret == l? len: -1;
1073 }
1074 
1075 
1076 int
curl_formget_ccsid(struct curl_httppost * form,void * arg,curl_formget_callback append,unsigned int ccsid)1077 curl_formget_ccsid(struct curl_httppost *form, void *arg,
1078                    curl_formget_callback append, unsigned int ccsid)
1079 {
1080   struct cfcdata lcfc;
1081 
1082   lcfc.append = append;
1083   lcfc.arg = arg;
1084   lcfc.ccsid = ccsid;
1085   return curl_formget(form, (void *) &lcfc, Curl_formget_callback_ccsid);
1086 }
1087 
1088 
1089 CURLcode
curl_easy_setopt_ccsid(CURL * curl,CURLoption tag,...)1090 curl_easy_setopt_ccsid(CURL *curl, CURLoption tag, ...)
1091 {
1092   CURLcode result;
1093   va_list arg;
1094   struct Curl_easy *data;
1095   char *s;
1096   char *cp;
1097   unsigned int ccsid;
1098   curl_off_t pfsize;
1099 
1100   data = (struct Curl_easy *) curl;
1101   va_start(arg, tag);
1102 
1103   switch(tag) {
1104 
1105   case CURLOPT_ABSTRACT_UNIX_SOCKET:
1106   case CURLOPT_ALTSVC:
1107   case CURLOPT_AWS_SIGV4:
1108   case CURLOPT_CAINFO:
1109   case CURLOPT_CAPATH:
1110   case CURLOPT_COOKIE:
1111   case CURLOPT_COOKIEFILE:
1112   case CURLOPT_COOKIEJAR:
1113   case CURLOPT_COOKIELIST:
1114   case CURLOPT_CRLFILE:
1115   case CURLOPT_CUSTOMREQUEST:
1116   case CURLOPT_DEFAULT_PROTOCOL:
1117   case CURLOPT_DNS_SERVERS:
1118   case CURLOPT_DNS_INTERFACE:
1119   case CURLOPT_DNS_LOCAL_IP4:
1120   case CURLOPT_DNS_LOCAL_IP6:
1121   case CURLOPT_DOH_URL:
1122   case CURLOPT_EGDSOCKET:
1123   case CURLOPT_ENCODING:
1124   case CURLOPT_FTPPORT:
1125   case CURLOPT_FTP_ACCOUNT:
1126   case CURLOPT_FTP_ALTERNATIVE_TO_USER:
1127   case CURLOPT_HSTS:
1128   case CURLOPT_INTERFACE:
1129   case CURLOPT_ISSUERCERT:
1130   case CURLOPT_KEYPASSWD:
1131   case CURLOPT_KRBLEVEL:
1132   case CURLOPT_LOGIN_OPTIONS:
1133   case CURLOPT_MAIL_AUTH:
1134   case CURLOPT_MAIL_FROM:
1135   case CURLOPT_NETRC_FILE:
1136   case CURLOPT_NOPROXY:
1137   case CURLOPT_PASSWORD:
1138   case CURLOPT_PINNEDPUBLICKEY:
1139   case CURLOPT_PRE_PROXY:
1140   case CURLOPT_PROXY:
1141   case CURLOPT_PROXYPASSWORD:
1142   case CURLOPT_PROXYUSERNAME:
1143   case CURLOPT_PROXYUSERPWD:
1144   case CURLOPT_PROXY_CAINFO:
1145   case CURLOPT_PROXY_CAPATH:
1146   case CURLOPT_PROXY_CRLFILE:
1147   case CURLOPT_PROXY_KEYPASSWD:
1148   case CURLOPT_PROXY_PINNEDPUBLICKEY:
1149   case CURLOPT_PROXY_SERVICE_NAME:
1150   case CURLOPT_PROXY_SSLCERT:
1151   case CURLOPT_PROXY_SSLCERTTYPE:
1152   case CURLOPT_PROXY_SSLKEY:
1153   case CURLOPT_PROXY_SSLKEYTYPE:
1154   case CURLOPT_PROXY_SSL_CIPHER_LIST:
1155   case CURLOPT_PROXY_TLS13_CIPHERS:
1156   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
1157   case CURLOPT_PROXY_TLSAUTH_TYPE:
1158   case CURLOPT_PROXY_TLSAUTH_USERNAME:
1159   case CURLOPT_RANDOM_FILE:
1160   case CURLOPT_RANGE:
1161   case CURLOPT_REFERER:
1162   case CURLOPT_REQUEST_TARGET:
1163   case CURLOPT_RTSP_SESSION_ID:
1164   case CURLOPT_RTSP_STREAM_URI:
1165   case CURLOPT_RTSP_TRANSPORT:
1166   case CURLOPT_SASL_AUTHZID:
1167   case CURLOPT_SERVICE_NAME:
1168   case CURLOPT_SOCKS5_GSSAPI_SERVICE:
1169   case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
1170   case CURLOPT_SSH_KNOWNHOSTS:
1171   case CURLOPT_SSH_PRIVATE_KEYFILE:
1172   case CURLOPT_SSH_PUBLIC_KEYFILE:
1173   case CURLOPT_SSLCERT:
1174   case CURLOPT_SSLCERTTYPE:
1175   case CURLOPT_SSLENGINE:
1176   case CURLOPT_SSLKEY:
1177   case CURLOPT_SSLKEYTYPE:
1178   case CURLOPT_SSL_CIPHER_LIST:
1179   case CURLOPT_SSL_EC_CURVES:
1180   case CURLOPT_TLS13_CIPHERS:
1181   case CURLOPT_TLSAUTH_PASSWORD:
1182   case CURLOPT_TLSAUTH_TYPE:
1183   case CURLOPT_TLSAUTH_USERNAME:
1184   case CURLOPT_UNIX_SOCKET_PATH:
1185   case CURLOPT_URL:
1186   case CURLOPT_USERAGENT:
1187   case CURLOPT_USERNAME:
1188   case CURLOPT_USERPWD:
1189   case CURLOPT_XOAUTH2_BEARER:
1190     s = va_arg(arg, char *);
1191     ccsid = va_arg(arg, unsigned int);
1192 
1193     if(s) {
1194       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
1195 
1196       if(!s) {
1197         result = CURLE_OUT_OF_MEMORY;
1198         break;
1199       }
1200     }
1201 
1202     result = curl_easy_setopt(curl, tag, s);
1203     free(s);
1204     break;
1205 
1206   case CURLOPT_COPYPOSTFIELDS:
1207     /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE
1208        prior to this call. In this case, convert the given byte count and
1209        replace the length according to the conversion result. */
1210     s = va_arg(arg, char *);
1211     ccsid = va_arg(arg, unsigned int);
1212 
1213     pfsize = data->set.postfieldsize;
1214 
1215     if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
1216       result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s);
1217       break;
1218     }
1219 
1220     if(pfsize == -1) {
1221       /* Data is null-terminated. */
1222       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
1223 
1224       if(!s) {
1225         result = CURLE_OUT_OF_MEMORY;
1226         break;
1227         }
1228       }
1229     else {
1230       /* Data length specified. */
1231       size_t len;
1232 
1233       if(pfsize < 0 || pfsize > SIZE_MAX) {
1234         result = CURLE_OUT_OF_MEMORY;
1235         break;
1236       }
1237 
1238       len = pfsize;
1239       pfsize = len * MAX_CONV_EXPANSION;
1240 
1241       if(pfsize > SIZE_MAX)
1242         pfsize = SIZE_MAX;
1243 
1244       cp = malloc(pfsize);
1245 
1246       if(!cp) {
1247         result = CURLE_OUT_OF_MEMORY;
1248         break;
1249       }
1250 
1251       pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid);
1252 
1253       if(pfsize < 0) {
1254         free(cp);
1255         result = CURLE_OUT_OF_MEMORY;
1256         break;
1257       }
1258 
1259       data->set.postfieldsize = pfsize;         /* Replace data size. */
1260       s = cp;
1261     }
1262 
1263     result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s);
1264     data->set.str[STRING_COPYPOSTFIELDS] = s;   /* Give to library. */
1265     break;
1266 
1267   case CURLOPT_ERRORBUFFER:                     /* This is an output buffer. */
1268   default:
1269     result = Curl_vsetopt(curl, tag, arg);
1270     break;
1271   }
1272 
1273   va_end(arg);
1274   return result;
1275 }
1276 
1277 
1278 char *
curl_form_long_value(long value)1279 curl_form_long_value(long value)
1280 {
1281   /* ILE/RPG cannot cast an integer to a pointer. This procedure does it. */
1282 
1283   return (char *) value;
1284 }
1285 
1286 
1287 char *
curl_pushheader_bynum_cssid(struct curl_pushheaders * h,size_t num,unsigned int ccsid)1288 curl_pushheader_bynum_cssid(struct curl_pushheaders *h,
1289                             size_t num, unsigned int ccsid)
1290 {
1291   char *d = (char *) NULL;
1292   char *s = curl_pushheader_bynum(h, num);
1293 
1294   if(s)
1295     d = dynconvert(ccsid, s, -1, ASCII_CCSID);
1296 
1297   return d;
1298 }
1299 
1300 
1301 char *
curl_pushheader_byname_ccsid(struct curl_pushheaders * h,const char * header,unsigned int ccsidin,unsigned int ccsidout)1302 curl_pushheader_byname_ccsid(struct curl_pushheaders *h, const char *header,
1303                              unsigned int ccsidin, unsigned int ccsidout)
1304 {
1305   char *d = (char *) NULL;
1306 
1307   if(header) {
1308     header = dynconvert(ASCII_CCSID, header, -1, ccsidin);
1309 
1310     if(header) {
1311       char *s = curl_pushheader_byname(h, header);
1312       free((char *) header);
1313 
1314       if(s)
1315         d = dynconvert(ccsidout, s, -1, ASCII_CCSID);
1316     }
1317   }
1318 
1319   return d;
1320 }
1321 
1322 static CURLcode
mime_string_call(curl_mimepart * part,const char * string,unsigned int ccsid,CURLcode (* mimefunc)(curl_mimepart * part,const char * string))1323 mime_string_call(curl_mimepart *part, const char *string, unsigned int ccsid,
1324                  CURLcode (*mimefunc)(curl_mimepart *part, const char *string))
1325 {
1326   char *s = (char *) NULL;
1327   CURLcode result;
1328 
1329   if(!string)
1330     return mimefunc(part, string);
1331   s = dynconvert(ASCII_CCSID, string, -1, ccsid);
1332   if(!s)
1333     return CURLE_OUT_OF_MEMORY;
1334 
1335   result = mimefunc(part, s);
1336   free(s);
1337   return result;
1338 }
1339 
1340 CURLcode
curl_mime_name_ccsid(curl_mimepart * part,const char * name,unsigned int ccsid)1341 curl_mime_name_ccsid(curl_mimepart *part, const char *name, unsigned int ccsid)
1342 {
1343   return mime_string_call(part, name, ccsid, curl_mime_name);
1344 }
1345 
1346 CURLcode
curl_mime_filename_ccsid(curl_mimepart * part,const char * filename,unsigned int ccsid)1347 curl_mime_filename_ccsid(curl_mimepart *part,
1348                          const char *filename, unsigned int ccsid)
1349 {
1350   return mime_string_call(part, filename, ccsid, curl_mime_filename);
1351 }
1352 
1353 CURLcode
curl_mime_type_ccsid(curl_mimepart * part,const char * mimetype,unsigned int ccsid)1354 curl_mime_type_ccsid(curl_mimepart *part,
1355                      const char *mimetype, unsigned int ccsid)
1356 {
1357   return mime_string_call(part, mimetype, ccsid, curl_mime_type);
1358 }
1359 
1360 CURLcode
curl_mime_encoder_ccsid(curl_mimepart * part,const char * encoding,unsigned int ccsid)1361 curl_mime_encoder_ccsid(curl_mimepart *part,
1362                        const char *encoding, unsigned int ccsid)
1363 {
1364   return mime_string_call(part, encoding, ccsid, curl_mime_encoder);
1365 }
1366 
1367 CURLcode
curl_mime_filedata_ccsid(curl_mimepart * part,const char * filename,unsigned int ccsid)1368 curl_mime_filedata_ccsid(curl_mimepart *part,
1369                          const char *filename, unsigned int ccsid)
1370 {
1371   return mime_string_call(part, filename, ccsid, curl_mime_filedata);
1372 }
1373 
1374 CURLcode
curl_mime_data_ccsid(curl_mimepart * part,const char * data,size_t datasize,unsigned int ccsid)1375 curl_mime_data_ccsid(curl_mimepart *part,
1376                      const char *data, size_t datasize, unsigned int ccsid)
1377 {
1378   char *s = (char *) NULL;
1379   CURLcode result;
1380 
1381   if(!data)
1382     return curl_mime_data(part, data, datasize);
1383   s = dynconvert(ASCII_CCSID, data, datasize, ccsid);
1384   if(!s)
1385     return CURLE_OUT_OF_MEMORY;
1386 
1387   result = curl_mime_data(part, s, datasize);
1388   free(s);
1389   return result;
1390 }
1391 
1392 CURLUcode
curl_url_get_ccsid(CURLU * handle,CURLUPart what,char ** part,unsigned int flags,unsigned int ccsid)1393 curl_url_get_ccsid(CURLU *handle, CURLUPart what, char **part,
1394                    unsigned int flags, unsigned int ccsid)
1395 {
1396   char *s = (char *)NULL;
1397   CURLUcode result;
1398 
1399   if(!part)
1400     return CURLUE_BAD_PARTPOINTER;
1401 
1402   *part = (char *)NULL;
1403   result = curl_url_get(handle, what, &s, flags);
1404   if(result == CURLUE_OK) {
1405     if(s) {
1406       *part = dynconvert(ccsid, s, -1, ASCII_CCSID);
1407       if(!*part)
1408         result = CURLUE_OUT_OF_MEMORY;
1409     }
1410   }
1411   if(s)
1412     free(s);
1413   return result;
1414 }
1415 
1416 CURLUcode
curl_url_set_ccsid(CURLU * handle,CURLUPart what,const char * part,unsigned int flags,unsigned int ccsid)1417 curl_url_set_ccsid(CURLU *handle, CURLUPart what, const char *part,
1418                    unsigned int flags, unsigned int ccsid)
1419 {
1420   char *s = (char *)NULL;
1421   CURLUcode result;
1422 
1423   if(part) {
1424     s = dynconvert(ASCII_CCSID, part, -1, ccsid);
1425     if(!s)
1426       return CURLUE_OUT_OF_MEMORY;
1427   }
1428   result = curl_url_set(handle, what, s, flags);
1429   if(s)
1430     free(s);
1431   return result;
1432 }
1433 
1434 const struct curl_easyoption *
curl_easy_option_by_name_ccsid(const char * name,unsigned int ccsid)1435 curl_easy_option_by_name_ccsid(const char *name, unsigned int ccsid)
1436 {
1437   const struct curl_easyoption *option = NULL;
1438 
1439   if(name) {
1440     char *s = dynconvert(ASCII_CCSID, name, -1, ccsid);
1441 
1442     if(s) {
1443       option = curl_easy_option_by_name(s);
1444       free(s);
1445     }
1446   }
1447 
1448   return option;
1449 }
1450 
1451 /* Return option name in the given ccsid. */
1452 const char *
curl_easy_option_get_name_ccsid(const struct curl_easyoption * option,unsigned int ccsid)1453 curl_easy_option_get_name_ccsid(const struct curl_easyoption *option,
1454                                 unsigned int ccsid)
1455 {
1456   char *name = NULL;
1457 
1458   if(option && option->name)
1459     name = dynconvert(ccsid, option->name, -1, ASCII_CCSID);
1460 
1461   return (const char *) name;
1462 }
1463