1081 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1081 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***************************************************************************
 | |
|  *                                  _   _ ____  _
 | |
|  *  Project                     ___| | | |  _ \| |
 | |
|  *                             / __| | | | |_) | |
 | |
|  *                            | (__| |_| |  _ <| |___
 | |
|  *                             \___|\___/|_| \_\_____|
 | |
|  *
 | |
|  * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 | |
|  *
 | |
|  * This software is licensed as described in the file COPYING, which
 | |
|  * you should have received as part of this distribution. The terms
 | |
|  * are also available at http://curl.haxx.se/docs/copyright.html.
 | |
|  *
 | |
|  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 | |
|  * copies of the Software, and permit persons to whom the Software is
 | |
|  * furnished to do so, under the terms of the COPYING file.
 | |
|  *
 | |
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 | |
|  * KIND, either express or implied.
 | |
|  *
 | |
|  * $Id: os400sys.c,v 1.6 2008-09-24 12:22:17 yangtse Exp $
 | |
|  *
 | |
|  ***************************************************************************/
 | |
| 
 | |
| /* OS/400 additional support. */
 | |
| 
 | |
| #include "config-os400.h"       /* Not setup.h: we only need some defines. */
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/socket.h>
 | |
| #include <sys/un.h>
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stddef.h>
 | |
| #include <string.h>
 | |
| #include <pthread.h>
 | |
| #include <netdb.h>
 | |
| #include <qadrt.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #ifdef USE_QSOSSL
 | |
| #include <qsossl.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_GSSAPI
 | |
| #include <gssapi.h>
 | |
| #endif
 | |
| 
 | |
| #ifndef CURL_DISABLE_LDAP
 | |
| #include <ldap.h>
 | |
| #endif
 | |
| 
 | |
| #include <netinet/in.h>
 | |
| #include <arpa/inet.h>
 | |
| 
 | |
| #include "os400sys.h"
 | |
| 
 | |
| 
 | |
| /**
 | |
| ***     QADRT OS/400 ASCII runtime defines only the most used procedures, but
 | |
| ***             but a lot of them are not supported. This module implements
 | |
| ***             ASCII wrappers for those that are used by libcurl, but not
 | |
| ***             defined by QADRT.
 | |
| **/
 | |
| 
 | |
| #pragma convert(0)                              /* Restore EBCDIC. */
 | |
| 
 | |
| 
 | |
| #define MIN_BYTE_GAIN   1024    /* Minimum gain when shortening a buffer. */
 | |
| 
 | |
| typedef struct {
 | |
|         unsigned long   size;                   /* Buffer size. */
 | |
|         char *          buf;                    /* Buffer address. */
 | |
| }               buffer_t;
 | |
| 
 | |
| 
 | |
| static char *   buffer_undef(localkey_t key, long size);
 | |
| static char *   buffer_threaded(localkey_t key, long size);
 | |
| static char *   buffer_unthreaded(localkey_t key, long size);
 | |
| 
 | |
| static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
 | |
| static pthread_key_t    thdkey;
 | |
| static buffer_t *       locbufs;
 | |
| 
 | |
| char *  (* Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
 | |
| 
 | |
| 
 | |
| static void
 | |
| thdbufdestroy(void * private)
 | |
| 
 | |
| {
 | |
|   localkey_t i;
 | |
|   buffer_t * p;
 | |
| 
 | |
|   if (private) {
 | |
|     p = (buffer_t *) private;
 | |
| 
 | |
|     for (i = (localkey_t) 0; i < LK_LAST; i++) {
 | |
|       if (p->buf)
 | |
|         free(p->buf);
 | |
| 
 | |
|       p++;
 | |
|       }
 | |
| 
 | |
|     free(private);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| terminate(void)
 | |
| 
 | |
| {
 | |
|   if (Curl_thread_buffer == buffer_threaded) {
 | |
|     locbufs = pthread_getspecific(thdkey);
 | |
|     pthread_setspecific(thdkey, (void *) NULL);
 | |
|     pthread_key_delete(thdkey);
 | |
|     }
 | |
| 
 | |
|   if (Curl_thread_buffer != buffer_undef) {
 | |
|     thdbufdestroy((void *) locbufs);
 | |
|     locbufs = (buffer_t *) NULL;
 | |
|     }
 | |
| 
 | |
|   Curl_thread_buffer = buffer_undef;
 | |
| }
 | |
| 
 | |
| 
 | |
| static char *
 | |
| get_buffer(buffer_t * buf, long size)
 | |
| 
 | |
| {
 | |
|   char * cp;
 | |
| 
 | |
|   /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long.
 | |
|      Return the buffer address. */
 | |
| 
 | |
|   if (size < 0)
 | |
|     return buf->buf;
 | |
| 
 | |
|   if (!buf->buf) {
 | |
|     if ((buf->buf = malloc(size)))
 | |
|       buf->size = size;
 | |
| 
 | |
|     return buf->buf;
 | |
|     }
 | |
| 
 | |
|   if ((unsigned long) size <= buf->size) {
 | |
|     /* Shorten the buffer only if it frees a significant byte count. This
 | |
|        avoids some realloc() overhead. */
 | |
| 
 | |
|     if (buf->size - size < MIN_BYTE_GAIN)
 | |
|       return buf->buf;
 | |
|     }
 | |
| 
 | |
|   /* Resize the buffer. */
 | |
| 
 | |
|   if ((cp = realloc(buf->buf, size))) {
 | |
|     buf->buf = cp;
 | |
|     buf->size = size;
 | |
|     }
 | |
|   else if (size <= buf->size)
 | |
|     cp = buf->buf;
 | |
| 
 | |
|   return cp;
 | |
| }
 | |
| 
 | |
| 
 | |
| static char *
 | |
| buffer_unthreaded(localkey_t key, long size)
 | |
| 
 | |
| {
 | |
|   return get_buffer(locbufs + key, size);
 | |
| }
 | |
| 
 | |
| 
 | |
| static char *
 | |
| buffer_threaded(localkey_t key, long size)
 | |
| 
 | |
| {
 | |
|   buffer_t * bufs;
 | |
| 
 | |
|   /* Get the buffer for the given local key in the current thread, and
 | |
|      make sure it is at least `size'-byte long. Set `size' to < 0 to get
 | |
|      its address only. */
 | |
| 
 | |
|   bufs = (buffer_t *) pthread_getspecific(thdkey);
 | |
| 
 | |
|   if (!bufs) {
 | |
|     if (size < 0)
 | |
|       return (char *) NULL;             /* No buffer yet. */
 | |
| 
 | |
|     /* Allocate buffer descriptors for the current thread. */
 | |
| 
 | |
|     if (!(bufs = calloc((size_t) LK_LAST, sizeof *bufs)))
 | |
|       return (char *) NULL;
 | |
| 
 | |
|     if (pthread_setspecific(thdkey, (void *) bufs)) {
 | |
|       free(bufs);
 | |
|       return (char *) NULL;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   return get_buffer(bufs + key, size);
 | |
| }
 | |
| 
 | |
| 
 | |
| static char *
 | |
| buffer_undef(localkey_t key, long size)
 | |
| 
 | |
| {
 | |
|   /* Define the buffer system, get the buffer for the given local key in
 | |
|      the current thread, and make sure it is at least `size'-byte long.
 | |
|      Set `size' to < 0 to get its address only. */
 | |
| 
 | |
|   pthread_mutex_lock(&mutex);
 | |
| 
 | |
|   /* Determine if we can use pthread-specific data. */
 | |
| 
 | |
|   if (Curl_thread_buffer == buffer_undef) {     /* If unchanged during lock. */
 | |
|     if (!pthread_key_create(&thdkey, thdbufdestroy))
 | |
|       Curl_thread_buffer = buffer_threaded;
 | |
|     else if (!(locbufs = calloc((size_t) LK_LAST,
 | |
|                                              sizeof *locbufs))) {
 | |
|       pthread_mutex_unlock(&mutex);
 | |
|       return (char *) NULL;
 | |
|       }
 | |
|     else
 | |
|         Curl_thread_buffer = buffer_unthreaded;
 | |
| 
 | |
|     atexit(terminate);
 | |
|     }
 | |
| 
 | |
|   pthread_mutex_unlock(&mutex);
 | |
|   return Curl_thread_buffer(key, size);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_getnameinfo_a(const struct sockaddr * sa, socklen_t salen,
 | |
|               char * nodename, socklen_t nodenamelen,
 | |
|               char * servname, socklen_t servnamelen,
 | |
|               int flags)
 | |
| 
 | |
| {
 | |
|   char * enodename;
 | |
|   char * eservname;
 | |
|   int status;
 | |
|   int i;
 | |
| 
 | |
|   enodename = (char *) NULL;
 | |
|   eservname = (char *) NULL;
 | |
| 
 | |
|   if (nodename && nodenamelen)
 | |
|     if (!(enodename = malloc(nodenamelen)))
 | |
|       return EAI_MEMORY;
 | |
| 
 | |
|   if (servname && servnamelen)
 | |
|     if (!(eservname = malloc(servnamelen))) {
 | |
|       if (enodename)
 | |
|         free(enodename);
 | |
| 
 | |
|       return EAI_MEMORY;
 | |
|       }
 | |
| 
 | |
|   status = getnameinfo(sa, salen, enodename, nodenamelen,
 | |
|                        eservname, servnamelen, flags);
 | |
| 
 | |
|   if (!status) {
 | |
|     if (enodename) {
 | |
|       i = QadrtConvertE2A(nodename, enodename,
 | |
|         nodenamelen - 1, strlen(enodename));
 | |
|       nodename[i] = '\0';
 | |
|       }
 | |
| 
 | |
|     if (eservname) {
 | |
|       i = QadrtConvertE2A(servname, eservname,
 | |
|         servnamelen - 1, strlen(eservname));
 | |
|       servname[i] = '\0';
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   if (enodename)
 | |
|     free(enodename);
 | |
| 
 | |
|   if (eservname)
 | |
|     free(eservname);
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_getaddrinfo_a(const char * nodename, const char * servname,
 | |
|             const struct addrinfo * hints,
 | |
|             struct addrinfo * * res)
 | |
| 
 | |
| {
 | |
|   char * enodename;
 | |
|   char * eservname;
 | |
|   int status;
 | |
|   int i;
 | |
| 
 | |
|   enodename = (char *) NULL;
 | |
|   eservname = (char *) NULL;
 | |
| 
 | |
|   if (nodename) {
 | |
|     i = strlen(nodename);
 | |
| 
 | |
|     if (!(enodename = malloc(i + 1)))
 | |
|       return EAI_MEMORY;
 | |
| 
 | |
|     i = QadrtConvertA2E(enodename, nodename, i, i);
 | |
|     enodename[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   if (servname) {
 | |
|     i = strlen(servname);
 | |
| 
 | |
|     if (!(eservname = malloc(i + 1))) {
 | |
|       if (enodename)
 | |
|         free(enodename);
 | |
| 
 | |
|       return EAI_MEMORY;
 | |
|       }
 | |
| 
 | |
|     QadrtConvertA2E(eservname, servname, i, i);
 | |
|     eservname[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   status = getaddrinfo(enodename, eservname, hints, res);
 | |
| 
 | |
|   if (enodename)
 | |
|     free(enodename);
 | |
| 
 | |
|   if (eservname)
 | |
|     free(eservname);
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef USE_QSOSSL
 | |
| 
 | |
| /* ASCII wrappers for the SSL procedures. */
 | |
| 
 | |
| int
 | |
| Curl_SSL_Init_Application_a(SSLInitApp * init_app)
 | |
| 
 | |
| {
 | |
|   int rc;
 | |
|   unsigned int i;
 | |
|   SSLInitApp ia;
 | |
| 
 | |
|   if (!init_app || !init_app->applicationID || !init_app->applicationIDLen)
 | |
|     return SSL_Init_Application(init_app);
 | |
| 
 | |
|   memcpy((char *) &ia, (char *) init_app, sizeof ia);
 | |
|   i = ia.applicationIDLen;
 | |
| 
 | |
|   if (!(ia.applicationID = malloc(i + 1))) {
 | |
|     errno = ENOMEM;
 | |
|     return SSL_ERROR_IO;
 | |
|     }
 | |
| 
 | |
|   QadrtConvertA2E(ia.applicationID, init_app->applicationID, i, i);
 | |
|   ia.applicationID[i] = '\0';
 | |
|   rc = SSL_Init_Application(&ia);
 | |
|   free(ia.applicationID);
 | |
|   init_app->localCertificateLen = ia.localCertificateLen;
 | |
|   init_app->sessionType = ia.sessionType;
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_SSL_Init_a(SSLInit * init)
 | |
| 
 | |
| {
 | |
|   int rc;
 | |
|   unsigned int i;
 | |
|   SSLInit ia;
 | |
| 
 | |
|   if (!init || (!init->keyringFileName && !init->keyringPassword))
 | |
|     return SSL_Init(init);
 | |
| 
 | |
|   memcpy((char *) &ia, (char *) init, sizeof ia);
 | |
| 
 | |
|   if (ia.keyringFileName) {
 | |
|     i = strlen(ia.keyringFileName);
 | |
| 
 | |
|     if (!(ia.keyringFileName = malloc(i + 1))) {
 | |
|       errno = ENOMEM;
 | |
|       return SSL_ERROR_IO;
 | |
|       }
 | |
| 
 | |
|     QadrtConvertA2E(ia.keyringFileName, init->keyringFileName, i, i);
 | |
|     ia.keyringFileName[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   if (ia.keyringPassword) {
 | |
|     i = strlen(ia.keyringPassword);
 | |
| 
 | |
|     if (!(ia.keyringPassword = malloc(i + 1))) {
 | |
|       if (ia.keyringFileName)
 | |
|         free(ia.keyringFileName);
 | |
| 
 | |
|       errno = ENOMEM;
 | |
|       return SSL_ERROR_IO;
 | |
|       }
 | |
| 
 | |
|     QadrtConvertA2E(ia.keyringPassword, init->keyringPassword, i, i);
 | |
|     ia.keyringPassword[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   rc = SSL_Init(&ia);
 | |
| 
 | |
|   if (ia.keyringFileName)
 | |
|     free(ia.keyringFileName);
 | |
| 
 | |
|   if (ia.keyringPassword)
 | |
|     free(ia.keyringPassword);
 | |
| 
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| Curl_SSL_Strerror_a(int sslreturnvalue, SSLErrorMsg * serrmsgp)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * cp;
 | |
|   char * cp2;
 | |
| 
 | |
|   cp = SSL_Strerror(sslreturnvalue, serrmsgp);
 | |
| 
 | |
|   if (!cp)
 | |
|     return cp;
 | |
| 
 | |
|   i = strlen(cp);
 | |
| 
 | |
|   if (!(cp2 = Curl_thread_buffer(LK_SSL_ERROR, MAX_CONV_EXPANSION * i + 1)))
 | |
|     return cp2;
 | |
| 
 | |
|   i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
 | |
|   cp2[i] = '\0';
 | |
|   return cp2;
 | |
| }
 | |
| 
 | |
| #endif /* USE_QSOSSL */
 | |
| 
 | |
| 
 | |
| #ifdef HAVE_GSSAPI
 | |
| 
 | |
| /* ASCII wrappers for the GSSAPI procedures. */
 | |
| 
 | |
| static int
 | |
| Curl_gss_convert_in_place(OM_uint32 * minor_status, gss_buffer_t buf)
 | |
| 
 | |
| {
 | |
|   unsigned int i;
 | |
|   char * t;
 | |
| 
 | |
|   /* Convert `buf' in place, from EBCDIC to ASCII.
 | |
|      If error, release the buffer and return -1. Else return 0. */
 | |
| 
 | |
|   i = buf->length;
 | |
| 
 | |
|   if (i) {
 | |
|     if (!(t = malloc(i))) {
 | |
|       gss_release_buffer(minor_status, buf);
 | |
| 
 | |
|       if (minor_status)
 | |
|         *minor_status = ENOMEM;
 | |
| 
 | |
|       return -1;
 | |
|       }
 | |
| 
 | |
|     QadrtConvertE2A(t, buf->value, i, i);
 | |
|     memcpy(buf->value, t, i);
 | |
|     free(t);
 | |
|     }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 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)
 | |
| 
 | |
| {
 | |
|   int rc;
 | |
|   unsigned int i;
 | |
|   gss_buffer_desc in;
 | |
| 
 | |
|   if (!in_name || !in_name->value || !in_name->length)
 | |
|     return gss_import_name(minor_status, in_name, in_name_type, out_name);
 | |
| 
 | |
|   memcpy((char *) &in, (char *) in_name, sizeof in);
 | |
|   i = in.length;
 | |
| 
 | |
|   if (!(in.value = malloc(i + 1))) {
 | |
|     if (minor_status)
 | |
|       *minor_status = ENOMEM;
 | |
| 
 | |
|     return GSS_S_FAILURE;
 | |
|     }
 | |
| 
 | |
|   QadrtConvertA2E(in.value, in_name->value, i, i);
 | |
|   ((char *) in.value)[i] = '\0';
 | |
|   rc = gss_import_name(minor_status, &in, in_name_type, out_name);
 | |
|   free(in.value);
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| 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)
 | |
| 
 | |
| {
 | |
|   int rc;
 | |
| 
 | |
|   rc = gss_display_status(minor_status, status_value, status_type,
 | |
|                               mech_type, message_context, status_string);
 | |
| 
 | |
|   if (rc != GSS_S_COMPLETE || !status_string ||
 | |
|       !status_string->length || !status_string->value)
 | |
|     return rc;
 | |
| 
 | |
|   /* No way to allocate a buffer here, because it will be released by
 | |
|      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
 | |
|      with ASCII to return it. */
 | |
| 
 | |
|   if (Curl_gss_convert_in_place(minor_status, status_string))
 | |
|     return GSS_S_FAILURE;
 | |
| 
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| 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)
 | |
| 
 | |
| {
 | |
|   int rc;
 | |
|   unsigned int i;
 | |
|   gss_buffer_desc in;
 | |
|   gss_buffer_t inp;
 | |
| 
 | |
|   in.value = NULL;
 | |
| 
 | |
|   if ((inp = input_token))
 | |
|     if (inp->length && inp->value) {
 | |
|       i = inp->length;
 | |
| 
 | |
|       if (!(in.value = malloc(i + 1))) {
 | |
|         if (minor_status)
 | |
|           *minor_status = ENOMEM;
 | |
| 
 | |
|         return GSS_S_FAILURE;
 | |
|         }
 | |
| 
 | |
|       QadrtConvertA2E(in.value, input_token->value, i, i);
 | |
|       ((char *) in.value)[i] = '\0';
 | |
|       in.length = i;
 | |
|       inp = ∈
 | |
|       }
 | |
| 
 | |
|   rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
 | |
|                              target_name, mech_type, req_flags, time_req,
 | |
|                              input_chan_bindings, inp, actual_mech_type,
 | |
|                              output_token, ret_flags, time_rec);
 | |
| 
 | |
|   if (in.value)
 | |
|     free(in.value);
 | |
| 
 | |
|   if (rc != GSS_S_COMPLETE || !output_token ||
 | |
|       !output_token->length || !output_token->value)
 | |
|     return rc;
 | |
| 
 | |
|   /* No way to allocate a buffer here, because it will be released by
 | |
|      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
 | |
|      with ASCII to return it. */
 | |
| 
 | |
|   if (Curl_gss_convert_in_place(minor_status, output_token))
 | |
|     return GSS_S_FAILURE;
 | |
| 
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| OM_uint32
 | |
| Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
 | |
|                               gss_ctx_id_t * context_handle,
 | |
|                               gss_buffer_t output_token)
 | |
| 
 | |
| {
 | |
|   int rc;
 | |
| 
 | |
|   rc = gss_delete_sec_context(minor_status, context_handle, output_token);
 | |
| 
 | |
|   if (rc != GSS_S_COMPLETE || !output_token ||
 | |
|       !output_token->length || !output_token->value)
 | |
|     return rc;
 | |
| 
 | |
|   /* No way to allocate a buffer here, because it will be released by
 | |
|      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
 | |
|      with ASCII to return it. */
 | |
| 
 | |
|   if (Curl_gss_convert_in_place(minor_status, output_token))
 | |
|     return GSS_S_FAILURE;
 | |
| 
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| #endif /* HAVE_GSSAPI */
 | |
| 
 | |
| 
 | |
| #ifndef CURL_DISABLE_LDAP
 | |
| 
 | |
| /* ASCII wrappers for the LDAP procedures. */
 | |
| 
 | |
| void *
 | |
| Curl_ldap_init_a(char * host, int port)
 | |
| 
 | |
| {
 | |
|   unsigned int i;
 | |
|   char * ehost;
 | |
|   void * result;
 | |
| 
 | |
|   if (!host)
 | |
|     return (void *) ldap_init(host, port);
 | |
| 
 | |
|   i = strlen(host);
 | |
| 
 | |
|   if (!(ehost = malloc(i + 1)))
 | |
|     return (void *) NULL;
 | |
| 
 | |
|   QadrtConvertA2E(ehost, host, i, i);
 | |
|   ehost[i] = '\0';
 | |
|   result = (void *) ldap_init(ehost, port);
 | |
|   free(ehost);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_ldap_simple_bind_s_a(void * ld, char * dn, char * passwd)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * edn;
 | |
|   char * epasswd;
 | |
| 
 | |
|   edn = (char *) NULL;
 | |
|   epasswd = (char *) NULL;
 | |
| 
 | |
|   if (dn) {
 | |
|     i = strlen(dn);
 | |
| 
 | |
|     if (!(edn = malloc(i + 1)))
 | |
|       return LDAP_NO_MEMORY;
 | |
| 
 | |
|     QadrtConvertA2E(edn, dn, i, i);
 | |
|     edn[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   if (passwd) {
 | |
|     i = strlen(passwd);
 | |
| 
 | |
|     if (!(epasswd = malloc(i + 1))) {
 | |
|       if (edn)
 | |
|         free(edn);
 | |
| 
 | |
|       return LDAP_NO_MEMORY;
 | |
|       }
 | |
| 
 | |
|     QadrtConvertA2E(epasswd, passwd, i, i);
 | |
|     epasswd[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   i = ldap_simple_bind_s(ld, edn, epasswd);
 | |
| 
 | |
|   if (epasswd)
 | |
|     free(epasswd);
 | |
| 
 | |
|   if (edn)
 | |
|     free(edn);
 | |
| 
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_ldap_search_s_a(void * ld, char * base, int scope, char * filter,
 | |
|                      char * * attrs, int attrsonly, LDAPMessage * * res)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   int j;
 | |
|   char * ebase;
 | |
|   char * efilter;
 | |
|   char * * eattrs;
 | |
|   int status;
 | |
| 
 | |
|   ebase = (char *) NULL;
 | |
|   efilter = (char *) NULL;
 | |
|   eattrs = (char * *) NULL;
 | |
|   status = LDAP_SUCCESS;
 | |
| 
 | |
|   if (base) {
 | |
|     i = strlen(base);
 | |
| 
 | |
|     if (!(ebase = malloc(i + 1)))
 | |
|       status = LDAP_NO_MEMORY;
 | |
|     else {
 | |
|       QadrtConvertA2E(ebase, base, i, i);
 | |
|       ebase[i] = '\0';
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   if (filter && status == LDAP_SUCCESS) {
 | |
|     i = strlen(filter);
 | |
| 
 | |
|     if (!(efilter = malloc(i + 1)))
 | |
|       status = LDAP_NO_MEMORY;
 | |
|     else {
 | |
|       QadrtConvertA2E(efilter, filter, i, i);
 | |
|       efilter[i] = '\0';
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   if (attrs && status == LDAP_SUCCESS) {
 | |
|     for (i = 0; attrs[i++];)
 | |
|       ;
 | |
| 
 | |
|     if (!(eattrs = calloc(i, sizeof *eattrs)))
 | |
|       status = LDAP_NO_MEMORY;
 | |
|     else {
 | |
|       for (j = 0; attrs[j]; j++) {
 | |
|         i = strlen(attrs[j]);
 | |
| 
 | |
|         if (!(eattrs[j] = malloc(i + 1))) {
 | |
|           status = LDAP_NO_MEMORY;
 | |
|           break;
 | |
|           }
 | |
| 
 | |
|         QadrtConvertA2E(eattrs[j], attrs[j], i, i);
 | |
|         eattrs[j][i] = '\0';
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   if (status == LDAP_SUCCESS)
 | |
|     status = ldap_search_s(ld, ebase? ebase: "", scope,
 | |
|                            efilter? efilter: "(objectclass=*)",
 | |
|                            eattrs, attrsonly, res);
 | |
| 
 | |
|   if (eattrs) {
 | |
|     for (j = 0; eattrs[j]; j++)
 | |
|       free(eattrs[j]);
 | |
| 
 | |
|     free(eattrs);
 | |
|     }
 | |
| 
 | |
|   if (efilter)
 | |
|     free(efilter);
 | |
| 
 | |
|   if (ebase)
 | |
|     free(ebase);
 | |
| 
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| struct berval * *
 | |
| Curl_ldap_get_values_len_a(void * ld, LDAPMessage * entry, const char * attr)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * cp;
 | |
|   struct berval * * result;
 | |
| 
 | |
|   cp = (char *) NULL;
 | |
| 
 | |
|   if (attr) {
 | |
|     i = strlen(attr);
 | |
| 
 | |
|     if (!(cp = malloc(i + 1))) {
 | |
|       ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
 | |
|                        ldap_err2string(LDAP_NO_MEMORY));
 | |
|       return (struct berval * *) NULL;
 | |
|       }
 | |
| 
 | |
|     QadrtConvertA2E(cp, attr, i, i);
 | |
|     cp[i] = '\0';
 | |
|     }
 | |
| 
 | |
|   result = ldap_get_values_len(ld, entry, cp);
 | |
| 
 | |
|   if (cp)
 | |
|     free(cp);
 | |
| 
 | |
|   /* Result data are binary in nature, so they haven't been converted to EBCDIC.
 | |
|      Therefore do not convert. */
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| Curl_ldap_err2string_a(int error)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * cp;
 | |
|   char * cp2;
 | |
| 
 | |
|   cp = ldap_err2string(error);
 | |
| 
 | |
|   if (!cp)
 | |
|     return cp;
 | |
| 
 | |
|   i = strlen(cp);
 | |
| 
 | |
|   if (!(cp2 = Curl_thread_buffer(LK_LDAP_ERROR, MAX_CONV_EXPANSION * i + 1)))
 | |
|     return cp2;
 | |
| 
 | |
|   i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
 | |
|   cp2[i] = '\0';
 | |
|   return cp2;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| Curl_ldap_get_dn_a(void * ld, LDAPMessage * entry)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * cp;
 | |
|   char * cp2;
 | |
| 
 | |
|   cp = ldap_get_dn(ld, entry);
 | |
| 
 | |
|   if (!cp)
 | |
|     return cp;
 | |
| 
 | |
|   i = strlen(cp);
 | |
| 
 | |
|   if (!(cp2 = malloc(i + 1)))
 | |
|     return cp2;
 | |
| 
 | |
|   QadrtConvertE2A(cp2, cp, i, i);
 | |
| 
 | |
|   /* No way to allocate a buffer here, because it will be released by
 | |
|      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
 | |
|      overwrite the EBCDIC buffer with ASCII to return it. */
 | |
| 
 | |
|   strcpy(cp, cp2);
 | |
|   free(cp2);
 | |
|   return cp;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| Curl_ldap_first_attribute_a(void * ld,
 | |
|                             LDAPMessage * entry, BerElement * * berptr)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * cp;
 | |
|   char * cp2;
 | |
| 
 | |
|   cp = ldap_first_attribute(ld, entry, berptr);
 | |
| 
 | |
|   if (!cp)
 | |
|     return cp;
 | |
| 
 | |
|   i = strlen(cp);
 | |
| 
 | |
|   if (!(cp2 = malloc(i + 1)))
 | |
|     return cp2;
 | |
| 
 | |
|   QadrtConvertE2A(cp2, cp, i, i);
 | |
| 
 | |
|   /* No way to allocate a buffer here, because it will be released by
 | |
|      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
 | |
|      overwrite the EBCDIC buffer with ASCII to return it. */
 | |
| 
 | |
|   strcpy(cp, cp2);
 | |
|   free(cp2);
 | |
|   return cp;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| Curl_ldap_next_attribute_a(void * ld,
 | |
|                            LDAPMessage * entry, BerElement * berptr)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   char * cp;
 | |
|   char * cp2;
 | |
| 
 | |
|   cp = ldap_next_attribute(ld, entry, berptr);
 | |
| 
 | |
|   if (!cp)
 | |
|     return cp;
 | |
| 
 | |
|   i = strlen(cp);
 | |
| 
 | |
|   if (!(cp2 = malloc(i + 1)))
 | |
|     return cp2;
 | |
| 
 | |
|   QadrtConvertE2A(cp2, cp, i, i);
 | |
| 
 | |
|   /* No way to allocate a buffer here, because it will be released by
 | |
|      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
 | |
|      overwrite the EBCDIC buffer with ASCII to return it. */
 | |
| 
 | |
|   strcpy(cp, cp2);
 | |
|   free(cp2);
 | |
|   return cp;
 | |
| }
 | |
| 
 | |
| #endif /* CURL_DISABLE_LDAP */
 | |
| 
 | |
| 
 | |
| static int
 | |
| convert_sockaddr(struct sockaddr_storage * dstaddr,
 | |
|                                 const struct sockaddr * srcaddr, int srclen)
 | |
| 
 | |
| {
 | |
|   const struct sockaddr_un * srcu;
 | |
|   struct sockaddr_un * dstu;
 | |
|   unsigned int i;
 | |
|   unsigned int dstsize;
 | |
| 
 | |
|   /* Convert a socket address into job CCSID, if needed. */
 | |
| 
 | |
|   if (!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
 | |
|       sizeof srcaddr->sa_family || srclen > sizeof *dstaddr) {
 | |
|     errno = EINVAL;
 | |
|     return -1;
 | |
|     }
 | |
| 
 | |
|   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
 | |
| 
 | |
|   switch (srcaddr->sa_family) {
 | |
| 
 | |
|   case AF_UNIX:
 | |
|     srcu = (const struct sockaddr_un *) srcaddr;
 | |
|     dstu = (struct sockaddr_un *) dstaddr;
 | |
|     dstsize = sizeof *dstaddr - offsetof(struct sockaddr_un, sun_path);
 | |
|     srclen -= offsetof(struct sockaddr_un, sun_path);
 | |
|     i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
 | |
|     dstu->sun_path[i] = '\0';
 | |
|     i += offsetof(struct sockaddr_un, sun_path);
 | |
|     srclen = i;
 | |
|     }
 | |
| 
 | |
|   return srclen;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   struct sockaddr_storage laddr;
 | |
| 
 | |
|   i = convert_sockaddr(&laddr, destaddr, addrlen);
 | |
| 
 | |
|   if (i < 0)
 | |
|     return -1;
 | |
| 
 | |
|   return connect(sd, (struct sockaddr *) &laddr, i);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   struct sockaddr_storage laddr;
 | |
| 
 | |
|   i = convert_sockaddr(&laddr, localaddr, addrlen);
 | |
| 
 | |
|   if (i < 0)
 | |
|     return -1;
 | |
| 
 | |
|   return bind(sd, (struct sockaddr *) &laddr, i);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_os400_sendto(int sd, char * buffer, int buflen, int flags,
 | |
|                                 struct sockaddr * dstaddr, int addrlen)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   struct sockaddr_storage laddr;
 | |
| 
 | |
|   i = convert_sockaddr(&laddr, dstaddr, addrlen);
 | |
| 
 | |
|   if (i < 0)
 | |
|     return -1;
 | |
| 
 | |
|   return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags,
 | |
|                                 struct sockaddr * fromaddr, int * addrlen)
 | |
| 
 | |
| {
 | |
|   int i;
 | |
|   int rcvlen;
 | |
|   int laddrlen;
 | |
|   const struct sockaddr_un * srcu;
 | |
|   struct sockaddr_un * dstu;
 | |
|   struct sockaddr_storage laddr;
 | |
| 
 | |
|   if (!fromaddr || !addrlen || *addrlen <= 0)
 | |
|     return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
 | |
| 
 | |
|   laddrlen = sizeof laddr;
 | |
|   laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
 | |
|   rcvlen = recvfrom(sd, buffer, buflen, flags,
 | |
|                     (struct sockaddr *) &laddr, &laddrlen);
 | |
| 
 | |
|   if (rcvlen < 0)
 | |
|     return rcvlen;
 | |
| 
 | |
|   switch (laddr.ss_family) {
 | |
| 
 | |
|   case AF_UNIX:
 | |
|     srcu = (const struct sockaddr_un *) &laddr;
 | |
|     dstu = (struct sockaddr_un *) fromaddr;
 | |
|     i = *addrlen - offsetof(struct sockaddr_un, sun_path);
 | |
|     laddrlen -= offsetof(struct sockaddr_un, sun_path);
 | |
|     i = QadrtConvertE2A(dstu->sun_path, srcu->sun_path, i, laddrlen);
 | |
|     laddrlen = i + offsetof(struct sockaddr_un, sun_path);
 | |
| 
 | |
|     if (laddrlen < *addrlen)
 | |
|       dstu->sun_path[i] = '\0';
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case AF_UNSPEC:
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     if (laddrlen > *addrlen)
 | |
|       laddrlen = *addrlen;
 | |
| 
 | |
|     if (laddrlen)
 | |
|       memcpy((char *) fromaddr, (char *) &laddr, laddrlen);
 | |
| 
 | |
|     break;
 | |
|     }
 | |
| 
 | |
|   *addrlen = laddrlen;
 | |
|   return rcvlen;
 | |
| }
 |