From 5ed19841bf0292dd94dd04bf8518c1704a9014fa Mon Sep 17 00:00:00 2001
From: Henri Doreau <henri.doreau@cea.fr>
Date: Tue, 13 Aug 2013 14:07:15 +0200
Subject: [PATCH] Publish results (almost) directly on facebook.

W00t how cool LOL!! :D xD
---
 NmapOps.cc              |  3 ++
 NmapOps.h               |  3 ++
 nmap.cc                 | 16 ++++++++-
 nsock/include/nsock.h   |  3 +-
 nsock/src/nsock_write.c |  3 +-
 output.cc               | 94 +++++++++++++++++++++++++++++++++++++++++++++++--
 output.h                |  2 +-
 7 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/NmapOps.cc b/NmapOps.cc
index a8a5c19..5b957bf 100644
--- a/NmapOps.cc
+++ b/NmapOps.cc
@@ -367,6 +367,9 @@ void NmapOps::Initialize() {
   release_memory = false;
   topportlevel = -1;
 #ifndef NOLUA
+  facebook = 0;
+  fb_uid = NULL;
+  fb_tkn = NULL;
   script = 0;
   scriptargs = NULL;
   scriptversion = 0;
diff --git a/NmapOps.h b/NmapOps.h
index d905d0d..adeb935 100644
--- a/NmapOps.h
+++ b/NmapOps.h
@@ -195,6 +195,9 @@ class NmapOps {
      Nmap will still do an ARP ping scan of a local network even when
      the pref is SEND_IP_WEAK */
   int sendpref;
+  bool facebook;
+  const char *fb_uid;
+  const char *fb_tkn;
   bool packetTrace() { return (debugging >= 3)? true : pTrace;  }
   bool versionTrace() { return packetTrace()? true : vTrace;  }
 #ifndef NOLUA
diff --git a/nmap.cc b/nmap.cc
index 90fcde3..1acc6b5 100644
--- a/nmap.cc
+++ b/nmap.cc
@@ -551,6 +551,7 @@ void parse_options(int argc, char **argv) {
   int option_index;
 
   struct option long_options[] = {
+    {"facebook", required_argument, 0, 0},
     {"version", no_argument, 0, 'V'},
     {"verbose", no_argument, 0, 'v'},
     {"datadir", required_argument, 0, 0},
@@ -786,6 +787,17 @@ void parse_options(int argc, char **argv) {
           if (o.ttl < 0 || o.ttl > 255) {
             fatal("ttl option must be a number between 0 and 255 (inclusive)");
           }
+        } else if (strcmp(long_options[option_index].name, "facebook") == 0) {
+          char *sep;
+
+          sep = strstr(optarg, "/");
+          if (sep == NULL)
+            fatal("Invalid format, use: --facebook <uid/token>");
+
+          optarg[sep - optarg] = '\0'; /* I don't care, this patch is a joke */
+          o.fb_uid = strdup(optarg);
+          o.fb_tkn = strdup(sep + 1);
+          o.facebook = true;
         } else if (strcmp(long_options[option_index].name, "datadir") == 0) {
           o.datadir = strdup(optarg);
         } else if (strcmp(long_options[option_index].name, "servicedb") == 0) {
@@ -1430,7 +1442,7 @@ void  apply_delayed_options() {
 
   /* Open the log files, now that we know whether the user wants them appended
      or overwritten */
-  if (delayed_options.normalfilename) {
+  if (delayed_options.normalfilename || o.facebook) {
     log_open(LOG_NORMAL, o.append_output, delayed_options.normalfilename);
     free(delayed_options.normalfilename);
   }
@@ -2104,6 +2116,8 @@ int nmap_main(int argc, char *argv[]) {
 
   eth_close_cached();
 
+  log_close(LOG_NORMAL);
+
   if (o.release_memory) {
     nmap_free_mem();
   }
diff --git a/nsock/include/nsock.h b/nsock/include/nsock.h
index e34f090..7fa5fcc 100644
--- a/nsock/include/nsock.h
+++ b/nsock/include/nsock.h
@@ -591,7 +591,8 @@ nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handl
 /* Same as nsock_write except you can use a printf-style format and you can only
  * use this for ASCII strings */
 nsock_event_id nsock_printf(nsock_pool nsp, nsock_iod nsiod,
-                            nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... );
+                            nsock_ev_handler handler, int timeout_msecs,
+                            void *userdata, const char *format, ... );
 
 /* Send back an NSE_TYPE_TIMER after the number of milliseconds specified.  Of
  * course it can also return due to error, cancellation, etc. */
diff --git a/nsock/src/nsock_write.c b/nsock/src/nsock_write.c
index fc88348..3773485 100644
--- a/nsock/src/nsock_write.c
+++ b/nsock/src/nsock_write.c
@@ -163,7 +163,8 @@ nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod,
 
 /* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */
 nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
-          nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ...) {
+          nsock_ev_handler handler, int timeout_msecs, void *userdata,
+          const char *format, ...) {
   mspool *nsp = (mspool *)ms_pool;
   msiod *nsi = (msiod *)ms_iod;
   msevent *nse;
diff --git a/output.cc b/output.cc
index d07fb41..11f72aa 100644
--- a/output.cc
+++ b/output.cc
@@ -149,6 +149,9 @@
 #include <list>
 #include <sstream>
 
+#define FB_HOST     "graph.facebook.com"
+#define FB_PORT     80
+
 extern NmapOps o;
 static const char *logtypes[LOG_NUM_FILES] = LOG_NAMES;
 
@@ -230,6 +233,85 @@ static char *servicefp_sf_remove(const char *str) {
   return temp;
 }
 
+static int urlencode_fread(char *dst, FILE *stream) {
+  int idx = 0;
+  size_t readlen;
+  char chunk[128];
+
+  while ((readlen = fread(chunk, 1, sizeof(chunk), stream)) > 0) {
+    unsigned int i;
+
+    for (i = 0; i < readlen; i++) {
+      if (isalnum(chunk[i]))
+        dst[idx++] = chunk[i];
+      else
+        idx += sprintf(dst + idx, "%%%02X", (int)chunk[i]);
+    }
+  }
+  return 0;
+}
+
+static void fb_connect_hdl(nsock_pool nsp, nsock_event nse, void *udata) {
+  // nothing to do
+}
+
+static void fb_publish_hdl(nsock_pool nsp, nsock_event nse, void *udata) {
+  // nothing to do
+}
+
+static void facebook_publish(FILE *stream) {
+  int rc;
+  long fsize;
+  char *msg;
+  nsock_pool nsp;
+  nsock_iod iod;
+  struct sockaddr_storage ss;
+  size_t sslen = sizeof(ss);
+
+  fsize = ftell(stream);
+  msg = (char *)safe_zalloc((3 * fsize) + 1);
+
+  rewind(stream);
+  urlencode_fread(msg, stream);
+
+  nsp = nsp_new(NULL);
+  iod = nsi_new(nsp, NULL);
+
+  nsock_set_log_function(nsp, nmap_nsock_stderr_logger);
+  nmap_adjust_loglevel(nsp, true);
+
+  nsp_setdevice(nsp, o.device);
+  
+  if (o.proxy_chain)
+    nsp_set_proxychain(nsp, o.proxy_chain);
+
+  rc = resolve(FB_HOST, FB_PORT, &ss, &sslen, AF_INET);
+  if (rc) {
+    // Facebook unreachable! Life's too hard, let's just DIE!
+    fatal("resolve(%s): %s\n", FB_HOST, gai_strerror(rc));
+  }
+
+  nsock_connect_tcp(nsp, iod, fb_connect_hdl, 5000, NULL, (struct sockaddr *)&ss,
+                    sslen, FB_PORT);
+
+  nsock_printf(nsp, iod, fb_publish_hdl, 10000, NULL,
+               "POST /%s/feed HTTP/1.1\r\n"
+               "Host: %s\r\n"
+               "Content-type: application/x-www-form-urlencoded\r\n"
+               "access_token=%s&message=%s\r\n\r\n",
+               o.fb_uid,
+               FB_HOST,
+               o.fb_tkn,
+               msg);
+
+  nsock_loop(nsp, 10000);
+
+  nsi_delete(iod, 0);
+  nsp_delete(nsp);
+
+  free(msg);
+}
+
 // Prints an XML <service> element for the information given in
 // serviceDeduction.  This function should only be called if ether
 // the service name or the service fingerprint is non-null.
@@ -1035,9 +1117,13 @@ void log_close(int logt) {
   int i;
   if (logt < 0 || logt > LOG_FILE_MASK)
     return;
-  for (i = 0; logt; logt >>= 1, i++)
-    if (o.logfd[i] && (logt & 1))
+  for (i = 0; logt; logt >>= 1, i++) {
+    if (o.logfd[i] && (logt & 1)) {
+      if (o.facebook && (logt & LOG_NORMAL)) 
+        facebook_publish(o.logfd[i]);
       fclose(o.logfd[i]);
+    }
+  }
 }
 
 /* Flush the given log stream(s).  In other words, all buffered output
@@ -1095,7 +1181,9 @@ int log_open(int logt, int append, char *filename) {
   }
   if (o.logfd[i])
     fatal("Only one %s output filename allowed", logtypes[i]);
-  if (*filename == '-' && *(filename + 1) == '\0') {
+  if (filename == NULL) {
+    o.logfd[i] = tmpfile();
+  } else if (*filename == '-' && *(filename + 1) == '\0') {
     o.logfd[i] = stdout;
     o.nmap_stdout = fopen(DEVNULL, "w");
     if (!o.nmap_stdout)
diff --git a/output.h b/output.h
index a5d224a..78b65f8 100644
--- a/output.h
+++ b/output.h
@@ -142,7 +142,7 @@
 #define LOG_SKID_NOXLT 4096
 #define LOG_MAX LOG_SKID_NOXLT /* The maximum log type value */
 
-#define LOG_PLAIN LOG_NORMAL|LOG_SKID|LOG_STDOUT
+#define LOG_PLAIN (LOG_NORMAL|LOG_SKID|LOG_STDOUT)
 
 #define LOG_NAMES {"normal", "machine", "$Cr!pT |<!dd!3", "XML"}
 
-- 
1.7.11.7

