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