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