1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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 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 USE_QSOSSL
42#include <qsossl.h>
43#endif
44
45#ifdef HAVE_GSSAPI
46#include <gssapi.h>
47#endif
48
49#ifndef CURL_DISABLE_LDAP
50#include <ldap.h>
51#endif
52
53#include <netinet/in.h>
54#include <arpa/inet.h>
55
56#include "os400sys.h"
57
58
59/**
60***     QADRT OS/400 ASCII runtime defines only the most used procedures, but
61***             but a lot of them are not supported. This module implements
62***             ASCII wrappers for those that are used by libcurl, but not
63***             defined by QADRT.
64**/
65
66#pragma convert(0)                              /* Restore EBCDIC. */
67
68
69#define MIN_BYTE_GAIN   1024    /* Minimum gain when shortening a buffer. */
70
71typedef struct {
72        unsigned long   size;                   /* Buffer size. */
73        char *          buf;                    /* Buffer address. */
74}               buffer_t;
75
76
77static char *   buffer_undef(localkey_t key, long size);
78static char *   buffer_threaded(localkey_t key, long size);
79static char *   buffer_unthreaded(localkey_t key, long size);
80
81static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
82static pthread_key_t    thdkey;
83static buffer_t *       locbufs;
84
85char *  (* Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
86
87
88static void
89thdbufdestroy(void * private)
90
91{
92  localkey_t i;
93  buffer_t * p;
94
95  if (private) {
96    p = (buffer_t *) private;
97
98    for (i = (localkey_t) 0; i < LK_LAST; i++) {
99      if (p->buf)
100        free(p->buf);
101
102      p++;
103      }
104
105    free(private);
106    }
107}
108
109
110static void
111terminate(void)
112
113{
114  if (Curl_thread_buffer == buffer_threaded) {
115    locbufs = pthread_getspecific(thdkey);
116    pthread_setspecific(thdkey, (void *) NULL);
117    pthread_key_delete(thdkey);
118    }
119
120  if (Curl_thread_buffer != buffer_undef) {
121    thdbufdestroy((void *) locbufs);
122    locbufs = (buffer_t *) NULL;
123    }
124
125  Curl_thread_buffer = buffer_undef;
126}
127
128
129static char *
130get_buffer(buffer_t * buf, long size)
131
132{
133  char * cp;
134
135  /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long.
136     Return the buffer address. */
137
138  if (size < 0)
139    return buf->buf;
140
141  if (!buf->buf) {
142    if ((buf->buf = malloc(size)))
143      buf->size = size;
144
145    return buf->buf;
146    }
147
148  if ((unsigned long) size <= buf->size) {
149    /* Shorten the buffer only if it frees a significant byte count. This
150       avoids some realloc() overhead. */
151
152    if (buf->size - size < MIN_BYTE_GAIN)
153      return buf->buf;
154    }
155
156  /* Resize the buffer. */
157
158  if ((cp = realloc(buf->buf, size))) {
159    buf->buf = cp;
160    buf->size = size;
161    }
162  else if (size <= buf->size)
163    cp = buf->buf;
164
165  return cp;
166}
167
168
169static char *
170buffer_unthreaded(localkey_t key, long size)
171
172{
173  return get_buffer(locbufs + key, size);
174}
175
176
177static char *
178buffer_threaded(localkey_t key, long size)
179
180{
181  buffer_t * bufs;
182
183  /* Get the buffer for the given local key in the current thread, and
184     make sure it is at least `size'-byte long. Set `size' to < 0 to get
185     its address only. */
186
187  bufs = (buffer_t *) pthread_getspecific(thdkey);
188
189  if (!bufs) {
190    if (size < 0)
191      return (char *) NULL;             /* No buffer yet. */
192
193    /* Allocate buffer descriptors for the current thread. */
194
195    if (!(bufs = calloc((size_t) LK_LAST, sizeof *bufs)))
196      return (char *) NULL;
197
198    if (pthread_setspecific(thdkey, (void *) bufs)) {
199      free(bufs);
200      return (char *) NULL;
201      }
202    }
203
204  return get_buffer(bufs + key, size);
205}
206
207
208static char *
209buffer_undef(localkey_t key, long size)
210
211{
212  /* Define the buffer system, get the buffer for the given local key in
213     the current thread, and make sure it is at least `size'-byte long.
214     Set `size' to < 0 to get its address only. */
215
216  pthread_mutex_lock(&mutex);
217
218  /* Determine if we can use pthread-specific data. */
219
220  if (Curl_thread_buffer == buffer_undef) {     /* If unchanged during lock. */
221    if (!pthread_key_create(&thdkey, thdbufdestroy))
222      Curl_thread_buffer = buffer_threaded;
223    else if (!(locbufs = calloc((size_t) LK_LAST,
224                                             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
239int
240Curl_getnameinfo_a(const struct sockaddr * sa, curl_socklen_t salen,
241              char * nodename, curl_socklen_t nodenamelen,
242              char * servname, curl_socklen_t servnamelen,
243              int flags)
244
245{
246  char * enodename;
247  char * eservname;
248  int status;
249  int i;
250
251  enodename = (char *) NULL;
252  eservname = (char *) NULL;
253
254  if (nodename && nodenamelen)
255    if (!(enodename = malloc(nodenamelen)))
256      return EAI_MEMORY;
257
258  if (servname && servnamelen)
259    if (!(eservname = malloc(servnamelen))) {
260      if (enodename)
261        free(enodename);
262
263      return EAI_MEMORY;
264      }
265
266  status = getnameinfo(sa, salen, enodename, nodenamelen,
267                       eservname, servnamelen, flags);
268
269  if (!status) {
270    if (enodename) {
271      i = QadrtConvertE2A(nodename, enodename,
272        nodenamelen - 1, strlen(enodename));
273      nodename[i] = '\0';
274      }
275
276    if (eservname) {
277      i = QadrtConvertE2A(servname, eservname,
278        servnamelen - 1, strlen(eservname));
279      servname[i] = '\0';
280      }
281    }
282
283  if (enodename)
284    free(enodename);
285
286  if (eservname)
287    free(eservname);
288
289  return status;
290}
291
292
293int
294Curl_getaddrinfo_a(const char * nodename, const char * servname,
295            const struct addrinfo * hints,
296            struct addrinfo * * res)
297
298{
299  char * enodename;
300  char * eservname;
301  int status;
302  int i;
303
304  enodename = (char *) NULL;
305  eservname = (char *) NULL;
306
307  if (nodename) {
308    i = strlen(nodename);
309
310    if (!(enodename = malloc(i + 1)))
311      return EAI_MEMORY;
312
313    i = QadrtConvertA2E(enodename, nodename, i, i);
314    enodename[i] = '\0';
315    }
316
317  if (servname) {
318    i = strlen(servname);
319
320    if (!(eservname = malloc(i + 1))) {
321      if (enodename)
322        free(enodename);
323
324      return EAI_MEMORY;
325      }
326
327    QadrtConvertA2E(eservname, servname, i, i);
328    eservname[i] = '\0';
329    }
330
331  status = getaddrinfo(enodename, eservname, hints, res);
332
333  if (enodename)
334    free(enodename);
335
336  if (eservname)
337    free(eservname);
338
339  return status;
340}
341
342
343#ifdef USE_QSOSSL
344
345/* ASCII wrappers for the SSL procedures. */
346
347int
348Curl_SSL_Init_Application_a(SSLInitApp * init_app)
349
350{
351  int rc;
352  unsigned int i;
353  SSLInitApp ia;
354
355  if (!init_app || !init_app->applicationID || !init_app->applicationIDLen)
356    return SSL_Init_Application(init_app);
357
358  memcpy((char *) &ia, (char *) init_app, sizeof ia);
359  i = ia.applicationIDLen;
360
361  if (!(ia.applicationID = malloc(i + 1))) {
362    errno = ENOMEM;
363    return SSL_ERROR_IO;
364    }
365
366  QadrtConvertA2E(ia.applicationID, init_app->applicationID, i, i);
367  ia.applicationID[i] = '\0';
368  rc = SSL_Init_Application(&ia);
369  free(ia.applicationID);
370  init_app->localCertificateLen = ia.localCertificateLen;
371  init_app->sessionType = ia.sessionType;
372  return rc;
373}
374
375
376int
377Curl_SSL_Init_a(SSLInit * init)
378
379{
380  int rc;
381  unsigned int i;
382  SSLInit ia;
383
384  if (!init || (!init->keyringFileName && !init->keyringPassword))
385    return SSL_Init(init);
386
387  memcpy((char *) &ia, (char *) init, sizeof ia);
388
389  if (ia.keyringFileName) {
390    i = strlen(ia.keyringFileName);
391
392    if (!(ia.keyringFileName = malloc(i + 1))) {
393      errno = ENOMEM;
394      return SSL_ERROR_IO;
395      }
396
397    QadrtConvertA2E(ia.keyringFileName, init->keyringFileName, i, i);
398    ia.keyringFileName[i] = '\0';
399    }
400
401  if (ia.keyringPassword) {
402    i = strlen(ia.keyringPassword);
403
404    if (!(ia.keyringPassword = malloc(i + 1))) {
405      if (ia.keyringFileName)
406        free(ia.keyringFileName);
407
408      errno = ENOMEM;
409      return SSL_ERROR_IO;
410      }
411
412    QadrtConvertA2E(ia.keyringPassword, init->keyringPassword, i, i);
413    ia.keyringPassword[i] = '\0';
414    }
415
416  rc = SSL_Init(&ia);
417
418  if (ia.keyringFileName)
419    free(ia.keyringFileName);
420
421  if (ia.keyringPassword)
422    free(ia.keyringPassword);
423
424  return rc;
425}
426
427
428char *
429Curl_SSL_Strerror_a(int sslreturnvalue, SSLErrorMsg * serrmsgp)
430
431{
432  int i;
433  char * cp;
434  char * cp2;
435
436  cp = SSL_Strerror(sslreturnvalue, serrmsgp);
437
438  if (!cp)
439    return cp;
440
441  i = strlen(cp);
442
443  if (!(cp2 = Curl_thread_buffer(LK_SSL_ERROR, MAX_CONV_EXPANSION * i + 1)))
444    return cp2;
445
446  i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
447  cp2[i] = '\0';
448  return cp2;
449}
450
451#endif /* USE_QSOSSL */
452
453
454#ifdef HAVE_GSSAPI
455
456/* ASCII wrappers for the GSSAPI procedures. */
457
458static int
459Curl_gss_convert_in_place(OM_uint32 * minor_status, gss_buffer_t buf)
460
461{
462  unsigned int i;
463  char * t;
464
465  /* Convert `buf' in place, from EBCDIC to ASCII.
466     If error, release the buffer and return -1. Else return 0. */
467
468  i = buf->length;
469
470  if (i) {
471    if (!(t = malloc(i))) {
472      gss_release_buffer(minor_status, buf);
473
474      if (minor_status)
475        *minor_status = ENOMEM;
476
477      return -1;
478      }
479
480    QadrtConvertE2A(t, buf->value, i, i);
481    memcpy(buf->value, t, i);
482    free(t);
483    }
484
485  return 0;
486}
487
488
489OM_uint32
490Curl_gss_import_name_a(OM_uint32 * minor_status, gss_buffer_t in_name,
491                       gss_OID in_name_type, gss_name_t * out_name)
492
493{
494  int rc;
495  unsigned int i;
496  gss_buffer_desc in;
497
498  if (!in_name || !in_name->value || !in_name->length)
499    return gss_import_name(minor_status, in_name, in_name_type, out_name);
500
501  memcpy((char *) &in, (char *) in_name, sizeof in);
502  i = in.length;
503
504  if (!(in.value = malloc(i + 1))) {
505    if (minor_status)
506      *minor_status = ENOMEM;
507
508    return GSS_S_FAILURE;
509    }
510
511  QadrtConvertA2E(in.value, in_name->value, i, i);
512  ((char *) in.value)[i] = '\0';
513  rc = gss_import_name(minor_status, &in, in_name_type, out_name);
514  free(in.value);
515  return rc;
516}
517
518
519OM_uint32
520Curl_gss_display_status_a(OM_uint32 * minor_status, OM_uint32 status_value,
521                   int status_type, gss_OID mech_type,
522                   gss_msg_ctx_t * message_context, gss_buffer_t status_string)
523
524{
525  int rc;
526
527  rc = gss_display_status(minor_status, status_value, status_type,
528                              mech_type, message_context, status_string);
529
530  if (rc != GSS_S_COMPLETE || !status_string ||
531      !status_string->length || !status_string->value)
532    return rc;
533
534  /* No way to allocate a buffer here, because it will be released by
535     gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
536     with ASCII to return it. */
537
538  if (Curl_gss_convert_in_place(minor_status, status_string))
539    return GSS_S_FAILURE;
540
541  return rc;
542}
543
544
545OM_uint32
546Curl_gss_init_sec_context_a(OM_uint32 * minor_status, gss_cred_id_t cred_handle,
547                            gss_ctx_id_t * context_handle,
548                            gss_name_t target_name, gss_OID mech_type,
549                            gss_flags_t req_flags, OM_uint32 time_req,
550                            gss_channel_bindings_t input_chan_bindings,
551                            gss_buffer_t input_token,
552                            gss_OID * actual_mech_type,
553                            gss_buffer_t output_token, gss_flags_t * ret_flags,
554                            OM_uint32 * time_rec)
555
556{
557  int rc;
558  unsigned int i;
559  gss_buffer_desc in;
560  gss_buffer_t inp;
561
562  in.value = NULL;
563
564  if ((inp = input_token))
565    if (inp->length && inp->value) {
566      i = inp->length;
567
568      if (!(in.value = malloc(i + 1))) {
569        if (minor_status)
570          *minor_status = ENOMEM;
571
572        return GSS_S_FAILURE;
573        }
574
575      QadrtConvertA2E(in.value, input_token->value, i, i);
576      ((char *) in.value)[i] = '\0';
577      in.length = i;
578      inp = &in;
579      }
580
581  rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
582                             target_name, mech_type, req_flags, time_req,
583                             input_chan_bindings, inp, actual_mech_type,
584                             output_token, ret_flags, time_rec);
585
586  if (in.value)
587    free(in.value);
588
589  if (rc != GSS_S_COMPLETE || !output_token ||
590      !output_token->length || !output_token->value)
591    return rc;
592
593  /* No way to allocate a buffer here, because it will be released by
594     gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
595     with ASCII to return it. */
596
597  if (Curl_gss_convert_in_place(minor_status, output_token))
598    return GSS_S_FAILURE;
599
600  return rc;
601}
602
603
604OM_uint32
605Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
606                              gss_ctx_id_t * context_handle,
607                              gss_buffer_t output_token)
608
609{
610  int rc;
611
612  rc = gss_delete_sec_context(minor_status, context_handle, output_token);
613
614  if (rc != GSS_S_COMPLETE || !output_token ||
615      !output_token->length || !output_token->value)
616    return rc;
617
618  /* No way to allocate a buffer here, because it will be released by
619     gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
620     with ASCII to return it. */
621
622  if (Curl_gss_convert_in_place(minor_status, output_token))
623    return GSS_S_FAILURE;
624
625  return rc;
626}
627
628#endif /* HAVE_GSSAPI */
629
630
631#ifndef CURL_DISABLE_LDAP
632
633/* ASCII wrappers for the LDAP procedures. */
634
635void *
636Curl_ldap_init_a(char * host, int port)
637
638{
639  unsigned int i;
640  char * ehost;
641  void * result;
642
643  if (!host)
644    return (void *) ldap_init(host, port);
645
646  i = strlen(host);
647
648  if (!(ehost = malloc(i + 1)))
649    return (void *) NULL;
650
651  QadrtConvertA2E(ehost, host, i, i);
652  ehost[i] = '\0';
653  result = (void *) ldap_init(ehost, port);
654  free(ehost);
655  return result;
656}
657
658
659int
660Curl_ldap_simple_bind_s_a(void * ld, char * dn, char * passwd)
661
662{
663  int i;
664  char * edn;
665  char * epasswd;
666
667  edn = (char *) NULL;
668  epasswd = (char *) NULL;
669
670  if (dn) {
671    i = strlen(dn);
672
673    if (!(edn = malloc(i + 1)))
674      return LDAP_NO_MEMORY;
675
676    QadrtConvertA2E(edn, dn, i, i);
677    edn[i] = '\0';
678    }
679
680  if (passwd) {
681    i = strlen(passwd);
682
683    if (!(epasswd = malloc(i + 1))) {
684      if (edn)
685        free(edn);
686
687      return LDAP_NO_MEMORY;
688      }
689
690    QadrtConvertA2E(epasswd, passwd, i, i);
691    epasswd[i] = '\0';
692    }
693
694  i = ldap_simple_bind_s(ld, edn, epasswd);
695
696  if (epasswd)
697    free(epasswd);
698
699  if (edn)
700    free(edn);
701
702  return i;
703}
704
705
706int
707Curl_ldap_search_s_a(void * ld, char * base, int scope, char * filter,
708                     char * * attrs, int attrsonly, LDAPMessage * * res)
709
710{
711  int i;
712  int j;
713  char * ebase;
714  char * efilter;
715  char * * eattrs;
716  int status;
717
718  ebase = (char *) NULL;
719  efilter = (char *) NULL;
720  eattrs = (char * *) NULL;
721  status = LDAP_SUCCESS;
722
723  if (base) {
724    i = strlen(base);
725
726    if (!(ebase = malloc(i + 1)))
727      status = LDAP_NO_MEMORY;
728    else {
729      QadrtConvertA2E(ebase, base, i, i);
730      ebase[i] = '\0';
731      }
732    }
733
734  if (filter && status == LDAP_SUCCESS) {
735    i = strlen(filter);
736
737    if (!(efilter = malloc(i + 1)))
738      status = LDAP_NO_MEMORY;
739    else {
740      QadrtConvertA2E(efilter, filter, i, i);
741      efilter[i] = '\0';
742      }
743    }
744
745  if (attrs && status == LDAP_SUCCESS) {
746    for (i = 0; attrs[i++];)
747      ;
748
749    if (!(eattrs = calloc(i, sizeof *eattrs)))
750      status = LDAP_NO_MEMORY;
751    else {
752      for (j = 0; attrs[j]; j++) {
753        i = strlen(attrs[j]);
754
755        if (!(eattrs[j] = malloc(i + 1))) {
756          status = LDAP_NO_MEMORY;
757          break;
758          }
759
760        QadrtConvertA2E(eattrs[j], attrs[j], i, i);
761        eattrs[j][i] = '\0';
762        }
763      }
764    }
765
766  if (status == LDAP_SUCCESS)
767    status = ldap_search_s(ld, ebase? ebase: "", scope,
768                           efilter? efilter: "(objectclass=*)",
769                           eattrs, attrsonly, res);
770
771  if (eattrs) {
772    for (j = 0; eattrs[j]; j++)
773      free(eattrs[j]);
774
775    free(eattrs);
776    }
777
778  if (efilter)
779    free(efilter);
780
781  if (ebase)
782    free(ebase);
783
784  return status;
785}
786
787
788struct berval * *
789Curl_ldap_get_values_len_a(void * ld, LDAPMessage * entry, const char * attr)
790
791{
792  int i;
793  char * cp;
794  struct berval * * result;
795
796  cp = (char *) NULL;
797
798  if (attr) {
799    i = strlen(attr);
800
801    if (!(cp = malloc(i + 1))) {
802      ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
803                       ldap_err2string(LDAP_NO_MEMORY));
804      return (struct berval * *) NULL;
805      }
806
807    QadrtConvertA2E(cp, attr, i, i);
808    cp[i] = '\0';
809    }
810
811  result = ldap_get_values_len(ld, entry, cp);
812
813  if (cp)
814    free(cp);
815
816  /* Result data are binary in nature, so they haven't been converted to EBCDIC.
817     Therefore do not convert. */
818
819  return result;
820}
821
822
823char *
824Curl_ldap_err2string_a(int error)
825
826{
827  int i;
828  char * cp;
829  char * cp2;
830
831  cp = ldap_err2string(error);
832
833  if (!cp)
834    return cp;
835
836  i = strlen(cp);
837
838  if (!(cp2 = Curl_thread_buffer(LK_LDAP_ERROR, MAX_CONV_EXPANSION * i + 1)))
839    return cp2;
840
841  i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
842  cp2[i] = '\0';
843  return cp2;
844}
845
846
847char *
848Curl_ldap_get_dn_a(void * ld, LDAPMessage * entry)
849
850{
851  int i;
852  char * cp;
853  char * cp2;
854
855  cp = ldap_get_dn(ld, entry);
856
857  if (!cp)
858    return cp;
859
860  i = strlen(cp);
861
862  if (!(cp2 = malloc(i + 1)))
863    return cp2;
864
865  QadrtConvertE2A(cp2, cp, i, i);
866  cp2[i] = '\0';
867
868  /* No way to allocate a buffer here, because it will be released by
869     ldap_memfree() and ldap_memalloc() does not exist. The solution is to
870     overwrite the EBCDIC buffer with ASCII to return it. */
871
872  strcpy(cp, cp2);
873  free(cp2);
874  return cp;
875}
876
877
878char *
879Curl_ldap_first_attribute_a(void * ld,
880                            LDAPMessage * entry, BerElement * * berptr)
881
882{
883  int i;
884  char * cp;
885  char * cp2;
886
887  cp = ldap_first_attribute(ld, entry, berptr);
888
889  if (!cp)
890    return cp;
891
892  i = strlen(cp);
893
894  if (!(cp2 = malloc(i + 1)))
895    return cp2;
896
897  QadrtConvertE2A(cp2, cp, i, i);
898  cp2[i] = '\0';
899
900  /* No way to allocate a buffer here, because it will be released by
901     ldap_memfree() and ldap_memalloc() does not exist. The solution is to
902     overwrite the EBCDIC buffer with ASCII to return it. */
903
904  strcpy(cp, cp2);
905  free(cp2);
906  return cp;
907}
908
909
910char *
911Curl_ldap_next_attribute_a(void * ld,
912                           LDAPMessage * entry, BerElement * berptr)
913
914{
915  int i;
916  char * cp;
917  char * cp2;
918
919  cp = ldap_next_attribute(ld, entry, berptr);
920
921  if (!cp)
922    return cp;
923
924  i = strlen(cp);
925
926  if (!(cp2 = malloc(i + 1)))
927    return cp2;
928
929  QadrtConvertE2A(cp2, cp, i, i);
930  cp2[i] = '\0';
931
932  /* No way to allocate a buffer here, because it will be released by
933     ldap_memfree() and ldap_memalloc() does not exist. The solution is to
934     overwrite the EBCDIC buffer with ASCII to return it. */
935
936  strcpy(cp, cp2);
937  free(cp2);
938  return cp;
939}
940
941#endif /* CURL_DISABLE_LDAP */
942
943
944static int
945convert_sockaddr(struct sockaddr_storage * dstaddr,
946                                const struct sockaddr * srcaddr, int srclen)
947
948{
949  const struct sockaddr_un * srcu;
950  struct sockaddr_un * dstu;
951  unsigned int i;
952  unsigned int dstsize;
953
954  /* Convert a socket address into job CCSID, if needed. */
955
956  if (!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
957      sizeof srcaddr->sa_family || srclen > sizeof *dstaddr) {
958    errno = EINVAL;
959    return -1;
960    }
961
962  memcpy((char *) dstaddr, (char *) srcaddr, srclen);
963
964  switch (srcaddr->sa_family) {
965
966  case AF_UNIX:
967    srcu = (const struct sockaddr_un *) srcaddr;
968    dstu = (struct sockaddr_un *) dstaddr;
969    dstsize = sizeof *dstaddr - offsetof(struct sockaddr_un, sun_path);
970    srclen -= offsetof(struct sockaddr_un, sun_path);
971    i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
972    dstu->sun_path[i] = '\0';
973    i += offsetof(struct sockaddr_un, sun_path);
974    srclen = i;
975    }
976
977  return srclen;
978}
979
980
981int
982Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen)
983
984{
985  int i;
986  struct sockaddr_storage laddr;
987
988  i = convert_sockaddr(&laddr, destaddr, addrlen);
989
990  if (i < 0)
991    return -1;
992
993  return connect(sd, (struct sockaddr *) &laddr, i);
994}
995
996
997int
998Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen)
999
1000{
1001  int i;
1002  struct sockaddr_storage laddr;
1003
1004  i = convert_sockaddr(&laddr, localaddr, addrlen);
1005
1006  if (i < 0)
1007    return -1;
1008
1009  return bind(sd, (struct sockaddr *) &laddr, i);
1010}
1011
1012
1013int
1014Curl_os400_sendto(int sd, char * buffer, int buflen, int flags,
1015                                struct sockaddr * dstaddr, int addrlen)
1016
1017{
1018  int i;
1019  struct sockaddr_storage laddr;
1020
1021  i = convert_sockaddr(&laddr, dstaddr, addrlen);
1022
1023  if (i < 0)
1024    return -1;
1025
1026  return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
1027}
1028
1029
1030int
1031Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags,
1032                                struct sockaddr * fromaddr, int * addrlen)
1033
1034{
1035  int i;
1036  int rcvlen;
1037  int laddrlen;
1038  const struct sockaddr_un * srcu;
1039  struct sockaddr_un * dstu;
1040  struct sockaddr_storage laddr;
1041
1042  if (!fromaddr || !addrlen || *addrlen <= 0)
1043    return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
1044
1045  laddrlen = sizeof laddr;
1046  laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
1047  rcvlen = recvfrom(sd, buffer, buflen, flags,
1048                    (struct sockaddr *) &laddr, &laddrlen);
1049
1050  if (rcvlen < 0)
1051    return rcvlen;
1052
1053  switch (laddr.ss_family) {
1054
1055  case AF_UNIX:
1056    srcu = (const struct sockaddr_un *) &laddr;
1057    dstu = (struct sockaddr_un *) fromaddr;
1058    i = *addrlen - offsetof(struct sockaddr_un, sun_path);
1059    laddrlen -= offsetof(struct sockaddr_un, sun_path);
1060    i = QadrtConvertE2A(dstu->sun_path, srcu->sun_path, i, laddrlen);
1061    laddrlen = i + offsetof(struct sockaddr_un, sun_path);
1062
1063    if (laddrlen < *addrlen)
1064      dstu->sun_path[i] = '\0';
1065
1066    break;
1067
1068  case AF_UNSPEC:
1069    break;
1070
1071  default:
1072    if (laddrlen > *addrlen)
1073      laddrlen = *addrlen;
1074
1075    if (laddrlen)
1076      memcpy((char *) fromaddr, (char *) &laddr, laddrlen);
1077
1078    break;
1079    }
1080
1081  *addrlen = laddrlen;
1082  return rcvlen;
1083}
1084