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