summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <>2010-07-30 21:41:50 +0000
committererdgeist <>2010-07-30 21:41:50 +0000
commit6dac4efa6181e2696ea112c3f1826f529160ceef (patch)
tree0f081ca75b0f35d727314c78c4b0f33fdf93af25
parenta4b65f17eb73100a3fd4ec1f4de7cee56aa5131b (diff)
Can do v6 and reconnect.
-rwxr-xr-xsample-count.fmt4
-rwxr-xr-xsample-devlog.fmt4
-rwxr-xr-xsample-erdgeist.fmt4
-rwxr-xr-xsample-mAsq.fmt4
-rwxr-xr-xsample-oldstyle.fmt2
-rwxr-xr-xsample-xzivi.fmt4
-rwxr-xr-xvchat-client.c64
-rwxr-xr-xvchat-commands.c3
-rwxr-xr-xvchat-config.h8
-rwxr-xr-xvchat-protocol.c193
-rwxr-xr-xvchat-ssl.c112
-rwxr-xr-xvchat-ssl.h3
-rwxr-xr-xvchat.h2
13 files changed, 186 insertions, 221 deletions
diff --git a/sample-count.fmt b/sample-count.fmt
index d008991..bab9751 100755
--- a/sample-count.fmt
+++ b/sample-count.fmt
@@ -42,8 +42,8 @@ FS_IDLE = "^8%s"
42FS_TIME = "^5[%H:%M]-- ^0" 42FS_TIME = "^5[%H:%M]-- ^0"
43FS_TOPICW = "[ Channel %d: %s" 43FS_TOPICW = "[ Channel %d: %s"
44FS_NOTOPICW = "[ Channel %d has no topic" 44FS_NOTOPICW = "[ Channel %d has no topic"
45FS_CONSOLE = "%s@%s:%d, use .h to get help" 45FS_CONSOLE = "%s@%s:%s, use .h to get help"
46FS_CONNECTED = "^2# Connected to '^6%s^2', port ^6%d^2 ..." 46FS_CONNECTED = "^2# Connected to '^6%s^2', port ^6%s^2 ..."
47FS_TOPIC = "^2# Channel ^6%d^2 topic is: '^0%s^2'" 47FS_TOPIC = "^2# Channel ^6%d^2 topic is: '^0%s^2'"
48FS_NOTOPIC = "^2# Channel ^6%d^2 has no topic" 48FS_NOTOPIC = "^2# Channel ^6%d^2 has no topic"
49FS_CHGTOPIC = "^2# ^6%s^2 changes topic to: '^0%s^2'" 49FS_CHGTOPIC = "^2# ^6%s^2 changes topic to: '^0%s^2'"
diff --git a/sample-devlog.fmt b/sample-devlog.fmt
index e70364d..ac30551 100755
--- a/sample-devlog.fmt
+++ b/sample-devlog.fmt
@@ -47,8 +47,8 @@ FS_IDLE = "^8%s"
47FS_TIME = "^2[%H:%M]^0 " 47FS_TIME = "^2[%H:%M]^0 "
48FS_TOPICW = "[ Channel %d: %s" 48FS_TOPICW = "[ Channel %d: %s"
49FS_NOTOPICW = "[ Channel %d has no topic" 49FS_NOTOPICW = "[ Channel %d has no topic"
50FS_CONSOLE = "%s@%s:%d, use .h to get help" 50FS_CONSOLE = "%s@%s:%s, use .h to get help"
51FS_CONNECTED = "^2# Connected to '^0%s^2', port ^0%d^2 ..." 51FS_CONNECTED = "^2# Connected to '^0%s^2', port ^0%s^2 ..."
52FS_TOPIC = "^1# Channel ^6%d^2 topic is: '^0%s^2'" 52FS_TOPIC = "^1# Channel ^6%d^2 topic is: '^0%s^2'"
53FS_NOTOPIC = "^1# Channel ^6%d^2 has no topic" 53FS_NOTOPIC = "^1# Channel ^6%d^2 has no topic"
54FS_CHGTOPIC = "^1# ^4%s^1 changes topic to: '^0%s^1'" 54FS_CHGTOPIC = "^1# ^4%s^1 changes topic to: '^0%s^1'"
diff --git a/sample-erdgeist.fmt b/sample-erdgeist.fmt
index 5fc87e1..7545d3d 100755
--- a/sample-erdgeist.fmt
+++ b/sample-erdgeist.fmt
@@ -42,8 +42,8 @@ FS_TIME = "^9[%H:%M]^0 "
42FS_CONSOLETIME = "[%H:%M] " 42FS_CONSOLETIME = "[%H:%M] "
43FS_TOPICW = "[ Channel %d: %s" 43FS_TOPICW = "[ Channel %d: %s"
44FS_NOTOPICW = "[ Channel %d has no topic" 44FS_NOTOPICW = "[ Channel %d has no topic"
45FS_CONSOLE = "%s@%s:%d, use .h to get help" 45FS_CONSOLE = "%s@%s:%s, use .h to get help"
46FS_CONNECTED = "^2# Connected to '^0%s^2', port ^0%d^2 ..." 46FS_CONNECTED = "^2# Connected to '^0%s^2', port ^0%s^2 ..."
47FS_TOPIC = "^1# Channel ^6%d^2 topic is: '^0%s^2'" 47FS_TOPIC = "^1# Channel ^6%d^2 topic is: '^0%s^2'"
48FS_NOTOPIC = "^1# Channel ^6%d^2 has no topic" 48FS_NOTOPIC = "^1# Channel ^6%d^2 has no topic"
49FS_CHGTOPIC = "^1# ^4%s^1 changes topic to: '^0%s^1'" 49FS_CHGTOPIC = "^1# ^4%s^1 changes topic to: '^0%s^1'"
diff --git a/sample-mAsq.fmt b/sample-mAsq.fmt
index 9bed139..af001d7 100755
--- a/sample-mAsq.fmt
+++ b/sample-mAsq.fmt
@@ -42,8 +42,8 @@ FS_IDLE = "^8%s"
42FS_TIME = "^5%H:%M^0 " 42FS_TIME = "^5%H:%M^0 "
43FS_TOPICW = "[ Channel %d: %s" 43FS_TOPICW = "[ Channel %d: %s"
44FS_NOTOPICW = "[ Channel %d has no topic" 44FS_NOTOPICW = "[ Channel %d has no topic"
45FS_CONSOLE = "%s@%s:%d, use .h to get help" 45FS_CONSOLE = "%s@%s:%s, use .h to get help"
46FS_CONNECTED = "^2*^0C^2* Connected to '^6%s^2', port ^6%d^2 ..." 46FS_CONNECTED = "^2*^0C^2* Connected to '^6%s^2', port ^6%s^2 ..."
47FS_TOPIC = "^2*^0T^2* Channel ^6%d^2 topic is: '^0%s^2'" 47FS_TOPIC = "^2*^0T^2* Channel ^6%d^2 topic is: '^0%s^2'"
48FS_NOTOPIC = "^2*^0T^2* Channel ^6%d^2 has no topic" 48FS_NOTOPIC = "^2*^0T^2* Channel ^6%d^2 has no topic"
49FS_CHGTOPIC = "^5*^0T^2* ^6%s^2 changes topic to: '^0%s^2'" 49FS_CHGTOPIC = "^5*^0T^2* ^6%s^2 changes topic to: '^0%s^2'"
diff --git a/sample-oldstyle.fmt b/sample-oldstyle.fmt
index a1b0eb5..d0d8f17 100755
--- a/sample-oldstyle.fmt
+++ b/sample-oldstyle.fmt
@@ -43,7 +43,7 @@ FS_TIME = "^0%H:%M "
43FS_TOPICW = "Channel %d: %s" 43FS_TOPICW = "Channel %d: %s"
44FS_NOTOPICW = "Channel %d has no topic" 44FS_NOTOPICW = "Channel %d has no topic"
45FS_CONSOLE = "-=- VChat V0.1 -=- type .h for help -=-" 45FS_CONSOLE = "-=- VChat V0.1 -=- type .h for help -=-"
46FS_CONNECTED = "^0* Connected to '%s', port %d ..." 46FS_CONNECTED = "^0* Connected to '%s', port %s ..."
47FS_TOPIC = "^0* Channel %d topic is: '%s'" 47FS_TOPIC = "^0* Channel %d topic is: '%s'"
48FS_NOTOPIC = "^0* Channel %d has no topic" 48FS_NOTOPIC = "^0* Channel %d has no topic"
49FS_CHGTOPIC = "^0* %s changed the channel topic to '%s'" 49FS_CHGTOPIC = "^0* %s changed the channel topic to '%s'"
diff --git a/sample-xzivi.fmt b/sample-xzivi.fmt
index f839366..dbbf2b4 100755
--- a/sample-xzivi.fmt
+++ b/sample-xzivi.fmt
@@ -41,8 +41,8 @@ FS_IDLE = "^1^b%s^B"
41FS_TIME = "^4[%H:%M]^0 " 41FS_TIME = "^4[%H:%M]^0 "
42FS_TOPICW = "Channel %d: %s" 42FS_TOPICW = "Channel %d: %s"
43FS_NOTOPICW = "Channel %d has no topic" 43FS_NOTOPICW = "Channel %d has no topic"
44FS_CONSOLE = "%s@%s:%d" 44FS_CONSOLE = "%s@%s:%s"
45FS_CONNECTED = "# Connected to %s:%d ..." 45FS_CONNECTED = "# Connected to %s:%s ..."
46FS_TOPIC = "# Channel %d topic is: ^6%s" 46FS_TOPIC = "# Channel %d topic is: ^6%s"
47FS_NOTOPIC = "# Channel %d has no topic" 47FS_NOTOPIC = "# Channel %d has no topic"
48FS_CHGTOPIC = "# ^b%s^B changes topic to: ^6%s" 48FS_CHGTOPIC = "# ^b%s^B changes topic to: ^6%s"
diff --git a/vchat-client.c b/vchat-client.c
index c80e374..b7f993c 100755
--- a/vchat-client.c
+++ b/vchat-client.c
@@ -44,6 +44,8 @@ int status = 1;
44int ownquit = 0; 44int ownquit = 0;
45/* we set this, we DONT want to quit */ 45/* we set this, we DONT want to quit */
46int wantreconnect = 0; 46int wantreconnect = 0;
47static int reconnect_delay = 6;
48static time_t reconnect_time = 0;
47 49
48/* error string to show after exit */ 50/* error string to show after exit */
49char errstr[ERRSTRSIZE] = "\0"; 51char errstr[ERRSTRSIZE] = "\0";
@@ -65,7 +67,7 @@ static void parsecfg(char *line) {
65 char *param=line; 67 char *param=line;
66 char *value=NULL; 68 char *value=NULL;
67 69
68 /* handle quotes value is empty, so wecan use it */ 70 /* handle quotes value is empty, so we can use it */
69 value = strchr(line,'#'); 71 value = strchr(line,'#');
70 if (value) { /* the line contains a cute little quote */ 72 if (value) { /* the line contains a cute little quote */
71 value[0]='\0'; /* ignore the rest of the line */ 73 value[0]='\0'; /* ignore the rest of the line */
@@ -414,7 +416,8 @@ void calleverysecond( void ) {
414 quitrequest--; 416 quitrequest--;
415 if(outputcountdown && !--outputcountdown) 417 if(outputcountdown && !--outputcountdown)
416 hideout( ); 418 hideout( );
417 419 if( reconnect_time && ( time( NULL ) > reconnect_time ) )
420 status = 0;
418} 421}
419 422
420/* this function is called in the master loop */ 423/* this function is called in the master loop */
@@ -425,33 +428,33 @@ eventloop (void)
425 fd_set readfds = masterfds; 428 fd_set readfds = masterfds;
426 struct timeval tv = { 1, 0}; 429 struct timeval tv = { 1, 0};
427 430
428 switch (select (serverfd + 1, &readfds, NULL, NULL, &tv)) 431 switch (select (serverfd + 2, &readfds, NULL, NULL, &tv))
429 { 432 {
430 case -1: 433 case -1:
431 /* EINTR is most likely a SIGWINCH - ignore for now */ 434 /* EINTR is most likely a SIGWINCH - ignore for now */
432 if (errno != EINTR) 435 if (errno != EINTR)
433 { 436 {
434 snprintf (tmpstr, TMPSTRSIZE, "Select fails, %s.", strerror(errno)); 437 snprintf (tmpstr, TMPSTRSIZE, "Select fails, %s.", strerror(errno));
435 strncpy(errstr,tmpstr,TMPSTRSIZE-2); 438 strncpy(errstr,tmpstr,TMPSTRSIZE-2);
436 errstr[TMPSTRSIZE-2] = '\0'; 439 errstr[TMPSTRSIZE-2] = '\0';
437 strcat(errstr,"\n"); 440 strcat(errstr,"\n");
438 writecf (FS_ERR,tmpstr); 441 writecf (FS_ERR,tmpstr);
439 /* see this as an error condition and bail out */ 442 /* see this as an error condition and bail out */
440 status = 0; 443 status = 0;
441 } 444 }
442 break; 445 break;
443 case 0: 446 case 0:
444 /* time out reached */ 447 /* time out reached */
445 calleverysecond(); 448 calleverysecond();
446 break; 449 break;
447 default: 450 default:
448 /* something to read from user & we're logged in or have a cert? */ 451 /* something to read from user & we're logged in or have a cert? */
449 if (FD_ISSET (0, &readfds) && loggedin) 452 if (FD_ISSET (0, &readfds) )
450 userinput (); 453 userinput ();
451 454
452 /* something to read from server? */ 455 /* something to read from server? */
453 if (FD_ISSET (serverfd, &readfds)) 456 if (serverfd!=-1 && FD_ISSET (serverfd, &readfds))
454 networkinput (); 457 networkinput ();
455 break; 458 break;
456 } 459 }
457} 460}
@@ -495,7 +498,7 @@ main (int argc, char **argv)
495#endif 498#endif
496 499
497 switch (pchar) { 500 switch (pchar) {
498 case -1 : cmdsunparsed = 0; break; 501 case -1 : cmdsunparsed = 0; break;
499 case 'C': loadconfig(optarg); break; 502 case 'C': loadconfig(optarg); break;
500 case 'F': setstroption(CF_FORMFILE,optarg); break; 503 case 'F': setstroption(CF_FORMFILE,optarg); break;
501 case 'l': setintoption(CF_USESSL,0); break; 504 case 'l': setintoption(CF_USESSL,0); break;
@@ -528,21 +531,30 @@ main (int argc, char **argv)
528 initui (); 531 initui ();
529 532
530 while( status ) { 533 while( status ) {
534 /* add stdin to masterfds */
535 FD_ZERO (&masterfds);
536 FD_SET (0, &masterfds);
537
531 /* attempt connection */ 538 /* attempt connection */
532 if (!vcconnect (getstroption(CF_SERVERHOST), getstroption(CF_SERVERPORT))) { 539 if (vcconnect (getstroption(CF_SERVERHOST), getstroption(CF_SERVERPORT))) {
533 snprintf (tmpstr, TMPSTRSIZE, "Could not connect to server, %s.", 540 snprintf (tmpstr, TMPSTRSIZE, "Could not connect to server, %s.", strerror(errno));
534 strerror(errno)); 541 strncpy(errstr,tmpstr,TMPSTRSIZE-2);
535 strncpy(errstr,tmpstr,TMPSTRSIZE-2); 542 errstr[TMPSTRSIZE-2] = '\0';
536 errstr[TMPSTRSIZE-2] = '\0'; 543 strcat(errstr,"\n");
537 strcat(errstr,"\n"); 544 writecf (FS_ERR,tmpstr);
538 writecf (FS_ERR,tmpstr); 545
539 /* exit condition */ 546 if( getintoption( CF_AUTORECONN ) ) {
540 status = 0; 547 snprintf (tmpstr, TMPSTRSIZE, "reconnecting in %d seconds", reconnect_delay );
548 writecf (FS_ERR, tmpstr);
549 reconnect_delay = ( reconnect_delay * 15 ) / 10;
550 reconnect_time = time( NULL ) + reconnect_delay;
551 } else
552 status = 0;
541 } else { 553 } else {
542 /* add stdin & server to masterdfs */ 554 /* add serverfd to masterfds, reset reconnect delay */
543 FD_ZERO (&masterfds);
544 FD_SET (0, &masterfds);
545 FD_SET (serverfd, &masterfds); 555 FD_SET (serverfd, &masterfds);
556 reconnect_delay = 6;
557 reconnect_time = 0;
546 } 558 }
547 559
548 while (status) 560 while (status)
diff --git a/vchat-commands.c b/vchat-commands.c
index 651878c..0c8ca26 100755
--- a/vchat-commands.c
+++ b/vchat-commands.c
@@ -393,12 +393,13 @@ command_quit(char *tail)
393 /* send users message to server */ 393 /* send users message to server */
394 snprintf (tmpstr, TMPSTRSIZE, ".x %s", tail); 394 snprintf (tmpstr, TMPSTRSIZE, ".x %s", tail);
395 networkoutput (tmpstr); 395 networkoutput (tmpstr);
396 396
397 /* show action in channel window */ 397 /* show action in channel window */
398 writechan (tmpstr); 398 writechan (tmpstr);
399 399
400 /* Inform vchat-client, that the closing connection 400 /* Inform vchat-client, that the closing connection
401 following is intended */ 401 following is intended */
402 status = 0;
402 ownquit = 1; 403 ownquit = 1;
403} 404}
404 405
diff --git a/vchat-config.h b/vchat-config.h
index 34866b1..3511c68 100755
--- a/vchat-config.h
+++ b/vchat-config.h
@@ -23,7 +23,6 @@
23#endif 23#endif
24 24
25/* configuration array with structure as defined in vchat.h */ 25/* configuration array with structure as defined in vchat.h */
26extern unsigned int usessl;
27extern unsigned int ignssl; 26extern unsigned int ignssl;
28extern unsigned int usetime; 27extern unsigned int usetime;
29extern unsigned int hscroll; 28extern unsigned int hscroll;
@@ -41,7 +40,7 @@ static volatile configoption configoptions[] = {
41 {CF_FORMFILE, CO_STR, "formatfile", "~/.vchat/formats", NULL, { NULL } }, 40 {CF_FORMFILE, CO_STR, "formatfile", "~/.vchat/formats", NULL, { NULL } },
42 {CF_LOGINSCRIPT, CO_STR, "loginscript","~/.vchat/loginscript", NULL, { NULL } }, 41 {CF_LOGINSCRIPT, CO_STR, "loginscript","~/.vchat/loginscript", NULL, { NULL } },
43 {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }}, 42 {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }},
44 {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { .pint = &usessl } }, 43 {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { NULL } },
45 {CF_IGNSSL, CO_INT, "ignssl", (char *) 0, (char *)-1, { .pint = &ignssl } }, 44 {CF_IGNSSL, CO_INT, "ignssl", (char *) 0, (char *)-1, { .pint = &ignssl } },
46 {CF_USECERT, CO_INT, "usecert", (char *) 1, (char *)-1, { NULL } }, 45 {CF_USECERT, CO_INT, "usecert", (char *) 1, (char *)-1, { NULL } },
47 {CF_USETIME, CO_INT, "usetime", (char *) 1, (char *)-1, { .pint = &usetime } }, 46 {CF_USETIME, CO_INT, "usetime", (char *) 1, (char *)-1, { .pint = &usetime } },
@@ -100,8 +99,9 @@ static formatstring formatstrings[] = {
100 FE( FS_CONSOLETIME, "[%H:%M] "), 99 FE( FS_CONSOLETIME, "[%H:%M] "),
101 FE( FS_TOPICW, "[ Channel %d: %s"), 100 FE( FS_TOPICW, "[ Channel %d: %s"),
102 FE( FS_NOTOPICW, "[ Channel %d has no topic"), 101 FE( FS_NOTOPICW, "[ Channel %d has no topic"),
103 FE( FS_CONSOLE, "%s@%s:%d, use .h to get help "), 102 FE( FS_CONSOLE, "%s@%s:%s, use .h to get help "),
104 FE( FS_CONNECTED, "\0012# Connected to '\0016%s\0012', port \0016%d\0012 ..."), 103 FE( FS_CONNECTED, "\0012# Connected to '\0016%s\0012', port \0016%s\0012 ..."),
104 FE( FS_CANTCONNECT, "\0012# Can not connect to '\0016%s\0012', port \0016%s\0012 ..."),
105 FE( FS_TOPIC, "\0012# Channel \0016%d\0012 topic is: '\0010%s\0012'"), 105 FE( FS_TOPIC, "\0012# Channel \0016%d\0012 topic is: '\0010%s\0012'"),
106 FE( FS_NOTOPIC, "\0012# Channel \0016%d\0012 has no topic"), 106 FE( FS_NOTOPIC, "\0012# Channel \0016%d\0012 has no topic"),
107 FE( FS_CHGTOPIC, "\0012# \0016%s\0012 changes topic to: '\0010%s\0012'"), 107 FE( FS_CHGTOPIC, "\0012# \0016%s\0012 changes topic to: '\0010%s\0012'"),
diff --git a/vchat-protocol.c b/vchat-protocol.c
index aefe419..700f6c7 100755
--- a/vchat-protocol.c
+++ b/vchat-protocol.c
@@ -40,18 +40,17 @@ char *vchat_io_version = "$Id$";
40 40
41/* externally used variables */ 41/* externally used variables */
42int serverfd = -1; 42int serverfd = -1;
43unsigned int usingcert = 1;
44 43
45/* locally global variables */ 44/* locally global variables */
46/* SSL-connection */ 45/* our connection BIO */
47static BIO *sslconn = NULL; 46static BIO *server_conn = NULL;
48 47
49/* declaration of local helper functions */ 48/* declaration of local helper functions */
50static void usersignon (char *); 49static void usersignon (char *);
51static void usersignoff (char *); 50static void usersignoff (char *);
52static void usernickchange (char *); 51static void usernickchange (char *);
53static void userjoin (char *); 52static void userjoin (char *);
54static void userleave (char *); 53static void userleave (char *);
55static void receivenicks (char *message); 54static void receivenicks (char *message);
56static void justloggedin (char *message); 55static void justloggedin (char *message);
57static void nickerr (char *message); 56static void nickerr (char *message);
@@ -64,7 +63,6 @@ static void serverlogin (char *message);
64static void idleprompt (char *message); 63static void idleprompt (char *message);
65static void topicchange (char *message); 64static void topicchange (char *message);
66static void pmnotsent (char *message); 65static void pmnotsent (char *message);
67static int getportnum (char *port);
68 66
69/* declaration of server message array */ 67/* declaration of server message array */
70#include "vchat-messages.h" 68#include "vchat-messages.h"
@@ -72,116 +70,129 @@ static int getportnum (char *port);
72/* status-variable from vchat-client.c 70/* status-variable from vchat-client.c
73 * eventloop is done as long as this is true */ 71 * eventloop is done as long as this is true */
74extern int status; 72extern int status;
75
76int usessl = 1;
77int ignssl = 0; 73int ignssl = 0;
78char *encoding; 74char *encoding;
79 75
76static int connect_socket( char *server, char *port ) {
77 struct addrinfo hints, *res, *res0;
78 int s, error;
79
80 memset(&hints, 0, sizeof(hints));
81 hints.ai_family = PF_UNSPEC;
82 hints.ai_socktype = SOCK_STREAM;
83 error = getaddrinfo( server, port, &hints, &res0 );
84 if (error) return -1;
85 s = -1;
86 for (res = res0; res; res = res->ai_next) {
87 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
88 if (s < 0) continue;
89 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
90 close(s);
91 s = -1;
92 continue;
93 }
94 break; /* okay we got one */
95 }
96 freeaddrinfo(res0);
97 return s;
98}
99
80/* connects to server */ 100/* connects to server */
81int 101int
82vcconnect (char *server, char *port) 102vcconnect (char *server, char *port)
83{ 103{
84 /* used for tilde expansion of cert & key filenames */ 104 /* used for tilde expansion of cert & key filenames */
85 char *tildex = NULL; 105 char *tildex = NULL;
86
87 /* vchat connection x509 store */
88 vc_x509store_t vc_store;
89 106
90 /* SSL-context */ 107 /* vchat connection x509 store */
91 SSL_CTX *sslctx = NULL; 108 vc_x509store_t vc_store;
92 109
93 /* pointer to tilde-expanded certificate/keyfile-names */ 110 /* SSL-context */
94 char *certfile = NULL, *keyfile = NULL; 111 SSL_CTX *sslctx = NULL;
95 112
96 SSL_library_init (); 113 /* pointer to tilde-expanded certificate/keyfile-names */
97 SSL_load_error_strings(); 114 char *certfile = NULL, *keyfile = NULL;
98 115
99 vc_init_x509store(&vc_store); 116 /* Connect to the server */
117 serverfd = connect_socket( server, port );
118 if( serverfd < 0 ) {
119 /* inform user */
120 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port );
121 writechan (tmpstr);
122 return -1;
123 }
124 /* Abstract server IO in openssls BIO */
125 server_conn = BIO_new_socket( serverfd, 1 );
126
127 /* If SSL is requested, get our ssl-BIO running */
128 if( server_conn && getintoption(CF_USESSL) ) {
129 static int sslinit;
130 if( !sslinit++ ) {
131 SSL_library_init ();
132 SSL_load_error_strings();
133 }
100 134
101 vc_x509store_setflags(&vc_store, VC_X509S_SSL_VERIFY_PEER); 135 vc_init_x509store(&vc_store);
102 /* get name of certificate file */ 136 vc_x509store_setflags(&vc_store, VC_X509S_SSL_VERIFY_PEER);
103 certfile = getstroption (CF_CERTFILE);
104 137
105 /* do we have a certificate file? */ 138 /* get name of certificate file */
106 if (certfile) { 139 certfile = getstroption (CF_CERTFILE);
140 /* do we have a certificate file? */
141 if (certfile) {
107 /* does the filename start with a tilde? expand it! */ 142 /* does the filename start with a tilde? expand it! */
108 if (certfile[0] == '~') 143 if (certfile[0] == '~')
109 tildex = tilde_expand (certfile); 144 tildex = tilde_expand (certfile);
110 else 145 else
111 tildex = certfile; 146 tildex = certfile;
112
113 if (usingcert) {
114
115 vc_x509store_setflags(&vc_store, VC_X509S_USE_CERTIFICATE);
116 vc_x509store_setcertfile(&vc_store, tildex);
117 147
118 /* get name of key file */ 148 vc_x509store_setflags(&vc_store, VC_X509S_USE_CERTIFICATE);
119 keyfile = getstroption (CF_KEYFILE); 149 vc_x509store_setcertfile(&vc_store, tildex);
120 150
121 /* if we don't have a key file, the key may be in the cert file */ 151 /* get name of key file */
122 if (!keyfile) 152 keyfile = getstroption (CF_KEYFILE);
123 keyfile = certfile;
124 153
125 /* does the filename start with a tilde? expand it! */ 154 /* if we don't have a key file, the key may be in the cert file */
126 if (keyfile[0] == '~') 155 if (!keyfile)
127 tildex = tilde_expand (keyfile); 156 keyfile = certfile;
128 else
129 tildex = keyfile;
130
131 vc_x509store_set_pkeycb(&vc_store, (vc_askpass_cb_t)passprompt);
132 vc_x509store_setkeyfile(&vc_store, tildex);
133
134 /* check if OpenSSL thinks key & cert belong together */
135 /* result = SSL_CTX_check_private_key (sslctx); THS TODO (->
136 * vchat-ssl.c) */
137 }
138 }
139
140 usessl = getintoption(CF_USESSL);
141 vc_x509store_setignssl(&vc_store, getintoption(CF_IGNSSL));
142 157
143 sslconn = vc_connect(server, getportnum(port), usessl, &vc_store, &sslctx); 158 /* does the filename start with a tilde? expand it! */
159 if (keyfile[0] == '~')
160 tildex = tilde_expand (keyfile);
161 else
162 tildex = keyfile;
144 163
145 if(sslconn == NULL) { 164 vc_x509store_set_pkeycb(&vc_store, (vc_askpass_cb_t)passprompt);
146 exitui(); 165 vc_x509store_setkeyfile(&vc_store, tildex);
147 exit(-1); 166 }
148 } 167 vc_x509store_setignssl(&vc_store, getintoption(CF_IGNSSL));
149 168
150 serverfd = BIO_get_fd(sslconn, 0); 169 /* upgrade our plain BIO to ssl */
170 if( vc_connect_ssl( &server_conn, &vc_store, &sslctx ) )
171 BIO_free_all( server_conn );
172 }
151 173
152 /* inform user */ 174 if( !server_conn ) {
153 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CONNECTED), server, getportnum(port)); 175 /* inform user */
154 writechan (tmpstr); 176 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port );
177 writechan (tmpstr);
178 return -1;
179 }
155 180
156 /* dump x509 details here... TODO */ 181 /* inform user */
157 writecf (FS_DBG,"# SSL Server information: TODO :)"); 182 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CONNECTED), server, port);
183 writechan (tmpstr);
158 184
159 /* if we didn't fail until now, we've got a connection. */ 185 /* if we didn't fail until now, we've got a connection. */
160 return 1; 186 return 0;
161} 187}
162 188
163/* disconnect from server */ 189/* disconnect from server */
164void 190void
165vcdisconnect () 191vcdisconnect () {
166{ 192 BIO_free_all( server_conn );
167 close (serverfd);
168 serverfd = -1; 193 serverfd = -1;
169} 194}
170 195
171/* lookup a port number by service string */
172static int getportnum (char *port)
173{
174 char *endpt = NULL;
175 struct servent *service = getservbyname(port, "tcp");
176 int dport = strtoul( port, &endpt, 10);
177
178 if( service )
179 return htons( service->s_port );
180 if( (*endpt == 0) && ((char *)port != endpt) )
181 return dport;
182 return -1;
183}
184
185/* handle a pm not sent error 196/* handle a pm not sent error
186 * format: 412 %s */ 197 * format: 412 %s */
187static void 198static void
@@ -358,7 +369,7 @@ justloggedin (char *message)
358 setstroption(CF_NICK,str1); 369 setstroption(CF_NICK,str1);
359 370
360 /* show change in console window */ 371 /* show change in console window */
361 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), nick, getstroption (CF_SERVERHOST), getportnum(getstroption (CF_SERVERPORT))); 372 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), nick, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT));
362 consoleline (NULL); 373 consoleline (NULL);
363 374
364 /* announce login as servermessage */ 375 /* announce login as servermessage */
@@ -401,7 +412,7 @@ ownnickchange (char *newnick)
401 setstroption(CF_NICK,newnick); 412 setstroption(CF_NICK,newnick);
402 413
403 /* show change in console window */ 414 /* show change in console window */
404 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), nick, getstroption (CF_SERVERHOST), getportnum(getstroption (CF_SERVERPORT))); 415 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), nick, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT));
405 consoleline (NULL); 416 consoleline (NULL);
406} 417}
407 418
@@ -533,7 +544,7 @@ receivenicks (char *message)
533 str2 = strchr (str1, ' '); 544 str2 = strchr (str1, ' ');
534 /* there is another user? terminate this one */ 545 /* there is another user? terminate this one */
535 if (str2) { 546 if (str2) {
536 str2[0] = '\0'; 547 str2[0] = '\0';
537 str2++; 548 str2++;
538 } 549 }
539 550
@@ -826,7 +837,7 @@ networkinput (void)
826 buf[BUFSIZE-1] = '\0'; /* sanity stop */ 837 buf[BUFSIZE-1] = '\0'; /* sanity stop */
827 838
828 /* receive data at offset */ 839 /* receive data at offset */
829 bytes = BIO_read (sslconn, &buf[bufoff], BUFSIZE-1 - bufoff); 840 bytes = BIO_read (server_conn, &buf[bufoff], BUFSIZE-1 - bufoff);
830 841
831 /* no bytes transferred? raise error message, bail out */ 842 /* no bytes transferred? raise error message, bail out */
832 if (bytes < 0) 843 if (bytes < 0)
@@ -875,8 +886,8 @@ networkinput (void)
875 } 886 }
876 887
877 /* move line along .. */ 888 /* move line along .. */
878 ltmp = tmp; 889 ltmp = tmp;
879 } 890 }
880 /* buffer exhausted, move partial line to start of buffer and go on .. */ 891 /* buffer exhausted, move partial line to start of buffer and go on .. */
881 bufoff = (bytes+bufoff) - (ltmp-buf); 892 bufoff = (bytes+bufoff) - (ltmp-buf);
882 if (bufoff > 0) 893 if (bufoff > 0)
@@ -895,10 +906,10 @@ networkoutput (char *msg)
895#endif 906#endif
896 907
897 /* send data to server */ 908 /* send data to server */
898 if (BIO_write (sslconn, msg, strlen (msg)) != strlen (msg)) 909 if (BIO_write (server_conn, msg, strlen (msg)) != strlen (msg))
899 writecf (FS_ERR,"Message sending fuzzy."); 910 writecf (FS_ERR,"Message sending fuzzy.");
900 911
901 /* send line termination to server */ 912 /* send line termination to server */
902 if (BIO_write (sslconn, "\r\n", 2) != 2) 913 if (BIO_write (server_conn, "\r\n", 2) != 2)
903 writecf (FS_ERR,"Message sending fuzzy."); 914 writecf (FS_ERR,"Message sending fuzzy.");
904} 915}
diff --git a/vchat-ssl.c b/vchat-ssl.c
index 3c191c2..1a1ff16 100755
--- a/vchat-ssl.c
+++ b/vchat-ssl.c
@@ -11,7 +11,7 @@
11 * without even the implied warranty of merchantability or fitness for a 11 * without even the implied warranty of merchantability or fitness for a
12 * particular purpose. In no event shall the copyright holder be liable for 12 * particular purpose. In no event shall the copyright holder be liable for
13 * any direct, indirect, incidental or special damages arising in any way out 13 * any direct, indirect, incidental or special damages arising in any way out
14 * of the use of this software. 14 * of the use of this software.
15 * 15 *
16 */ 16 */
17 17
@@ -111,31 +111,19 @@ SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store )
111 } else if(vc_store->use_key) 111 } else if(vc_store->use_key)
112 r=SSL_CTX_use_PrivateKey(ctx, vc_store->use_key); 112 r=SSL_CTX_use_PrivateKey(ctx, vc_store->use_key);
113 113
114 if(r!=1) 114 if( r!=1 || !SSL_CTX_check_private_key(ctx))
115 VC_SETCERT_ERR_EXIT(store, ctx, "Load private key failed"); 115 VC_SETCERT_ERR_EXIT(store, ctx, "Load private key failed");
116
117 } 116 }
118 117
119 SSL_CTX_set_app_data(ctx, vc_store); 118 SSL_CTX_set_app_data(ctx, vc_store);
120 return(ctx); 119 return(ctx);
121} 120}
122 121
123#define VC_CONNSSL_ERR_EXIT(_cx, cx, cn) do { \ 122int vc_connect_ssl( BIO **conn, vc_x509store_t *vc_store, SSL_CTX **ctx)
124 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR] %s", \
125 ERR_error_string (ERR_get_error (), NULL)); \
126 writecf(FS_ERR, tmpstr); \
127 if(cn) BIO_free_all(cn); \
128 if(*cx) SSL_CTX_free(*cx); \
129 if(_cx) *cx = 0; \
130 return(0); \
131 } while(0)
132
133BIO * vc_connect_ssl(char *host, int port, vc_x509store_t *vc_store,
134 SSL_CTX **ctx)
135{ 123{
136 BIO *conn = NULL; 124 BIO *ssl_conn = NULL;
137 int _ctx = 0; 125 int _ctx = 0;
138 126
139 if(*ctx) { 127 if(*ctx) {
140 CRYPTO_add( &((*ctx)->references), 1, CRYPTO_LOCK_SSL_CTX ); 128 CRYPTO_add( &((*ctx)->references), 1, CRYPTO_LOCK_SSL_CTX );
141 if( vc_store && vc_store != SSL_CTX_get_app_data(*ctx) ) { 129 if( vc_store && vc_store != SSL_CTX_get_app_data(*ctx) ) {
@@ -147,72 +135,26 @@ BIO * vc_connect_ssl(char *host, int port, vc_x509store_t *vc_store,
147 _ctx = 1; 135 _ctx = 1;
148 } 136 }
149 137
150 if( !(conn = BIO_new_ssl_connect(*ctx)) ) 138 ssl_conn = BIO_new_ssl(*ctx, 1);
151 VC_CONNSSL_ERR_EXIT(_ctx, ctx, conn); 139 if(_ctx)
152 140 SSL_CTX_free(*ctx);
153 BIO_set_conn_hostname(conn, host);
154 BIO_set_conn_int_port(conn, &port);
155 141
156 fflush(stdout); 142 if( ssl_conn ) {
157 if(BIO_do_connect(conn) <= 0) 143 BIO_push( ssl_conn, *conn );
158 VC_CONNSSL_ERR_EXIT(_ctx, ctx, conn); 144 *conn = ssl_conn;
145 fflush(stdout);
146 if( BIO_do_handshake( *conn ) > 0 )
147 return 0;
148 }
159 149
160 if(_ctx) 150 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR] %s", ERR_error_string (ERR_get_error (), NULL));
161 SSL_CTX_free(*ctx); 151 writecf(FS_ERR, tmpstr);
162 152
163 return(conn); 153 return 1;
164}
165
166#define VC_CONN_ERR_EXIT(cn) do { \
167 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR] %s", \
168 ERR_error_string(ERR_get_error(), NULL)); \
169 if(ERR_get_error()) \
170 writecf(FS_ERR, tmpstr); \
171 if(cn) BIO_free_all(cn); \
172 return(NULL); \
173 } while(0)
174
175#define VC_VERIFICATION_ERR_EXIT(cn, err) do { \
176 snprintf(tmpstr, TMPSTRSIZE, \
177 "[SSL ERROR] certificate verify failed: %s", err); \
178 writecf(FS_ERR, tmpstr); \
179 if(cn && !ignore_ssl) { BIO_free_all(cn); return(NULL); } \
180 } while(0)
181
182BIO * vc_connect( char *host, int port, int use_ssl,
183 vc_x509store_t *vc_store, SSL_CTX **ctx)
184{
185 BIO *conn = NULL;
186 SSL *ssl = NULL;
187
188 if(use_ssl) {
189 if( !(conn = vc_connect_ssl(host, port, vc_store, ctx)) )
190 VC_CONN_ERR_EXIT(conn);
191
192
193 BIO_get_ssl(conn, &ssl);
194 if(!vc_verify_cert_hostname(SSL_get_peer_certificate(ssl), host))
195 VC_VERIFICATION_ERR_EXIT(conn, "Hostname does not match!");
196
197 return(conn);
198 }
199
200 *ctx = 0;
201
202 if( !(conn = BIO_new_connect(host)) )
203 VC_CONN_ERR_EXIT(conn);
204
205 BIO_set_conn_int_port(conn, &port);
206
207 if(BIO_do_connect(conn) <= 0)
208 VC_CONN_ERR_EXIT(conn);
209
210 return(conn);
211} 154}
212 155
213int vc_verify_cert_hostname(X509 *cert, char *host) 156int vc_verify_cert_hostname(X509 *cert, char *host)
214{ 157{
215
216 int i = 0; 158 int i = 0;
217 int j = 0; 159 int j = 0;
218 int n = 0; 160 int n = 0;
@@ -231,39 +173,39 @@ int vc_verify_cert_hostname(X509 *cert, char *host)
231 memset(&name, 0, sizeof(name)); 173 memset(&name, 0, sizeof(name));
232 174
233 if((extcount = X509_get_ext_count(cert)) > 0) { 175 if((extcount = X509_get_ext_count(cert)) > 0) {
234 176
235 for(i=0; !ok && i < extcount; i++) { 177 for(i=0; !ok && i < extcount; i++) {
236 178
237 meth = NULL; 179 meth = NULL;
238 180
239 ext = X509_get_ext(cert, i); 181 ext = X509_get_ext(cert, i);
240 extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); 182 extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
241 183
242 if(!strcasecmp(extstr, "subjectAltName")) { 184 if(!strcasecmp(extstr, "subjectAltName")) {
243 185
244 if( !(meth = X509V3_EXT_get(ext)) ) 186 if( !(meth = X509V3_EXT_get(ext)) )
245 break; 187 break;
246 188
247 if( !(meth->d2i) ) 189 if( !(meth->d2i) )
248 break; 190 break;
249 191
250 data = ext->value->data; 192 data = ext->value->data;
251 193
252 val = meth->i2v(meth, meth->d2i(0, &data, ext->value->length), 0); 194 val = meth->i2v(meth, meth->d2i(0, &data, ext->value->length), 0);
253 for( j=0, n=sk_CONF_VALUE_num(val); j<n; j++ ) { 195 for( j=0, n=sk_CONF_VALUE_num(val); j<n; j++ ) {
254 nval = sk_CONF_VALUE_value(val, j); 196 nval = sk_CONF_VALUE_value(val, j);
255 if( !strcasecmp(nval->name, "DNS") && 197 if( !strcasecmp(nval->name, "DNS") &&
256 !strcasecmp(nval->value, host) ) { 198 !strcasecmp(nval->value, host) ) {
257 ok = 1; 199 ok = 1;
258 break; 200 break;
259 } 201 }
260 } 202 }
261 } 203 }
262 } 204 }
263 } 205 }
264 206
265 if( !ok && (subj = X509_get_subject_name(cert)) && 207 if( !ok && (subj = X509_get_subject_name(cert)) &&
266 X509_NAME_get_text_by_NID(subj, NID_commonName, 208 X509_NAME_get_text_by_NID(subj, NID_commonName,
267 name, sizeof(name)) > 0 ) { 209 name, sizeof(name)) > 0 ) {
268 name[sizeof(name)-1] = '\0'; 210 name[sizeof(name)-1] = '\0';
269 if(!strcasecmp(name, host)) 211 if(!strcasecmp(name, host))
@@ -331,7 +273,7 @@ X509_STORE *vc_x509store_create(vc_x509store_t *vc_store)
331 X509_STORE_set_flags( store, 273 X509_STORE_set_flags( store,
332 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); 274 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL );
333 } 275 }
334 276
335 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) ) 277 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) )
336 VC_STORE_ERR_EXIT(store); 278 VC_STORE_ERR_EXIT(store);
337 279
diff --git a/vchat-ssl.h b/vchat-ssl.h
index 58e9dec..c745c97 100755
--- a/vchat-ssl.h
+++ b/vchat-ssl.h
@@ -21,8 +21,7 @@ typedef struct {
21 21
22/* prototypes */ 22/* prototypes */
23 23
24BIO * vc_connect(char *, int , int, vc_x509store_t *, SSL_CTX **); 24int vc_connect_ssl(BIO **conn, vc_x509store_t *, SSL_CTX **);
25BIO * vc_connect_ssl(char *, int, vc_x509store_t *, SSL_CTX **);
26SSL_CTX * vc_create_sslctx( vc_x509store_t *); 25SSL_CTX * vc_create_sslctx( vc_x509store_t *);
27void vc_init_x509store(vc_x509store_t *); 26void vc_init_x509store(vc_x509store_t *);
28void vc_cleanup_x509store(vc_x509store_t *); 27void vc_cleanup_x509store(vc_x509store_t *);
diff --git a/vchat.h b/vchat.h
index d8054bd..5e2bff9 100755
--- a/vchat.h
+++ b/vchat.h
@@ -43,7 +43,7 @@ CF_ENCODING, CF_BELLPRIV, CF_AUTORECONN } confopt;
43 43
44/* format strings */ 44/* format strings */
45typedef enum { FS_PLAIN, FS_CHAN, FS_PRIV, FS_SERV, FS_GLOB, FS_DBG, FS_ERR, 45typedef enum { FS_PLAIN, FS_CHAN, FS_PRIV, FS_SERV, FS_GLOB, FS_DBG, FS_ERR,
46FS_IDLE, FS_TIME, FS_CONSOLETIME, FS_TOPICW, FS_NOTOPICW, FS_CONSOLE, FS_CONNECTED, 46FS_IDLE, FS_TIME, FS_CONSOLETIME, FS_TOPICW, FS_NOTOPICW, FS_CONSOLE, FS_CONNECTED, FS_CANTCONNECT,
47FS_TOPIC, FS_NOTOPIC, FS_CHGTOPIC, FS_USONLINE, FS_USMATCH, FS_SIGNON, FS_SIGNOFF, 47FS_TOPIC, FS_NOTOPIC, FS_CHGTOPIC, FS_USONLINE, FS_USMATCH, FS_SIGNON, FS_SIGNOFF,
48FS_JOIN, FS_LEAVE, FS_NICKCHANGE, FS_UNKNOWNMSG, FS_BOGUSMSG, FS_RXPUBURL, 48FS_JOIN, FS_LEAVE, FS_NICKCHANGE, FS_UNKNOWNMSG, FS_BOGUSMSG, FS_RXPUBURL,
49FS_MYPUBURL, FS_RXPUBMSG, FS_MYPUBMSG, FS_TXPUBMSG, FS_RXPRIVMSG, FS_TXPRIVMSG, 49FS_MYPUBURL, FS_RXPUBMSG, FS_MYPUBMSG, FS_TXPUBMSG, FS_RXPRIVMSG, FS_TXPRIVMSG,