diff --git a/.gitmodules b/.gitmodules
index 2d33dcf..8c4fa01 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "psyclpc"]
path = psyclpc
- url = git://git.tgbit.net/psyclpc
+ url = git://git.psyced.org/git/psyclpc
diff --git a/CHANGESTODO b/CHANGESTODO
index a53834b..ba6631f 100644
--- a/CHANGESTODO
+++ b/CHANGESTODO
@@ -184,6 +184,8 @@ problems that should disappear when we move away from _nick's:
- IRC shows "*** k kindly asks for your friendship." for remote
friendship requests. eh! where's the uniform!?
- remote /topic shows wrong nick
++ allow newbies to use /nick and switch to a different newbie name?
+ (also, forbid +alias from being used by newbies?)
> PRESENCE STATUS
+ all _status_person need to be upgraded to _status_presence with
diff --git a/install.sh b/install.sh
index 77108f7..243c77b 100755
--- a/install.sh
+++ b/install.sh
@@ -955,6 +955,7 @@ _path_configuration = $CONFIG_DIR
; (absolute or relative to _path_configuration)
_path_PEM_key = key.pem
_path_PEM_certificate = cert.pem
+; You can run 'make' in the 'utility/gencert' folder to create a pair
; Path to the TLS trust directory where certs are kept.
; If unset this will default to your system installation's defaults.
diff --git a/utility/gencert/Makefile b/utility/gencert/Makefile
new file mode 100644
index 0000000..57bd015
--- /dev/null
+++ b/utility/gencert/Makefile
@@ -0,0 +1,32 @@
+# taken from prosody.im, originally written by zash. MIT license
+#
+.DEFAULT: localhost.cert
+keysize=2048
+
+# How to:
+# First, `make yourhost.cnf` which creates a openssl config file.
+# Then edit this file and fill in the details you want it to have,
+# and add or change hosts and components it should cover.
+# Then `make yourhost.key` to create your private key, you can
+# include keysize=number to change the size of the key.
+# Then you can either `make yourhost.csr` to generate a certificate
+# signing request that you can submit to a CA, or `make yourhost.cert`
+# to generate a self signed certificate.
+
+.PRECIOUS: %.cnf %.key
+
+# To request a cert
+%.csr: %.cnf %.key
+ openssl req -new -key $(lastword $^) -out $@ -utf8 -config $(firstword $^)
+
+# Self signed
+%.cert: %.cnf %.key
+ openssl req -new -x509 -nodes -key $(lastword $^) -days 365 \
+ -sha1 -out $@ -utf8 -config $(firstword $^)
+
+%.cnf:
+ sed 's,example\.com,$*,g' openssl.cnf > $@
+
+%.key:
+ openssl genrsa $(keysize) > $@
+ @chmod 400 -c $@
diff --git a/utility/gencert/openssl.cnf b/utility/gencert/openssl.cnf
new file mode 100644
index 0000000..49e5305
--- /dev/null
+++ b/utility/gencert/openssl.cnf
@@ -0,0 +1,53 @@
+# based on the prosody certs/openssl.cnf by zash - MIT license
+#
+# note: if you have an internationalized domain name, be very careful
+# about encoding it properly.
+oid_section = new_oids
+
+[ new_oids ]
+
+# RFC 3920 section 5.1.1 defines this OID
+xmppAddr = 1.3.6.1.5.5.7.8.5
+
+# RFC 4985 defines this OID
+SRVName = 1.3.6.1.5.5.7.8.7
+
+[ req ]
+
+default_bits = 4096
+default_keyfile = example.com.key
+distinguished_name = distinguished_name
+req_extensions = v3_extensions
+x509_extensions = v3_extensions
+string_mask = utf8only
+
+# ask about the DN?
+prompt = no
+
+[ distinguished_name ]
+
+commonName = example.com
+countryName = GB
+localityName = The Internet
+organizationName = Your Organisation
+organizationalUnitName = IT Department
+emailAddress = psycmaster@example.com
+
+[ v3_extensions ]
+
+# for certificate requests (req_extensions)
+# and self-signed certificates (x509_extensions)
+# note: setting keyUsage does not work for self-signed certs
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature,keyEncipherment
+extendedKeyUsage = serverAuth,clientAuth
+subjectAltName = @subject_alternative_name
+
+[ subject_alternative_name ]
+
+# See http://tools.ietf.org/html/rfc6120#section-13.7.1.2 for more info
+
+DNS.0 = example.com
+otherName.0 = SRVName;IA5STRING:_xmpp-client.example.com
+otherName.1 = SRVName;IA5STRING:_xmpp-server.example.com
+otherName.2 = SRVName;IA5STRING:_psyc.example.com
diff --git a/world/default/de/html.textdb b/world/default/de/html.textdb
index b94ba36..4af5112 100644
--- a/world/default/de/html.textdb
+++ b/world/default/de/html.textdb
@@ -795,14 +795,6 @@ _PAGES_help_settings
|
/set miniphotofile http://<Web-Adresse>
|A thumbnail size photo of yours, to be used for lists of friends.
|
-|
-| /set keyfile http://<Web-Adresse>
-|Für die Freunde der verschlüsselten Kommunikation, hier kann die
-|Adresse der eigenen public-key Datei abgelegt werden wonach
-|Freunde verschlüsselte Email austauschen oder, mit einem
-|geeigneten PSYC
-|client, direkt verschlüsselt chatten können.
-|
|
| /set startpage http://<Web-Adresse>
|Hiermit kann eine Startseite eingestellt werden, welche sofort nach
diff --git a/world/default/de/plain.textdb b/world/default/de/plain.textdb
index 3d2405e..74f4db2 100644
--- a/world/default/de/plain.textdb
+++ b/world/default/de/plain.textdb
@@ -1,6 +1,15 @@
## vim:syntax=mail
## Check utf-8: Praise Atatürk!
+_status_circuit_encryption_cipher
+|Gratuliere! Deine Verbindung ist mit Folgenlosigkeit verschlüsselt.
+
+_warning_circuit_encryption_cipher
+|Deine Verbindung ist leider ohne Folgenlosigkeit verschlüsselt.
+
+_error_circuit_encryption_cipher
+|Deine Verbindung ist ohne Folgenlosigkeit verschlüsselt.
+
_failure_disabled_function_register
|Registrierung ist auf diesem Server deaktiviert.
diff --git a/world/default/en/html.textdb b/world/default/en/html.textdb
index d8a08a4..76d0e7a 100644
--- a/world/default/en/html.textdb
+++ b/world/default/en/html.textdb
@@ -877,13 +877,6 @@ _PAGES_help_settings
| /set miniphotofile http://<web-address>
|A thumbnail size photo of yours, to be used for lists of friends.
|
-| /set keyfile http://<web-address>
-|invites you to store the address of your public key file,
-|allowing for encrypted communication to happen between you and
-|your friends, provided you are both using an encryption capable
-|PSYC client,
-|or at least email.
-|
| /set stylefile http://<web-address>
|lets you specify a cascading style sheet file for personalized
|presentation of your profile!
diff --git a/world/default/en/plain.textdb b/world/default/en/plain.textdb
index 552f0bc..151d789 100644
--- a/world/default/en/plain.textdb
+++ b/world/default/en/plain.textdb
@@ -1,6 +1,15 @@
## vim:syntax=mail
## Check utf-8: Praise Atatürk!
+_status_circuit_encryption_cipher
+|Congratulations. Your connection is encrypted with forward secrecy.
+
+_warning_circuit_encryption_cipher
+|Your cipher choice does not provide forward secrecy.
+
+_error_circuit_encryption_cipher
+|Unfortunately your cipher choice does not provide forward secrecy.
+
_failure_disabled_function_register
|Registration disabled on this server.
diff --git a/world/default/it/plain.textdb b/world/default/it/plain.textdb
index ce34307..d1a94cc 100644
--- a/world/default/it/plain.textdb
+++ b/world/default/it/plain.textdb
@@ -1,6 +1,15 @@
## vim:syntax=mail
## tradotto al 30% ... cerca /TODO/ per continuare
+_status_circuit_encryption_cipher
+|Muy bueno! La tua connessione è crittata senza conseguenze.
+
+_warning_circuit_encryption_cipher
+|La tua connessione non è crittata senza conseguenze.
+
+_error_circuit_encryption_cipher
+|Purtroppo la tua connessione non è crittata senza conseguenze.
+
_failure_disabled_function_register
|Registrazione di nuovi utenti disabilitata su questo server.
diff --git a/world/drivers/ldmud/master/accept.c b/world/drivers/ldmud/master/accept.c
index 11b96c1..16c42dc 100644
--- a/world/drivers/ldmud/master/accept.c
+++ b/world/drivers/ldmud/master/accept.c
@@ -46,16 +46,22 @@ void notify_shutdown_first(int progress) {
* input_to() can't be called from here.
*
* uid is only passed if USE_AUTHLOCAL is built into the driver.
+ *
+ * strange how int port and string service came into existence here
+ * since the driver isn't passing such arguments and there is no
+ * reason to call this from anywhere else. i presume they are a
+ * mistake!
*/
object connect(int uid, int port, string service) {
int peerport;
mixed arg, t;
+ unless (port) port = query_mud_port();
// now that's a bit of preprocessor magic you don't need to understand.. ;)
- D2( if (uid) D("master:connected on port "+ query_mud_port() +" by uid "
- + uid +"\n");
+ D2( if (uid) D("master:connected on port "+ port +" by uid "
+ + uid +"("+ service + ")\n");
else) {
- D3(D("master:connected on port "+query_mud_port()
+ D3(D("master:connected on port "+port
+" by "+query_ip_name()+"\n");)
}
#ifndef H_DEFAULT_PROMPT
@@ -69,26 +75,111 @@ object connect(int uid, int port, string service) {
return clone_object(NET_PATH "utility/onhold");
}
- // we dont want the telnet machine most of the time
- // but disabling and re-enabling it for telnet doesn't work
- switch(port || query_mud_port()) {
-#if HAS_PORT(PSYC_PORT, PSYC_PATH) && AUTODETECT
- case PSYC_PORT:
+#define TLS_INIT \
+ if (tls_available()) { \
+ t = tls_init_connection(ME); \
+ if (t < 0 && t != ERR_TLS_NOT_DETECTED) { \
+ P2(( "TLS(%O) on port %O: %O\n", t, port, tls_error(t) )); \
+ } \
+ }
+
+// doesn't work. at this point autodetect hasn't completed.. so to
+// make sure TLS is enabled we need to check again later in the
+// server object.. FIXME :(
+#define TLS_ENFORCE \
+ if (tls_query_connection_state(ME) == 0) \
+ return (object) 0;
+
+#if __EFUN_DEFINED__(tls_want_peer_certificate)
+// Specify that a subsequent call to tls_init_connection
+// should request a peer certificate.
+# define TLS_INIT_GET_CERT \
+ if (tls_available()) { \
+ tls_want_peer_certificate(ME); \
+ t = tls_init_connection(ME); \
+ if (t < 0 && t != ERR_TLS_NOT_DETECTED) { \
+ P2(( "TLS(%O) on port %O: %O\n", t, port, tls_error(t) )); \
+ } \
+ }
+#else
+# define TLS_INIT_GET_CERT TLS_INIT
+#endif
+
+ // in the first switch we handle ports that MUST not support
+ // immediate TLS (currently that's just 5269) or that want a
+ // peer certificate from the other side (PSYC). for all other
+ // ports the default is to attempt a TLS autodetection.
+ switch(port) {
+#if HAS_PORT(JABBER_S2S_PORT, JABBER_PATH)
+ case JABBER_S2S_PORT:
+# ifdef DRIVER_HAS_CALL_BY_REFERENCE
+ arg = ME;
+ query_ip_number(&arg);
+ // this assumes network byte order provided by driver
+ peerport = pointerp(arg) ? (arg[2]*256 + arg[3]) : 0;
+ if (peerport < 0) peerport = 65536 + peerport;
+ if (peerport == JABBER_S2S_SERVICE) peerport = 0;
+# else
+ // as long as the object names don't collide, this is okay too
+ peerport = 65536 + random(9999999);
+# endif
+# if __EFUN_DEFINED__(enable_telnet)
+ enable_telnet(0);
+# endif
+ t = "S:xmpp:"+query_ip_number();
+ // it's just an object name, but let's be consequent minus peerport
+ if (peerport) t += ":-"+peerport;
+# ifdef _flag_log_sockets_XMPP
+ SIMUL_EFUN_FILE -> log_file("RAW_XMPP", "\n\n%O: %O -> load(%O, %O)",
+ ME, t,
+# ifdef _flag_log_hosts
+ query_ip_number(),
+# else
+ "?",
+# endif
+ -peerport);
+# endif
+ P3(("%O -> load(%O, %O)\n", t, query_ip_number(), -peerport))
+ return t -> load(query_ip_number(), -peerport);
#endif
#if HAS_PORT(PSYCS_PORT, PSYC_PATH)
case PSYCS_PORT: // inofficial & temporary
- // make TLS available even on the default psyc port using the autodetection feature
- if (tls_available()) {
-# if __EFUN_DEFINED__(tls_want_peer_certificate)
- tls_want_peer_certificate(ME);
-# endif
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) {
- PP(( "TLS on %O: %O\n", query_mud_port(), tls_error(t) ));
- }
- }
-#endif // fall thru
-#if HAS_PORT(PSYC_PORT, PSYC_PATH) &&! AUTODETECT
+ TLS_INIT_GET_CERT
+ break;
+#endif
+#if HAS_PORT(PSYC_PORT, PSYC_PATH) && AUTODETECT
+ case PSYC_PORT:
+ // make TLS available on the default PSYC port
+ // using the autodetection feature (official approach)
+ TLS_INIT_GET_CERT
+ break;
+#endif
+#if HAS_PORT(SPYCS_PORT, SPYC_PATH)
+ case SPYCS_PORT: // even more inofficial
+ TLS_INIT_GET_CERT
+ break;
+#endif
+#if HAS_PORT(SPYC_PORT, SPYC_PATH) && AUTODETECT
+ case SPYC_PORT: // even more inofficial
+ TLS_INIT_GET_CERT
+ break;
+#endif
+ default:
+#if AUTODETECT
+ // if autodetect is available, let's check if this connection
+ // has TLS enabled and activate it, no matter which protocol.
+ TLS_INIT
+#endif
+ break;
+ }
+
+ // if we got here, we may have initialized TLS successfully
+ switch(port) {
+#if HAS_PORT(PSYCS_PORT, PSYC_PATH)
+ case PSYCS_PORT: // inofficial & temporary
+ TLS_ENFORCE
+#endif
+#if HAS_PORT(PSYC_PORT, PSYC_PATH)
case PSYC_PORT:
#endif
#if HAS_PORT(PSYC_PORT, PSYC_PATH) || HAS_PORT(PSYCS_PORT, PSYC_PATH)
@@ -117,15 +208,10 @@ object connect(int uid, int port, string service) {
return t -> load(query_ip_number(), -peerport);
#endif
-// dedicated SPYC port.. should not be used, we have AUTODETECT
+// dedicated SPYC port.. should not be used
#if HAS_PORT(SPYCS_PORT, SPYC_PATH)
case SPYCS_PORT: // interim name for PSYC 1.0 according to SPEC
-# if __EFUN_DEFINED__(tls_want_peer_certificate)
- tls_want_peer_certificate(ME);
-# endif
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
#endif // fall thru
#if HAS_PORT(SPYC_PORT, SPYC_PATH)
case SPYC_PORT:
@@ -160,9 +246,7 @@ object connect(int uid, int port, string service) {
#if HAS_PORT(POP3S_PORT, POP3_PATH)
case POP3S_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
return clone_object(POP3_PATH "server");
#endif
#if HAS_PORT(POP3_PORT, POP3_PATH)
@@ -172,9 +256,7 @@ object connect(int uid, int port, string service) {
#if HAS_PORT(SMTPS_PORT, NNTP_PATH)
case SMTPS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
return clone_object(SMTP_PATH "server");
#endif
#if HAS_PORT(SMTP_PORT, SMTP_PATH)
@@ -190,9 +272,7 @@ object connect(int uid, int port, string service) {
#if HAS_PORT(NNTPS_PORT, NNTP_PATH)
case NNTPS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
return clone_object(NNTP_PATH "server");
#endif
#if HAS_PORT(NNTP_PORT, NNTP_PATH)
@@ -202,51 +282,19 @@ object connect(int uid, int port, string service) {
#if HAS_PORT(JABBERS_PORT, JABBER_PATH)
case JABBERS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
return clone_object(JABBER_PATH "server");
#endif
#if HAS_PORT(JABBER_PORT, JABBER_PATH)
case JABBER_PORT:
# if __EFUN_DEFINED__(enable_telnet)
+ // we dont want the telnet machine most of the time
+ // but disabling and re-enabling it for telnet doesn't work
enable_telnet(0); // are you sure!???
# endif
return clone_object(JABBER_PATH "server");
#endif
-#if HAS_PORT(JABBER_S2S_PORT, JABBER_PATH)
- case JABBER_S2S_PORT:
-# ifdef DRIVER_HAS_CALL_BY_REFERENCE
- arg = ME;
- query_ip_number(&arg);
- // this assumes network byte order provided by driver
- peerport = pointerp(arg) ? (arg[2]*256 + arg[3]) : 0;
- if (peerport < 0) peerport = 65536 + peerport;
- if (peerport == JABBER_S2S_SERVICE) peerport = 0;
-# else
- // as long as the object names don't collide, this is okay too
- peerport = 65536 + random(9999999);
-# endif
-# if __EFUN_DEFINED__(enable_telnet)
- enable_telnet(0);
-# endif
- t = "S:xmpp:"+query_ip_number();
- // it's just an object name, but let's be consequent minus peerport
- if (peerport) t += ":-"+peerport;
-# ifdef _flag_log_sockets_XMPP
- SIMUL_EFUN_FILE -> log_file("RAW_XMPP", "\n\n%O: %O -> load(%O, %O)",
- ME, t,
-# ifdef _flag_log_hosts
- query_ip_number(),
-# else
- "?",
-# endif
- -peerport);
-# endif
- P3(("%O -> load(%O, %O)\n", t, query_ip_number(), -peerport))
- return t -> load(query_ip_number(), -peerport);
-#endif
#if 0 //__EFUN_DEFINED__(enable_binary)
// work in progress
case 8888:
@@ -258,18 +306,14 @@ object connect(int uid, int port, string service) {
enable_telnet(0);
return clone_object(NET_PATH "rtmp/protocol");
#endif
+
#if HAS_PORT(IRCS_PORT, IRC_PATH)
case IRCS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
return clone_object(IRC_PATH "server");
#endif
#if HAS_PORT(IRC_PORT, IRC_PATH)
- case IRC_PORT: // we could enable AUTODETECT for this..
-# if 0 // __EFUN_DEFINED__(enable_telnet)
- enable_telnet(0); // shouldn't harm.. but it does!!!
-# endif
+ case IRC_PORT:
return clone_object(IRC_PATH "server");
#endif
@@ -283,16 +327,13 @@ object connect(int uid, int port, string service) {
#if HAS_PORT(TELNETS_PORT, TELNET_PATH)
case TELNETS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
// we could do the UID2NICK thing here, too, but why should we?
// what do you need tls for on a localhost tcp link?
return clone_object(TELNET_PATH "server");
#endif
#if HAS_PORT(TELNET_PORT, TELNET_PATH)
- case TELNET_PORT: // we could enable AUTODETECT for this.. (wait 4s)
-// set_prompt("> ");
+ case TELNET_PORT:
t = clone_object(TELNET_PATH "server");
# ifdef UID2NICK
if (uid && (arg = UID2NICK(uid))) { t -> sName(arg); }
@@ -302,30 +343,18 @@ object connect(int uid, int port, string service) {
#if HAS_PORT(HTTPS_PORT, HTTP_PATH)
case HTTPS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0) {
- D1( if (t != ERR_TLS_NOT_DETECTED) PP(( "TLS(%O) on %O: %O\n",
- t, query_mud_port(), tls_error(t) )); )
-#if !HAS_PORT(HTTP_PORT, HTTP_PATH)
- // if we have no http port, it may be intentional
- return (object)0;
-#endif
- }
- D2( else if (t > 0) PP(( "Setting up TLS connection in the background.\n" )); )
- D2( else PP(( "Oh yeah, I'm initializing an https session!\n" )); )
+ TLS_ENFORCE
return clone_object(HTTP_PATH "server");
#endif
- /* don't fall thru. allow for https: to be available without http: */
+ // don't fall thru. allow for https: to be available without http:
#if HAS_PORT(HTTP_PORT, HTTP_PATH)
- case HTTP_PORT: // AUTODETECT on the HTTP port? we could do that too
+ case HTTP_PORT:
return clone_object(HTTP_PATH "server");
#endif
#if HAS_PORT(MUDS_PORT, MUD_PATH)
case MUDS_PORT:
- t = tls_init_connection(this_object());
- if (t < 0 && t != ERR_TLS_NOT_DETECTED) PP(( "TLS on %O: %O\n",
- query_mud_port(), tls_error(t) ));
+ TLS_ENFORCE
return clone_object(MUD_PATH "login");
#endif
#if HAS_PORT(MUD_PORT, MUD_PATH)
@@ -335,9 +364,8 @@ object connect(int uid, int port, string service) {
return clone_object(MUD_PATH "login");
#endif
}
-
- PP(("Received connection on port %O which isn't configured.\n",
- query_mud_port()));
+
+ P0(("Received connection on port %O which isn't configured.\n", port));
return (object)0;
}
@@ -345,10 +373,10 @@ object connect(int uid, int port, string service) {
#ifdef DRIVER_HAS_RENAMED_CLONES
// named clones -lynx
object compile_object(string file) {
- P3((">> compile_object(%O)\n", file))
string path, name;
object rob;
+ P3((">> compile_object(%O)\n", file))
# ifdef PSYC_PATH
if (abbrev("S:psyc:", file)) {
rob = clone_object(PSYC_PATH "server");
diff --git a/world/net/jabber/active.c b/world/net/jabber/active.c
index acfdc40..4419e1f 100644
--- a/world/net/jabber/active.c
+++ b/world/net/jabber/active.c
@@ -31,6 +31,7 @@ inherit NET_PATH "name";
volatile mixed gateways;
volatile mixed *dialback_queue;
+volatile mapping certinfo;
volatile string streamid;
volatile float streamversion;
@@ -312,39 +313,39 @@ tls_logon(result) {
//
// if the cert is ok, we can set authenticated to 1
// to skip dialback
- mixed cert = tls_certificate(ME, 0);
- P3(("active::certinfo %O\n", cert))
- if (mappingp(cert)) {
- unless (certificate_check_name(hostname, cert, "xmpp-server")) {
+ certinfo = tls_certificate(ME, 0);
+ P3(("active::certinfo %O\n", certinfo))
+ if (mappingp(certinfo)) {
+ unless (tls_check_service_identity(hostname, certinfo, "xmpp-server")) {
#ifdef _flag_report_bogus_certificates
monitor_report("_error_invalid_certificate_identity",
sprintf("%O presented a certificate that "
"contains %O/%O",
- hostname, cert["2.5.4.3"],
- cert["2.5.29.17:1.3.6.1.5.5.7.8.5"]));
+ hostname, certinfo["2.5.4.3"],
+ certinfo["2.5.29.17:1.3.6.1.5.5.7.8.5"]));
#endif
#ifdef _flag_log_bogus_certificates
- log_file("CERTS", S("%O %O %O id?\n", ME, hostname, cert));
+ log_file("CERTS", S("%O %O %O id?\n", ME, hostname, certinfo));
#else
P1(("TLS: %s presented a certificate with unexpected identity.\n", hostname))
- P2(("%O\n", cert))
+ P2(("%O\n", certinfo))
#endif
#if 0 //def _flag_reject_bogus_certificates
QUIT
return 1;
#endif
}
- else if (cert[0] != 0) {
+ else if (certinfo[0] != 0) {
#ifdef _flag_report_bogus_certificates
monitor_report("_error_untrusted_certificate",
sprintf("%O certificate could not be verified",
hostname));
#endif
#ifdef _flag_log_bogus_certificates
- log_file("CERTS", S("%O %O %O\n", ME, hostname, cert));
+ log_file("CERTS", S("%O %O %O\n", ME, hostname, certinfo));
#else
P1(("TLS: %s presented untrusted certificate.\n", hostname))
- P2(("%O\n", cert))
+ P2(("%O\n", certinfo))
#endif
#if 0 //def _flag_reject_bogus_certificates
// QUIT is wrong...
diff --git a/world/net/jabber/common.c b/world/net/jabber/common.c
index 0f2ab3a..877e82a 100644
--- a/world/net/jabber/common.c
+++ b/world/net/jabber/common.c
@@ -393,7 +393,9 @@ xmpp_error(node, xmpperror) {
return 0;
}
-// deprecated - use certificate_check_name from library/tls.c instead
+// deprecated - use tls_check_service_identity from library/tls.c instead
+// is this being used at all? -- no longer, but keep it around a little
+// for backward compat
#ifdef WANT_S2S_TLS
certificate_check_jabbername(name, cert) {
mixed t;
diff --git a/world/net/jabber/gateway.c b/world/net/jabber/gateway.c
index c88c0b5..a4ae72e 100644
--- a/world/net/jabber/gateway.c
+++ b/world/net/jabber/gateway.c
@@ -291,7 +291,7 @@ jabberMsg(XMLNode node) {
// paranoia note: as with XEP 0178 we might want to check dns anyway to
// protect against stolen certificates
if (mappingp(certinfo) && certinfo[0] == 0
- && node["@from"] && certificate_check_name(node["@from"], certinfo, "xmpp-server")) {
+ && node["@from"] && tls_check_service_identity(node["@from"], certinfo, "xmpp-server")) {
P2(("dialback without dialback %O\n", certinfo))
verify_connection(node["@to"], node["@from"], "valid");
} else {
@@ -414,7 +414,7 @@ jabberMsg(XMLNode node) {
*/
int success = 0;
- success = certificate_check_name(t, certinfo, "xmpp-server");
+ success = tls_check_service_identity(t, certinfo, "xmpp-server");
if (success) {
emitraw("");
P2(("successful sasl external authentication with "
@@ -542,8 +542,8 @@ open_stream(XMLNode node) {
// sasl external if we know that it will succeed
// later on
if (node["@from"] &&
- certificate_check_name(node["@from"],
- certinfo, "xmpp-server")) {
+ tls_check_service_identity(node["@from"], certinfo,
+ "xmpp-server")) {
packet += "";
packet += "EXTERNAL";
packet += "";
diff --git a/world/net/jabber/server.c b/world/net/jabber/server.c
index b1d1625..ae3767e 100644
--- a/world/net/jabber/server.c
+++ b/world/net/jabber/server.c
@@ -490,6 +490,7 @@ open_stream(XMLNode node) {
#if __EFUN_DEFINED__(tls_available)
if (tls_available() && tls_query_connection_state(ME) > 0
&& mappingp(certinfo) && certinfo[0] == 0
+ // why do we use the old one here?
&& certificate_check_jabbername(0, certinfo)) {
features += "EXTERNAL";
}
@@ -512,5 +513,6 @@ certificate_check_jabbername(name, certinfo) {
// plan: prefer subjectAltName:id-on-xmppAddr,
// but allow email (1.2.840.113549.1.9.1)
// and subjectAltName:rfc822Name
+ // FIXME: do something useful here...
return 0;
}
diff --git a/world/net/library/dns.c b/world/net/library/dns.c
index 5337487..02f1df7 100644
--- a/world/net/library/dns.c
+++ b/world/net/library/dns.c
@@ -614,6 +614,13 @@ void dns_srv_resolve(string hostname, string service, string proto, closure call
// dumme bevormundung. wegen der musste ich jetzt ewig lang suchen:
//unless (proto == "tcp" || proto == "udp") return;
// da wir mit nem String arbeiten muessen
+
+#ifdef __IDNA__
+ if (catch(hostname = idna_to_ascii(TO_UTF8(hostname)); nolog)) {
+ P0(("catch: punycode %O in %O\n", hostname, ME))
+ return;
+ }
+#endif
req = sprintf("_%s._%s.%s", service, proto, hostname);
rc = send_erq(ERQ_LOOKUP_SRV, req, lambda(({ 'wu }),
({ (#',),
diff --git a/world/net/library/tls.c b/world/net/library/tls.c
index c975171..eb5e70a 100644
--- a/world/net/library/tls.c
+++ b/world/net/library/tls.c
@@ -1,4 +1,7 @@
#include // vim syntax=lpc
+#include
+#include
+
mapping tls_certificate(object who, int longnames) {
mixed *extra, extensions;
mapping cert;
@@ -85,7 +88,7 @@ mapping tls_certificate(object who, int longnames) {
// generalized variant of the old certificate_check_jabbername
// RFC 6125 describes the process in more detail
-int certificate_check_name(string name, mixed cert, string scheme) {
+int tls_check_service_identity(string name, mixed cert, string scheme) {
mixed t;
string idn;
// FIXME: should probably be more careful about internationalized
@@ -111,6 +114,8 @@ int certificate_check_name(string name, mixed cert, string scheme) {
// subjectAlternativeName - SRV ID - FIXME
// unfortunately, the only ones I have encountered so far were ... unusable
+ // what they should like is "_psyc.name" - i.e. "_" + scheme + "." + name
+ // no wildcards probably
if ((t = cert["2.5.29.17:1.3.6.1.5.5.7.8.7"])) {
P2(("encountered SRVName, please tell fippo: %O\n", t))
}
@@ -121,6 +126,7 @@ int certificate_check_name(string name, mixed cert, string scheme) {
#if 0
// id-on-xmppAddr - have not seen them issued by anyone but
// startcom and those usually include dnsname, too
+ // utf8-encoded
if ((t = cert["2.5.29.17:1.3.6.1.5.5.7.8.5"])) {
if (pointerp(t)) {
if (member(t, name) != -1) return 1;
@@ -142,7 +148,11 @@ int certificate_check_name(string name, mixed cert, string scheme) {
// look for idn encoded stuff
foreach(string cn : t) {
+#ifdef __IDNA__
idn = NAMEPREP(idna_to_unicode(cn));
+#else
+ idn = NAMEPREP(cn);
+#endif
if (idn == name) return 1;
}
return 0;
@@ -157,3 +167,20 @@ int certificate_check_name(string name, mixed cert, string scheme) {
}
return 0;
}
+
+int tls_check_cipher(object sock, string scheme) {
+ string t;
+ mixed m = tls_query_connection_info(sock);
+
+ P3(("%O is using the %O cipher.\n", sock, m[TLS_CIPHER]))
+ // shouldn't our negotiation have ensured we have PFS?
+
+ if (stringp(t = m[TLS_CIPHER]) &&! abbrev("DHE", t)) {
+ monitor_report("_warning_circuit_encryption_cipher_details",
+ object_name(sock) +" · using "+ t +" cipher");
+ // we can't expect that degree of privacy from jabber, for now
+ if (scheme != "xmpp") return 0;
+ }
+ return 1;
+}
+
diff --git a/world/net/psyc/circuit.c b/world/net/psyc/circuit.c
index 0f82c61..97515a7 100644
--- a/world/net/psyc/circuit.c
+++ b/world/net/psyc/circuit.c
@@ -209,48 +209,41 @@ int logon(int neverfails) {
#ifdef __TLS__
sAuthHosts(([ ])); // reset authhosts
- if (tls_available() && tls_query_connection_state(ME) == 1 && mappingp(cert = tls_certificate(ME, 0))) {
- if (cert[0] != 0) {
- // log error 17 or 18 + cert here
- P0(("%O encountered a cert verify error %O in %O\n", ME,
- cert[0], cert))
- // and goodbye.
+ if (tls_available() && tls_query_connection_state(ME) == 1) {
+ unless (tls_check_cipher(ME, "psyc")) {
+ croak("_error_circuit_encryption_cipher",
+ "Your cipher choice does not provide forward secrecy.");
+ QUIT
+ }
+ if (mappingp(cert = tls_certificate(ME, 0))) {
+ if (cert[0] != 0) {
+ // log error 17 or 18 + cert here
+ P0(("%O encountered a cert verify error %O in %O\n", ME,
+ cert[0], cert))
+ // and goodbye.
# ifdef _flag_enable_certificate_any
- remove_interactive(ME);
- return 0;
+ remove_interactive(ME);
+ return 0;
# endif
- }
- if (m = cert["2.5.29.17:dNSName"]) {
- // FIXME: this does not yet handle wildcard DNS names
- P1(("%O believing dNSName %O\n", ME, m))
- // probably also: register_target?
- // but be careful never to register_target wildcards
- if (stringp(m)) sAuthenticated(m);
- else foreach(t : m) sAuthenticated(t);
- }
-//#ifdef _flag_allow_certificate_name_common // to be switched this year
-# ifndef _flag_disallow_certificate_name_common
- // assume that CN is a host
- // as this is an assumption only, we may NEVER register_target it
- // note: CN is deprecated for good reasons.
- else if (t = cert["2.5.4.3"]) {
- P1(("%O believing CN %O\n", ME, t))
- sAuthenticated(t);
- }
-# endif
- if (m = tls_query_connection_info(ME)) {
- P2(("%O is using the %O cipher.\n", ME, m[TLS_CIPHER]))
- // shouldn't our negotiation have ensured we have PFS?
- if (stringp(t = m[TLS_CIPHER]) &&! abbrev("DHE", t)) {
-// croak("_warning_circuit_encryption_cipher",
-// "Your cipher choice does not provide forward secrecy.");
- monitor_report(
- "_warning_circuit_encryption_cipher_details",
- object_name(ME) +" · using "+ t +" cipher");
- //debug_message(sprintf(
- // "TLS connection info for %O is %O\n", ME, m));
- //QUIT // are we ready for *this* !???
}
+ if (m = cert["2.5.29.17:dNSName"]) {
+ // FIXME: this does not yet handle wildcard DNS names
+ P1(("%O believing dNSName %O\n", ME, m))
+ // probably also: register_target?
+ // but be careful never to register_target wildcards
+ if (stringp(m)) sAuthenticated(m);
+ else foreach(t : m) sAuthenticated(t);
+ }
+ //#ifdef _flag_allow_certificate_name_common // to be switched this year
+# ifndef _flag_disallow_certificate_name_common
+ // assume that CN is a host
+ // as this is an assumption only, we may NEVER register_target it
+ // note: CN is deprecated for good reasons.
+ else if (t = cert["2.5.4.3"]) {
+ P1(("%O believing CN %O\n", ME, t))
+ sAuthenticated(t);
+ }
+# endif
}
}
#endif
diff --git a/world/net/spyc/circuit.c b/world/net/spyc/circuit.c
index 4fb1cf3..8c3946c 100644
--- a/world/net/spyc/circuit.c
+++ b/world/net/spyc/circuit.c
@@ -36,9 +36,13 @@ volatile string netloc;
mapping instate = ([ ]);
mapping outstate;
-mapping legal_senders;
+volatile mapping legal_senders;
-array(mixed) verify_queue = ({ });
+volatile array(mixed) verify_queue = ({ });
+
+#ifdef __TLS__
+volatile mapping certinfo;
+#endif
volatile int flags = 0;
@@ -103,52 +107,23 @@ int logon(int failure) {
instate = ([ "_INTERNAL_origin" : ME ]);
outstate = ([ ]);
#ifdef __TLS__
- mixed cert;
- if (tls_available() && tls_query_connection_state(ME) == 1 && mappingp(cert = tls_certificate(ME, 0))) {
- mixed m, t;
- if (cert[0] != 0) {
- // log error 17 + cert here
- // and goodbye.
- P0(("%O encountered a cert verify error %O in %O\n", ME,
- cert[0], cert))
- remove_interactive(ME);
- return 0;
- }
- if (m = cert["2.5.29.17:dNSName"]) {
- // FIXME: this does not yet handle wildcard DNS names
- P1(("%O believing dNSName %O\n", ME, m))
- // probably also: register_target?
- // but be careful never to register_target wildcards
- if (stringp(m))
- sAuthenticated(m);
- else
- foreach(t : m)
- sAuthenticated(t);
- }
-//#ifdef _flag_allow_certificate_name_common // to be switched this year
-#ifndef _flag_disallow_certificate_name_common
- // assume that CN is a host
- // as this is an assumption only, we may NEVER register_target it
- // note: CN is deprecated for good reasons.
- else if (t = cert["2.5.4.3"]) {
- P1(("%O believing CN %O\n", ME, t))
- sAuthenticated(t);
- }
-#endif
- if (m = tls_query_connection_info(ME)) {
- P2(("%O is using the %O cipher.\n", ME, m[TLS_CIPHER]))
- // shouldn't our negotiation have ensured we have PFS?
- if (stringp(t = m[TLS_CIPHER]) &&! abbrev("DHE", t)) {
-// croak("_warning_circuit_encryption_cipher",
-// "Your cipher choice does not provide forward secrecy.");
- monitor_report(
- "_warning_circuit_encryption_cipher_details",
- object_name(ME) +" · using "+ t +" cipher");
- //debug_message(sprintf(
- // "TLS connection info for %O is %O\n", ME, m));
- //QUIT // are we ready for *this* !???
+ P0(("circuit logon %O %O\n", tls_available(), tls_query_connection_state(ME)))
+ // FIXME: needs to handle the not-detected case
+ if (tls_available()) {
+ if (tls_query_connection_state(ME) == 0 && !isServer()) {
+ P0(("%O turning on TLS\n", ME))
+ tls_init_connection(ME, #'logon);
+ return 1;
+ } else if (tls_query_connection_state(ME) == 1) {
+ certinfo = tls_certificate(ME, 0);
+ P0(("certinfo: %O\n", certinfo))
+ unless (tls_check_cipher(ME, "psyc")) {
+ croak("_error_circuit_encryption_cipher",
+ "Your cipher choice does not provide forward secrecy.");
+ //destruct(ME);
+ }
+
}
- }
}
#endif
@@ -205,7 +180,8 @@ first_response() {
// note: this is circuit-messaging
void circuit_msg(string mc, mapping vars, string data) {
mapping rv = ([ ]);
- mixed *u;
+ mixed *su;
+ mixed *tu;
switch(mc) {
case "_request_authorization":
if (vars["_tag"]) {
@@ -218,14 +194,14 @@ void circuit_msg(string mc, mapping vars, string data) {
rv["_uniform_target"] = vars["_uniform_target"];
rv["_uniform_source"] = vars["_uniform_source"];
- u = parse_uniform(vars["_uniform_target"]);
- if (!(u && is_localhost(u[UHost]))) {
+ tu = parse_uniform(vars["_uniform_target"]);
+ if (!(tu && is_localhost(tu[UHost]))) {
msg(0, "_error_invalid_uniform_target", "[_uniform_target] is not hosted here.", rv);
return;
}
- u = parse_uniform(vars["_uniform_source"]);
+ su = parse_uniform(vars["_uniform_source"]);
// qAuthenticated does that:u[UHost] = NAMEPREP(u[UHost]);
- if (qAuthenticated(u[UHost])) {
+ if (qAuthenticated(su[UHost])) {
// possibly different _uniform_target only
if (flags & TCP_PENDING_TIMEOUT) {
P0(("removing call out\n"))
@@ -233,10 +209,22 @@ void circuit_msg(string mc, mapping vars, string data) {
flags -= TCP_PENDING_TIMEOUT;
}
msg(0, "_status_authorization", 0, rv);
- // } else if (tls_query_connection_state(ME) == 1 && ...) {
- // FIXME
+#ifdef __TLS__
+ } else if (tls_query_connection_state(ME) == 1
+ && mappingp(certinfo)
+ && certinfo[0] == 0
+ && tls_check_service_identity(su[UHost], certinfo, "psyc") == 1) {
+ sAuthenticated(su[UHost]);
+ if (flags & TCP_PENDING_TIMEOUT) {
+ P0(("removing call out\n"))
+ remove_call_out(#'quit);
+ flags -= TCP_PENDING_TIMEOUT;
+ }
+ msg(0, "_status_authorization", 0, rv);
+#endif
} else {
- string ho = u[UHost];
+ // FIXME: lynX wants to do that only for trusted hosts
+ string ho = su[UHost];
// FIXME: this actually needs to consider srv, too...
dns_resolve(ho, (:
// FIXME: psyc/parse::deliver is much better here
diff --git a/world/net/twitter/client.c b/world/net/twitter/client.c
index 4776ae2..fd963a1 100644
--- a/world/net/twitter/client.c
+++ b/world/net/twitter/client.c
@@ -72,7 +72,7 @@ object load(object usr, mapping opts) {
void check_status_update(string body, string headers, int http_status) {
P3(("twitter/client:parse_status_update(%O, %O, %O)\n", body, headers, http_status))
if (http_status != R_OK)
- sendmsg(user, "_error_twitter_status_update", "Error: failed to post status update on twitter.");
+ sendmsg(user, "_failure_update_twitter", "Unable to post status update on twitter.");
}
void status_update(string text) {
diff --git a/world/net/user.c b/world/net/user.c
index 8544738..b043218 100644
--- a/world/net/user.c
+++ b/world/net/user.c
@@ -1545,16 +1545,6 @@ logon() {
string t;
P2(("LOGON %O from %O\n", ME, query_ip_name() ))
- unless (legal_host(query_ip_number(), 0, 0, 0)) {
- // this happens when people reconnect during the shutdown
- // procedure.. and also when they are banned, but huh..
- // that hardly ever happens :)
- w("_error_rejected_address",
- "You are temporarily not permitted to connect here.");
- //"I'm afraid you are no longer welcome here.");
- return remove_interactive(ME);
- // and the object will deteriorate when user gives up..
- }
// shouldn't this be qScheme() instead? little paranoid TODO
// but then we would have to move qScheme() from the server.c's
// into the common.c's .. well, we could do that some day
@@ -1564,7 +1554,32 @@ logon() {
beQuiet = -1; // never turn off less interesting enter/leave echoes
// makeToken() isn't a good idea here, apparently
sTextPath(v("layout"), v("language"), t);
- // cannot if (greeting) this since jabber:iq:auth depends on this
+ unless (legal_host(query_ip_number(), 0, 0, 0)) {
+ // this happens when people reconnect during the shutdown
+ // procedure.. and also when they are banned, but huh..
+ // that hardly ever happens :)
+ //
+ // w() needs to be called *after* sTextPath
+ w("_error_rejected_address",
+ "You are currently not permitted to connect here.");
+ return remove_interactive(ME);
+ // and the object will deteriorate when user gives up..
+ //
+ // with the #'quit call_out.. or was it meant to
+ // deteriorate differently?
+ }
+#ifdef __TLS__
+ if (tls_query_connection_state(ME) == 1) {
+ if (tls_check_cipher(ME, t)) {
+ unless (beQuiet) w("_status_circuit_encryption_cipher");
+ } else {
+ // i bet jabber users will love this
+ w("_warning_circuit_encryption_cipher");
+ //return remove_interactive(ME);
+ }
+ }
+#endif
+ // cannot if (greeting) here this since jabber:iq:auth depends on this
// also greeting will only be defined after ::logon()
// (use another w() maybe?)
w("_notice_login", 0, ([ "_nick": MYNICK,
diff --git a/world/net/usercmd.i b/world/net/usercmd.i
index 1057027..c7b4b5c 100644
--- a/world/net/usercmd.i
+++ b/world/net/usercmd.i
@@ -2455,9 +2455,15 @@ friend(rm, entity, ni, trustee) {
// normally auto-acknowledge this request
sendmsg(entity, "_request_friendship_implied",
0, ([ "_nick": MYNICK, "_degree_availability": availability ]) );
- sendmsg(entity, "_request_status_person",
- 0, ([ "_nick": MYNICK ]) );
- // did i just say something about symmetry?
+ // don't know how this hack got here but it drives some
+ // jabber servers nuts as you are not supposed to probe
+ // people that you aren't subscribed to, yet
+ //sendmsg(entity, "_request_status_person",
+ // 0, ([ "_nick": MYNICK ]) );
+ // we should instead ensure we are always sending our presence
+ // status once a subscription is completed.. FIXME
+ // or we just scrap it all and redo context subscription
+ // strictly as suggested by the new specs.. sigh
#ifdef TRY_THIS
// currently friend() only gets called from
// online commands. so we skip the if