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