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