Adapting last changes to OS400:
[platform/upstream/curl.git] / packages / OS400 / os400sys.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2008, 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  * $Id$
22  *
23  ***************************************************************************/
24
25 /* OS/400 additional support. */
26
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 = (buffer_t *) 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 = (buffer_t *) 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, socklen_t salen,
241               char * nodename, socklen_t nodenamelen,
242               char * servname, 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 int
344 Curl_inet_ntoa_r_a(struct in_addr internet_address,
345                    char * output_buffer, int output_buffer_length)
346
347 {
348   int rc;
349   int i;
350   char * cp;
351
352   if (!output_buffer || output_buffer_length < 16)
353     return inet_ntoa_r(internet_address, output_buffer, output_buffer_length);
354
355   if (!(cp = malloc(output_buffer_length + 1)))
356     return -1;
357
358   rc = inet_ntoa_r(internet_address, cp, output_buffer_length);
359
360   if (rc) {
361     free(cp);
362     return rc;
363     }
364
365   cp[output_buffer_length - 1] = '\0';
366   i = strlen(cp);
367   QadrtConvertE2A(output_buffer, cp, i, i);
368   output_buffer[i] = '\0';
369   free(cp);
370   return rc;
371 }
372
373
374 #ifdef USE_QSOSSL
375
376 /* ASCII wrappers for the SSL procedures. */
377
378 int
379 Curl_SSL_Init_Application_a(SSLInitApp * init_app)
380
381 {
382   int rc;
383   unsigned int i;
384   SSLInitApp ia;
385
386   if (!init_app || !init_app->applicationID || !init_app->applicationIDLen)
387     return SSL_Init_Application(init_app);
388
389   memcpy((char *) &ia, (char *) init_app, sizeof ia);
390   i = ia.applicationIDLen;
391
392   if (!(ia.applicationID = malloc(i + 1))) {
393     errno = ENOMEM;
394     return SSL_ERROR_IO;
395     }
396
397   QadrtConvertA2E(ia.applicationID, init_app->applicationID, i, i);
398   ia.applicationID[i] = '\0';
399   rc = SSL_Init_Application(&ia);
400   free(ia.applicationID);
401   init_app->localCertificateLen = ia.localCertificateLen;
402   init_app->sessionType = ia.sessionType;
403   return rc;
404 }
405
406
407 int
408 Curl_SSL_Init_a(SSLInit * init)
409
410 {
411   int rc;
412   unsigned int i;
413   SSLInit ia;
414
415   if (!init || (!init->keyringFileName && !init->keyringPassword))
416     return SSL_Init(init);
417
418   memcpy((char *) &ia, (char *) init, sizeof ia);
419
420   if (ia.keyringFileName) {
421     i = strlen(ia.keyringFileName);
422
423     if (!(ia.keyringFileName = malloc(i + 1))) {
424       errno = ENOMEM;
425       return SSL_ERROR_IO;
426       }
427
428     QadrtConvertA2E(ia.keyringFileName, init->keyringFileName, i, i);
429     ia.keyringFileName[i] = '\0';
430     }
431
432   if (ia.keyringPassword) {
433     i = strlen(ia.keyringPassword);
434
435     if (!(ia.keyringPassword = malloc(i + 1))) {
436       if (ia.keyringFileName)
437         free(ia.keyringFileName);
438
439       errno = ENOMEM;
440       return SSL_ERROR_IO;
441       }
442
443     QadrtConvertA2E(ia.keyringPassword, init->keyringPassword, i, i);
444     ia.keyringPassword[i] = '\0';
445     }
446
447   rc = SSL_Init(&ia);
448
449   if (ia.keyringFileName)
450     free(ia.keyringFileName);
451
452   if (ia.keyringPassword)
453     free(ia.keyringPassword);
454
455   return rc;
456 }
457
458
459 char *
460 Curl_SSL_Strerror_a(int sslreturnvalue, SSLErrorMsg * serrmsgp)
461
462 {
463   int i;
464   char * cp;
465   char * cp2;
466
467   cp = SSL_Strerror(sslreturnvalue, serrmsgp);
468
469   if (!cp)
470     return cp;
471
472   i = strlen(cp);
473
474   if (!(cp2 = Curl_thread_buffer(LK_SSL_ERROR, MAX_CONV_EXPANSION * i + 1)))
475     return cp2;
476
477   i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
478   cp2[i] = '\0';
479   return cp2;
480 }
481
482 #endif /* USE_QSOSSL */
483
484
485 #ifdef HAVE_GSSAPI
486
487 /* ASCII wrappers for the GSSAPI procedures. */
488
489 static int
490 Curl_gss_convert_in_place(OM_uint32 * minor_status, gss_buffer_t buf)
491
492 {
493   unsigned int i;
494   char * t;
495
496   /* Convert `buf' in place, from EBCDIC to ASCII.
497      If error, release the buffer and return -1. Else return 0. */
498
499   i = buf->length;
500
501   if (i) {
502     if (!(t = malloc(i))) {
503       gss_release_buffer(minor_status, buf);
504
505       if (minor_status)
506         *minor_status = ENOMEM;
507
508       return -1;
509       }
510
511     QadrtConvertE2A(t, buf->value, i, i);
512     memcpy(buf->value, t, i);
513     free(t);
514     }
515
516   return 0;
517 }
518
519
520 OM_uint32
521 Curl_gss_import_name_a(OM_uint32 * minor_status, gss_buffer_t in_name,
522                        gss_OID in_name_type, gss_name_t * out_name)
523
524 {
525   int rc;
526   unsigned int i;
527   gss_buffer_desc in;
528
529   if (!in_name || !in_name->value || !in_name->length)
530     return gss_import_name(minor_status, in_name, in_name_type, out_name);
531
532   memcpy((char *) &in, (char *) in_name, sizeof in);
533   i = in.length;
534
535   if (!(in.value = malloc(i + 1))) {
536     if (minor_status)
537       *minor_status = ENOMEM;
538
539     return GSS_S_FAILURE;
540     }
541
542   QadrtConvertA2E(in.value, in_name->value, i, i);
543   ((char *) in.value)[i] = '\0';
544   rc = gss_import_name(minor_status, &in, in_name_type, out_name);
545   free(in.value);
546   return rc;
547 }
548
549
550 OM_uint32
551 Curl_gss_display_status_a(OM_uint32 * minor_status, OM_uint32 status_value,
552                    int status_type, gss_OID mech_type,
553                    gss_msg_ctx_t * message_context, gss_buffer_t status_string)
554
555 {
556   int rc;
557
558   rc = gss_display_status(minor_status, status_value, status_type,
559                               mech_type, message_context, status_string);
560
561   if (rc != GSS_S_COMPLETE || !status_string ||
562       !status_string->length || !status_string->value)
563     return rc;
564
565   /* No way to allocate a buffer here, because it will be released by
566      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
567      with ASCII to return it. */
568
569   if (Curl_gss_convert_in_place(minor_status, status_string))
570     return GSS_S_FAILURE;
571
572   return rc;
573 }
574
575
576 OM_uint32
577 Curl_gss_init_sec_context_a(OM_uint32 * minor_status, gss_cred_id_t cred_handle,
578                             gss_ctx_id_t * context_handle,
579                             gss_name_t target_name, gss_OID mech_type,
580                             gss_flags_t req_flags, OM_uint32 time_req,
581                             gss_channel_bindings_t input_chan_bindings,
582                             gss_buffer_t input_token,
583                             gss_OID * actual_mech_type,
584                             gss_buffer_t output_token, gss_flags_t * ret_flags,
585                             OM_uint32 * time_rec)
586
587 {
588   int rc;
589   unsigned int i;
590   gss_buffer_desc in;
591   gss_buffer_t inp;
592
593   in.value = NULL;
594
595   if ((inp = input_token))
596     if (inp->length && inp->value) {
597       i = inp->length;
598
599       if (!(in.value = malloc(i + 1))) {
600         if (minor_status)
601           *minor_status = ENOMEM;
602
603         return GSS_S_FAILURE;
604         }
605
606       QadrtConvertA2E(in.value, input_token->value, i, i);
607       ((char *) in.value)[i] = '\0';
608       in.length = i;
609       inp = &in;
610       }
611
612   rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
613                              target_name, mech_type, req_flags, time_req,
614                              input_chan_bindings, inp, actual_mech_type,
615                              output_token, ret_flags, time_rec);
616
617   if (in.value)
618     free(in.value);
619
620   if (rc != GSS_S_COMPLETE || !output_token ||
621       !output_token->length || !output_token->value)
622     return rc;
623
624   /* No way to allocate a buffer here, because it will be released by
625      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
626      with ASCII to return it. */
627
628   if (Curl_gss_convert_in_place(minor_status, output_token))
629     return GSS_S_FAILURE;
630
631   return rc;
632 }
633
634
635 OM_uint32
636 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
637                               gss_ctx_id_t * context_handle,
638                               gss_buffer_t output_token)
639
640 {
641   int rc;
642
643   rc = gss_delete_sec_context(minor_status, context_handle, output_token);
644
645   if (rc != GSS_S_COMPLETE || !output_token ||
646       !output_token->length || !output_token->value)
647     return rc;
648
649   /* No way to allocate a buffer here, because it will be released by
650      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
651      with ASCII to return it. */
652
653   if (Curl_gss_convert_in_place(minor_status, output_token))
654     return GSS_S_FAILURE;
655
656   return rc;
657 }
658
659 #endif /* HAVE_GSSAPI */
660
661
662 #ifndef CURL_DISABLE_LDAP
663
664 /* ASCII wrappers for the LDAP procedures. */
665
666 void *
667 Curl_ldap_init_a(char * host, int port)
668
669 {
670   unsigned int i;
671   char * ehost;
672   void * result;
673
674   if (!host)
675     return (void *) ldap_init(host, port);
676
677   i = strlen(host);
678
679   if (!(ehost = malloc(i + 1)))
680     return (void *) NULL;
681
682   QadrtConvertA2E(ehost, host, i, i);
683   ehost[i] = '\0';
684   result = (void *) ldap_init(ehost, port);
685   free(ehost);
686   return result;
687 }
688
689
690 int
691 Curl_ldap_simple_bind_s_a(void * ld, char * dn, char * passwd)
692
693 {
694   int i;
695   char * edn;
696   char * epasswd;
697
698   edn = (char *) NULL;
699   epasswd = (char *) NULL;
700
701   if (dn) {
702     i = strlen(dn);
703
704     if (!(edn = malloc(i + 1)))
705       return LDAP_NO_MEMORY;
706
707     QadrtConvertA2E(edn, dn, i, i);
708     edn[i] = '\0';
709     }
710
711   if (passwd) {
712     i = strlen(passwd);
713
714     if (!(epasswd = malloc(i + 1))) {
715       if (edn)
716         free(edn);
717
718       return LDAP_NO_MEMORY;
719       }
720
721     QadrtConvertA2E(epasswd, passwd, i, i);
722     epasswd[i] = '\0';
723     }
724
725   i = ldap_simple_bind_s(ld, edn, epasswd);
726
727   if (epasswd)
728     free(epasswd);
729
730   if (edn)
731     free(edn);
732
733   return i;
734 }
735
736
737 int
738 Curl_ldap_search_s_a(void * ld, char * base, int scope, char * filter,
739                      char * * attrs, int attrsonly, LDAPMessage * * res)
740
741 {
742   int i;
743   int j;
744   char * ebase;
745   char * efilter;
746   char * * eattrs;
747   int status;
748
749   ebase = (char *) NULL;
750   efilter = (char *) NULL;
751   eattrs = (char * *) NULL;
752   status = LDAP_SUCCESS;
753
754   if (base) {
755     i = strlen(base);
756
757     if (!(ebase = malloc(i + 1)))
758       status = LDAP_NO_MEMORY;
759     else {
760       QadrtConvertA2E(ebase, base, i, i);
761       ebase[i] = '\0';
762       }
763     }
764
765   if (filter && status == LDAP_SUCCESS) {
766     i = strlen(filter);
767
768     if (!(efilter = malloc(i + 1)))
769       status = LDAP_NO_MEMORY;
770     else {
771       QadrtConvertA2E(efilter, filter, i, i);
772       efilter[i] = '\0';
773       }
774     }
775
776   if (attrs && status == LDAP_SUCCESS) {
777     for (i = 0; attrs[i++];)
778       ;
779
780     if (!(eattrs = (char * *) calloc(i, sizeof *eattrs)))
781       status = LDAP_NO_MEMORY;
782     else {
783       for (j = 0; attrs[j]; j++) {
784         i = strlen(attrs[j]);
785
786         if (!(eattrs[j] = malloc(i + 1))) {
787           status = LDAP_NO_MEMORY;
788           break;
789           }
790
791         QadrtConvertA2E(eattrs[j], attrs[j], i, i);
792         eattrs[j][i] = '\0';
793         }
794       }
795     }
796
797   if (status == LDAP_SUCCESS)
798     status = ldap_search_s(ld, ebase? ebase: "", scope,
799                            efilter? efilter: "(objectclass=*)",
800                            eattrs, attrsonly, res);
801
802   if (eattrs) {
803     for (j = 0; eattrs[j]; j++)
804       free(eattrs[j]);
805
806     free(eattrs);
807     }
808
809   if (efilter)
810     free(efilter);
811
812   if (ebase)
813     free(ebase);
814
815   return status;
816 }
817
818
819 struct berval * *
820 Curl_ldap_get_values_len_a(void * ld, LDAPMessage * entry, const char * attr)
821
822 {
823   int i;
824   char * cp;
825   struct berval * * result;
826
827   cp = (char *) NULL;
828
829   if (attr) {
830     i = strlen(attr);
831
832     if (!(cp = malloc(i + 1))) {
833       ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
834                        ldap_err2string(LDAP_NO_MEMORY));
835       return (struct berval * *) NULL;
836       }
837
838     QadrtConvertA2E(cp, attr, i, i);
839     cp[i] = '\0';
840     }
841
842   result = ldap_get_values_len(ld, entry, cp);
843
844   if (cp)
845     free(cp);
846
847   /* Result data are binary in nature, so they haven't been converted to EBCDIC.
848      Therefore do not convert. */
849
850   return result;
851 }
852
853
854 char *
855 Curl_ldap_err2string_a(int error)
856
857 {
858   int i;
859   char * cp;
860   char * cp2;
861
862   cp = ldap_err2string(error);
863
864   if (!cp)
865     return cp;
866
867   i = strlen(cp);
868
869   if (!(cp2 = Curl_thread_buffer(LK_LDAP_ERROR, MAX_CONV_EXPANSION * i + 1)))
870     return cp2;
871
872   i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
873   cp2[i] = '\0';
874   return cp2;
875 }
876
877
878 char *
879 Curl_ldap_get_dn_a(void * ld, LDAPMessage * entry)
880
881 {
882   int i;
883   char * cp;
884   char * cp2;
885
886   cp = ldap_get_dn(ld, entry);
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_first_attribute_a(void * ld,
910                             LDAPMessage * entry, BerElement * * berptr)
911
912 {
913   int i;
914   char * cp;
915   char * cp2;
916
917   cp = ldap_first_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
939 char *
940 Curl_ldap_next_attribute_a(void * ld,
941                            LDAPMessage * entry, BerElement * berptr)
942
943 {
944   int i;
945   char * cp;
946   char * cp2;
947
948   cp = ldap_next_attribute(ld, entry, berptr);
949
950   if (!cp)
951     return cp;
952
953   i = strlen(cp);
954
955   if (!(cp2 = malloc(i + 1)))
956     return cp2;
957
958   QadrtConvertE2A(cp2, cp, i, i);
959
960   /* No way to allocate a buffer here, because it will be released by
961      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
962      overwrite the EBCDIC buffer with ASCII to return it. */
963
964   strcpy(cp, cp2);
965   free(cp2);
966   return cp;
967 }
968
969 #endif /* CURL_DISABLE_LDAP */
970
971
972 static int
973 convert_sockaddr(struct sockaddr_storage * dstaddr,
974                                 const struct sockaddr * srcaddr, int srclen)
975
976 {
977   const struct sockaddr_un * srcu;
978   struct sockaddr_un * dstu;
979   unsigned int i;
980   unsigned int dstsize;
981
982   /* Convert a socket address into job CCSID, if needed. */
983
984   if (!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
985       sizeof srcaddr->sa_family || srclen > sizeof *dstaddr) {
986     errno = EINVAL;
987     return -1;
988     }
989
990   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
991
992   switch (srcaddr->sa_family) {
993
994   case AF_UNIX:
995     srcu = (const struct sockaddr_un *) srcaddr;
996     dstu = (struct sockaddr_un *) dstaddr;
997     dstsize = sizeof *dstaddr - offsetof(struct sockaddr_un, sun_path);
998     srclen -= offsetof(struct sockaddr_un, sun_path);
999     i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
1000     dstu->sun_path[i] = '\0';
1001     i += offsetof(struct sockaddr_un, sun_path);
1002     srclen = i;
1003     }
1004
1005   return srclen;
1006 }
1007
1008
1009 int
1010 Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen)
1011
1012 {
1013   int i;
1014   struct sockaddr_storage laddr;
1015
1016   i = convert_sockaddr(&laddr, destaddr, addrlen);
1017
1018   if (i < 0)
1019     return -1;
1020
1021   return connect(sd, (struct sockaddr *) &laddr, i);
1022 }
1023
1024
1025 int
1026 Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen)
1027
1028 {
1029   int i;
1030   struct sockaddr_storage laddr;
1031
1032   i = convert_sockaddr(&laddr, localaddr, addrlen);
1033
1034   if (i < 0)
1035     return -1;
1036
1037   return bind(sd, (struct sockaddr *) &laddr, i);
1038 }
1039
1040
1041 int
1042 Curl_os400_sendto(int sd, char * buffer, int buflen, int flags,
1043                                 struct sockaddr * dstaddr, int addrlen)
1044
1045 {
1046   int i;
1047   struct sockaddr_storage laddr;
1048
1049   i = convert_sockaddr(&laddr, dstaddr, addrlen);
1050
1051   if (i < 0)
1052     return -1;
1053
1054   return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
1055 }
1056
1057
1058 int
1059 Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags,
1060                                 struct sockaddr * fromaddr, int * addrlen)
1061
1062 {
1063   int i;
1064   int rcvlen;
1065   int laddrlen;
1066   const struct sockaddr_un * srcu;
1067   struct sockaddr_un * dstu;
1068   struct sockaddr_storage laddr;
1069
1070   if (!fromaddr || !addrlen || *addrlen <= 0)
1071     return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
1072
1073   laddrlen = sizeof laddr;
1074   laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
1075   rcvlen = recvfrom(sd, buffer, buflen, flags,
1076                     (struct sockaddr *) &laddr, &laddrlen);
1077
1078   if (rcvlen < 0)
1079     return rcvlen;
1080
1081   switch (laddr.ss_family) {
1082
1083   case AF_UNIX:
1084     srcu = (const struct sockaddr_un *) &laddr;
1085     dstu = (struct sockaddr_un *) fromaddr;
1086     i = *addrlen - offsetof(struct sockaddr_un, sun_path);
1087     laddrlen -= offsetof(struct sockaddr_un, sun_path);
1088     i = QadrtConvertE2A(dstu->sun_path, srcu->sun_path, i, laddrlen);
1089     laddrlen = i + offsetof(struct sockaddr_un, sun_path);
1090
1091     if (laddrlen < *addrlen)
1092       dstu->sun_path[i] = '\0';
1093
1094     break;
1095
1096   case AF_UNSPEC:
1097     break;
1098
1099   default:
1100     if (laddrlen > *addrlen)
1101       laddrlen = *addrlen;
1102
1103     if (laddrlen)
1104       memcpy((char *) fromaddr, (char *) &laddr, laddrlen);
1105
1106     break;
1107     }
1108
1109   *addrlen = laddrlen;
1110   return rcvlen;
1111 }