1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2020, 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  *
22  ***************************************************************************/
23 
24 /* OS/400 additional support. */
25 
26 #include <curl/curl.h>
27 #include "config-os400.h"  /* Not curl_setup.h: we only need some defines. */
28 
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <string.h>
36 #include <pthread.h>
37 #include <netdb.h>
38 #include <qadrt.h>
39 #include <errno.h>
40 
41 #ifdef HAVE_ZLIB_H
42 #include <zlib.h>
43 #endif
44 
45 #ifdef USE_GSKIT
46 #include <gskssl.h>
47 #include <qsoasync.h>
48 #endif
49 
50 #ifdef HAVE_GSSAPI
51 #include <gssapi.h>
52 #endif
53 
54 #ifndef CURL_DISABLE_LDAP
55 #include <ldap.h>
56 #endif
57 
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 
61 #include "os400sys.h"
62 
63 /**
64 *** QADRT OS/400 ASCII runtime defines only the most used procedures, but a
65 *** lot of them are not supported. This module implements ASCII wrappers for
66 *** those that are used by libcurl, but not defined by QADRT.
67 **/
68 
69 #pragma convert(0)                              /* Restore EBCDIC. */
70 
71 #define MIN_BYTE_GAIN   1024    /* Minimum gain when shortening a buffer. */
72 
73 struct buffer_t {
74   unsigned long size;            /* Buffer size. */
75   char *buf;                     /* Buffer address. */
76 };
77 
78 
79 static char *buffer_undef(localkey_t key, long size);
80 static char *buffer_threaded(localkey_t key, long size);
81 static char *buffer_unthreaded(localkey_t key, long size);
82 
83 static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
84 static pthread_key_t    thdkey;
85 static struct buffer_t *locbufs;
86 
87 char *(*Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
88 
thdbufdestroy(void * private)89 static void thdbufdestroy(void *private)
90 {
91   if(private) {
92     struct buffer_t *p = (struct buffer_t *) private;
93     localkey_t i;
94 
95     for(i = (localkey_t) 0; i < LK_LAST; i++) {
96       free(p->buf);
97       p++;
98     }
99 
100     free(private);
101   }
102 }
103 
104 
105 static void
terminate(void)106 terminate(void)
107 {
108   if(Curl_thread_buffer == buffer_threaded) {
109     locbufs = pthread_getspecific(thdkey);
110     pthread_setspecific(thdkey, (void *) NULL);
111     pthread_key_delete(thdkey);
112   }
113 
114   if(Curl_thread_buffer != buffer_undef) {
115     thdbufdestroy((void *) locbufs);
116     locbufs = (struct buffer_t *) NULL;
117   }
118 
119   Curl_thread_buffer = buffer_undef;
120 }
121 
122 
123 static char *
get_buffer(struct buffer_t * buf,long size)124 get_buffer(struct buffer_t *buf, long size)
125 {
126   char *cp;
127 
128   /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long.
129      Return the buffer address. */
130 
131   if(size < 0)
132     return buf->buf;
133 
134   if(!buf->buf) {
135     buf->buf = malloc(size);
136     if(buf->buf)
137       buf->size = size;
138 
139     return buf->buf;
140   }
141 
142   if((unsigned long) size <= buf->size) {
143     /* Shorten the buffer only if it frees a significant byte count. This
144        avoids some realloc() overhead. */
145 
146     if(buf->size - size < MIN_BYTE_GAIN)
147       return buf->buf;
148   }
149 
150   /* Resize the buffer. */
151 
152   cp = realloc(buf->buf, size);
153   if(cp) {
154     buf->buf = cp;
155     buf->size = size;
156   }
157   else if(size <= buf->size)
158     cp = buf->buf;
159 
160   return cp;
161 }
162 
163 
164 static char *
buffer_unthreaded(localkey_t key,long size)165 buffer_unthreaded(localkey_t key, long size)
166 {
167   return get_buffer(locbufs + key, size);
168 }
169 
170 
171 static char *
buffer_threaded(localkey_t key,long size)172 buffer_threaded(localkey_t key, long size)
173 {
174   struct buffer_t *bufs;
175 
176   /* Get the buffer for the given local key in the current thread, and
177      make sure it is at least `size'-byte long. Set `size' to < 0 to get
178      its address only. */
179 
180   bufs = (struct buffer_t *) pthread_getspecific(thdkey);
181 
182   if(!bufs) {
183     if(size < 0)
184       return (char *) NULL;             /* No buffer yet. */
185 
186     /* Allocate buffer descriptors for the current thread. */
187 
188     bufs = calloc((size_t) LK_LAST, sizeof(*bufs));
189     if(!bufs)
190       return (char *) NULL;
191 
192     if(pthread_setspecific(thdkey, (void *) bufs)) {
193       free(bufs);
194       return (char *) NULL;
195     }
196   }
197 
198   return get_buffer(bufs + key, size);
199 }
200 
201 
202 static char *
buffer_undef(localkey_t key,long size)203 buffer_undef(localkey_t key, long size)
204 {
205   /* Define the buffer system, get the buffer for the given local key in
206      the current thread, and make sure it is at least `size'-byte long.
207      Set `size' to < 0 to get its address only. */
208 
209   pthread_mutex_lock(&mutex);
210 
211   /* Determine if we can use pthread-specific data. */
212 
213   if(Curl_thread_buffer == buffer_undef) {      /* If unchanged during lock. */
214     if(!pthread_key_create(&thdkey, thdbufdestroy))
215       Curl_thread_buffer = buffer_threaded;
216     else {
217       locbufs = calloc((size_t) LK_LAST, sizeof(*locbufs));
218       if(!locbufs) {
219         pthread_mutex_unlock(&mutex);
220         return (char *) NULL;
221       }
222       else
223         Curl_thread_buffer = buffer_unthreaded;
224     }
225 
226     atexit(terminate);
227   }
228 
229   pthread_mutex_unlock(&mutex);
230   return Curl_thread_buffer(key, size);
231 }
232 
233 
234 static char *
set_thread_string(localkey_t key,const char * s)235 set_thread_string(localkey_t key, const char *s)
236 {
237   int i;
238   char *cp;
239 
240   if(!s)
241     return (char *) NULL;
242 
243   i = strlen(s) + 1;
244   cp = Curl_thread_buffer(key, MAX_CONV_EXPANSION * i + 1);
245 
246   if(cp) {
247     i = QadrtConvertE2A(cp, s, MAX_CONV_EXPANSION * i, i);
248     cp[i] = '\0';
249   }
250 
251   return cp;
252 }
253 
254 
255 int
Curl_getnameinfo_a(const struct sockaddr * sa,curl_socklen_t salen,char * nodename,curl_socklen_t nodenamelen,char * servname,curl_socklen_t servnamelen,int flags)256 Curl_getnameinfo_a(const struct sockaddr *sa, curl_socklen_t salen,
257                    char *nodename, curl_socklen_t nodenamelen,
258                    char *servname, curl_socklen_t servnamelen,
259                    int flags)
260 {
261   char *enodename = NULL;
262   char *eservname = NULL;
263   int status;
264 
265   if(nodename && nodenamelen) {
266     enodename = malloc(nodenamelen);
267     if(!enodename)
268       return EAI_MEMORY;
269   }
270 
271   if(servname && servnamelen) {
272     eservname = malloc(servnamelen);
273     if(!eservname) {
274       free(enodename);
275       return EAI_MEMORY;
276     }
277   }
278 
279   status = getnameinfo(sa, salen, enodename, nodenamelen,
280                        eservname, servnamelen, flags);
281 
282   if(!status) {
283     int i;
284     if(enodename) {
285       i = QadrtConvertE2A(nodename, enodename,
286                           nodenamelen - 1, strlen(enodename));
287       nodename[i] = '\0';
288     }
289 
290     if(eservname) {
291       i = QadrtConvertE2A(servname, eservname,
292                           servnamelen - 1, strlen(eservname));
293       servname[i] = '\0';
294     }
295   }
296 
297   free(enodename);
298   free(eservname);
299   return status;
300 }
301 
302 int
Curl_getaddrinfo_a(const char * nodename,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)303 Curl_getaddrinfo_a(const char *nodename, const char *servname,
304                    const struct addrinfo *hints,
305                    struct addrinfo **res)
306 {
307   char *enodename;
308   char *eservname;
309   int status;
310   int i;
311 
312   enodename = (char *) NULL;
313   eservname = (char *) NULL;
314 
315   if(nodename) {
316     i = strlen(nodename);
317 
318     enodename = malloc(i + 1);
319     if(!enodename)
320       return EAI_MEMORY;
321 
322     i = QadrtConvertA2E(enodename, nodename, i, i);
323     enodename[i] = '\0';
324   }
325 
326   if(servname) {
327     i = strlen(servname);
328 
329     eservname = malloc(i + 1);
330     if(!eservname) {
331       free(enodename);
332       return EAI_MEMORY;
333     }
334 
335     QadrtConvertA2E(eservname, servname, i, i);
336     eservname[i] = '\0';
337   }
338 
339   status = getaddrinfo(enodename, eservname, hints, res);
340   free(enodename);
341   free(eservname);
342   return status;
343 }
344 
345 #ifdef USE_GSKIT
346 
347 /* ASCII wrappers for the GSKit procedures. */
348 
349 /*
350  * EBCDIC --> ASCII string mapping table.
351  * Some strings returned by GSKit are dynamically allocated and automatically
352  * released when closing the handle.
353  * To provide the same functionality, we use a "private" handle that
354  * holds the GSKit handle and a list of string mappings. This will allow
355  * avoid conversion of already converted strings and releasing them upon
356  * close time.
357  */
358 
359 struct gskstrlist {
360   struct gskstrlist *next;
361   const char *ebcdicstr;
362   const char *asciistr;
363 };
364 
365 struct Curl_gsk_descriptor {
366   gsk_handle h;
367   struct gskstrlist *strlist;
368 };
369 
Curl_gsk_environment_open(gsk_handle * my_env_handle)370 int Curl_gsk_environment_open(gsk_handle *my_env_handle)
371 {
372   struct Curl_gsk_descriptor *p;
373   int rc;
374 
375   if(!my_env_handle)
376     return GSK_OS400_ERROR_INVALID_POINTER;
377   p = (struct Curl_gsk_descriptor *) malloc(sizeof(*p));
378   if(!p)
379     return GSK_INSUFFICIENT_STORAGE;
380   p->strlist = (struct gskstrlist *) NULL;
381   rc = gsk_environment_open(&p->h);
382   if(rc != GSK_OK)
383     free(p);
384   else
385     *my_env_handle = (gsk_handle) p;
386   return rc;
387 }
388 
Curl_gsk_secure_soc_open(gsk_handle my_env_handle,gsk_handle * my_session_handle)389 int Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
390                              gsk_handle *my_session_handle)
391 {
392   struct Curl_gsk_descriptor *p;
393   gsk_handle h;
394   int rc;
395 
396   if(!my_env_handle)
397     return GSK_INVALID_HANDLE;
398   if(!my_session_handle)
399     return GSK_OS400_ERROR_INVALID_POINTER;
400   h = ((struct Curl_gsk_descriptor *) my_env_handle)->h;
401   p = (struct Curl_gsk_descriptor *) malloc(sizeof(*p));
402   if(!p)
403     return GSK_INSUFFICIENT_STORAGE;
404   p->strlist = (struct gskstrlist *) NULL;
405   rc = gsk_secure_soc_open(h, &p->h);
406   if(rc != GSK_OK)
407     free(p);
408   else
409     *my_session_handle = (gsk_handle) p;
410   return rc;
411 }
412 
gsk_free_handle(struct Curl_gsk_descriptor * p)413 static void gsk_free_handle(struct Curl_gsk_descriptor *p)
414 {
415   struct gskstrlist *q;
416 
417   while((q = p->strlist)) {
418     p->strlist = q;
419     free((void *) q->asciistr);
420     free(q);
421   }
422   free(p);
423 }
424 
Curl_gsk_environment_close(gsk_handle * my_env_handle)425 int Curl_gsk_environment_close(gsk_handle *my_env_handle)
426 {
427   struct Curl_gsk_descriptor *p;
428   int rc;
429 
430   if(!my_env_handle)
431     return GSK_OS400_ERROR_INVALID_POINTER;
432   if(!*my_env_handle)
433     return GSK_INVALID_HANDLE;
434   p = (struct Curl_gsk_descriptor *) *my_env_handle;
435   rc = gsk_environment_close(&p->h);
436   if(rc == GSK_OK) {
437     gsk_free_handle(p);
438     *my_env_handle = (gsk_handle) NULL;
439   }
440   return rc;
441 }
442 
443 
Curl_gsk_secure_soc_close(gsk_handle * my_session_handle)444 int Curl_gsk_secure_soc_close(gsk_handle *my_session_handle)
445 {
446   struct Curl_gsk_descriptor *p;
447   int rc;
448 
449   if(!my_session_handle)
450     return GSK_OS400_ERROR_INVALID_POINTER;
451   if(!*my_session_handle)
452     return GSK_INVALID_HANDLE;
453   p = (struct Curl_gsk_descriptor *) *my_session_handle;
454   rc = gsk_secure_soc_close(&p->h);
455   if(rc == GSK_OK) {
456     gsk_free_handle(p);
457     *my_session_handle = (gsk_handle) NULL;
458   }
459   return rc;
460 }
461 
Curl_gsk_environment_init(gsk_handle my_env_handle)462 int Curl_gsk_environment_init(gsk_handle my_env_handle)
463 {
464   struct Curl_gsk_descriptor *p;
465 
466   if(!my_env_handle)
467     return GSK_INVALID_HANDLE;
468   p = (struct Curl_gsk_descriptor *) my_env_handle;
469   return gsk_environment_init(p->h);
470 }
471 
472 
Curl_gsk_secure_soc_init(gsk_handle my_session_handle)473 int Curl_gsk_secure_soc_init(gsk_handle my_session_handle)
474 {
475   struct Curl_gsk_descriptor *p;
476 
477   if(!my_session_handle)
478     return GSK_INVALID_HANDLE;
479   p = (struct Curl_gsk_descriptor *) my_session_handle;
480   return gsk_secure_soc_init(p->h);
481 }
482 
483 
484 int
Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle,GSK_BUF_ID bufID,const char * buffer,int bufSize)485 Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID,
486                                 const char *buffer, int bufSize)
487 {
488   struct Curl_gsk_descriptor *p;
489   char *ebcdicbuf;
490   int rc;
491 
492   if(!my_gsk_handle)
493     return GSK_INVALID_HANDLE;
494   if(!buffer)
495     return GSK_OS400_ERROR_INVALID_POINTER;
496   if(bufSize < 0)
497     return GSK_ATTRIBUTE_INVALID_LENGTH;
498   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
499   if(!bufSize)
500     bufSize = strlen(buffer);
501   ebcdicbuf = malloc(bufSize + 1);
502   if(!ebcdicbuf)
503     return GSK_INSUFFICIENT_STORAGE;
504   QadrtConvertA2E(ebcdicbuf, buffer, bufSize, bufSize);
505   ebcdicbuf[bufSize] = '\0';
506   rc = gsk_attribute_set_buffer(p->h, bufID, ebcdicbuf, bufSize);
507   free(ebcdicbuf);
508   return rc;
509 }
510 
511 
512 int
Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle,GSK_ENUM_ID enumID,GSK_ENUM_VALUE enumValue)513 Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID,
514                             GSK_ENUM_VALUE enumValue)
515 {
516   struct Curl_gsk_descriptor *p;
517 
518   if(!my_gsk_handle)
519     return GSK_INVALID_HANDLE;
520   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
521   return gsk_attribute_set_enum(p->h, enumID, enumValue);
522 }
523 
524 
525 int
Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,GSK_NUM_ID numID,int numValue)526 Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
527                                      GSK_NUM_ID numID, int numValue)
528 {
529   struct Curl_gsk_descriptor *p;
530 
531   if(!my_gsk_handle)
532     return GSK_INVALID_HANDLE;
533   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
534   return gsk_attribute_set_numeric_value(p->h, numID, numValue);
535 }
536 
537 
538 int
Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,GSK_CALLBACK_ID callBackID,void * callBackAreaPtr)539 Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
540                                 GSK_CALLBACK_ID callBackID,
541                                 void *callBackAreaPtr)
542 {
543   struct Curl_gsk_descriptor *p;
544 
545   if(!my_gsk_handle)
546     return GSK_INVALID_HANDLE;
547   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
548   return gsk_attribute_set_callback(p->h, callBackID, callBackAreaPtr);
549 }
550 
551 
552 static int
cachestring(struct Curl_gsk_descriptor * p,const char * ebcdicbuf,int bufsize,const char ** buffer)553 cachestring(struct Curl_gsk_descriptor *p,
554             const char *ebcdicbuf, int bufsize, const char **buffer)
555 {
556   int rc;
557   char *asciibuf;
558   struct gskstrlist *sp;
559 
560   for(sp = p->strlist; sp; sp = sp->next)
561     if(sp->ebcdicstr == ebcdicbuf)
562       break;
563   if(!sp) {
564     sp = (struct gskstrlist *) malloc(sizeof(*sp));
565     if(!sp)
566       return GSK_INSUFFICIENT_STORAGE;
567     asciibuf = malloc(bufsize + 1);
568     if(!asciibuf) {
569       free(sp);
570       return GSK_INSUFFICIENT_STORAGE;
571     }
572     QadrtConvertE2A(asciibuf, ebcdicbuf, bufsize, bufsize);
573     asciibuf[bufsize] = '\0';
574     sp->ebcdicstr = ebcdicbuf;
575     sp->asciistr = asciibuf;
576     sp->next = p->strlist;
577     p->strlist = sp;
578   }
579   *buffer = sp->asciistr;
580   return GSK_OK;
581 }
582 
583 
584 int
Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle,GSK_BUF_ID bufID,const char ** buffer,int * bufSize)585 Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID,
586                                 const char **buffer, int *bufSize)
587 {
588   struct Curl_gsk_descriptor *p;
589   int rc;
590   const char *mybuf;
591   int mylen;
592 
593   if(!my_gsk_handle)
594     return GSK_INVALID_HANDLE;
595   if(!buffer || !bufSize)
596     return GSK_OS400_ERROR_INVALID_POINTER;
597   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
598   rc = gsk_attribute_get_buffer(p->h, bufID, &mybuf, &mylen);
599   if(rc != GSK_OK)
600     return rc;
601   rc = cachestring(p, mybuf, mylen, buffer);
602   if(rc == GSK_OK)
603     *bufSize = mylen;
604   return rc;
605 }
606 
607 
608 int
Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle,GSK_ENUM_ID enumID,GSK_ENUM_VALUE * enumValue)609 Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID,
610                             GSK_ENUM_VALUE *enumValue)
611 {
612   struct Curl_gsk_descriptor *p;
613 
614   if(!my_gsk_handle)
615     return GSK_INVALID_HANDLE;
616   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
617   return gsk_attribute_get_enum(p->h, enumID, enumValue);
618 }
619 
620 
621 int
Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,GSK_NUM_ID numID,int * numValue)622 Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
623                                      GSK_NUM_ID numID, int *numValue)
624 {
625   struct Curl_gsk_descriptor *p;
626 
627   if(!my_gsk_handle)
628     return GSK_INVALID_HANDLE;
629   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
630   return gsk_attribute_get_numeric_value(p->h, numID, numValue);
631 }
632 
633 
634 int
Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,GSK_CERT_ID certID,const gsk_cert_data_elem ** certDataElem,int * certDataElementCount)635 Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
636                                  GSK_CERT_ID certID,
637                                  const gsk_cert_data_elem **certDataElem,
638                                  int *certDataElementCount)
639 {
640   struct Curl_gsk_descriptor *p;
641 
642   if(!my_gsk_handle)
643     return GSK_INVALID_HANDLE;
644   p = (struct Curl_gsk_descriptor *) my_gsk_handle;
645   /* No need to convert code: text results are already in ASCII. */
646   return gsk_attribute_get_cert_info(p->h, certID,
647                                      certDataElem, certDataElementCount);
648 }
649 
650 
651 int
Curl_gsk_secure_soc_misc(gsk_handle my_session_handle,GSK_MISC_ID miscID)652 Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, GSK_MISC_ID miscID)
653 {
654   struct Curl_gsk_descriptor *p;
655 
656   if(!my_session_handle)
657     return GSK_INVALID_HANDLE;
658   p = (struct Curl_gsk_descriptor *) my_session_handle;
659   return gsk_secure_soc_misc(p->h, miscID);
660 }
661 
662 
663 int
Curl_gsk_secure_soc_read(gsk_handle my_session_handle,char * readBuffer,int readBufSize,int * amtRead)664 Curl_gsk_secure_soc_read(gsk_handle my_session_handle, char *readBuffer,
665                          int readBufSize, int *amtRead)
666 {
667   struct Curl_gsk_descriptor *p;
668 
669   if(!my_session_handle)
670     return GSK_INVALID_HANDLE;
671   p = (struct Curl_gsk_descriptor *) my_session_handle;
672   return gsk_secure_soc_read(p->h, readBuffer, readBufSize, amtRead);
673 }
674 
675 
676 int
Curl_gsk_secure_soc_write(gsk_handle my_session_handle,char * writeBuffer,int writeBufSize,int * amtWritten)677 Curl_gsk_secure_soc_write(gsk_handle my_session_handle, char *writeBuffer,
678                           int writeBufSize, int *amtWritten)
679 {
680   struct Curl_gsk_descriptor *p;
681 
682   if(!my_session_handle)
683     return GSK_INVALID_HANDLE;
684   p = (struct Curl_gsk_descriptor *) my_session_handle;
685   return gsk_secure_soc_write(p->h, writeBuffer, writeBufSize, amtWritten);
686 }
687 
688 
689 const char *
Curl_gsk_strerror_a(int gsk_return_value)690 Curl_gsk_strerror_a(int gsk_return_value)
691 {
692   return set_thread_string(LK_GSK_ERROR, gsk_strerror(gsk_return_value));
693 }
694 
695 int
Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,int IOCompletionPort,Qso_OverlappedIO_t * communicationsArea)696 Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
697                               int IOCompletionPort,
698                               Qso_OverlappedIO_t *communicationsArea)
699 {
700   struct Curl_gsk_descriptor *p;
701 
702   if(!my_session_handle)
703     return GSK_INVALID_HANDLE;
704   p = (struct Curl_gsk_descriptor *) my_session_handle;
705   return gsk_secure_soc_startInit(p->h, IOCompletionPort, communicationsArea);
706 }
707 
708 #endif /* USE_GSKIT */
709 
710 #ifdef HAVE_GSSAPI
711 
712 /* ASCII wrappers for the GSSAPI procedures. */
713 
714 static int
Curl_gss_convert_in_place(OM_uint32 * minor_status,gss_buffer_t buf)715 Curl_gss_convert_in_place(OM_uint32 *minor_status, gss_buffer_t buf)
716 {
717   unsigned int i = buf->length;
718 
719   /* Convert `buf' in place, from EBCDIC to ASCII.
720      If error, release the buffer and return -1. Else return 0. */
721 
722   if(i) {
723     char *t = malloc(i);
724     if(!t) {
725       gss_release_buffer(minor_status, buf);
726 
727       if(minor_status)
728         *minor_status = ENOMEM;
729 
730       return -1;
731     }
732 
733     QadrtConvertE2A(t, buf->value, i, i);
734     memcpy(buf->value, t, i);
735     free(t);
736   }
737 
738   return 0;
739 }
740 
741 
742 OM_uint32
Curl_gss_import_name_a(OM_uint32 * minor_status,gss_buffer_t in_name,gss_OID in_name_type,gss_name_t * out_name)743 Curl_gss_import_name_a(OM_uint32 *minor_status, gss_buffer_t in_name,
744                        gss_OID in_name_type, gss_name_t *out_name)
745 {
746   int rc;
747   unsigned int i;
748   gss_buffer_desc in;
749 
750   if(!in_name || !in_name->value || !in_name->length)
751     return gss_import_name(minor_status, in_name, in_name_type, out_name);
752 
753   memcpy((char *) &in, (char *) in_name, sizeof(in));
754   i = in.length;
755 
756   in.value = malloc(i + 1);
757   if(!in.value) {
758     if(minor_status)
759       *minor_status = ENOMEM;
760 
761     return GSS_S_FAILURE;
762   }
763 
764   QadrtConvertA2E(in.value, in_name->value, i, i);
765   ((char *) in.value)[i] = '\0';
766   rc = gss_import_name(minor_status, &in, in_name_type, out_name);
767   free(in.value);
768   return rc;
769 }
770 
771 OM_uint32
Curl_gss_display_status_a(OM_uint32 * minor_status,OM_uint32 status_value,int status_type,gss_OID mech_type,gss_msg_ctx_t * message_context,gss_buffer_t status_string)772 Curl_gss_display_status_a(OM_uint32 *minor_status, OM_uint32 status_value,
773                           int status_type, gss_OID mech_type,
774                           gss_msg_ctx_t *message_context,
775                           gss_buffer_t status_string)
776 {
777   int rc;
778 
779   rc = gss_display_status(minor_status, status_value, status_type,
780                           mech_type, message_context, status_string);
781 
782   if(rc != GSS_S_COMPLETE || !status_string ||
783      !status_string->length || !status_string->value)
784     return rc;
785 
786   /* No way to allocate a buffer here, because it will be released by
787      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
788      with ASCII to return it. */
789 
790   if(Curl_gss_convert_in_place(minor_status, status_string))
791     return GSS_S_FAILURE;
792 
793   return rc;
794 }
795 
796 OM_uint32
Curl_gss_init_sec_context_a(OM_uint32 * minor_status,gss_cred_id_t cred_handle,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID mech_type,gss_flags_t req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,gss_flags_t * ret_flags,OM_uint32 * time_rec)797 Curl_gss_init_sec_context_a(OM_uint32 *minor_status,
798                             gss_cred_id_t cred_handle,
799                             gss_ctx_id_t *context_handle,
800                             gss_name_t target_name, gss_OID mech_type,
801                             gss_flags_t req_flags, OM_uint32 time_req,
802                             gss_channel_bindings_t input_chan_bindings,
803                             gss_buffer_t input_token,
804                             gss_OID *actual_mech_type,
805                             gss_buffer_t output_token, gss_flags_t *ret_flags,
806                             OM_uint32 *time_rec)
807 {
808   int rc;
809   gss_buffer_desc in;
810   gss_buffer_t inp;
811 
812   in.value = NULL;
813   inp = input_token;
814 
815   if(inp) {
816     if(inp->length && inp->value) {
817       unsigned int i = inp->length;
818 
819       in.value = malloc(i + 1);
820       if(!in.value) {
821         if(minor_status)
822           *minor_status = ENOMEM;
823 
824         return GSS_S_FAILURE;
825       }
826 
827       QadrtConvertA2E(in.value, input_token->value, i, i);
828       ((char *) in.value)[i] = '\0';
829       in.length = i;
830       inp = &in;
831     }
832   }
833 
834   rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
835                             target_name, mech_type, req_flags, time_req,
836                             input_chan_bindings, inp, actual_mech_type,
837                             output_token, ret_flags, time_rec);
838   free(in.value);
839 
840   if(rc != GSS_S_COMPLETE || !output_token ||
841      !output_token->length || !output_token->value)
842     return rc;
843 
844   /* No way to allocate a buffer here, because it will be released by
845      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
846      with ASCII to return it. */
847 
848   if(Curl_gss_convert_in_place(minor_status, output_token))
849     return GSS_S_FAILURE;
850 
851   return rc;
852 }
853 
854 
855 OM_uint32
Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t output_token)856 Curl_gss_delete_sec_context_a(OM_uint32 *minor_status,
857                               gss_ctx_id_t *context_handle,
858                               gss_buffer_t output_token)
859 {
860   int rc;
861 
862   rc = gss_delete_sec_context(minor_status, context_handle, output_token);
863 
864   if(rc != GSS_S_COMPLETE || !output_token ||
865      !output_token->length || !output_token->value)
866     return rc;
867 
868   /* No way to allocate a buffer here, because it will be released by
869      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
870      with ASCII to return it. */
871 
872   if(Curl_gss_convert_in_place(minor_status, output_token))
873     return GSS_S_FAILURE;
874 
875   return rc;
876 }
877 
878 #endif /* HAVE_GSSAPI */
879 
880 #ifndef CURL_DISABLE_LDAP
881 
882 /* ASCII wrappers for the LDAP procedures. */
883 
884 void *
Curl_ldap_init_a(char * host,int port)885 Curl_ldap_init_a(char *host, int port)
886 {
887   unsigned int i;
888   char *ehost;
889   void *result;
890 
891   if(!host)
892     return (void *) ldap_init(host, port);
893 
894   i = strlen(host);
895 
896   ehost = malloc(i + 1);
897   if(!ehost)
898     return (void *) NULL;
899 
900   QadrtConvertA2E(ehost, host, i, i);
901   ehost[i] = '\0';
902   result = (void *) ldap_init(ehost, port);
903   free(ehost);
904   return result;
905 }
906 
907 int
Curl_ldap_simple_bind_s_a(void * ld,char * dn,char * passwd)908 Curl_ldap_simple_bind_s_a(void *ld, char *dn, char *passwd)
909 {
910   int i;
911   char *edn;
912   char *epasswd;
913 
914   edn = (char *) NULL;
915   epasswd = (char *) NULL;
916 
917   if(dn) {
918     i = strlen(dn);
919 
920     edn = malloc(i + 1);
921     if(!edn)
922       return LDAP_NO_MEMORY;
923 
924     QadrtConvertA2E(edn, dn, i, i);
925     edn[i] = '\0';
926   }
927 
928   if(passwd) {
929     i = strlen(passwd);
930 
931     epasswd = malloc(i + 1);
932     if(!epasswd) {
933       free(edn);
934       return LDAP_NO_MEMORY;
935     }
936 
937     QadrtConvertA2E(epasswd, passwd, i, i);
938     epasswd[i] = '\0';
939   }
940 
941   i = ldap_simple_bind_s(ld, edn, epasswd);
942   free(epasswd);
943   free(edn);
944   return i;
945 }
946 
947 int
Curl_ldap_search_s_a(void * ld,char * base,int scope,char * filter,char ** attrs,int attrsonly,LDAPMessage ** res)948 Curl_ldap_search_s_a(void *ld, char *base, int scope, char *filter,
949                      char **attrs, int attrsonly, LDAPMessage **res)
950 {
951   int i;
952   int j;
953   char *ebase;
954   char *efilter;
955   char **eattrs;
956   int status;
957 
958   ebase = (char *) NULL;
959   efilter = (char *) NULL;
960   eattrs = (char **) NULL;
961   status = LDAP_SUCCESS;
962 
963   if(base) {
964     i = strlen(base);
965 
966     ebase = malloc(i + 1);
967     if(!ebase)
968       status = LDAP_NO_MEMORY;
969     else {
970       QadrtConvertA2E(ebase, base, i, i);
971       ebase[i] = '\0';
972     }
973   }
974 
975   if(filter && status == LDAP_SUCCESS) {
976     i = strlen(filter);
977 
978     efilter = malloc(i + 1);
979     if(!efilter)
980       status = LDAP_NO_MEMORY;
981     else {
982       QadrtConvertA2E(efilter, filter, i, i);
983       efilter[i] = '\0';
984     }
985   }
986 
987   if(attrs && status == LDAP_SUCCESS) {
988     for(i = 0; attrs[i++];)
989       ;
990 
991     eattrs = calloc(i, sizeof(*eattrs));
992     if(!eattrs)
993       status = LDAP_NO_MEMORY;
994     else {
995       for(j = 0; attrs[j]; j++) {
996         i = strlen(attrs[j]);
997 
998         eattrs[j] = malloc(i + 1);
999         if(!eattrs[j]) {
1000           status = LDAP_NO_MEMORY;
1001           break;
1002         }
1003 
1004         QadrtConvertA2E(eattrs[j], attrs[j], i, i);
1005         eattrs[j][i] = '\0';
1006       }
1007     }
1008   }
1009 
1010   if(status == LDAP_SUCCESS)
1011     status = ldap_search_s(ld, ebase? ebase: "", scope,
1012                            efilter? efilter: "(objectclass=*)",
1013                            eattrs, attrsonly, res);
1014 
1015   if(eattrs) {
1016     for(j = 0; eattrs[j]; j++)
1017       free(eattrs[j]);
1018 
1019     free(eattrs);
1020   }
1021 
1022   free(efilter);
1023   free(ebase);
1024   return status;
1025 }
1026 
1027 
1028 struct berval **
Curl_ldap_get_values_len_a(void * ld,LDAPMessage * entry,const char * attr)1029 Curl_ldap_get_values_len_a(void *ld, LDAPMessage *entry, const char *attr)
1030 {
1031   char *cp;
1032   struct berval **result;
1033 
1034   cp = (char *) NULL;
1035 
1036   if(attr) {
1037     int i = strlen(attr);
1038 
1039     cp = malloc(i + 1);
1040     if(!cp) {
1041       ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
1042                        ldap_err2string(LDAP_NO_MEMORY));
1043       return (struct berval **) NULL;
1044     }
1045 
1046     QadrtConvertA2E(cp, attr, i, i);
1047     cp[i] = '\0';
1048   }
1049 
1050   result = ldap_get_values_len(ld, entry, cp);
1051   free(cp);
1052 
1053   /* Result data are binary in nature, so they haven't been
1054      converted to EBCDIC. Therefore do not convert. */
1055 
1056   return result;
1057 }
1058 
1059 char *
Curl_ldap_err2string_a(int error)1060 Curl_ldap_err2string_a(int error)
1061 {
1062   return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error));
1063 }
1064 
1065 char *
Curl_ldap_get_dn_a(void * ld,LDAPMessage * entry)1066 Curl_ldap_get_dn_a(void *ld, LDAPMessage *entry)
1067 {
1068   int i;
1069   char *cp;
1070   char *cp2;
1071 
1072   cp = ldap_get_dn(ld, entry);
1073 
1074   if(!cp)
1075     return cp;
1076 
1077   i = strlen(cp);
1078 
1079   cp2 = malloc(i + 1);
1080   if(!cp2)
1081     return cp2;
1082 
1083   QadrtConvertE2A(cp2, cp, i, i);
1084   cp2[i] = '\0';
1085 
1086   /* No way to allocate a buffer here, because it will be released by
1087      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
1088      overwrite the EBCDIC buffer with ASCII to return it. */
1089 
1090   strcpy(cp, cp2);
1091   free(cp2);
1092   return cp;
1093 }
1094 
1095 char *
Curl_ldap_first_attribute_a(void * ld,LDAPMessage * entry,BerElement ** berptr)1096 Curl_ldap_first_attribute_a(void *ld,
1097                             LDAPMessage *entry, BerElement **berptr)
1098 {
1099   int i;
1100   char *cp;
1101   char *cp2;
1102 
1103   cp = ldap_first_attribute(ld, entry, berptr);
1104 
1105   if(!cp)
1106     return cp;
1107 
1108   i = strlen(cp);
1109 
1110   cp2 = malloc(i + 1);
1111   if(!cp2)
1112     return cp2;
1113 
1114   QadrtConvertE2A(cp2, cp, i, i);
1115   cp2[i] = '\0';
1116 
1117   /* No way to allocate a buffer here, because it will be released by
1118      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
1119      overwrite the EBCDIC buffer with ASCII to return it. */
1120 
1121   strcpy(cp, cp2);
1122   free(cp2);
1123   return cp;
1124 }
1125 
1126 char *
Curl_ldap_next_attribute_a(void * ld,LDAPMessage * entry,BerElement * berptr)1127 Curl_ldap_next_attribute_a(void *ld,
1128                            LDAPMessage *entry, BerElement *berptr)
1129 {
1130   int i;
1131   char *cp;
1132   char *cp2;
1133 
1134   cp = ldap_next_attribute(ld, entry, berptr);
1135 
1136   if(!cp)
1137     return cp;
1138 
1139   i = strlen(cp);
1140 
1141   cp2 = malloc(i + 1);
1142   if(!cp2)
1143     return cp2;
1144 
1145   QadrtConvertE2A(cp2, cp, i, i);
1146   cp2[i] = '\0';
1147 
1148   /* No way to allocate a buffer here, because it will be released by
1149      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
1150      overwrite the EBCDIC buffer with ASCII to return it. */
1151 
1152   strcpy(cp, cp2);
1153   free(cp2);
1154   return cp;
1155 }
1156 
1157 #endif /* CURL_DISABLE_LDAP */
1158 
1159 static int
sockaddr2ebcdic(struct sockaddr_storage * dstaddr,const struct sockaddr * srcaddr,int srclen)1160 sockaddr2ebcdic(struct sockaddr_storage *dstaddr,
1161                 const struct sockaddr *srcaddr, int srclen)
1162 {
1163   const struct sockaddr_un *srcu;
1164   struct sockaddr_un *dstu;
1165   unsigned int i;
1166   unsigned int dstsize;
1167 
1168   /* Convert a socket address to job CCSID, if needed. */
1169 
1170   if(!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
1171      sizeof(srcaddr->sa_family) || srclen > sizeof(*dstaddr)) {
1172     errno = EINVAL;
1173     return -1;
1174   }
1175 
1176   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
1177 
1178   switch(srcaddr->sa_family) {
1179 
1180   case AF_UNIX:
1181     srcu = (const struct sockaddr_un *) srcaddr;
1182     dstu = (struct sockaddr_un *) dstaddr;
1183     dstsize = sizeof(*dstaddr) - offsetof(struct sockaddr_un, sun_path);
1184     srclen -= offsetof(struct sockaddr_un, sun_path);
1185     i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
1186     dstu->sun_path[i] = '\0';
1187     srclen = i + offsetof(struct sockaddr_un, sun_path);
1188   }
1189 
1190   return srclen;
1191 }
1192 
1193 
1194 static int
sockaddr2ascii(struct sockaddr * dstaddr,int dstlen,const struct sockaddr_storage * srcaddr,int srclen)1195 sockaddr2ascii(struct sockaddr *dstaddr, int dstlen,
1196                const struct sockaddr_storage *srcaddr, int srclen)
1197 {
1198   const struct sockaddr_un *srcu;
1199   struct sockaddr_un *dstu;
1200   unsigned int dstsize;
1201 
1202   /* Convert a socket address to ASCII, if needed. */
1203 
1204   if(!srclen)
1205     return 0;
1206   if(srclen > dstlen)
1207     srclen = dstlen;
1208   if(!srcaddr || srclen < 0) {
1209     errno = EINVAL;
1210     return -1;
1211   }
1212 
1213   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
1214 
1215   if(srclen >= offsetof(struct sockaddr_storage, ss_family) +
1216      sizeof(srcaddr->ss_family)) {
1217     switch(srcaddr->ss_family) {
1218 
1219     case AF_UNIX:
1220       srcu = (const struct sockaddr_un *) srcaddr;
1221       dstu = (struct sockaddr_un *) dstaddr;
1222       dstsize = dstlen - offsetof(struct sockaddr_un, sun_path);
1223       srclen -= offsetof(struct sockaddr_un, sun_path);
1224       if(dstsize > 0 && srclen > 0) {
1225         srclen = QadrtConvertE2A(dstu->sun_path, srcu->sun_path,
1226                                  dstsize - 1, srclen);
1227         dstu->sun_path[srclen] = '\0';
1228       }
1229       srclen += offsetof(struct sockaddr_un, sun_path);
1230     }
1231   }
1232 
1233   return srclen;
1234 }
1235 
1236 int
Curl_os400_connect(int sd,struct sockaddr * destaddr,int addrlen)1237 Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen)
1238 {
1239   int i;
1240   struct sockaddr_storage laddr;
1241 
1242   i = sockaddr2ebcdic(&laddr, destaddr, addrlen);
1243 
1244   if(i < 0)
1245     return -1;
1246 
1247   return connect(sd, (struct sockaddr *) &laddr, i);
1248 }
1249 
1250 int
Curl_os400_bind(int sd,struct sockaddr * localaddr,int addrlen)1251 Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen)
1252 {
1253   int i;
1254   struct sockaddr_storage laddr;
1255 
1256   i = sockaddr2ebcdic(&laddr, localaddr, addrlen);
1257 
1258   if(i < 0)
1259     return -1;
1260 
1261   return bind(sd, (struct sockaddr *) &laddr, i);
1262 }
1263 
1264 int
Curl_os400_sendto(int sd,char * buffer,int buflen,int flags,struct sockaddr * dstaddr,int addrlen)1265 Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
1266                   struct sockaddr *dstaddr, int addrlen)
1267 {
1268   int i;
1269   struct sockaddr_storage laddr;
1270 
1271   i = sockaddr2ebcdic(&laddr, dstaddr, addrlen);
1272 
1273   if(i < 0)
1274     return -1;
1275 
1276   return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
1277 }
1278 
1279 int
Curl_os400_recvfrom(int sd,char * buffer,int buflen,int flags,struct sockaddr * fromaddr,int * addrlen)1280 Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
1281                     struct sockaddr *fromaddr, int *addrlen)
1282 {
1283   int rcvlen;
1284   struct sockaddr_storage laddr;
1285   int laddrlen = sizeof(laddr);
1286 
1287   if(!fromaddr || !addrlen || *addrlen <= 0)
1288     return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
1289 
1290   laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
1291   rcvlen = recvfrom(sd, buffer, buflen, flags,
1292                     (struct sockaddr *) &laddr, &laddrlen);
1293 
1294   if(rcvlen < 0)
1295     return rcvlen;
1296 
1297   if(laddr.ss_family == AF_UNSPEC)
1298     laddrlen = 0;
1299   else {
1300     laddrlen = sockaddr2ascii(fromaddr, *addrlen, &laddr, laddrlen);
1301     if(laddrlen < 0)
1302       return laddrlen;
1303   }
1304   *addrlen = laddrlen;
1305   return rcvlen;
1306 }
1307 
1308 int
Curl_os400_getpeername(int sd,struct sockaddr * addr,int * addrlen)1309 Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen)
1310 {
1311   struct sockaddr_storage laddr;
1312   int laddrlen = sizeof(laddr);
1313   int retcode = getpeername(sd, (struct sockaddr *) &laddr, &laddrlen);
1314 
1315   if(!retcode) {
1316     laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
1317     if(laddrlen < 0)
1318       return laddrlen;
1319     *addrlen = laddrlen;
1320   }
1321 
1322   return retcode;
1323 }
1324 
1325 int
Curl_os400_getsockname(int sd,struct sockaddr * addr,int * addrlen)1326 Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen)
1327 {
1328   struct sockaddr_storage laddr;
1329   int laddrlen = sizeof(laddr);
1330   int retcode = getsockname(sd, (struct sockaddr *) &laddr, &laddrlen);
1331 
1332   if(!retcode) {
1333     laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
1334     if(laddrlen < 0)
1335       return laddrlen;
1336     *addrlen = laddrlen;
1337   }
1338 
1339   return retcode;
1340 }
1341 
1342 
1343 #ifdef HAVE_LIBZ
1344 const char *
Curl_os400_zlibVersion(void)1345 Curl_os400_zlibVersion(void)
1346 {
1347   return set_thread_string(LK_ZLIB_VERSION, zlibVersion());
1348 }
1349 
1350 
1351 int
Curl_os400_inflateInit_(z_streamp strm,const char * version,int stream_size)1352 Curl_os400_inflateInit_(z_streamp strm, const char *version, int stream_size)
1353 {
1354   z_const char *msgb4 = strm->msg;
1355   int ret;
1356 
1357   ret = inflateInit(strm);
1358 
1359   if(strm->msg != msgb4)
1360     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1361 
1362   return ret;
1363 }
1364 
1365 int
Curl_os400_inflateInit2_(z_streamp strm,int windowBits,const char * version,int stream_size)1366 Curl_os400_inflateInit2_(z_streamp strm, int windowBits,
1367                          const char *version, int stream_size)
1368 {
1369   z_const char *msgb4 = strm->msg;
1370   int ret;
1371 
1372   ret = inflateInit2(strm, windowBits);
1373 
1374   if(strm->msg != msgb4)
1375     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1376 
1377   return ret;
1378 }
1379 
1380 int
Curl_os400_inflate(z_streamp strm,int flush)1381 Curl_os400_inflate(z_streamp strm, int flush)
1382 {
1383   z_const char *msgb4 = strm->msg;
1384   int ret;
1385 
1386   ret = inflate(strm, flush);
1387 
1388   if(strm->msg != msgb4)
1389     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1390 
1391   return ret;
1392 }
1393 
1394 int
Curl_os400_inflateEnd(z_streamp strm)1395 Curl_os400_inflateEnd(z_streamp strm)
1396 {
1397   z_const char *msgb4 = strm->msg;
1398   int ret;
1399 
1400   ret = inflateEnd(strm);
1401 
1402   if(strm->msg != msgb4)
1403     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1404 
1405   return ret;
1406 }
1407 
1408 #endif
1409