Michael Wallner provided a patch that allows "SESS" to be set with
CURLOPT_COOKIELIST, which then makes all session cookies get cleared. (slightly
edited by me, and the re-indent in cookie.c was also done by me)
diff --git a/lib/cookie.c b/lib/cookie.c
index a8519c4..d934868 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -733,68 +733,81 @@
 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
                                    char *host, char *path, bool secure)
 {
-   struct Cookie *newco;
-   struct Cookie *co;
-   time_t now = time(NULL);
-   struct Cookie *mainco=NULL;
+  struct Cookie *newco;
+  struct Cookie *co;
+  time_t now = time(NULL);
+  struct Cookie *mainco=NULL;
 
-   if(!c || !c->cookies)
-      return NULL; /* no cookie struct or no cookies in the struct */
+  if(!c || !c->cookies)
+    return NULL; /* no cookie struct or no cookies in the struct */
 
-   co = c->cookies;
+  co = c->cookies;
 
-   while(co) {
-     /* only process this cookie if it is not expired or had no expire
-        date AND that if the cookie requires we're secure we must only
-        continue if we are! */
-     if( (co->expires<=0 || (co->expires> now)) &&
-         (co->secure?secure:TRUE) ) {
+  while(co) {
+    /* only process this cookie if it is not expired or had no expire
+       date AND that if the cookie requires we're secure we must only
+       continue if we are! */
+    if( (co->expires<=0 || (co->expires> now)) &&
+        (co->secure?secure:TRUE) ) {
 
-       /* now check if the domain is correct */
-       if(!co->domain ||
-          (co->tailmatch && tailmatch(co->domain, host)) ||
-          (!co->tailmatch && strequal(host, co->domain)) ) {
-         /* the right part of the host matches the domain stuff in the
-            cookie data */
+      /* now check if the domain is correct */
+      if(!co->domain ||
+         (co->tailmatch && tailmatch(co->domain, host)) ||
+         (!co->tailmatch && strequal(host, co->domain)) ) {
+        /* the right part of the host matches the domain stuff in the
+           cookie data */
 
-         /* now check the left part of the path with the cookies path
-            requirement */
-         if(!co->path ||
-            checkprefix(co->path, path) ) {
+        /* now check the left part of the path with the cookies path
+           requirement */
+        if(!co->path ||
+           checkprefix(co->path, path) ) {
 
-           /* and now, we know this is a match and we should create an
-              entry for the return-linked-list */
+          /* and now, we know this is a match and we should create an
+             entry for the return-linked-list */
 
-           newco = (struct Cookie *)malloc(sizeof(struct Cookie));
-           if(newco) {
-             /* first, copy the whole source cookie: */
-             memcpy(newco, co, sizeof(struct Cookie));
+          newco = (struct Cookie *)malloc(sizeof(struct Cookie));
+          if(newco) {
+            /* first, copy the whole source cookie: */
+            memcpy(newco, co, sizeof(struct Cookie));
 
-             /* then modify our next */
-             newco->next = mainco;
+            /* then modify our next */
+            newco->next = mainco;
 
-             /* point the main to us */
-             mainco = newco;
-           }
-           else {
-              /* failure, clear up the allocated chain and return NULL */
-             while(mainco) {
-               co = mainco->next;
-               free(mainco);
-               mainco = co;
-             }
+            /* point the main to us */
+            mainco = newco;
+          }
+          else {
+            /* failure, clear up the allocated chain and return NULL */
+            while(mainco) {
+              co = mainco->next;
+              free(mainco);
+              mainco = co;
+            }
 
-             return NULL;
-           }
-         }
-       }
-     }
-     co = co->next;
-   }
+            return NULL;
+          }
+        }
+      }
+    }
+    co = co->next;
+  }
 
-   return mainco; /* return the new list */
+  return mainco; /* return the new list */
 }
 
+/*****************************************************************************
+ *
+ * Curl_cookie_clearall()
+ *
+ * Clear all existing cookies and reset the counter.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearall(struct CookieInfo *cookies)
+{
+  Curl_cookie_freelist(cookies->cookies);
+  cookies->cookies = NULL;
+  cookies->numcookies = 0;
+}
 
 /*****************************************************************************
  *
@@ -806,17 +819,56 @@
 
 void Curl_cookie_freelist(struct Cookie *co)
 {
-   struct Cookie *next;
-   if(co) {
-      while(co) {
-         next = co->next;
-         free(co); /* we only free the struct since the "members" are all
+  struct Cookie *next;
+  if(co) {
+    while(co) {
+      next = co->next;
+      free(co); /* we only free the struct since the "members" are all
                       just copied! */
-         co = next;
-      }
-   }
+      co = next;
+    }
+  }
 }
 
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearsess()
+ *
+ * Free all session cookies in the cookies list.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearsess(struct CookieInfo *cookies)
+{
+  struct Cookie *first, *curr, *next, *prev = NULL;
+
+  if(!cookies->cookies)
+    return;
+
+  first = curr = prev = cookies->cookies;
+
+  for(; curr; curr = next) {
+    next = curr->next;
+    if(!curr->expires) {
+      if(first == curr)
+        first = next;
+
+      if(prev == curr)
+        prev = next;
+      else
+        prev->next = next;
+
+      free(curr);
+      cookies->numcookies--;
+    }
+    else
+      prev = curr;
+  }
+
+  cookies->cookies = first;
+}
+
+
 /*****************************************************************************
  *
  * Curl_cookie_cleanup()
@@ -826,20 +878,20 @@
  ****************************************************************************/
 void Curl_cookie_cleanup(struct CookieInfo *c)
 {
-   struct Cookie *co;
-   struct Cookie *next;
-   if(c) {
-      if(c->filename)
-         free(c->filename);
-      co = c->cookies;
+  struct Cookie *co;
+  struct Cookie *next;
+  if(c) {
+    if(c->filename)
+      free(c->filename);
+    co = c->cookies;
 
-      while(co) {
-         next = co->next;
-         freecookie(co);
-         co = next;
-      }
-      free(c); /* free the base struct as well */
-   }
+    while(co) {
+      next = co->next;
+      freecookie(co);
+      co = next;
+    }
+    free(c); /* free the base struct as well */
+  }
 }
 
 /* get_netscape_format()
@@ -850,24 +902,24 @@
 */
 static char *get_netscape_format(const struct Cookie *co)
 {
-   return aprintf(
-     "%s%s\t" /* domain */
-     "%s\t"   /* tailmatch */
-     "%s\t"   /* path */
-     "%s\t"   /* secure */
-     "%" FORMAT_OFF_T "\t"   /* expires */
-     "%s\t"   /* name */
-     "%s",    /* value */
-     /* Make sure all domains are prefixed with a dot if they allow
-        tailmatching. This is Mozilla-style. */
-     (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
-     co->domain?co->domain:"unknown",
-     co->tailmatch?"TRUE":"FALSE",
-     co->path?co->path:"/",
-     co->secure?"TRUE":"FALSE",
-     co->expires,
-     co->name,
-     co->value?co->value:"");
+  return aprintf(
+    "%s%s\t" /* domain */
+    "%s\t"   /* tailmatch */
+    "%s\t"   /* path */
+    "%s\t"   /* secure */
+    "%" FORMAT_OFF_T "\t"   /* expires */
+    "%s\t"   /* name */
+    "%s",    /* value */
+    /* Make sure all domains are prefixed with a dot if they allow
+       tailmatching. This is Mozilla-style. */
+    (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
+    co->domain?co->domain:"unknown",
+    co->tailmatch?"TRUE":"FALSE",
+    co->path?co->path:"/",
+    co->secure?"TRUE":"FALSE",
+    co->expires,
+    co->name,
+    co->value?co->value:"");
 }
 
 /*