1 /* tclink.c - Library code for the TCLink client API. */
14 #include <arpa/inet.h>
16 #include <netinet/in.h>
19 #include <sys/socket.h>
21 #include <sys/types.h>
29 #include <sys/types.h>
31 #include <openssl/crypto.h>
32 #include <openssl/err.h>
33 #include <openssl/pem.h>
34 #include <openssl/rand.h>
35 #include <openssl/ssl.h>
36 #include <openssl/x509.h>
39 #define strcasecmp(x, y) stricmp(x, y)
41 #define closesocket(x) close(x)
44 #define DEFAULT_HOST "pgw1.trustcommerce.com"
46 /* changed from forty second to one hundred second to reflect more complicated
47 * transaction processing logic */
48 #define TIMEOUT 100 /* seconds */
49 #define TC_BUFF_MAX 32000
50 #define TC_LINE_MAX ((PARAM_MAX_LEN * 2) + 2)
52 char tclink_version
[] =
53 TCLINK_VERSION
; /* TCLINK_VERSION is defined in Makefile */
54 char tclink_host
[] = DEFAULT_HOST
;
55 int tclink_port
= 443;
57 /*************************************************/
58 /* Data structures used only within this module. */
59 /*************************************************/
61 /* Variables used for transaction data. */
63 typedef struct param_data
67 struct param_data
* next
;
70 typedef struct _TCLinkCon
78 const SSL_METHOD
* meth
;
83 /* Transaction parameters, sent and received */
84 param
*send_param_list
, *send_param_tail
;
85 param
* recv_param_list
;
87 /* Connection status */
93 int (*validate_cert
)(int, void*);
98 /*************************************
99 * Internal functions, not exported. *
100 *************************************/
102 /* Random number from min to max. */
104 number(int min
, int max
)
107 return (rand_r((unsigned int*)&t
) % (max
- min
+ 1)) + min
;
110 /* Check if path points to a regular file */
112 is_regular_file(const char* path
)
116 return S_ISREG(st
.st_mode
);
119 /* Safe string copy and append functions. */
120 #define SAFE_COPY(d, s) safe_copy((d), (s), sizeof(d));
121 #define SAFE_APPEND(d, s) safe_append((d), (s), sizeof(d));
124 safe_copy(char* dst
, const char* src
, int size
)
126 int len
= (int) strlen(src
);
130 strncpy(dst
, src
, size
- 1);
133 return (len
>= size
);
137 safe_append(char* dst
, const char* src
, int size
)
139 int dlen
= (int) strlen(dst
);
140 int slen
= (int) strlen(src
);
141 int avail
= size
- dlen
;
146 strcpy(dst
+ dlen
, src
);
148 strncpy(dst
+ dlen
, src
, avail
- 1);
151 return (slen
>= avail
);
154 /* Add a parameter-value pair to the recieved list. */
156 AddRecvParam(TCLinkCon
* c
, const char* name
, const char* value
)
160 if (name
[0] == 0 || value
[0] == 0)
163 p
= (param
*)malloc(sizeof(param
));
164 p
->name
= strdup(name
);
165 p
->value
= strdup(value
);
166 p
->next
= c
->recv_param_list
;
167 c
->recv_param_list
= p
;
170 /* Add a string to the received list. */
172 AddRecvString(TCLinkCon
* c
, char* string
)
174 char* ptr
= strchr(string
, '=');
179 AddRecvParam(c
, string
, ptr
+ 1);
184 /* Deallocate the send list. */
186 ClearSendList(TCLinkCon
* c
)
189 for (p
= c
->send_param_list
; p
; p
= next
) {
196 c
->send_param_list
= c
->send_param_tail
= NULL
;
199 /* Deallocate the recv list. */
201 ClearRecvList(TCLinkCon
* c
)
204 for (p
= c
->recv_param_list
; p
; p
= next
) {
211 c
->recv_param_list
= NULL
;
215 do_SSL_randomize(void)
221 int randbuf
[RAND_VALS
];
227 /* if they have a /dev/urandom we can skip this function */
228 if (RAND_status() != 0)
232 RAND_seed((char*)&t
, sizeof(time_t));
234 /* have they specified a random file with RANDFILE environment variable? */
235 use_rand_file
= RAND_file_name(fname
, sizeof(fname
)) ? 1 : 0;
237 RAND_load_file(fname
, 4096);
239 /* stuff it with packets of random numbers until it is satisfied */
240 for (i
= 0; i
< 256 && RAND_status() == 0; i
++) {
241 for (c
= 0; c
< RAND_VALS
; c
++)
242 randbuf
[c
] = rand_r((unsigned int*)&t
);
243 RAND_seed((char*)randbuf
, sizeof(int) * RAND_VALS
);
247 /* Make sure all of the ssl objects are properly initialized.
250 init_ssl(TCLinkCon
* c
)
258 /* do some SSL setup */
260 do_SSL_randomize(); /* handle systems without /dev/urandom */
261 #if OPENSSL_VERSION_NUMBER < 0x10100000L
262 c
->meth
= SSLv23_client_method();
263 c
->ctx_options
= SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
| SSL_OP_NO_TLSv1
;
265 c
->meth
= TLS_client_method();
266 c
->ctx_options
= SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
| SSL_OP_NO_TLSv1
|
267 SSL_OP_NO_TLSv1_1
| SSL_OP_NO_TICKET
;
275 c
->ctx
= SSL_CTX_new(c
->meth
);
280 SSL_CTX_set_options(c
->ctx
, c
->ctx_options
);
281 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
282 SSL_CTX_set_min_proto_version(c
->ctx
, TLS1_2_VERSION
);
285 is_file
= is_regular_file(TCLINK_CA_PATH
);
286 val
= SSL_CTX_load_verify_locations(
287 c
->ctx
, is_file
? TCLINK_CA_PATH
: NULL
, is_file
? NULL
: TCLINK_CA_PATH
);
290 return 0; // failed to populate cert store
292 /* turn on certificate chain validation */
293 SSL_CTX_set_verify(c
->ctx
, SSL_VERIFY_PEER
, NULL
);
297 c
->ssl
= SSL_new(c
->ctx
);
299 SSL_CTX_free(c
->ctx
);
308 /* Open a socket to the host_ip specified. Returns the socket's file
309 * descriptor on success (the open attempt is underway) or -1 for failure
310 * (should never happen in practice). Note that this function DOES NOT block
311 * and wait for the connection; you'll need to select() on the socket later to
312 * see if it opened successfully.
315 BeginConnection(TCLinkCon
* c
, int host_ip
)
317 struct sockaddr_in sa
;
320 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
326 ioctlsocket(sd
, FIONBIO
, ¶m
);
328 fcntl(sd
, F_SETFL
, O_NONBLOCK
);
331 memset(&sa
, 0, sizeof(sa
));
332 sa
.sin_family
= AF_INET
;
333 sa
.sin_addr
.s_addr
= host_ip
;
334 sa
.sin_port
= htons(tclink_port
);
336 connect(sd
, (struct sockaddr
*)&sa
, sizeof(sa
));
341 /* This function is called on a socket file descriptor once the connection has
342 * been established and we're ready to negotiate SSL. If the SSL handshake
343 * fails for some reason (such as the host on the other end not using SSL), it
344 * will return 0 for failure. Success returns 1.
347 FinishConnection(TCLinkCon
* c
, int sd
)
349 int ssl_connected
, is_error
, errcode
, res
;
351 time_t start
, remaining
;
355 /* check if socket has connected successfully */
358 getsockopt(sd
, SOL_SOCKET
, SO_ERROR
, (char*)&val
, &size
);
367 // Call init_ssl to make sure everything is setup properly.
371 SSL_set_fd(c
->ssl
, sd
);
377 while (!ssl_connected
&& !is_error
) {
379 remaining
= 5 - (time(0) - start
);
380 if (remaining
<= 0) {
385 res
= SSL_connect(c
->ssl
);
387 ssl_connected
= ((res
== 1) && SSL_is_init_finished(c
->ssl
));
389 if (!ssl_connected
) {
391 FD_SET((unsigned)sd
, &in
);
393 FD_SET((unsigned)sd
, &out
);
395 FD_SET((unsigned)sd
, &err
);
396 /* the documentation does not suggest that both error types occur at the
397 * same time so the retry logic will consume all the outstanding events we
398 * do not actually use oob data, but if it is sent, it is treated as an
401 errcode
= SSL_get_error(c
->ssl
, res
);
404 /* no error, we should have a connection, check again */
407 case SSL_ERROR_WANT_READ
:
408 /* no error, just wait for more data */
409 tv
.tv_sec
= remaining
;
411 /* posix-2001 says the function will modify the appropriate
413 if (select(sd
+ 1, &in
, NULL
, &err
, &tv
) < 0 ||
414 FD_ISSET((unsigned)sd
, &err
))
417 case SSL_ERROR_WANT_WRITE
:
418 /* no error, just wait for more data */
419 tv
.tv_sec
= remaining
;
421 if (select(sd
+ 1, NULL
, &out
, &err
, &tv
) < 0 ||
422 FD_ISSET((unsigned)sd
, &err
))
425 case SSL_ERROR_ZERO_RETURN
: /* peer closed the connection */
426 case SSL_ERROR_SSL
: /* error in SSL handshake */
439 ioctlsocket(sd
, FIONBIO
, ¶m
); // make the socket blocking again
441 fcntl(sd
, F_SETFL
, 0); /* make the socket blocking again */
444 /* verify that server certificate is authentic */
445 server_cert
= SSL_get_peer_certificate(c
->ssl
);
449 if (c
->validate_cert
&& c
->validate_cert(0, server_cert
) != 0) {
450 X509_free(server_cert
);
453 X509_free(server_cert
);
458 /* This function should be called on list of socket file descriptors (sd) to
459 * determine if any have opened successfully. If so, it will return which one
460 * (index into the array). Otherwise it returns -1 if none have successfully
461 * opened. This function will block for a maximum of 3 seconds. As this function
462 * calls FinishConnection(), you shouldn't need to do anything special after it
463 * returns success - the socket is set up and ready for use.
466 CheckConnection(TCLinkCon
* c
, int* sd
, int num_sd
)
468 fd_set wr_set
, err_set
;
472 tv
.tv_sec
= 3; /* wait 3 seconds for soc->mething to happen */
475 /* build the fd_sets used for select() */
478 for (i
= 0; i
< num_sd
; i
++) {
481 FD_SET(sd
[i
], &wr_set
);
482 FD_SET(sd
[i
], &err_set
);
487 /* run the select and see what we have waiting for us */
488 if (select(max_sd
+ 1, NULL
, &wr_set
, &err_set
, &tv
) < 1)
489 return -1; /* I hope this never happens */
491 for (i
= 0; i
< num_sd
; i
++)
493 if (FD_ISSET(sd
[i
], &err_set
)) {
494 /* error - close the socket and mark it defunct */
497 } else if (FD_ISSET(sd
[i
], &wr_set
)) {
498 /* socket has opened! try to negotiate SSL */
499 if (FinishConnection(c
, sd
[i
])) {
500 /* socket is ready to go, so return success */
504 /* SSL handshake had errors, close the socket and mark it defunct */
507 // Clear the ssl environment too.
516 /* if we get here, nothing much interesting happened during those 3 seconds */
520 /* Open a connection to one of the TrustCommerce gateway servers. */
522 Connect(TCLinkCon
* c
, int host_hash
)
524 struct hostent default_he
;
527 unsigned int** gw
= NULL
;
533 time_t last_connect
[MAX_HOSTS
];
538 int i
, j
, sort
, sort_val
;
540 for (i
= 0; i
< MAX_HOSTS
; i
++)
546 srand((unsigned) time(0));
548 /* These are used as BACKUP ONLY if the DNS if offline. */
549 addr
[0] = inet_addr("206.82.213.130");
550 addr
[1] = inet_addr("208.72.241.130");
551 addr_list
[0] = (char*)&addr
[0];
552 addr_list
[1] = (char*)&addr
[1];
554 default_he
.h_addr_list
= addr_list
;
556 /* determine IP addresses of gateway */
561 struct hostent tmpres
;
563 struct hostent
* he
= NULL
;
567 he
= gethostbyname(tclink_host
);
572 gethostbyname_r(tclink_host
, &tmpres
, tmpbuf
, sizeof(tmpbuf
), &he
, &herr
);
577 if (ret
== 0 && he
!= NULL
) {
580 /* fall back to hardcoded IPs in an emergency */
585 for (c
->num_ips
= 0; he
->h_addr_list
[c
->num_ips
]; c
->num_ips
++)
588 c
->ip
= (int*)malloc(c
->num_ips
* sizeof(int));
589 gw
= (int unsigned**)he
->h_addr_list
;
591 /* sort the IP address list before storing it */
592 for (i
= 0; i
< c
->num_ips
; i
++) {
595 for (j
= 1; j
< c
->num_ips
; j
++)
596 if (*gw
[j
] > (unsigned int)sort_val
) {
609 /* This loop works as follows:
610 * Grab the first host. Try to open a connection to it. If there was an
611 * error (host down or unreachable) go to the next one. If nothing has
612 * happened after 3 seconds, open a second socket (the first one is still
613 * open!) and try with the next fail-over host. Continue to do this for a
614 * maximum of MAX_HOSTS sockets, or until our TIMEOUT value runs out. We also
615 * keep track of how recently we tried to connect to a given host, so that we
616 * avoid saturating the machines in a heavy-load situation (which could be
617 * caused by anything from heavy internet lag between the local host and the
618 * TrustCommerce servers, to heavy load on the servers themselves due to half
619 * a million people trying to run credit card transactions in the same half
620 * second - unlikely, but certainly possible.)
622 c
->start_time
= time(0);
624 memset(last_connect
, 0, MAX_HOSTS
* sizeof(time_t));
626 host
= host_hash
% c
->num_ips
;
628 for (; time(0) < (c
->start_time
+ TIMEOUT
); c
->pass
++) {
629 /* retry the first host at least once */
632 if (host
>= c
->num_ips
)
635 /* only connect if we haven't tried this host before, or it's been a little
636 * while (note random modifier to help stagger network traffic) */
637 if (last_connect
[host
] == 0 ||
638 (time(0) - last_connect
[host
]) >= number(TIMEOUT
/ 4, TIMEOUT
)) {
639 if (num_sd
< MAX_HOSTS
) {
640 /* fire up a new connection to this host */
642 last_connect
[host
] = time(0);
644 sd
[num_sd
] = BeginConnection(c
, c
->ip
[host
]);
650 /* scan all current sockets and see if we've made a successful connection
651 * somewhere. note that this also includes SSL and all that sort of fun,
652 * so once it returns success, we're all done. */
654 if (CheckConnection(c
, sd
, num_sd
) >= 0) {
655 /* Success: close all other file handles and return */
656 for (i
= 0; i
< num_sd
; i
++)
657 if (sd
[i
] >= 0 && sd
[i
] != c
->sd
)
664 usleep(1000); // sleep for 1 millisecond
667 // We couldn't connect successfully to any endpoint/s.
668 // Close any open sockets to avoid leaks.
669 for (i
= 0; i
< num_sd
; i
++) {
679 /* Send a chunk of data through a connection previously opened with Connect().
682 Send(TCLinkCon
* c
, const char* string
)
684 if (SSL_write(c
->ssl
, string
, (unsigned) strlen(string
)) < 0)
690 /* Peel a line off the current input. Note that this DOESN'T necessarily wait
691 * for all input to come in, only up to a "\n". -1 is returned for a network
692 * error, otherwise it returns the length of the line read. If there is not a
693 * complete line pending for read this will block until there is, or an error
697 ReadLine(TCLinkCon
* c
, char* buffer
, char* destbuf
)
704 while (1) /* we wait for a line to come in or an error to occur */
706 char* eol
= strchr(buffer
, '\n');
708 /* peel off the line and return it */
710 safe_copy(destbuf
, buffer
, TC_LINE_MAX
);
711 memmove(buffer
, eol
, strlen(eol
) + 1);
712 return (int) strlen(destbuf
);
714 if (c
->is_error
== 1)
717 /* do socket work to grab the most recent chunk of incoming data */
719 FD_SET(c
->sd
, &read
);
721 FD_SET(c
->sd
, &error
);
725 sel
= select(c
->sd
+ 1, &read
, NULL
, &error
, &tv
);
728 else if (FD_ISSET(c
->sd
, &error
))
730 else if (FD_ISSET(c
->sd
, &read
)) {
731 int buffer_end
= (int) strlen(buffer
);
733 SSL_read(c
->ssl
, buffer
+ buffer_end
, TC_BUFF_MAX
- 1 - buffer_end
);
735 int error_type
= SSL_get_error(c
->ssl
, size
);
736 switch (error_type
) {
737 /* this would never happen in practice */
739 /* this wouldn't happen either because the ssl transport is blocking
741 case SSL_ERROR_WANT_READ
:
742 case SSL_ERROR_WANT_WRITE
:
743 buffer
[buffer_end
] = 0;
746 /* these others should not really happen but if they do, we bail */
747 /* we would never get any more data and it looks like the callee is
748 * expecting something */
749 case SSL_ERROR_ZERO_RETURN
:
750 case SSL_ERROR_WANT_CONNECT
:
751 case SSL_ERROR_WANT_ACCEPT
:
752 case SSL_ERROR_SYSCALL
:
753 case SSL_ERROR_WANT_X509_LOOKUP
:
762 buffer
[buffer_end
+ size
] = 0;
768 /* Closes a connection opened with Connect() and frees memory associated with
769 * it. You ONLY need to Close() connections which opened successfully; those
770 * that don't clean up after themselves before Connect() returns.
776 /* The full shutdown presented here is more for completeness than necessity;
777 * at this point in the application, we have already received the end
778 * trailer (or bust) which is generally accompanied by a close notify
779 * message. If the software chooses to respond to the close notify (per TLS
780 * specification) this would result in at least reading the incoming close
781 * notify and issuing our own. Because this entails an additional round
782 * trip that is not needed (the transaction is done after the accompanying
783 * END), there does not appear to be a benefit to it at all. By default
784 * though, this configuration is enabled and can be disabled by the
785 * integrator for performance reasons.
787 if (c
->full_ssl_close
) {
788 int status
= SSL_shutdown(c
->ssl
);
790 status
= SSL_shutdown(c
->ssl
);
792 SSL_set_shutdown(c
->ssl
, SSL_SENT_SHUTDOWN
| SSL_RECEIVED_SHUTDOWN
);
804 stuff_string(char* buf
, int* len
, int size
, const char* add
)
806 int newlen
= (int) strlen(add
);
807 if ((*len
+ newlen
) >= size
)
808 newlen
= size
- *len
- 1;
811 strncpy(buf
+ *len
, add
, newlen
);
816 /**********************************************
817 * API functions exported to the user client. *
818 **********************************************/
823 extern int TCLinkDefaultValidate(int, void*);
825 TCLinkCon
* c
= (TCLinkCon
*)malloc(sizeof(TCLinkCon
));
836 c
->send_param_list
= NULL
;
837 c
->send_param_tail
= NULL
;
838 c
->recv_param_list
= NULL
;
845 c
->validate_cert
= TCLinkDefaultValidate
;
846 c
->full_ssl_close
= 1;
848 return (TCLinkHandle
)c
;
852 TCLinkSetFullClose(TCLinkHandle handle
, int full_ssl_close
)
854 TCLinkCon
* c
= (TCLinkCon
*)handle
;
855 int swap
= c
->full_ssl_close
;
856 c
->full_ssl_close
= full_ssl_close
? 1 : 0;
861 TCLinkSetValidateCallback(TCLinkHandle handle
, int (*validate_cert
)(int, void*))
863 TCLinkCon
* c
= (TCLinkCon
*)handle
;
864 if (validate_cert
== NULL
) {
865 extern int TCLinkDefaultValidate(int, void*);
866 c
->validate_cert
= TCLinkDefaultValidate
;
868 c
->validate_cert
= validate_cert
;
872 TCLinkPushParam(TCLinkHandle handle
, const char* name
, const char* value
)
877 TCLinkCon
* c
= (TCLinkCon
*)handle
;
880 p
= (param
*)malloc(sizeof(param
));
881 p
->name
= strdup(name
);
882 p
->value
= strdup(value
);
884 if (c
->send_param_tail
)
885 c
->send_param_tail
->next
= p
;
887 c
->send_param_list
= p
;
888 c
->send_param_tail
= p
;
890 /* remove newlines and equals signs from the parameter name */
891 for (ch
= p
->name
; *ch
; ch
++)
892 if (*ch
== '=' || *ch
== '\n')
895 /* remove newlines from the value */
896 for (ch
= p
->value
; *ch
; ch
++)
903 TCLinkSend(TCLinkHandle handle
)
906 char buf
[TC_BUFF_MAX
], destbuf
[TC_LINE_MAX
];
907 const int BUF2_LEN
= 2048;
913 TCLinkCon
* c
= (TCLinkCon
*)handle
;
917 /* build most of the string we will send to the processor */
918 sprintf(buf
, "BEGIN\nversion=%s\n", tclink_version
);
920 for (p
= c
->send_param_list
; p
; p
= next
) {
922 full
= full
|| SAFE_COPY(buf2
, p
->name
);
923 full
= full
|| SAFE_APPEND(buf2
, "=");
924 full
= full
|| SAFE_APPEND(buf2
, p
->value
);
925 full
= full
|| SAFE_APPEND(buf2
, "\n");
926 full
= full
|| SAFE_APPEND(buf
, buf2
);
927 if (!full
&& !strcasecmp(p
->name
, "custid")) {
929 host_hash
= atoi(p
->value
);
930 host_hash
= (host_hash
/ 100) + (host_hash
% 100);
938 c
->send_param_list
= c
->send_param_tail
= NULL
;
940 /* try to make the connection */
941 if (!full
&& !Connect(c
, host_hash
)) {
942 Close(c
); /* clean up any memory Connect() may have left lying around */
943 AddRecvParam(c
, "status", "error");
944 AddRecvParam(c
, "errortype", "cantconnect");
949 /* append some data about the connection */
951 buf2
, BUF2_LEN
, "pass=%d\ntime=%ld\n", c
->pass
, time(0) - c
->start_time
);
952 full
= full
|| SAFE_APPEND(buf
, buf2
);
954 SAFE_APPEND(buf
, "dns=n\n");
955 full
= full
|| SAFE_APPEND(buf
, "END\n");
960 AddRecvParam(c
, "status", "baddata");
961 AddRecvParam(c
, "error", "badlength");
962 AddRecvParam(c
, "offenders", "request");
969 buf
[0] = destbuf
[0] = 0; /* recycle buf */
972 int len
= ReadLine(c
, buf
, destbuf
);
977 if (strcasecmp(destbuf
, "BEGIN") == 0) {
983 } else if (strcasecmp(destbuf
, "END") == 0) {
984 state
= (state
!= 1) ? -1 : 2;
987 if (state
!= 1 || !AddRecvString(c
, destbuf
)) {
1001 AddRecvParam(c
, "status", "error");
1002 AddRecvParam(c
, "errortype", "linkfailure");
1007 TCLinkGetResponse(TCLinkHandle handle
, const char* name
, char* value
)
1010 TCLinkCon
* c
= (TCLinkCon
*)handle
;
1012 for (p
= c
->recv_param_list
; p
; p
= p
->next
)
1013 if (strcasecmp(name
, p
->name
) == 0) {
1014 safe_copy(value
, p
->value
, PARAM_MAX_LEN
);
1022 TCLinkGetEntireResponse(TCLinkHandle handle
, char* buf
, int size
)
1026 TCLinkCon
* c
= (TCLinkCon
*)handle
;
1028 for (p
= c
->recv_param_list
; p
; p
= p
->next
) {
1029 stuff_string(buf
, &len
, size
, p
->name
);
1030 stuff_string(buf
, &len
, size
, "=");
1031 stuff_string(buf
, &len
, size
, p
->value
);
1032 stuff_string(buf
, &len
, size
, "\n");
1039 TCLinkDestroy(TCLinkHandle handle
)
1041 TCLinkCon
* c
= (TCLinkCon
*)handle
;
1058 SSL_CTX_free(c
->ctx
);
1066 TCLinkGetVersion(char* buf
)
1068 strcpy(buf
, tclink_version
);