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