071fa482d1df41ce30287aed4c4eaacc55ca1fa3
[external/curl.git] / packages / OS400 / os400sys.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2010, 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
71 typedef struct {
72         unsigned long   size;                   /* Buffer size. */
73         char *          buf;                    /* Buffer address. */
74 }               buffer_t;
75
76
77 static char *   buffer_undef(localkey_t key, long size);
78 static char *   buffer_threaded(localkey_t key, long size);
79 static char *   buffer_unthreaded(localkey_t key, long size);
80
81 static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
82 static pthread_key_t    thdkey;
83 static buffer_t *       locbufs;
84
85 char *  (* Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
86
87
88 static void
89 thdbufdestroy(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
110 static void
111 terminate(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
129 static char *
130 get_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
169 static char *
170 buffer_unthreaded(localkey_t key, long size)
171
172 {
173   return get_buffer(locbufs + key, size);
174 }
175
176
177 static char *
178 buffer_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
208 static char *
209 buffer_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
239 int
240 Curl_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
293 int
294 Curl_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
347 int
348 Curl_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
376 int
377 Curl_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
428 char *
429 Curl_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
458 static int
459 Curl_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
489 OM_uint32
490 Curl_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
519 OM_uint32
520 Curl_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
545 OM_uint32
546 Curl_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
604 OM_uint32
605 Curl_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
635 void *
636 Curl_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
659 int
660 Curl_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
706 int
707 Curl_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
788 struct berval * *
789 Curl_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
823 char *
824 Curl_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
847 char *
848 Curl_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
867   /* No way to allocate a buffer here, because it will be released by
868      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
869      overwrite the EBCDIC buffer with ASCII to return it. */
870
871   strcpy(cp, cp2);
872   free(cp2);
873   return cp;
874 }
875
876
877 char *
878 Curl_ldap_first_attribute_a(void * ld,
879                             LDAPMessage * entry, BerElement * * berptr)
880
881 {
882   int i;
883   char * cp;
884   char * cp2;
885
886   cp = ldap_first_attribute(ld, entry, berptr);
887
888   if (!cp)
889     return cp;
890
891   i = strlen(cp);
892
893   if (!(cp2 = malloc(i + 1)))
894     return cp2;
895
896   QadrtConvertE2A(cp2, cp, i, i);
897
898   /* No way to allocate a buffer here, because it will be released by
899      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
900      overwrite the EBCDIC buffer with ASCII to return it. */
901
902   strcpy(cp, cp2);
903   free(cp2);
904   return cp;
905 }
906
907
908 char *
909 Curl_ldap_next_attribute_a(void * ld,
910                            LDAPMessage * entry, BerElement * berptr)
911
912 {
913   int i;
914   char * cp;
915   char * cp2;
916
917   cp = ldap_next_attribute(ld, entry, berptr);
918
919   if (!cp)
920     return cp;
921
922   i = strlen(cp);
923
924   if (!(cp2 = malloc(i + 1)))
925     return cp2;
926
927   QadrtConvertE2A(cp2, cp, i, i);
928
929   /* No way to allocate a buffer here, because it will be released by
930      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
931      overwrite the EBCDIC buffer with ASCII to return it. */
932
933   strcpy(cp, cp2);
934   free(cp2);
935   return cp;
936 }
937
938 #endif /* CURL_DISABLE_LDAP */
939
940
941 static int
942 convert_sockaddr(struct sockaddr_storage * dstaddr,
943                                 const struct sockaddr * srcaddr, int srclen)
944
945 {
946   const struct sockaddr_un * srcu;
947   struct sockaddr_un * dstu;
948   unsigned int i;
949   unsigned int dstsize;
950
951   /* Convert a socket address into job CCSID, if needed. */
952
953   if (!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
954       sizeof srcaddr->sa_family || srclen > sizeof *dstaddr) {
955     errno = EINVAL;
956     return -1;
957     }
958
959   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
960
961   switch (srcaddr->sa_family) {
962
963   case AF_UNIX:
964     srcu = (const struct sockaddr_un *) srcaddr;
965     dstu = (struct sockaddr_un *) dstaddr;
966     dstsize = sizeof *dstaddr - offsetof(struct sockaddr_un, sun_path);
967     srclen -= offsetof(struct sockaddr_un, sun_path);
968     i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
969     dstu->sun_path[i] = '\0';
970     i += offsetof(struct sockaddr_un, sun_path);
971     srclen = i;
972     }
973
974   return srclen;
975 }
976
977
978 int
979 Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen)
980
981 {
982   int i;
983   struct sockaddr_storage laddr;
984
985   i = convert_sockaddr(&laddr, destaddr, addrlen);
986
987   if (i < 0)
988     return -1;
989
990   return connect(sd, (struct sockaddr *) &laddr, i);
991 }
992
993
994 int
995 Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen)
996
997 {
998   int i;
999   struct sockaddr_storage laddr;
1000
1001   i = convert_sockaddr(&laddr, localaddr, addrlen);
1002
1003   if (i < 0)
1004     return -1;
1005
1006   return bind(sd, (struct sockaddr *) &laddr, i);
1007 }
1008
1009
1010 int
1011 Curl_os400_sendto(int sd, char * buffer, int buflen, int flags,
1012                                 struct sockaddr * dstaddr, int addrlen)
1013
1014 {
1015   int i;
1016   struct sockaddr_storage laddr;
1017
1018   i = convert_sockaddr(&laddr, dstaddr, addrlen);
1019
1020   if (i < 0)
1021     return -1;
1022
1023   return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
1024 }
1025
1026
1027 int
1028 Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags,
1029                                 struct sockaddr * fromaddr, int * addrlen)
1030
1031 {
1032   int i;
1033   int rcvlen;
1034   int laddrlen;
1035   const struct sockaddr_un * srcu;
1036   struct sockaddr_un * dstu;
1037   struct sockaddr_storage laddr;
1038
1039   if (!fromaddr || !addrlen || *addrlen <= 0)
1040     return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
1041
1042   laddrlen = sizeof laddr;
1043   laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
1044   rcvlen = recvfrom(sd, buffer, buflen, flags,
1045                     (struct sockaddr *) &laddr, &laddrlen);
1046
1047   if (rcvlen < 0)
1048     return rcvlen;
1049
1050   switch (laddr.ss_family) {
1051
1052   case AF_UNIX:
1053     srcu = (const struct sockaddr_un *) &laddr;
1054     dstu = (struct sockaddr_un *) fromaddr;
1055     i = *addrlen - offsetof(struct sockaddr_un, sun_path);
1056     laddrlen -= offsetof(struct sockaddr_un, sun_path);
1057     i = QadrtConvertE2A(dstu->sun_path, srcu->sun_path, i, laddrlen);
1058     laddrlen = i + offsetof(struct sockaddr_un, sun_path);
1059
1060     if (laddrlen < *addrlen)
1061       dstu->sun_path[i] = '\0';
1062
1063     break;
1064
1065   case AF_UNSPEC:
1066     break;
1067
1068   default:
1069     if (laddrlen > *addrlen)
1070       laddrlen = *addrlen;
1071
1072     if (laddrlen)
1073       memcpy((char *) fromaddr, (char *) &laddr, laddrlen);
1074
1075     break;
1076     }
1077
1078   *addrlen = laddrlen;
1079   return rcvlen;
1080 }