/* Monetra 5.x C API For any questions please contact support@mainstreetsoftworks.com Copyright (c) 2005, Main Street Softworks, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Main Street Softworks, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #ifndef _WIN32 #include #include #endif #include #include "libmonetra_main.h" #include "monetra.h" #ifdef _WIN32 typedef size_t ssize_t; #endif #ifdef ENABLE_SSL SSL_CTX *client_ctx = NULL; #endif /* BASE ROUTINES */ int M_InitEngine (const char *location) { char egd[255]; egd[0] = 0; #ifndef DISABLE_IP if (!M_InitSockets ()) return (0); #endif #ifdef ENABLE_SSL OpenSSL_add_ssl_algorithms (); SSL_load_error_strings (); #ifdef NEED_SEED strcpy (egd, "/var/run/egd-pool"); if (RAND_egd (egd) == -1) return (0); #endif if (location != NULL && strlen (location)) { client_ctx = SSL_CTX_new (SSLv23_client_method ()); if (client_ctx == NULL) return (0); SSL_CTX_load_verify_locations (client_ctx, location, NULL); } #endif return (1); } void M_DestroyEngine () { #ifdef ENABLE_SSL if (client_ctx != NULL) { SSL_CTX_free (client_ctx); client_ctx = NULL; } #endif } //Initializes the MCVE Connection structure void M_InitConn (M_CONN * myconn) { _M_CONN *conn; (*myconn) = (M_CONN) malloc (sizeof (_M_CONN) * 1); conn = (_M_CONN *) (*myconn); conn->conn_method = -1; conn->port = -1; conn->ptr = -1; conn->timeout = -1; conn->blocking = 0; conn->status = 0; conn->verifyconn = 1; conn->do_debug = 0; conn->verifyssl = 0; conn->max_conn_time = 5; conn->inbuf = NULL; conn->inbuf_cnt = 0; conn->inbuf_alloc = 0; conn->outbuf = NULL; conn->outbuf_cnt = 0; conn->outbuf_alloc = 0; conn->error_text = NULL; #ifdef ENABLE_SSL conn->ssl = NULL; conn->server_cert = NULL; conn->client_ctx = NULL; conn->ca_location[0] = 0; conn->sslkeyfile[0] = 0; conn->sslcertfile[0] = 0; #endif conn->outstanding_auths = 0; conn->queue_length = 0; conn->queue = NULL; conn->mutexreg = NULL; conn->mutexlock = NULL; conn->mutexunlock = NULL; conn->mutexunreg = NULL; conn->mutex = NULL; conn->validate_identifier=0; memset (conn->location, 0, 250); } int M_Register_mutexinit (M_CONN * myconn, M_Register_Mutex reg) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->mutexreg = reg; return (1); } int M_Register_mutexdestroy (M_CONN * myconn, M_Unregister_Mutex reg) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->mutexunreg = reg; return (1); } int M_Register_mutexlock (M_CONN * myconn, M_Mutex_Lock reg) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->mutexlock = reg; return (1); } int M_Register_mutexunlock (M_CONN * myconn, M_Mutex_Unlock reg) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->mutexunlock = reg; return (1); } int M_EnableThreadSafety (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); if (conn->mutexreg == NULL || conn->mutexunreg == NULL || conn->mutexlock == NULL || conn->mutexunlock == NULL) { return (0); } M_init_locks (myconn); if (conn->mutex == NULL) return (0); return (1); } int M_ValidateIdentifier(M_CONN * myconn, int tf) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->validate_identifier = tf; return (1); } int M_SetBlocking (M_CONN * myconn, int tf) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->blocking = tf; return (1); } int M_SetTimeout (M_CONN * myconn, long timeout) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->timeout = timeout; return (1); } /* 0 = off, 1 = on */ int M_SetLogging (M_CONN * myconn, int level) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->do_debug = level; return (1); } // Sets method and path for drop files // Returns 0 on error int M_SetDropFile (M_CONN * myconn, const char *df_location) { _M_CONN *conn = (_M_CONN *) (*myconn); if (strlen (df_location) > 249) return (0); if (!M_DirectoryExists (df_location)) return (0); strncpy (conn->location, df_location, 250); conn->conn_method = M_FILE; conn->status = M_CONNECTED; return (1); } // Sets method,location, and portnum for IP // Returns 0 on error int M_SetIP (M_CONN * myconn, const char *host, unsigned short port) { #ifndef DISABLE_IP _M_CONN *conn = (_M_CONN *) (*myconn); if (strlen (host) > 249 || strlen (host) < 1) return (0); strncpy (conn->location, host, 250); if (port < 1) return (0); conn->port = port; conn->conn_method = M_SOCKETS; return (1); #else return (0); #endif } int M_SetSSL_CAfile (M_CONN * myconn, const char *path) { #ifndef ENABLE_SSL return (0); #else _M_CONN *conn = (_M_CONN *) (*myconn); strncpy (conn->ca_location, path, sizeof (conn->ca_location)); return (1); #endif } int M_SetSSL_Files (M_CONN * myconn, const char *sslkeyfile, const char *sslcertfile) { #ifndef ENABLE_SSL return (0); #else _M_CONN *conn = (_M_CONN *) (*myconn); if (sslkeyfile != NULL) strncpy (conn->sslkeyfile, sslkeyfile, sizeof (conn->sslkeyfile)); if (sslcertfile != NULL) strncpy (conn->sslcertfile, sslcertfile, sizeof (conn->sslcertfile)); return (1); #endif } // Sets method and path for drop files // Returns 0 on error int M_SetSSL (M_CONN * myconn, const char *host, unsigned short port) { _M_CONN *conn = (_M_CONN *) (*myconn); #ifdef ENABLE_SSL if (host == NULL || strlen (host) > 249 || strlen (host) < 1) { M_Set_Conn_Error (myconn, "Invalid Host Name"); // Set Error // Text return (0); } strncpy (conn->location, host, 250); if (port < 1) { M_Set_Conn_Error (myconn, "Invalid Port Number"); // Set // Error // Text return (0); } conn->port = port; conn->conn_method = M_SSL; return (1); #else return (0); #endif } void M_VerifyConnection (M_CONN * myconn, int tf) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->verifyconn = tf; } void M_VerifySSLCert (M_CONN * myconn, int tf) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->verifyssl = tf; } int M_Connect (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); #ifdef ENABLE_SSL int connected; long err; #endif if (conn->conn_method == M_FILE) { return (1); // No connection necessary for Drop File #ifndef DISABLE_IP } else if (conn->conn_method == M_SOCKETS) { conn->ptr = M_ip_connect (myconn); if (conn->ptr == -1) { return (0); // Connection Failed } #ifdef ENABLE_SSL } else if (conn->conn_method == M_SSL) { connected = 0; /* * due to problems with simultaneous SSL connections on some client/ * server combinations, retry up to M_SSL_RETRIES times to connect * if only SSL_connect() has failed */ do { /* Prefer internal client_ctx creation */ if (client_ctx == NULL || strlen (conn->ca_location)) { conn->client_ctx = SSL_CTX_new (SSLv23_client_method ()); if (conn->client_ctx == NULL) { M_Set_Conn_Error (myconn, "SSL_CTX_new() failed"); return (0); } SSL_CTX_load_verify_locations (conn-> client_ctx, conn-> ca_location, NULL); if (strlen (conn->sslkeyfile)) { if (SSL_CTX_use_PrivateKey_file (conn->client_ctx, conn->sslkeyfile, SSL_FILETYPE_PEM) != 1) { M_Set_Conn_Error (myconn, "SSL_CTX_use_PrivateKey_file() failed"); SSL_CTX_free (conn-> client_ctx); conn->client_ctx = NULL; return (0); } } if (strlen (conn->sslcertfile)) { if (SSL_CTX_use_certificate_file (conn->client_ctx, conn->sslcertfile, SSL_FILETYPE_PEM) != 1) { M_Set_Conn_Error (myconn, "SSL_CTX_use_certificate_file() failed"); SSL_CTX_free (conn-> client_ctx); conn->client_ctx = NULL; return (0); } } } conn->ptr = M_ip_connect (myconn); if (conn->ptr == -1) { if (conn->client_ctx != NULL) { SSL_CTX_free (conn->client_ctx); conn->client_ctx = NULL; } return (0); // Connection Failed } if (conn->client_ctx != NULL) conn->ssl = SSL_new (conn->client_ctx); else conn->ssl = SSL_new (client_ctx); if (conn->ssl == NULL) { M_Set_Conn_Error (myconn, "SSL_new() failed"); // Set // Error // Text return (0); } err = SSL_set_fd (conn->ssl, conn->ptr); if (err == 0) { M_Set_Conn_Error (myconn, "SSL_set_fd() failed"); // Set // Error // Text return (0); // Connection Failed } if (SSL_connect (conn->ssl) != 1) { SSL_free (conn->ssl); conn->ssl = NULL; M_CloseSocket (conn->ptr); conn->ptr = -1; connected--; M_uwait (100000); } else connected = 1; } while (connected >= -M_SSL_RETRIES && connected != 1); if (connected != 1) { M_Set_Conn_Error (myconn, "SSL Negotiation Failed"); // Set // Error // Text return (0); } conn->server_cert = SSL_get_peer_certificate (conn->ssl); // printf("Server Certificate subject: %s\r\n", // X509_NAME_oneline(X509_get_subject_name((X509 // *)conn->server_cert),0,0)); // printf("Server Certificate issuer: %s\r\n", // X509_NAME_oneline(X509_get_issuer_name((X509 // *)conn->server_cert),0,0)); if (!conn->server_cert || (conn->verifyssl && (err = SSL_get_verify_result (conn->ssl)) != X509_V_OK)) { // SSL // Certificate // check // failed M_Set_Conn_Error (myconn, "SSL Certificate verification failed"); if (conn->ptr != -1) M_CloseSocket (conn->ptr); conn->ptr = -1; SSL_free ((SSL *) conn->ssl); conn->ssl = NULL; return (0); } #endif /* ENABLE_SSL */ #endif /* DISABLE_IP */ } conn->status = M_CONNECTED; #ifndef DISABLE_IP if ((conn->conn_method == M_SOCKETS || conn->conn_method == M_SSL) && conn->verifyconn) { if (!M_VerifyPing (myconn)) { M_Set_Conn_Error (myconn, "Monetra did not respond to a PING request. Ensure proper port number and MCVE v2.1 or greater."); if (conn->ptr != -1) M_CloseSocket (conn->ptr); conn->ptr = -1; #ifdef ENABLE_SSL if (conn->conn_method == M_SSL) SSL_free (conn->ssl); conn->ssl = NULL; #endif conn->status = M_DISCONNECTED; return (0); } } #endif /* DISABLE_IP */ conn->status = M_CONNECTED; return (1); } void M_MaxConnTimeout (M_CONN * myconn, int maxtime) { _M_CONN *conn = (_M_CONN *) (*myconn); conn->max_conn_time = maxtime; } const char *M_ConnectionError (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); return (conn->error_text); } // Closes MCVE Connection -- and is ready for M_CONN to be used again void M_DestroyConn (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); while (conn->queue != NULL) { M_DeleteTrans (myconn, (long) conn->queue); } #ifdef ENABLE_SSL if (conn->conn_method == M_SSL) { if (conn->ssl != NULL) { SSL_shutdown (conn->ssl); SSL_free ((SSL *) conn->ssl); } if (conn->client_ctx != NULL) { SSL_CTX_free (conn->client_ctx); } } conn->ssl = NULL; conn->client_ctx = NULL; conn->ca_location[0] = 0; conn->sslkeyfile[0] = 0; conn->sslcertfile[0] = 0; #endif #ifdef M_THREADSAFE M_destroy_locks (myconn); #endif conn->conn_method = -1; conn->port = -1; #ifndef DISABLE_IP if (conn->ptr != -1) M_CloseSocket (conn->ptr); #endif conn->ptr = -1; if (conn->inbuf != NULL) free (conn->inbuf); if (conn->outbuf != NULL) free (conn->outbuf); if (conn->error_text != NULL) free (conn->error_text); conn->inbuf_cnt = 0; conn->inbuf_alloc = 0; conn->outbuf_cnt = 0; conn->outbuf_alloc = 0; conn->error_text = NULL; conn->inbuf = NULL; conn->outbuf = NULL; conn->timeout = 0; conn->status = 0; conn->blocking = 0; conn->verifyssl = 0; conn->verifyconn = 0; conn->max_conn_time = 5; conn->outstanding_auths = 0; conn->queue_length = 0; if (conn->queue != NULL) free (conn->queue); conn->queue = NULL; free (conn); conn = NULL; } int M_Monitor (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); int ret = 0; if (conn->status == M_DISCONNECTED) { M_Set_Conn_Error (myconn, "Not Connected to Monetra"); // Set // Error // Text return (0); } if (conn->conn_method == M_FILE) { ret = M_Monitor_File (myconn); } else if (conn->conn_method == M_SOCKETS || conn->conn_method == M_SSL) { #ifndef DISABLE_IP ret = M_Monitor_IP (myconn); if (!ret) { M_CloseSocket (conn->ptr); conn->ptr = -1; #ifdef ENABLE_SSL if (conn->conn_method == M_SSL) { SSL_free ((SSL *) conn->ssl); conn->ssl = NULL; } #endif /* ENABLE_SSL */ M_Set_Conn_Error (myconn, "Unexpected disconnection from Monetra"); // Set // Error // Text conn->status = M_DISCONNECTED; } if (!M_ProcessBuffer (myconn)) return(1); /* Not a disconnect, but parse error */ #else return (0); #endif /* DISABLE_IP */ } return (ret); } int M_TransactionsSent (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); int ret = 0; if (conn->conn_method == M_FILE) { ret = 1; } else { M_lock (myconn); if (conn->outbuf_cnt == 0) ret = 1; M_unlock (myconn); } return (ret); } void M_DeleteTrans (M_CONN * myconn, M_uintptr identifier) { _M_CONN *conn = (_M_CONN *) (*myconn); int i, j; M_QUEUE *ptr = (M_QUEUE *) identifier; M_QUEUE *next = NULL, *prev = NULL, *base = NULL; if (!M_verify_trans_in_queue(myconn, identifier)) return; M_lock (myconn); if (ptr->transaction != NULL) { for (i = 0; i < ptr->transaction_fields; i++) { free (ptr->transaction[i].key); free (ptr->transaction[i].value); } free (ptr->transaction); ptr->transaction = NULL; } ptr->transaction_fields = 0; if (ptr->parsed_resp != NULL) { for (i = 0; i < ptr->resp_fields; i++) { free (ptr->parsed_resp[i].key); free (ptr->parsed_resp[i].value); } free (ptr->parsed_resp); ptr->parsed_resp = NULL; } ptr->resp_fields = 0; memset (ptr->identifier, 0, 29); ptr->status = M_UNUSED; if (ptr->auth != NULL) free (ptr->auth); ptr->auth = NULL; if (ptr->text != NULL) free (ptr->text); ptr->text = NULL; if (ptr->item != NULL) free (ptr->item); ptr->item = NULL; if (ptr->batch != NULL) free (ptr->batch); ptr->batch = NULL; ptr->code = -1; ptr->avs = -1; ptr->cv = -1; ptr->tid = -1; if (ptr->response != NULL) free (ptr->response); ptr->response = NULL; ptr->iscommadelimited = 0; if (ptr->separated != NULL) { for (i = 0; i < ptr->rows + 1; i++) { for (j = 0; j < ptr->columns; j++) { free (ptr->separated[i][j]); } free (ptr->separated[i]); } free (ptr->separated); } ptr->separated = NULL; ptr->columns = 0; ptr->rows = 0; conn->outstanding_auths--; prev = ptr->prev; next = ptr->next; base = conn->queue; /* We're only trans in queue */ if (base == ptr && ptr->next == ptr) { conn->queue = NULL; /* we're first trans in queue */ } else if (base == ptr) { conn->queue = next; next->prev = prev; prev->next = next; /* we're in the middle */ } else { next->prev = prev; prev->next = next; } free (ptr); M_unlock (myconn); } /* Get a new Queue Number, return the location */ M_uintptr M_TransNew (M_CONN * myconn) { M_QUEUE *ptr = NULL; char timeout[20]; _M_CONN *conn = (_M_CONN *) (*myconn); M_lock (myconn); ptr = M_NewQueueSlot (myconn); ptr->status = M_NEW; M_unlock (myconn); if (conn->timeout > 0) { M_snprintf (timeout, 20, "%ld", conn->timeout); M_TransParam_Add (myconn, (M_uintptr) ptr, "timeout", timeout); } return ((M_uintptr) ptr); } int M_VerifyTrans (M_CONN * myconn, M_uintptr identifier) { if (!M_verify_trans_in_queue(myconn, identifier)) return(0); return (1); } int M_TransSend (M_CONN * myconn, M_uintptr identifier) { _M_CONN *conn = (_M_CONN *) (*myconn); int ret; M_QUEUE *ptr = NULL; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); ptr = (M_QUEUE *) identifier; /* Can only send transactions in the M_NEW state */ if (ptr->status != M_NEW) return (0); if (!M_VerifyTrans (myconn, identifier)) { return (0); } ret = M_SendTransaction (myconn, ptr); if (ret) { conn->outstanding_auths++; /* Blocking mode is set, wait until trans is complete */ if (conn->blocking) { while (M_CheckStatus (myconn, identifier) == M_PENDING) { if (!M_Monitor (myconn)) { return (0); } M_uwait (20000); } } } return (ret); } const char *M_ResponseParam (M_CONN * myconn, M_uintptr identifier, const char *key) { int i; M_QUEUE *ptr = NULL; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); ptr = (M_QUEUE *) identifier; M_lock (myconn); for (i = 0; i < ptr->resp_fields; i++) { if (strcasecmp (key, ptr->parsed_resp[i].key) == 0) return (ptr->parsed_resp[i].value); } M_unlock (myconn); return (NULL); } char **M_ResponseKeys (M_CONN * myconn, M_uintptr identifier, int *num_keys) { char **ret = NULL; int i; M_QUEUE *ptr = NULL; (*num_keys)=0; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); ptr = (M_QUEUE *) identifier; M_lock (myconn); (*num_keys) = ptr->resp_fields; ret = (char **) malloc ((*num_keys) * sizeof (char *)); for (i = 0; i < (*num_keys); i++) { ret[i] = strdup (M_Safe (ptr->parsed_resp[i].key)); } M_unlock (myconn); return (ret); } M_EXPORT const char *M_ResponseKeys_index(char **keys, int num_keys, int index) { if (keys == NULL) return(NULL); if (index < 0) return(NULL); if (index >= num_keys) return(NULL); return(keys[index]); } int M_FreeResponseKeys (char **keys, int num_keys) { int i; for (i = 0; i < num_keys; i++) { free (keys[i]); } free (keys); return (1); } /* Add a custom Transaction Parameter (modules, etc) */ int M_TransParam_Add (M_CONN * myconn, M_uintptr identifier, const char *key, const char *value) { int field; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); field = ptr->transaction_fields; ptr->transaction = (M_TRANS *) realloc (ptr->transaction, (field + 1) * sizeof (M_TRANS)); ptr->transaction[field].key = MC_SAFE_strdup (key); ptr->transaction[field].value = MC_SAFE_strdup (value); ptr->transaction_fields++; return (1); } /* Instead of using MC_CUSTOM for M_TransParam, use this ... infact, deprecate * M_TransParam ! */ int M_TransKeyVal (M_CONN * myconn, M_uintptr identifier, const char *key, const char *value) { return(M_TransParam_Add(myconn, identifier, key, value)); } /* Add a new Transaction Parameter */ int M_TransParam (M_CONN * myconn, M_uintptr identifier, int key, ...) { char key_string[100]; char value_string[1024]; int trans_type; int excharges_type; int temp_tf; char *temp_str = NULL; va_list ap; char *temp = NULL; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); /* Make sure people don't add params to structures not in the M_NEW * state */ if (ptr->status != M_NEW) return (0); key_string[0] = 0; value_string[0] = 0; va_start (ap, key); switch (key) { case MC_TRANTYPE: MC_SAFE_strncpy (key_string, "action", 99); trans_type = va_arg (ap, int); if (trans_type < 1000) { MC_SAFE_strncpy (value_string, M_GetTypeString (trans_type), 1023); } else { MC_SAFE_strncpy (value_string, M_GetEngineAdminTypeString (trans_type), 1023); } ptr->type = trans_type; break; case MC_ADMIN: MC_SAFE_strncpy (key_string, "admin", 99); trans_type = va_arg (ap, int); MC_SAFE_strncpy (value_string, M_GetAdminTypeString (trans_type), 1023); ptr->admin = trans_type; break; case MC_USERNAME: MC_SAFE_strncpy (key_string, "username", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_PASSWORD: MC_SAFE_strncpy (key_string, "password", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_ACCOUNT: MC_SAFE_strncpy (key_string, "account", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_TRACKDATA: MC_SAFE_strncpy (key_string, "trackdata", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_EXPDATE: MC_SAFE_strncpy (key_string, "expdate", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_STREET: MC_SAFE_strncpy (key_string, "street", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_ZIP: MC_SAFE_strncpy (key_string, "zip", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_CV: MC_SAFE_strncpy (key_string, "cvv2", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_COMMENTS: MC_SAFE_strncpy (key_string, "comments", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_CLERKID: MC_SAFE_strncpy (key_string, "clerkid", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_STATIONID: MC_SAFE_strncpy (key_string, "stationid", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_APPRCODE: MC_SAFE_strncpy (key_string, "apprcode", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_AMOUNT: MC_SAFE_strncpy (key_string, "amount", 99); M_snprintf (value_string, 1023, "%.2f", va_arg (ap, double)); break; case MC_PTRANNUM: MC_SAFE_strncpy (key_string, "ptrannum", 99); M_snprintf (value_string, 1023, "%ld", va_arg (ap, long)); break; case MC_TIMESTAMP: MC_SAFE_strncpy (key_string, "timestamp", 99); M_snprintf (value_string, 1023, "%ld", va_arg (ap, long)); break; case MC_TTID: MC_SAFE_strncpy (key_string, "ttid", 99); M_snprintf (value_string, 1023, "%lld", va_arg (ap, M_int64)); break; case MC_USER: MC_SAFE_strncpy (key_string, "user", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_PWD: MC_SAFE_strncpy (key_string, "pwd", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_ACCT: MC_SAFE_strncpy (key_string, "acct", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_BDATE: MC_SAFE_strncpy (key_string, "bdate", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_EDATE: MC_SAFE_strncpy (key_string, "edate", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_BATCH: MC_SAFE_strncpy (key_string, "batch", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_FILE: MC_SAFE_strncpy (key_string, "file", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_AUDITTYPE: MC_SAFE_strncpy (key_string, "type", 99); trans_type = va_arg (ap, int); MC_SAFE_strncpy (value_string, M_GetTypeString (trans_type), 1023); break; case MC_CUSTOM: MC_SAFE_strncpy (key_string, va_arg (ap, char *), 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; /* Additional args for restaurant, lodging and auto rental */ case MC_EXAMOUNT: MC_SAFE_strncpy (key_string, "examount", 99); M_snprintf (value_string, 1023, "%.2f", va_arg (ap, double)); break; case MC_EXCHARGES: MC_SAFE_strncpy (key_string, "excharges", 99); excharges_type = va_arg (ap, int); MC_SAFE_strncpy (value_string, M_GetExchargesArgString (excharges_type), 1023); break; case MC_RATE: MC_SAFE_strncpy (key_string, "rate", 99); M_snprintf (value_string, 1023, "%.2f", va_arg (ap, double)); break; case MC_RENTERNAME: MC_SAFE_strncpy (key_string, "rentername", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_RETURNCITY: MC_SAFE_strncpy (key_string, "returncity", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_RETURNSTATE: MC_SAFE_strncpy (key_string, "returnstate", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_RETURNLOCATION: MC_SAFE_strncpy (key_string, "returnlocation", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_INQUIRY: MC_SAFE_strncpy (key_string, "inquiry", 99); temp_tf = va_arg (ap, int); if (temp_tf) { MC_SAFE_strncpy (value_string, "yes", 1023); } else { MC_SAFE_strncpy (value_string, "no", 1023); } break; case MC_PRIORITY: MC_SAFE_strncpy (key_string, "priority", 99); MC_SAFE_strncpy (value_string, M_GetPriorityString (va_arg (ap, int)), 1023); break; case MC_CARDTYPES: MC_SAFE_strncpy (key_string, "cardtypes", 99); MC_SAFE_strncpy (value_string, M_GetCardTypesString (va_arg (ap, int)), 1023); break; case MC_SUB: MC_SAFE_strncpy (key_string, "sub", 99); M_snprintf (value_string, 1023, "%d", va_arg (ap, int)); break; case MC_MARKER: MC_SAFE_strncpy (key_string, "marker", 99); M_snprintf (value_string, 1023, "%ld", va_arg (ap, long)); break; case MC_DEVICETYPE: MC_SAFE_strncpy (key_string, "devicetype", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_ERRORCODE: MC_SAFE_strncpy (key_string, "errorcode", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_NEWBATCH: MC_SAFE_strncpy (key_string, "newbatch", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_CURR: MC_SAFE_strncpy (key_string, "curr", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_DESCMERCH: MC_SAFE_strncpy (key_string, "descmerch", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_DESCLOC: MC_SAFE_strncpy (key_string, "descloc", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; case MC_ORIGTYPE: MC_SAFE_strncpy (key_string, "origtype", 99); trans_type = va_arg (ap, int); if (trans_type < 1000) { MC_SAFE_strncpy (value_string, M_GetTypeString (trans_type), 1023); } else { MC_SAFE_strncpy (value_string, M_GetEngineAdminTypeString (trans_type), 1023); } break; case MC_VOIDORIGTYPE: MC_SAFE_strncpy (key_string, "voidorigtype", 99); trans_type = va_arg (ap, int); if (trans_type < 1000) { MC_SAFE_strncpy (value_string, M_GetTypeString (trans_type), 1023); } else { MC_SAFE_strncpy (value_string, M_GetEngineAdminTypeString (trans_type), 1023); } break; case MC_PIN: MC_SAFE_strncpy (key_string, "pin", 99); MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); break; default: if (key >= 2000) { temp = M_GetUserArgString (key); if (temp != NULL && strlen (temp)) { MC_SAFE_strncpy (key_string, temp, 99); if (key == MC_USER_SUB) { M_snprintf (value_string, 1023, "%d", va_arg (ap, int)); } else if (key == MC_USER_CARDTYPES) { temp_str = M_GetCardTypesString (va_arg (ap, int)); MC_SAFE_strncpy (value_string, temp_str, 1023); free (temp_str); } else if (key == MC_USER_MODE) { temp_str = M_GetModeString (va_arg (ap, int)); MC_SAFE_strncpy (value_string, temp_str, 1023); free (temp_str); } else { MC_SAFE_strncpy (value_string, va_arg (ap, char *), 1023); } } } break; }; va_end (ap); /* should allow blank value */ if (strlen (key_string) /* && strlen(value_string) */ ) { /* Maintain compatability with MCVE 2.0-2.1 */ if (strcasecmp (key_string, "ttid") == 0) { M_TransParam_Add (myconn, identifier, "sid", value_string); } return (M_TransParam_Add (myconn, identifier, key_string, value_string)); } return (0); } /* RESPONSE CHECKING ROUTINES */ int M_ReturnStatus (M_CONN * myconn, M_uintptr identifier) { int status; const char *code; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); code = M_ResponseParam (myconn, identifier, "code"); if (code == NULL) return (M_SUCCESS); M_lock (myconn); if (ptr->code == -1) status = -1; else if (ptr->code == M_SUCCESS) status = M_SUCCESS; else if (ptr->code == M_AUTH) status = M_SUCCESS; else status = M_FAIL; M_unlock (myconn); return (status); } int M_ReturnCode (M_CONN * myconn, M_uintptr identifier) { int code; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); code = ptr->code; M_unlock (myconn); return (code); } long M_TransactionItem (M_CONN * myconn, M_uintptr identifier) { long item = -1; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); if (ptr->item != NULL) item = atol (ptr->item); M_unlock (myconn); return (item); } long M_TransactionBatch (M_CONN * myconn, M_uintptr identifier) { long batch = -1; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); if (ptr->batch != NULL) batch = atol (ptr->batch); M_unlock (myconn); return (batch); } M_int64 M_TransactionID (M_CONN * myconn, M_uintptr identifier) { M_int64 tid = -1; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); if (ptr->tid != -1) tid = ptr->tid; M_unlock (myconn); return (tid); } const char *M_TransactionAuth (M_CONN * myconn, M_uintptr identifier) { char *auth = NULL; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); M_lock (myconn); if (ptr->auth != NULL) auth = ptr->auth; M_unlock (myconn); return (auth); } const char *M_TransactionText (M_CONN * myconn, M_uintptr identifier) { char *text = NULL; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); M_lock (myconn); if (ptr->text != NULL) text = ptr->text; M_unlock (myconn); return (text); } int M_TransactionAVS (M_CONN * myconn, M_uintptr identifier) { int code; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); code = ptr->avs; M_unlock (myconn); return (code); } int M_TransactionCV (M_CONN * myconn, M_uintptr identifier) { int code; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); code = ptr->cv; M_unlock (myconn); return (code); } long M_TransInQueue (M_CONN * myconn) { _M_CONN *conn = (_M_CONN *) (*myconn); long auths; M_lock (myconn); auths = conn->outstanding_auths; M_unlock (myconn); return (auths); } int M_CheckStatus (M_CONN * myconn, M_uintptr identifier) { int status; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); M_lock (myconn); status = ptr->status; M_unlock (myconn); return (status); } long M_CompleteAuthorizations (M_CONN * myconn, M_uintptr **listings) { _M_CONN *conn = (_M_CONN *) (*myconn); long num = 0; M_QUEUE *ptr = NULL; M_lock (myconn); ptr = conn->queue; while (ptr != NULL) { if (ptr->status == M_DONE) num++; ptr = ptr->next; if (ptr == conn->queue) break; } if (num != 0 && listings != NULL) { (*listings) = (M_uintptr *) malloc ((num) * sizeof (M_uintptr)); num = 0; ptr = conn->queue; while (ptr != NULL) { if (ptr->status == M_DONE) { (*listings)[num++] = (M_uintptr)ptr; } ptr = ptr->next; if (ptr == conn->queue) break; } } M_unlock (myconn); return (num); } /* For non-C compatible languages (ones that don't understand arrays) */ M_EXPORT M_uintptr M_CompleteAuthorizations_index(M_uintptr *listings, int num_listings, int index) { if (index < 0) return(0); if (index >= num_listings) return(0); if (listings == NULL) return(0); return(listings[index]); } /* For non-C compatible languages (ones that don't understand arrays) */ M_EXPORT int M_FreeCompleteAuthorizations(M_uintptr *listings, int num_listings) { if (listings == NULL) return(0); if (num_listings <= 0) return(0); free(listings); return(1); } /* COMMA DELIMITED ROUTINES */ int M_IsCommaDelimited (M_CONN * myconn, M_uintptr identifier) { M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); return (ptr->iscommadelimited); } int M_ParseCommaDelimited (M_CONN * myconn, M_uintptr identifier) { int columns; long rows; int i; long j, row_num; int offset; long datalen; char *temp, *temp2, *str, **real_row; char *line_temp1, *line_temp2; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); columns = M_Count_CD_Columns (myconn, identifier); rows = M_Count_CD_Lines (myconn, identifier); ptr->separated = (char ***) malloc (rows * sizeof (char **)); for (j = 0; j < rows; j++) { ptr->separated[j] = (char **) malloc (columns * sizeof (char *)); } temp = ptr->response; real_row = malloc (sizeof (char *) * rows); real_row[0] = temp; row_num = 1; j = 0; datalen = strlen (M_Safe (ptr->response)); for (j = 0; j < datalen; j++) { /* Filter out \r's */ if (temp[j] == '\r') { temp[j] = '\0'; } else if (temp[j] == '\n') { temp[j] = '\0'; if (j + 1 < datalen) { real_row[row_num] = temp + j + 1; row_num++; } } } /* * while (temp[j] != '\0') { if (temp[j] == '\n') { temp[j] = '\0'; * if (temp[j + 1] != '\0') real_row[row_num] = temp + j + 1; * row_num++; } j++; } */ for (j = 0; j < rows; j++) { str = real_row[j]; if (str == NULL) break; offset = strlen (str) + 2; temp2 = temp + offset; temp = temp2; line_temp1 = str; for (i = 0; i < columns; i++) { line_temp2 = strchr (line_temp1, ','); if (line_temp2 == NULL) { ptr->separated[j][i] = M_midstr (line_temp1, 0, strlen (line_temp1)); break; } ptr->separated[j][i] = M_midstr (line_temp1, 0, strlen (line_temp1) - strlen (line_temp2)); line_temp1 = line_temp2 + 1; } } free (real_row); ptr->columns = columns; ptr->rows = rows - 1; return (1); } const char *M_GetCommaDelimited (M_CONN * myconn, M_uintptr identifier) { M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); return (ptr->response); } const char *M_GetCell (M_CONN * myconn, M_uintptr identifier, const char *column, long row) { int i; M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); for (i = 0; i < ptr->columns; i++) { if (strcasecmp (column, ptr->separated[0][i]) == 0) return (ptr->separated[row + 1][i]); } return (NULL); } const char *M_GetCellByNum (M_CONN * myconn, M_uintptr identifier, int column, long row) { M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); return (ptr->separated[row + 1][column]); } int M_NumColumns (M_CONN * myconn, M_uintptr identifier) { M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); return (ptr->columns); } long M_NumRows (M_CONN * myconn, M_uintptr identifier) { M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(0); return (ptr->rows); } const char *M_GetHeader (M_CONN * myconn, M_uintptr identifier, int column_num) { M_QUEUE *ptr = (M_QUEUE *) identifier; if (!M_verify_trans_in_queue(myconn, identifier)) return(NULL); return (ptr->separated[0][column_num]); } /* TEXT RESPONSE CONVERSIONS */ const char *M_TEXT_Code (int code) { char *text = NULL; switch (code) { case M_AUTH: text = "AUTH"; break; case M_DENY: text = "DENY"; break; case M_DUPL: text = "DUPLICATE TRANS"; break; case M_CALL: text = "CALL PROCESSOR"; break; case M_PKUP: text = "PICKUP CARD"; break; case M_RETRY: text = "RETRY"; break; case M_SETUP: text = "SETUP"; break; case M_TIMEOUT: text = "TIMEOUT"; break; case M_SUCCESS: text = "SUCCESS"; break; case M_FAIL: text = "FAIL"; break; case M_ERROR: text = "ERROR"; break; default: text = "UNKNOWN"; break; } return (text); } const char *M_TEXT_AVS (int code) { char *text = NULL; switch (code) { case M_STREET: text = "STREET FAILED"; break; case M_ZIP: text = "ZIP FAILED"; break; case M_GOOD: text = "GOOD"; break; case M_BAD: text = "BAD"; break; case M_UNKNOWN: text = "UNKNOWN"; break; default: text = "UNKNOWN"; break; } return (text); } const char *M_TEXT_CV (int code) { return (M_TEXT_AVS (code)); } char * M_SSLCert_gen_hash(const char *filename) { #ifdef ENABLE_SSL BIO *bio; X509 *x509; char *buf, *fingerprint; int fd, retval; ssize_t slen; struct stat sb; unsigned char md[EVP_MAX_MD_SIZE]; unsigned int i, md_size; fd = open(filename, O_RDONLY); #if 1 if (fd == -1) { fprintf(stderr, "cannot open() %s\n", strerror(errno)); return (0); } #else if (fd == -1) return (0); #endif retval = fstat(fd, &sb); if (retval == -1) { #if 1 fprintf(stderr, "cannot fstat() %s\n", strerror(errno)); #endif close(fd); return (0); } buf = malloc(sb.st_size + 1); if (buf == NULL) { #if 1 fprintf(stderr, "cannot malloc() %s\n", strerror(errno)); #endif close(fd); return (0); } slen = read(fd, buf, sb.st_size); if (slen != sb.st_size) { #if 1 fprintf(stderr, "cannot read() %s\n", strerror(errno)); #endif free(buf); close(fd); return (0); } buf[sb.st_size] = '\0'; close(fd); bio = BIO_new_mem_buf(buf, strlen(buf)); if (bio == NULL) { #if 1 fprintf(stderr, "BIO_new_mem_buf() failed\n"); #endif free(buf); return (0); } #if 1 x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); BIO_free(bio); #else x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); BIO_free(bio); free(buf); if (x509 == NULL) { fprintf(stderr, "PEM_read_bio_X509() failed\n"); return (0); } #endif md_size = sizeof(md); retval = X509_digest(x509, EVP_sha1(), md, &md_size); X509_free(x509); if (retval == 0 || md_size == 0) { fprintf(stderr, "X509_digest() failed\n"); return (0); } fingerprint = malloc(md_size * 3); if (fingerprint == NULL) { fprintf(stderr, "malloc() failed: %s\n", strerror(errno)); return (0); } memset(fingerprint, 0, md_size * 3); for (i = 0; i < md_size; i++) M_snprintf(fingerprint + i * 3, 4, "%02x%c", md[i], (i + 1 == md_size) ? '\0' : ':'); return (fingerprint); #else /* ENABLE_SSL */ return(NULL); #endif /* ENABLE_SSL */ }