]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
periodic TNCC
authorDaniel Lenski <dlenski@gmail.com>
Wed, 8 Apr 2020 06:10:14 +0000 (23:10 -0700)
committerDaniel Lenski <dlenski@gmail.com>
Wed, 8 Apr 2020 18:13:59 +0000 (11:13 -0700)
- Factor out oncp_send_tncc_command function
- Reuse csd_token and csd_starturl for TNCC state (just like GP already does)
- Teach `tncc-emulate.py` to send the TNCC interval *back* to OpenConnect
- Apply `--force-trojan` (vpninfo->trojan_interval) to TNCC as well

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
auth-juniper.c
oncp.c
openconnect-internal.h
trojans/tncc-emulate.py

index 69a870813e8e637a85b243801cf5147c26b58424..bafbae5808125902433cd2853971821113dfe059 100644 (file)
@@ -286,9 +286,42 @@ static xmlNodePtr find_form_node(xmlDocPtr doc)
        return NULL;
 }
 
+int oncp_send_tncc_command(struct openconnect_info *vpninfo, int start)
+{
+       const char *dspreauth = vpninfo->csd_token, *dsurl = vpninfo->csd_starturl ? : "null";
+       struct oc_text_buf *buf;
+       buf = buf_alloc();
+
+       if (start) {
+               buf_append(buf, "start\n");
+               buf_append(buf, "IC=%s\n", vpninfo->hostname);
+               buf_append(buf, "Cookie=%s\n", dspreauth);
+               buf_append(buf, "DSSIGNIN=%s\n", dsurl);
+       } else {
+               buf_append(buf, "setcookie\n");
+               buf_append(buf, "Cookie=%s\n", dspreauth);
+       }
+
+       if (buf_error(buf)) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to allocate memory for communication with TNCC\n"));
+               return buf_free(buf);
+       }
+       if (cancellable_send(vpninfo, vpninfo->tncc_fd, buf->data, buf->pos) != buf->pos) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to send command to TNCC\n"));
+               buf_free(buf);
+               return -EIO;
+       }
+
+       /* Mainloop timers need to know the last Trojan was invoked */
+       vpninfo->last_trojan = time(NULL);
+       return buf_free(buf);
+}
+
 static int check_cookie_success(struct openconnect_info *vpninfo)
 {
-       const char *dslast = NULL, *dsfirst = NULL, *dsurl = NULL, *dsid = NULL, *dspreauth = NULL;
+       const char *dslast = NULL, *dsfirst = NULL, *dsurl = NULL, *dsid = NULL;
        struct oc_vpn_option *cookie;
        struct oc_text_buf *buf;
 
@@ -301,27 +334,24 @@ static int check_cookie_success(struct openconnect_info *vpninfo)
                        dsid = cookie->value;
                else if (!strcmp(cookie->option, "DSSignInUrl"))
                        dsurl = cookie->value;
-               else if (!strcmp(cookie->option, "DSPREAUTH"))
-                       dspreauth = cookie->value;
+               else if (!strcmp(cookie->option, "DSSIGNIN")) {
+                       free(vpninfo->csd_starturl);
+                       vpninfo->csd_starturl = strdup(cookie->value);
+               } else if (!strcmp(cookie->option, "DSPREAUTH")) {
+                       free(vpninfo->csd_token);
+                       vpninfo->csd_token = strdup(cookie->value);
+               }
        }
        if (!dsid)
                return -ENOENT;
 
-       buf = buf_alloc();
        if (vpninfo->tncc_fd != -1) {
-               buf_append(buf, "setcookie\n");
-               buf_append(buf, "Cookie=%s\n", dspreauth);
-               if (buf_error(buf))
-                       return buf_free(buf);
-               if (send(vpninfo->tncc_fd, buf->data, buf->pos, 0) < 0) {
-                       vpn_progress(vpninfo, PRG_ERR,
-                                    _("Failed to send cookie to TNCC\n"));
-                       /* Continue anyway */
-               }
-               buf_truncate(buf);
+               /* update TNCC once we get a DSID cookie */
+               oncp_send_tncc_command(vpninfo, 0);
        }
 
        /* XXX: Do these need escaping? Could they theoreetically have semicolons in? */
+       buf = buf_alloc();
        buf_append(buf, "DSID=%s", dsid);
        if (dsfirst)
                buf_append(buf, "; DSFirst=%s", dsfirst);
@@ -349,18 +379,10 @@ static int tncc_preauth(struct openconnect_info *vpninfo)
 {
        int sockfd[2];
        pid_t pid;
-       struct oc_text_buf *buf;
-       struct oc_vpn_option *cookie;
-       const char *dspreauth = NULL, *dssignin = "null";
+       const char *dspreauth = vpninfo->csd_token;
        char recvbuf[1024];
-       int len, count;
+       int len, count, ret;
 
-       for (cookie = vpninfo->cookies; cookie; cookie = cookie->next) {
-               if (!strcmp(cookie->option, "DSPREAUTH"))
-                       dspreauth = cookie->value;
-               else if (!strcmp(cookie->option, "DSSIGNIN"))
-                       dssignin = cookie->value;
-       }
        if (!dspreauth) {
                vpn_progress(vpninfo, PRG_ERR,
                             _("No DSPREAUTH cookie; not attempting TNCC\n"));
@@ -404,6 +426,12 @@ static int tncc_preauth(struct openconnect_info *vpninfo)
                        goto out;
                if (setenv("TNCC_HOSTNAME", vpninfo->localname, 1))
                        goto out;
+               if (!vpninfo->trojan_interval) {
+                       char is[32];
+                       snprintf(is, 32, "%d", vpninfo->trojan_interval);
+                       if (setenv("TNCC_INTERVAL", is, 1))
+                               goto out;
+               }
 
                execl(vpninfo->csd_wrapper, vpninfo->csd_wrapper, vpninfo->hostname, NULL);
        out:
@@ -413,27 +441,16 @@ static int tncc_preauth(struct openconnect_info *vpninfo)
        }
        waitpid(pid, NULL, 0);
        close(sockfd[0]);
+       vpninfo->tncc_fd = sockfd[1];
 
-       buf = buf_alloc();
-       buf_append(buf, "start\n");
-       buf_append(buf, "IC=%s\n", vpninfo->hostname);
-       buf_append(buf, "Cookie=%s\n", dspreauth);
-       buf_append(buf, "DSSIGNIN=%s\n", dssignin);
-       if (buf_error(buf)) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("Failed to allocate memory for communication with TNCC\n"));
-               close(sockfd[1]);
-               return buf_free(buf);
+       ret = oncp_send_tncc_command(vpninfo, 1);
+       if (ret < 0) {
+       err:
+               close(vpninfo->tncc_fd);
+               vpninfo->tncc_fd = -1;
+               return ret;
        }
 
-       if (cancellable_send(vpninfo, sockfd[1], buf->data, buf->pos) != buf->pos) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("Failed to send start command to TNCC\n"));
-               buf_free(buf);
-               close(sockfd[1]);
-               return -EIO;
-       }
-       buf_free(buf);
        vpn_progress(vpninfo, PRG_DEBUG,
                     _("Sent start; waiting for response from TNCC\n"));
 
@@ -443,16 +460,16 @@ static int tncc_preauth(struct openconnect_info *vpninfo)
        respfail:
                vpn_progress(vpninfo, PRG_ERR,
                             _("Failed to read response from TNCC\n"));
-               close(sockfd[1]);
-               return -EIO;
+               ret = -EIO;
+               goto err;
        }
 
        if (strcmp(recvbuf, "200")) {
                vpn_progress(vpninfo, PRG_ERR,
                             _("Received unsuccessful %s response from TNCC\n"),
                             recvbuf);
-               close(sockfd[1]);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        vpn_progress(vpninfo, PRG_TRACE, _("TNCC response 200 OK\n"));
@@ -474,7 +491,20 @@ static int tncc_preauth(struct openconnect_info *vpninfo)
                     _("Got new DSPREAUTH cookie from TNCC: %s\n"),
                     recvbuf);
        http_add_cookie(vpninfo, "DSPREAUTH", recvbuf, 1);
-       vpninfo->tncc_fd = sockfd[1];
+
+       /* Fourth line, if present, is the interval to rerun TNCC */
+       len = cancellable_gets(vpninfo, sockfd[1], recvbuf, sizeof(recvbuf));
+       if (len < 0)
+               goto respfail;
+       if (len > 0) {
+               int interval = atoi(recvbuf);
+               if (interval != vpninfo->trojan_interval) {
+                       vpninfo->trojan_interval = interval;
+                       vpn_progress(vpninfo, PRG_DEBUG,
+                                    _("Got reauth interval from TNCC: %d seconds\n"),
+                                    interval);
+               }
+       }
 
        count = 0;
        do {
diff --git a/oncp.c b/oncp.c
index 71571a4961232943f7140628ec655bf7fea090c3..72b5ed77c0e291dbbfc108d91e7b8e3cb8086b4a 100644 (file)
--- a/oncp.c
+++ b/oncp.c
@@ -915,6 +915,11 @@ int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
                   handle that */
                int receive_mtu = MAX(16384, vpninfo->ip_info.mtu);
 
+               if (trojan_check_deadline(vpninfo, timeout)) {
+                       /* Periodic TNCC */
+                       oncp_send_tncc_command(vpninfo, 0);
+               }
+
                len = receive_mtu + vpninfo->pkt_trailer;
                if (!vpninfo->cstp_pkt) {
                        vpninfo->cstp_pkt = malloc(sizeof(struct pkt) + len);
index 9d4f62b2ba2374c85ab1ace106beb1bd984ad58b..09b747d595d8c22f1c12c0972c31cd3f0e51484f 100644 (file)
@@ -901,6 +901,7 @@ int compress_packet(struct openconnect_info *vpninfo, int compr_type, struct pkt
 
 /* auth-juniper.c */
 int oncp_obtain_cookie(struct openconnect_info *vpninfo);
+int oncp_send_tncc_command(struct openconnect_info *vpninfo, int first);
 void oncp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
 
 /* oncp.c */
index 8040693e0e7ab29912d5b6bd25593621844f6f43..140a1b08726509b52635f13d1efc895caff052b6 100755 (executable)
@@ -270,7 +270,7 @@ class x509cert(object):
         self.subject = self.decode_names(tbs['subject'])
 
 class tncc(object):
-    def __init__(self, vpn_host, device_id=None, funk=None, platform=None, hostname=None, mac_addrs=[], certs=[]):
+    def __init__(self, vpn_host, device_id=None, funk=None, platform=None, hostname=None, mac_addrs=[], certs=[], interval=None):
         self.vpn_host = vpn_host
         self.path = '/dana-na/'
 
@@ -279,6 +279,7 @@ class tncc(object):
         self.hostname = hostname
         self.mac_addrs = mac_addrs
         self.avail_certs = certs
+        self.interval = interval
 
         self.deviceid = device_id
 
@@ -508,6 +509,12 @@ class tncc(object):
         # Parse the data returned into a key/value dict
         response = self.parse_response()
 
+        if 'interval' in response:
+            m = int(response['interval'])
+            logging.debug('Got interval of %d minutes' % m)
+            if self.interval is None or self.interval > m*60:
+                self.interval = m*60
+
         # msg has the stuff we want, it's base64 encoded
         logging.debug('Receiving packet -')
         msg_raw = base64.b64decode(response['msg'])
@@ -597,11 +604,15 @@ class tncc_server(object):
                 args[key] = val
         if cmd == 'start':
             cookie = self.tncc.get_cookie(args['Cookie'], args['DSSIGNIN'])
-            resp = '200\n3\n%s\n\n' % cookie.value
-            sock.send(resp.encode('ascii'))
+            resp = ['200', '3', cookie.value]
+            if self.tncc.interval is not None:
+                resp.append(str(self.tncc.interval))
+            sock.send(('\n'.join(resp) + '\n\n').encode('ascii'))
         elif cmd == 'setcookie':
-            # FIXME: Support for periodic updates
-            dsid_value = args['Cookie']
+            cookie = self.tncc.get_cookie(args['Cookie'],
+                                          self.tncc.find_cookie('DSSIGNIN'))
+        else:
+            logging.warn('Unknown command %r' % cmd)
 
 def fingerprint_checking_SSLSocket(_fingerprint):
     class SSLSocket(ssl.SSLSocket):
@@ -621,6 +632,8 @@ if __name__ == "__main__":
 
     funk = 'TNCC_FUNK' in os.environ and os.environ['TNCC_FUNK'] != '0'
 
+    interval = int(os.environ.get('TNCC_INTERVAL', 0)) or None
+
     platform = os.environ.get('TNCC_PLATFORM', platform.system() + ' ' + platform.release())
 
     if 'TNCC_HWADDR' in os.environ:
@@ -668,7 +681,7 @@ if __name__ == "__main__":
     # \HKEY_CURRENT_USER\Software\Juniper Networks\Device Id
     device_id = os.environ.get('TNCC_DEVICE_ID')
 
-    t = tncc(vpn_host, device_id, funk, platform, hostname, mac_addrs, certs)
+    t = tncc(vpn_host, device_id, funk, platform, hostname, mac_addrs, certs, interval)
     sock = socket.fromfd(0, socket.AF_UNIX, socket.SOCK_SEQPACKET)
     server = tncc_server(sock, t)
     while True: