Home | History | Annotate | Download | only in OS400
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel (at) 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       free(p->buf);
    103       p++;
    104       }
    105 
    106     free(private);
    107     }
    108 }
    109 
    110 
    111 static 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 *
    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     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 
    170 static char *
    171 buffer_unthreaded(localkey_t key, long size)
    172 
    173 {
    174   return get_buffer(locbufs + key, size);
    175 }
    176 
    177 
    178 static char *
    179 buffer_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 
    209 static char *
    210 buffer_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 
    239 static char *
    240 set_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 
    261 int
    262 Curl_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 
    309 int
    310 Curl_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 
    366 struct gskstrlist {
    367   struct gskstrlist * next;
    368   const char * ebcdicstr;
    369   const char * asciistr;
    370 };
    371 
    372 struct Curl_gsk_descriptor {
    373   gsk_handle h;
    374   struct gskstrlist * strlist;
    375 };
    376 
    377 
    378 int
    379 Curl_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 
    399 int
    400 Curl_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 
    424 static void
    425 gsk_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 
    439 int
    440 Curl_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 
    459 int
    460 Curl_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 
    479 int
    480 Curl_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 
    492 int
    493 Curl_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 
    505 int
    506 Curl_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 
    533 int
    534 Curl_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 
    547 int
    548 Curl_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 
    561 int
    562 Curl_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 
    576 static int
    577 cachestring(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 
    607 int
    608 Curl_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 
    630 int
    631 Curl_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 
    644 int
    645 Curl_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 
    658 int
    659 Curl_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 
    676 int
    677 Curl_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 
    689 int
    690 Curl_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 
    703 int
    704 Curl_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 
    717 const char *
    718 Curl_gsk_strerror_a(int gsk_return_value)
    719 
    720 {
    721   return set_thread_string(LK_GSK_ERROR, gsk_strerror(gsk_return_value));
    722 }
    723 
    724 int
    725 Curl_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 
    746 static int
    747 Curl_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 
    777 OM_uint32
    778 Curl_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 
    807 OM_uint32
    808 Curl_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 
    833 OM_uint32
    834 Curl_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 
    891 OM_uint32
    892 Curl_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 
    922 void *
    923 Curl_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 
    946 int
    947 Curl_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 
    986 int
    987 Curl_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 
   1064 struct berval * *
   1065 Curl_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 
   1096 char *
   1097 Curl_ldap_err2string_a(int error)
   1098 
   1099 {
   1100   return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error));
   1101 }
   1102 
   1103 
   1104 char *
   1105 Curl_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 
   1135 char *
   1136 Curl_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 
   1167 char *
   1168 Curl_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 
   1201 static int
   1202 convert_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 
   1238 int
   1239 Curl_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 
   1254 int
   1255 Curl_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 
   1270 int
   1271 Curl_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 
   1287 int
   1288 Curl_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
   1344 const char *
   1345 Curl_os400_zlibVersion(void)
   1346 
   1347 {
   1348   return set_thread_string(LK_ZLIB_VERSION, zlibVersion());
   1349 }
   1350 
   1351 
   1352 int
   1353 Curl_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 
   1368 int
   1369 Curl_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 
   1385 int
   1386 Curl_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 
   1401 int
   1402 Curl_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