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 = ∈
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