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