blob: 862c7fd38e785805b334986a48f866d5b375562e [file] [log] [blame]
xf.li6c8fc1e2023-08-12 00:11:09 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, 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 USE_GSKIT
48#include <gskssl.h>
49#include <qsoasync.h>
50#endif
51
52#ifdef HAVE_GSSAPI
53#include <gssapi.h>
54#endif
55
56#ifndef CURL_DISABLE_LDAP
57#include <ldap.h>
58#endif
59
60#include <netinet/in.h>
61#include <arpa/inet.h>
62
63#include "os400sys.h"
64
65/**
66*** QADRT OS/400 ASCII runtime defines only the most used procedures, but a
67*** lot of them are not supported. This module implements ASCII wrappers for
68*** those that are used by libcurl, but not defined by QADRT.
69**/
70
71#pragma convert(0) /* Restore EBCDIC. */
72
73#define MIN_BYTE_GAIN 1024 /* Minimum gain when shortening a buffer. */
74
75struct buffer_t {
76 unsigned long size; /* Buffer size. */
77 char *buf; /* Buffer address. */
78};
79
80
81static char *buffer_undef(localkey_t key, long size);
82static char *buffer_threaded(localkey_t key, long size);
83static char *buffer_unthreaded(localkey_t key, long size);
84
85static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
86static pthread_key_t thdkey;
87static struct buffer_t *locbufs;
88
89char *(*Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
90
91static void thdbufdestroy(void *private)
92{
93 if(private) {
94 struct buffer_t *p = (struct buffer_t *) private;
95 localkey_t i;
96
97 for(i = (localkey_t) 0; i < LK_LAST; i++) {
98 free(p->buf);
99 p++;
100 }
101
102 free(private);
103 }
104}
105
106
107static void
108terminate(void)
109{
110 if(Curl_thread_buffer == buffer_threaded) {
111 locbufs = pthread_getspecific(thdkey);
112 pthread_setspecific(thdkey, (void *) NULL);
113 pthread_key_delete(thdkey);
114 }
115
116 if(Curl_thread_buffer != buffer_undef) {
117 thdbufdestroy((void *) locbufs);
118 locbufs = (struct buffer_t *) NULL;
119 }
120
121 Curl_thread_buffer = buffer_undef;
122}
123
124
125static char *
126get_buffer(struct buffer_t *buf, long size)
127{
128 char *cp;
129
130 /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long.
131 Return the buffer address. */
132
133 if(size < 0)
134 return buf->buf;
135
136 if(!buf->buf) {
137 buf->buf = malloc(size);
138 if(buf->buf)
139 buf->size = size;
140
141 return buf->buf;
142 }
143
144 if((unsigned long) size <= buf->size) {
145 /* Shorten the buffer only if it frees a significant byte count. This
146 avoids some realloc() overhead. */
147
148 if(buf->size - size < MIN_BYTE_GAIN)
149 return buf->buf;
150 }
151
152 /* Resize the buffer. */
153
154 cp = realloc(buf->buf, size);
155 if(cp) {
156 buf->buf = cp;
157 buf->size = size;
158 }
159 else if(size <= buf->size)
160 cp = buf->buf;
161
162 return cp;
163}
164
165
166static char *
167buffer_unthreaded(localkey_t key, long size)
168{
169 return get_buffer(locbufs + key, size);
170}
171
172
173static char *
174buffer_threaded(localkey_t key, long size)
175{
176 struct buffer_t *bufs;
177
178 /* Get the buffer for the given local key in the current thread, and
179 make sure it is at least `size'-byte long. Set `size' to < 0 to get
180 its address only. */
181
182 bufs = (struct buffer_t *) pthread_getspecific(thdkey);
183
184 if(!bufs) {
185 if(size < 0)
186 return (char *) NULL; /* No buffer yet. */
187
188 /* Allocate buffer descriptors for the current thread. */
189
190 bufs = calloc((size_t) LK_LAST, sizeof(*bufs));
191 if(!bufs)
192 return (char *) NULL;
193
194 if(pthread_setspecific(thdkey, (void *) bufs)) {
195 free(bufs);
196 return (char *) NULL;
197 }
198 }
199
200 return get_buffer(bufs + key, size);
201}
202
203
204static char *
205buffer_undef(localkey_t key, long size)
206{
207 /* Define the buffer system, get the buffer for the given local key in
208 the current thread, and make sure it is at least `size'-byte long.
209 Set `size' to < 0 to get its address only. */
210
211 pthread_mutex_lock(&mutex);
212
213 /* Determine if we can use pthread-specific data. */
214
215 if(Curl_thread_buffer == buffer_undef) { /* If unchanged during lock. */
216 if(!pthread_key_create(&thdkey, thdbufdestroy))
217 Curl_thread_buffer = buffer_threaded;
218 else {
219 locbufs = calloc((size_t) LK_LAST, sizeof(*locbufs));
220 if(!locbufs) {
221 pthread_mutex_unlock(&mutex);
222 return (char *) NULL;
223 }
224 else
225 Curl_thread_buffer = buffer_unthreaded;
226 }
227
228 atexit(terminate);
229 }
230
231 pthread_mutex_unlock(&mutex);
232 return Curl_thread_buffer(key, size);
233}
234
235
236static char *
237set_thread_string(localkey_t key, const char *s)
238{
239 int i;
240 char *cp;
241
242 if(!s)
243 return (char *) NULL;
244
245 i = strlen(s) + 1;
246 cp = Curl_thread_buffer(key, MAX_CONV_EXPANSION * i + 1);
247
248 if(cp) {
249 i = QadrtConvertE2A(cp, s, MAX_CONV_EXPANSION * i, i);
250 cp[i] = '\0';
251 }
252
253 return cp;
254}
255
256
257int
258Curl_getnameinfo_a(const struct sockaddr *sa, curl_socklen_t salen,
259 char *nodename, curl_socklen_t nodenamelen,
260 char *servname, curl_socklen_t servnamelen,
261 int flags)
262{
263 char *enodename = NULL;
264 char *eservname = NULL;
265 int status;
266
267 if(nodename && nodenamelen) {
268 enodename = malloc(nodenamelen);
269 if(!enodename)
270 return EAI_MEMORY;
271 }
272
273 if(servname && servnamelen) {
274 eservname = malloc(servnamelen);
275 if(!eservname) {
276 free(enodename);
277 return EAI_MEMORY;
278 }
279 }
280
281 status = getnameinfo(sa, salen, enodename, nodenamelen,
282 eservname, servnamelen, flags);
283
284 if(!status) {
285 int i;
286 if(enodename) {
287 i = QadrtConvertE2A(nodename, enodename,
288 nodenamelen - 1, strlen(enodename));
289 nodename[i] = '\0';
290 }
291
292 if(eservname) {
293 i = QadrtConvertE2A(servname, eservname,
294 servnamelen - 1, strlen(eservname));
295 servname[i] = '\0';
296 }
297 }
298
299 free(enodename);
300 free(eservname);
301 return status;
302}
303
304int
305Curl_getaddrinfo_a(const char *nodename, const char *servname,
306 const struct addrinfo *hints,
307 struct addrinfo **res)
308{
309 char *enodename;
310 char *eservname;
311 int status;
312 int i;
313
314 enodename = (char *) NULL;
315 eservname = (char *) NULL;
316
317 if(nodename) {
318 i = strlen(nodename);
319
320 enodename = malloc(i + 1);
321 if(!enodename)
322 return EAI_MEMORY;
323
324 i = QadrtConvertA2E(enodename, nodename, i, i);
325 enodename[i] = '\0';
326 }
327
328 if(servname) {
329 i = strlen(servname);
330
331 eservname = malloc(i + 1);
332 if(!eservname) {
333 free(enodename);
334 return EAI_MEMORY;
335 }
336
337 QadrtConvertA2E(eservname, servname, i, i);
338 eservname[i] = '\0';
339 }
340
341 status = getaddrinfo(enodename, eservname, hints, res);
342 free(enodename);
343 free(eservname);
344 return status;
345}
346
347#ifdef USE_GSKIT
348
349/* ASCII wrappers for the GSKit procedures. */
350
351/*
352 * EBCDIC --> ASCII string mapping table.
353 * Some strings returned by GSKit are dynamically allocated and automatically
354 * released when closing the handle.
355 * To provide the same functionality, we use a "private" handle that
356 * holds the GSKit handle and a list of string mappings. This will allow
357 * avoid conversion of already converted strings and releasing them upon
358 * close time.
359 */
360
361struct gskstrlist {
362 struct gskstrlist *next;
363 const char *ebcdicstr;
364 const char *asciistr;
365};
366
367struct Curl_gsk_descriptor {
368 gsk_handle h;
369 struct gskstrlist *strlist;
370};
371
372int Curl_gsk_environment_open(gsk_handle *my_env_handle)
373{
374 struct Curl_gsk_descriptor *p;
375 int rc;
376
377 if(!my_env_handle)
378 return GSK_OS400_ERROR_INVALID_POINTER;
379 p = (struct Curl_gsk_descriptor *) malloc(sizeof(*p));
380 if(!p)
381 return GSK_INSUFFICIENT_STORAGE;
382 p->strlist = (struct gskstrlist *) NULL;
383 rc = gsk_environment_open(&p->h);
384 if(rc != GSK_OK)
385 free(p);
386 else
387 *my_env_handle = (gsk_handle) p;
388 return rc;
389}
390
391int Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
392 gsk_handle *my_session_handle)
393{
394 struct Curl_gsk_descriptor *p;
395 gsk_handle h;
396 int rc;
397
398 if(!my_env_handle)
399 return GSK_INVALID_HANDLE;
400 if(!my_session_handle)
401 return GSK_OS400_ERROR_INVALID_POINTER;
402 h = ((struct Curl_gsk_descriptor *) my_env_handle)->h;
403 p = (struct Curl_gsk_descriptor *) malloc(sizeof(*p));
404 if(!p)
405 return GSK_INSUFFICIENT_STORAGE;
406 p->strlist = (struct gskstrlist *) NULL;
407 rc = gsk_secure_soc_open(h, &p->h);
408 if(rc != GSK_OK)
409 free(p);
410 else
411 *my_session_handle = (gsk_handle) p;
412 return rc;
413}
414
415static void gsk_free_handle(struct Curl_gsk_descriptor *p)
416{
417 struct gskstrlist *q;
418
419 while((q = p->strlist)) {
420 p->strlist = q;
421 free((void *) q->asciistr);
422 free(q);
423 }
424 free(p);
425}
426
427int Curl_gsk_environment_close(gsk_handle *my_env_handle)
428{
429 struct Curl_gsk_descriptor *p;
430 int rc;
431
432 if(!my_env_handle)
433 return GSK_OS400_ERROR_INVALID_POINTER;
434 if(!*my_env_handle)
435 return GSK_INVALID_HANDLE;
436 p = (struct Curl_gsk_descriptor *) *my_env_handle;
437 rc = gsk_environment_close(&p->h);
438 if(rc == GSK_OK) {
439 gsk_free_handle(p);
440 *my_env_handle = (gsk_handle) NULL;
441 }
442 return rc;
443}
444
445
446int Curl_gsk_secure_soc_close(gsk_handle *my_session_handle)
447{
448 struct Curl_gsk_descriptor *p;
449 int rc;
450
451 if(!my_session_handle)
452 return GSK_OS400_ERROR_INVALID_POINTER;
453 if(!*my_session_handle)
454 return GSK_INVALID_HANDLE;
455 p = (struct Curl_gsk_descriptor *) *my_session_handle;
456 rc = gsk_secure_soc_close(&p->h);
457 if(rc == GSK_OK) {
458 gsk_free_handle(p);
459 *my_session_handle = (gsk_handle) NULL;
460 }
461 return rc;
462}
463
464int Curl_gsk_environment_init(gsk_handle my_env_handle)
465{
466 struct Curl_gsk_descriptor *p;
467
468 if(!my_env_handle)
469 return GSK_INVALID_HANDLE;
470 p = (struct Curl_gsk_descriptor *) my_env_handle;
471 return gsk_environment_init(p->h);
472}
473
474
475int Curl_gsk_secure_soc_init(gsk_handle my_session_handle)
476{
477 struct Curl_gsk_descriptor *p;
478
479 if(!my_session_handle)
480 return GSK_INVALID_HANDLE;
481 p = (struct Curl_gsk_descriptor *) my_session_handle;
482 return gsk_secure_soc_init(p->h);
483}
484
485
486int
487Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID,
488 const char *buffer, int bufSize)
489{
490 struct Curl_gsk_descriptor *p;
491 char *ebcdicbuf;
492 int rc;
493
494 if(!my_gsk_handle)
495 return GSK_INVALID_HANDLE;
496 if(!buffer)
497 return GSK_OS400_ERROR_INVALID_POINTER;
498 if(bufSize < 0)
499 return GSK_ATTRIBUTE_INVALID_LENGTH;
500 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
501 if(!bufSize)
502 bufSize = strlen(buffer);
503 ebcdicbuf = malloc(bufSize + 1);
504 if(!ebcdicbuf)
505 return GSK_INSUFFICIENT_STORAGE;
506 QadrtConvertA2E(ebcdicbuf, buffer, bufSize, bufSize);
507 ebcdicbuf[bufSize] = '\0';
508 rc = gsk_attribute_set_buffer(p->h, bufID, ebcdicbuf, bufSize);
509 free(ebcdicbuf);
510 return rc;
511}
512
513
514int
515Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID,
516 GSK_ENUM_VALUE enumValue)
517{
518 struct Curl_gsk_descriptor *p;
519
520 if(!my_gsk_handle)
521 return GSK_INVALID_HANDLE;
522 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
523 return gsk_attribute_set_enum(p->h, enumID, enumValue);
524}
525
526
527int
528Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
529 GSK_NUM_ID numID, int numValue)
530{
531 struct Curl_gsk_descriptor *p;
532
533 if(!my_gsk_handle)
534 return GSK_INVALID_HANDLE;
535 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
536 return gsk_attribute_set_numeric_value(p->h, numID, numValue);
537}
538
539
540int
541Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
542 GSK_CALLBACK_ID callBackID,
543 void *callBackAreaPtr)
544{
545 struct Curl_gsk_descriptor *p;
546
547 if(!my_gsk_handle)
548 return GSK_INVALID_HANDLE;
549 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
550 return gsk_attribute_set_callback(p->h, callBackID, callBackAreaPtr);
551}
552
553
554static int
555cachestring(struct Curl_gsk_descriptor *p,
556 const char *ebcdicbuf, int bufsize, const char **buffer)
557{
558 int rc;
559 char *asciibuf;
560 struct gskstrlist *sp;
561
562 for(sp = p->strlist; sp; sp = sp->next)
563 if(sp->ebcdicstr == ebcdicbuf)
564 break;
565 if(!sp) {
566 sp = (struct gskstrlist *) malloc(sizeof(*sp));
567 if(!sp)
568 return GSK_INSUFFICIENT_STORAGE;
569 asciibuf = malloc(bufsize + 1);
570 if(!asciibuf) {
571 free(sp);
572 return GSK_INSUFFICIENT_STORAGE;
573 }
574 QadrtConvertE2A(asciibuf, ebcdicbuf, bufsize, bufsize);
575 asciibuf[bufsize] = '\0';
576 sp->ebcdicstr = ebcdicbuf;
577 sp->asciistr = asciibuf;
578 sp->next = p->strlist;
579 p->strlist = sp;
580 }
581 *buffer = sp->asciistr;
582 return GSK_OK;
583}
584
585
586int
587Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID,
588 const char **buffer, int *bufSize)
589{
590 struct Curl_gsk_descriptor *p;
591 int rc;
592 const char *mybuf;
593 int mylen;
594
595 if(!my_gsk_handle)
596 return GSK_INVALID_HANDLE;
597 if(!buffer || !bufSize)
598 return GSK_OS400_ERROR_INVALID_POINTER;
599 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
600 rc = gsk_attribute_get_buffer(p->h, bufID, &mybuf, &mylen);
601 if(rc != GSK_OK)
602 return rc;
603 rc = cachestring(p, mybuf, mylen, buffer);
604 if(rc == GSK_OK)
605 *bufSize = mylen;
606 return rc;
607}
608
609
610int
611Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID,
612 GSK_ENUM_VALUE *enumValue)
613{
614 struct Curl_gsk_descriptor *p;
615
616 if(!my_gsk_handle)
617 return GSK_INVALID_HANDLE;
618 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
619 return gsk_attribute_get_enum(p->h, enumID, enumValue);
620}
621
622
623int
624Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
625 GSK_NUM_ID numID, int *numValue)
626{
627 struct Curl_gsk_descriptor *p;
628
629 if(!my_gsk_handle)
630 return GSK_INVALID_HANDLE;
631 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
632 return gsk_attribute_get_numeric_value(p->h, numID, numValue);
633}
634
635
636int
637Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
638 GSK_CERT_ID certID,
639 const gsk_cert_data_elem **certDataElem,
640 int *certDataElementCount)
641{
642 struct Curl_gsk_descriptor *p;
643
644 if(!my_gsk_handle)
645 return GSK_INVALID_HANDLE;
646 p = (struct Curl_gsk_descriptor *) my_gsk_handle;
647 /* No need to convert code: text results are already in ASCII. */
648 return gsk_attribute_get_cert_info(p->h, certID,
649 certDataElem, certDataElementCount);
650}
651
652
653int
654Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, GSK_MISC_ID miscID)
655{
656 struct Curl_gsk_descriptor *p;
657
658 if(!my_session_handle)
659 return GSK_INVALID_HANDLE;
660 p = (struct Curl_gsk_descriptor *) my_session_handle;
661 return gsk_secure_soc_misc(p->h, miscID);
662}
663
664
665int
666Curl_gsk_secure_soc_read(gsk_handle my_session_handle, char *readBuffer,
667 int readBufSize, int *amtRead)
668{
669 struct Curl_gsk_descriptor *p;
670
671 if(!my_session_handle)
672 return GSK_INVALID_HANDLE;
673 p = (struct Curl_gsk_descriptor *) my_session_handle;
674 return gsk_secure_soc_read(p->h, readBuffer, readBufSize, amtRead);
675}
676
677
678int
679Curl_gsk_secure_soc_write(gsk_handle my_session_handle, char *writeBuffer,
680 int writeBufSize, int *amtWritten)
681{
682 struct Curl_gsk_descriptor *p;
683
684 if(!my_session_handle)
685 return GSK_INVALID_HANDLE;
686 p = (struct Curl_gsk_descriptor *) my_session_handle;
687 return gsk_secure_soc_write(p->h, writeBuffer, writeBufSize, amtWritten);
688}
689
690
691const char *
692Curl_gsk_strerror_a(int gsk_return_value)
693{
694 return set_thread_string(LK_GSK_ERROR, gsk_strerror(gsk_return_value));
695}
696
697int
698Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
699 int IOCompletionPort,
700 Qso_OverlappedIO_t *communicationsArea)
701{
702 struct Curl_gsk_descriptor *p;
703
704 if(!my_session_handle)
705 return GSK_INVALID_HANDLE;
706 p = (struct Curl_gsk_descriptor *) my_session_handle;
707 return gsk_secure_soc_startInit(p->h, IOCompletionPort, communicationsArea);
708}
709
710#endif /* USE_GSKIT */
711
712#ifdef HAVE_GSSAPI
713
714/* ASCII wrappers for the GSSAPI procedures. */
715
716static int
717Curl_gss_convert_in_place(OM_uint32 *minor_status, gss_buffer_t buf)
718{
719 unsigned int i = buf->length;
720
721 /* Convert `buf' in place, from EBCDIC to ASCII.
722 If error, release the buffer and return -1. Else return 0. */
723
724 if(i) {
725 char *t = malloc(i);
726 if(!t) {
727 gss_release_buffer(minor_status, buf);
728
729 if(minor_status)
730 *minor_status = ENOMEM;
731
732 return -1;
733 }
734
735 QadrtConvertE2A(t, buf->value, i, i);
736 memcpy(buf->value, t, i);
737 free(t);
738 }
739
740 return 0;
741}
742
743
744OM_uint32
745Curl_gss_import_name_a(OM_uint32 *minor_status, gss_buffer_t in_name,
746 gss_OID in_name_type, gss_name_t *out_name)
747{
748 int rc;
749 unsigned int i;
750 gss_buffer_desc in;
751
752 if(!in_name || !in_name->value || !in_name->length)
753 return gss_import_name(minor_status, in_name, in_name_type, out_name);
754
755 memcpy((char *) &in, (char *) in_name, sizeof(in));
756 i = in.length;
757
758 in.value = malloc(i + 1);
759 if(!in.value) {
760 if(minor_status)
761 *minor_status = ENOMEM;
762
763 return GSS_S_FAILURE;
764 }
765
766 QadrtConvertA2E(in.value, in_name->value, i, i);
767 ((char *) in.value)[i] = '\0';
768 rc = gss_import_name(minor_status, &in, in_name_type, out_name);
769 free(in.value);
770 return rc;
771}
772
773OM_uint32
774Curl_gss_display_status_a(OM_uint32 *minor_status, OM_uint32 status_value,
775 int status_type, gss_OID mech_type,
776 gss_msg_ctx_t *message_context,
777 gss_buffer_t status_string)
778{
779 int rc;
780
781 rc = gss_display_status(minor_status, status_value, status_type,
782 mech_type, message_context, status_string);
783
784 if(rc != GSS_S_COMPLETE || !status_string ||
785 !status_string->length || !status_string->value)
786 return rc;
787
788 /* No way to allocate a buffer here, because it will be released by
789 gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
790 with ASCII to return it. */
791
792 if(Curl_gss_convert_in_place(minor_status, status_string))
793 return GSS_S_FAILURE;
794
795 return rc;
796}
797
798OM_uint32
799Curl_gss_init_sec_context_a(OM_uint32 *minor_status,
800 gss_cred_id_t cred_handle,
801 gss_ctx_id_t *context_handle,
802 gss_name_t target_name, gss_OID mech_type,
803 gss_flags_t req_flags, OM_uint32 time_req,
804 gss_channel_bindings_t input_chan_bindings,
805 gss_buffer_t input_token,
806 gss_OID *actual_mech_type,
807 gss_buffer_t output_token, gss_flags_t *ret_flags,
808 OM_uint32 *time_rec)
809{
810 int rc;
811 gss_buffer_desc in;
812 gss_buffer_t inp;
813
814 in.value = NULL;
815 inp = input_token;
816
817 if(inp) {
818 if(inp->length && inp->value) {
819 unsigned int i = inp->length;
820
821 in.value = malloc(i + 1);
822 if(!in.value) {
823 if(minor_status)
824 *minor_status = ENOMEM;
825
826 return GSS_S_FAILURE;
827 }
828
829 QadrtConvertA2E(in.value, input_token->value, i, i);
830 ((char *) in.value)[i] = '\0';
831 in.length = i;
832 inp = &in;
833 }
834 }
835
836 rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
837 target_name, mech_type, req_flags, time_req,
838 input_chan_bindings, inp, actual_mech_type,
839 output_token, ret_flags, time_rec);
840 free(in.value);
841
842 if(rc != GSS_S_COMPLETE || !output_token ||
843 !output_token->length || !output_token->value)
844 return rc;
845
846 /* No way to allocate a buffer here, because it will be released by
847 gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
848 with ASCII to return it. */
849
850 if(Curl_gss_convert_in_place(minor_status, output_token))
851 return GSS_S_FAILURE;
852
853 return rc;
854}
855
856
857OM_uint32
858Curl_gss_delete_sec_context_a(OM_uint32 *minor_status,
859 gss_ctx_id_t *context_handle,
860 gss_buffer_t output_token)
861{
862 int rc;
863
864 rc = gss_delete_sec_context(minor_status, context_handle, output_token);
865
866 if(rc != GSS_S_COMPLETE || !output_token ||
867 !output_token->length || !output_token->value)
868 return rc;
869
870 /* No way to allocate a buffer here, because it will be released by
871 gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
872 with ASCII to return it. */
873
874 if(Curl_gss_convert_in_place(minor_status, output_token))
875 return GSS_S_FAILURE;
876
877 return rc;
878}
879
880#endif /* HAVE_GSSAPI */
881
882#ifndef CURL_DISABLE_LDAP
883
884/* ASCII wrappers for the LDAP procedures. */
885
886void *
887Curl_ldap_init_a(char *host, int port)
888{
889 unsigned int i;
890 char *ehost;
891 void *result;
892
893 if(!host)
894 return (void *) ldap_init(host, port);
895
896 i = strlen(host);
897
898 ehost = malloc(i + 1);
899 if(!ehost)
900 return (void *) NULL;
901
902 QadrtConvertA2E(ehost, host, i, i);
903 ehost[i] = '\0';
904 result = (void *) ldap_init(ehost, port);
905 free(ehost);
906 return result;
907}
908
909int
910Curl_ldap_simple_bind_s_a(void *ld, char *dn, char *passwd)
911{
912 int i;
913 char *edn;
914 char *epasswd;
915
916 edn = (char *) NULL;
917 epasswd = (char *) NULL;
918
919 if(dn) {
920 i = strlen(dn);
921
922 edn = malloc(i + 1);
923 if(!edn)
924 return LDAP_NO_MEMORY;
925
926 QadrtConvertA2E(edn, dn, i, i);
927 edn[i] = '\0';
928 }
929
930 if(passwd) {
931 i = strlen(passwd);
932
933 epasswd = malloc(i + 1);
934 if(!epasswd) {
935 free(edn);
936 return LDAP_NO_MEMORY;
937 }
938
939 QadrtConvertA2E(epasswd, passwd, i, i);
940 epasswd[i] = '\0';
941 }
942
943 i = ldap_simple_bind_s(ld, edn, epasswd);
944 free(epasswd);
945 free(edn);
946 return i;
947}
948
949int
950Curl_ldap_search_s_a(void *ld, char *base, int scope, char *filter,
951 char **attrs, int attrsonly, LDAPMessage **res)
952{
953 int i;
954 int j;
955 char *ebase;
956 char *efilter;
957 char **eattrs;
958 int status;
959
960 ebase = (char *) NULL;
961 efilter = (char *) NULL;
962 eattrs = (char **) NULL;
963 status = LDAP_SUCCESS;
964
965 if(base) {
966 i = strlen(base);
967
968 ebase = malloc(i + 1);
969 if(!ebase)
970 status = LDAP_NO_MEMORY;
971 else {
972 QadrtConvertA2E(ebase, base, i, i);
973 ebase[i] = '\0';
974 }
975 }
976
977 if(filter && status == LDAP_SUCCESS) {
978 i = strlen(filter);
979
980 efilter = malloc(i + 1);
981 if(!efilter)
982 status = LDAP_NO_MEMORY;
983 else {
984 QadrtConvertA2E(efilter, filter, i, i);
985 efilter[i] = '\0';
986 }
987 }
988
989 if(attrs && status == LDAP_SUCCESS) {
990 for(i = 0; attrs[i++];)
991 ;
992
993 eattrs = calloc(i, sizeof(*eattrs));
994 if(!eattrs)
995 status = LDAP_NO_MEMORY;
996 else {
997 for(j = 0; attrs[j]; j++) {
998 i = strlen(attrs[j]);
999
1000 eattrs[j] = malloc(i + 1);
1001 if(!eattrs[j]) {
1002 status = LDAP_NO_MEMORY;
1003 break;
1004 }
1005
1006 QadrtConvertA2E(eattrs[j], attrs[j], i, i);
1007 eattrs[j][i] = '\0';
1008 }
1009 }
1010 }
1011
1012 if(status == LDAP_SUCCESS)
1013 status = ldap_search_s(ld, ebase? ebase: "", scope,
1014 efilter? efilter: "(objectclass=*)",
1015 eattrs, attrsonly, res);
1016
1017 if(eattrs) {
1018 for(j = 0; eattrs[j]; j++)
1019 free(eattrs[j]);
1020
1021 free(eattrs);
1022 }
1023
1024 free(efilter);
1025 free(ebase);
1026 return status;
1027}
1028
1029
1030struct berval **
1031Curl_ldap_get_values_len_a(void *ld, LDAPMessage *entry, const char *attr)
1032{
1033 char *cp;
1034 struct berval **result;
1035
1036 cp = (char *) NULL;
1037
1038 if(attr) {
1039 int i = strlen(attr);
1040
1041 cp = malloc(i + 1);
1042 if(!cp) {
1043 ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
1044 ldap_err2string(LDAP_NO_MEMORY));
1045 return (struct berval **) NULL;
1046 }
1047
1048 QadrtConvertA2E(cp, attr, i, i);
1049 cp[i] = '\0';
1050 }
1051
1052 result = ldap_get_values_len(ld, entry, cp);
1053 free(cp);
1054
1055 /* Result data are binary in nature, so they haven't been
1056 converted to EBCDIC. Therefore do not convert. */
1057
1058 return result;
1059}
1060
1061char *
1062Curl_ldap_err2string_a(int error)
1063{
1064 return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error));
1065}
1066
1067char *
1068Curl_ldap_get_dn_a(void *ld, LDAPMessage *entry)
1069{
1070 int i;
1071 char *cp;
1072 char *cp2;
1073
1074 cp = ldap_get_dn(ld, entry);
1075
1076 if(!cp)
1077 return cp;
1078
1079 i = strlen(cp);
1080
1081 cp2 = malloc(i + 1);
1082 if(!cp2)
1083 return cp2;
1084
1085 QadrtConvertE2A(cp2, cp, i, i);
1086 cp2[i] = '\0';
1087
1088 /* No way to allocate a buffer here, because it will be released by
1089 ldap_memfree() and ldap_memalloc() does not exist. The solution is to
1090 overwrite the EBCDIC buffer with ASCII to return it. */
1091
1092 strcpy(cp, cp2);
1093 free(cp2);
1094 return cp;
1095}
1096
1097char *
1098Curl_ldap_first_attribute_a(void *ld,
1099 LDAPMessage *entry, BerElement **berptr)
1100{
1101 int i;
1102 char *cp;
1103 char *cp2;
1104
1105 cp = ldap_first_attribute(ld, entry, berptr);
1106
1107 if(!cp)
1108 return cp;
1109
1110 i = strlen(cp);
1111
1112 cp2 = malloc(i + 1);
1113 if(!cp2)
1114 return cp2;
1115
1116 QadrtConvertE2A(cp2, cp, i, i);
1117 cp2[i] = '\0';
1118
1119 /* No way to allocate a buffer here, because it will be released by
1120 ldap_memfree() and ldap_memalloc() does not exist. The solution is to
1121 overwrite the EBCDIC buffer with ASCII to return it. */
1122
1123 strcpy(cp, cp2);
1124 free(cp2);
1125 return cp;
1126}
1127
1128char *
1129Curl_ldap_next_attribute_a(void *ld,
1130 LDAPMessage *entry, BerElement *berptr)
1131{
1132 int i;
1133 char *cp;
1134 char *cp2;
1135
1136 cp = ldap_next_attribute(ld, entry, berptr);
1137
1138 if(!cp)
1139 return cp;
1140
1141 i = strlen(cp);
1142
1143 cp2 = malloc(i + 1);
1144 if(!cp2)
1145 return cp2;
1146
1147 QadrtConvertE2A(cp2, cp, i, i);
1148 cp2[i] = '\0';
1149
1150 /* No way to allocate a buffer here, because it will be released by
1151 ldap_memfree() and ldap_memalloc() does not exist. The solution is to
1152 overwrite the EBCDIC buffer with ASCII to return it. */
1153
1154 strcpy(cp, cp2);
1155 free(cp2);
1156 return cp;
1157}
1158
1159#endif /* CURL_DISABLE_LDAP */
1160
1161static int
1162sockaddr2ebcdic(struct sockaddr_storage *dstaddr,
1163 const struct sockaddr *srcaddr, int srclen)
1164{
1165 const struct sockaddr_un *srcu;
1166 struct sockaddr_un *dstu;
1167 unsigned int i;
1168 unsigned int dstsize;
1169
1170 /* Convert a socket address to job CCSID, if needed. */
1171
1172 if(!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
1173 sizeof(srcaddr->sa_family) || srclen > sizeof(*dstaddr)) {
1174 errno = EINVAL;
1175 return -1;
1176 }
1177
1178 memcpy((char *) dstaddr, (char *) srcaddr, srclen);
1179
1180 switch(srcaddr->sa_family) {
1181
1182 case AF_UNIX:
1183 srcu = (const struct sockaddr_un *) srcaddr;
1184 dstu = (struct sockaddr_un *) dstaddr;
1185 dstsize = sizeof(*dstaddr) - offsetof(struct sockaddr_un, sun_path);
1186 srclen -= offsetof(struct sockaddr_un, sun_path);
1187 i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
1188 dstu->sun_path[i] = '\0';
1189 srclen = i + offsetof(struct sockaddr_un, sun_path);
1190 }
1191
1192 return srclen;
1193}
1194
1195
1196static int
1197sockaddr2ascii(struct sockaddr *dstaddr, int dstlen,
1198 const struct sockaddr_storage *srcaddr, int srclen)
1199{
1200 const struct sockaddr_un *srcu;
1201 struct sockaddr_un *dstu;
1202 unsigned int dstsize;
1203
1204 /* Convert a socket address to ASCII, if needed. */
1205
1206 if(!srclen)
1207 return 0;
1208 if(srclen > dstlen)
1209 srclen = dstlen;
1210 if(!srcaddr || srclen < 0) {
1211 errno = EINVAL;
1212 return -1;
1213 }
1214
1215 memcpy((char *) dstaddr, (char *) srcaddr, srclen);
1216
1217 if(srclen >= offsetof(struct sockaddr_storage, ss_family) +
1218 sizeof(srcaddr->ss_family)) {
1219 switch(srcaddr->ss_family) {
1220
1221 case AF_UNIX:
1222 srcu = (const struct sockaddr_un *) srcaddr;
1223 dstu = (struct sockaddr_un *) dstaddr;
1224 dstsize = dstlen - offsetof(struct sockaddr_un, sun_path);
1225 srclen -= offsetof(struct sockaddr_un, sun_path);
1226 if(dstsize > 0 && srclen > 0) {
1227 srclen = QadrtConvertE2A(dstu->sun_path, srcu->sun_path,
1228 dstsize - 1, srclen);
1229 dstu->sun_path[srclen] = '\0';
1230 }
1231 srclen += offsetof(struct sockaddr_un, sun_path);
1232 }
1233 }
1234
1235 return srclen;
1236}
1237
1238int
1239Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen)
1240{
1241 int i;
1242 struct sockaddr_storage laddr;
1243
1244 i = sockaddr2ebcdic(&laddr, destaddr, addrlen);
1245
1246 if(i < 0)
1247 return -1;
1248
1249 return connect(sd, (struct sockaddr *) &laddr, i);
1250}
1251
1252int
1253Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen)
1254{
1255 int i;
1256 struct sockaddr_storage laddr;
1257
1258 i = sockaddr2ebcdic(&laddr, localaddr, addrlen);
1259
1260 if(i < 0)
1261 return -1;
1262
1263 return bind(sd, (struct sockaddr *) &laddr, i);
1264}
1265
1266int
1267Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
1268 struct sockaddr *dstaddr, int addrlen)
1269{
1270 int i;
1271 struct sockaddr_storage laddr;
1272
1273 i = sockaddr2ebcdic(&laddr, dstaddr, addrlen);
1274
1275 if(i < 0)
1276 return -1;
1277
1278 return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
1279}
1280
1281int
1282Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
1283 struct sockaddr *fromaddr, int *addrlen)
1284{
1285 int rcvlen;
1286 struct sockaddr_storage laddr;
1287 int laddrlen = sizeof(laddr);
1288
1289 if(!fromaddr || !addrlen || *addrlen <= 0)
1290 return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
1291
1292 laddr.ss_family = AF_UNSPEC; /* To detect if unused. */
1293 rcvlen = recvfrom(sd, buffer, buflen, flags,
1294 (struct sockaddr *) &laddr, &laddrlen);
1295
1296 if(rcvlen < 0)
1297 return rcvlen;
1298
1299 if(laddr.ss_family == AF_UNSPEC)
1300 laddrlen = 0;
1301 else {
1302 laddrlen = sockaddr2ascii(fromaddr, *addrlen, &laddr, laddrlen);
1303 if(laddrlen < 0)
1304 return laddrlen;
1305 }
1306 *addrlen = laddrlen;
1307 return rcvlen;
1308}
1309
1310int
1311Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen)
1312{
1313 struct sockaddr_storage laddr;
1314 int laddrlen = sizeof(laddr);
1315 int retcode = getpeername(sd, (struct sockaddr *) &laddr, &laddrlen);
1316
1317 if(!retcode) {
1318 laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
1319 if(laddrlen < 0)
1320 return laddrlen;
1321 *addrlen = laddrlen;
1322 }
1323
1324 return retcode;
1325}
1326
1327int
1328Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen)
1329{
1330 struct sockaddr_storage laddr;
1331 int laddrlen = sizeof(laddr);
1332 int retcode = getsockname(sd, (struct sockaddr *) &laddr, &laddrlen);
1333
1334 if(!retcode) {
1335 laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
1336 if(laddrlen < 0)
1337 return laddrlen;
1338 *addrlen = laddrlen;
1339 }
1340
1341 return retcode;
1342}
1343
1344
1345#ifdef HAVE_LIBZ
1346const char *
1347Curl_os400_zlibVersion(void)
1348{
1349 return set_thread_string(LK_ZLIB_VERSION, zlibVersion());
1350}
1351
1352
1353int
1354Curl_os400_inflateInit_(z_streamp strm, const char *version, int stream_size)
1355{
1356 z_const char *msgb4 = strm->msg;
1357 int ret;
1358
1359 ret = inflateInit(strm);
1360
1361 if(strm->msg != msgb4)
1362 strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1363
1364 return ret;
1365}
1366
1367int
1368Curl_os400_inflateInit2_(z_streamp strm, int windowBits,
1369 const char *version, int stream_size)
1370{
1371 z_const char *msgb4 = strm->msg;
1372 int ret;
1373
1374 ret = inflateInit2(strm, windowBits);
1375
1376 if(strm->msg != msgb4)
1377 strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1378
1379 return ret;
1380}
1381
1382int
1383Curl_os400_inflate(z_streamp strm, int flush)
1384{
1385 z_const char *msgb4 = strm->msg;
1386 int ret;
1387
1388 ret = inflate(strm, flush);
1389
1390 if(strm->msg != msgb4)
1391 strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1392
1393 return ret;
1394}
1395
1396int
1397Curl_os400_inflateEnd(z_streamp strm)
1398{
1399 z_const char *msgb4 = strm->msg;
1400 int ret;
1401
1402 ret = inflateEnd(strm);
1403
1404 if(strm->msg != msgb4)
1405 strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1406
1407 return ret;
1408}
1409
1410#endif