package/ushare: add libupnp 1.14.x support
authorFabrice Fontaine <fontaine.fabrice@gmail.com>
Mon, 25 Jan 2021 19:49:48 +0000 (20:49 +0100)
committerYann E. MORIN <yann.morin.1998@free.fr>
Mon, 25 Jan 2021 21:23:22 +0000 (22:23 +0100)
This switch is needed to fix CallStranger a.k.a. CVE-2020-12695

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
package/ushare/0004-switch-to-libupnp-1.14.x-API.patch [new file with mode: 0644]

diff --git a/package/ushare/0004-switch-to-libupnp-1.14.x-API.patch b/package/ushare/0004-switch-to-libupnp-1.14.x-API.patch
new file mode 100644 (file)
index 0000000..e200bb1
--- /dev/null
@@ -0,0 +1,433 @@
+From 4643b9cb9e6c0331fd663437a7ed8061b9edf971 Mon Sep 17 00:00:00 2001
+From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+Date: Mon, 24 Aug 2020 19:26:03 +0200
+Subject: [PATCH] switch to libupnp 1.14.x API
+
+Use the new libupnp 1.14.x API (i.e. UpnpInit2) to allow ushare to be
+protected against CallStranger a.k.a. CVE-2020-12695
+
+Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+[Retrieved from:
+https://github.com/ddugovic/uShare/commit/4643b9cb9e6c0331fd663437a7ed8061b9edf971]
+---
+ configure      |  2 --
+ src/http.c     | 50 +++++++++++++++++++++++++++++++-------------------
+ src/http.h     | 24 ++++++++++++++++++------
+ src/services.c | 28 ++++++++++++++++++----------
+ src/services.h |  6 +++---
+ src/ushare.c   | 36 ++++++++++++++++++------------------
+ src/ushare.h   |  2 +-
+ 7 files changed, 89 insertions(+), 59 deletions(-)
+
+diff --git a/configure b/configure
+index 20a08ed..4a3efe0 100755
+--- a/configure
++++ b/configure
+@@ -638,8 +638,6 @@ fi
+ echolog "Checking for libixml ..."
+ check_lib upnp/ixml.h ixmlRelaxParser -lixml || die "Error, can't find libixml !"
+-echolog "Checking for libthreadutil ..."
+-check_lib upnp/ThreadPool.h ThreadPoolAdd "-lthreadutil -lpthread" || die "Error, can't find libthreadutil !"
+ add_extralibs -lpthread
+ libupnp_min_version="1.4.2"
+diff --git a/src/http.c b/src/http.c
+index 8a4e67d..1e5b350 100644
+--- a/src/http.c
++++ b/src/http.c
+@@ -68,17 +68,19 @@ struct web_file_t {
+ static inline void
+-set_info_file (struct File_Info *info, const size_t length,
++set_info_file (UpnpFileInfo *info, const size_t length,
+                const char *content_type)
+ {
+-  info->file_length = length;
+-  info->last_modified = 0;
+-  info->is_directory = 0;
+-  info->is_readable = 1;
+-  info->content_type = ixmlCloneDOMString (content_type);
++  UpnpFileInfo_set_FileLength(info, length);
++  UpnpFileInfo_set_LastModified(info, 0);
++  UpnpFileInfo_set_IsDirectory(info, 0);
++  UpnpFileInfo_set_IsReadable(info, 1);
++  UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString (content_type));
+ }
+-int http_get_info (const char *filename, struct File_Info *info)
++int http_get_info (const char *filename, UpnpFileInfo *info,
++                   const void* cookie __attribute__((unused)),
++                   const void** requestCookie __attribute__((unused)))
+ {
+   extern struct ushare_t *ut;
+   struct upnp_entry_t *entry = NULL;
+@@ -143,15 +145,15 @@ int http_get_info (const char *filename, struct File_Info *info)
+   {
+     if (errno != EACCES)
+       return -1;
+-    info->is_readable = 0;
++    UpnpFileInfo_set_IsReadable(info, 0);
+   }
+   else
+-    info->is_readable = 1;
++    UpnpFileInfo_set_IsReadable(info, 1);
+   /* file exist and can be read */
+-  info->file_length = st.st_size;
+-  info->last_modified = st.st_mtime;
+-  info->is_directory = S_ISDIR (st.st_mode);
++  UpnpFileInfo_set_FileLength(info, st.st_size);
++  UpnpFileInfo_set_LastModified(info, st.st_mtime);
++  UpnpFileInfo_set_IsDirectory(info, S_ISDIR (st.st_mode));
+   protocol = 
+ #ifdef HAVE_DLNA
+@@ -172,11 +174,11 @@ int http_get_info (const char *filename, struct File_Info *info)
+   if (content_type)
+   {
+-    info->content_type = ixmlCloneDOMString (content_type);
++    UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString (content_type));
+     free (content_type);
+   }
+   else
+-    info->content_type = ixmlCloneDOMString ("");
++    UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString (""));
+   return 0;
+ }
+@@ -197,7 +199,9 @@ get_file_memory (const char *fullpath, const char *description,
+   return ((UpnpWebFileHandle) file);
+ }
+-UpnpWebFileHandle http_open (const char *filename, enum UpnpOpenFileMode mode)
++UpnpWebFileHandle http_open (const char *filename, enum UpnpOpenFileMode mode,
++                             const void* cookie __attribute__((unused)),
++                             const void* requestCookie __attribute__((unused)))
+ {
+   extern struct ushare_t *ut;
+   struct upnp_entry_t *entry = NULL;
+@@ -250,7 +254,9 @@ UpnpWebFileHandle http_open (const char *filename, enum UpnpOpenFileMode mode)
+   return ((UpnpWebFileHandle) file);
+ }
+-int http_read (UpnpWebFileHandle fh, char *buf, size_t buflen)
++int http_read (UpnpWebFileHandle fh, char *buf, size_t buflen,
++               const void* cookie __attribute__((unused)),
++               const void* requestCookie __attribute__((unused)))
+ {
+   struct web_file_t *file = (struct web_file_t *) fh;
+   ssize_t len = -1;
+@@ -285,14 +291,18 @@ int http_read (UpnpWebFileHandle fh, char *buf, size_t buflen)
+ int http_write (UpnpWebFileHandle fh __attribute__((unused)),
+             char *buf __attribute__((unused)),
+-            size_t buflen __attribute__((unused)))
++            size_t buflen __attribute__((unused)),
++            const void* cookie __attribute__((unused)),
++            const void* requestCookie __attribute__((unused)))
+ {
+   log_verbose ("http write\n");
+   return 0;
+ }
+-int http_seek (UpnpWebFileHandle fh, off_t offset, int origin)
++int http_seek (UpnpWebFileHandle fh, off_t offset, int origin,
++               const void* cookie __attribute__((unused)),
++               const void* requestCookie __attribute__((unused)))
+ {
+   struct web_file_t *file = (struct web_file_t *) fh;
+   off_t newpos = -1;
+@@ -366,7 +376,9 @@ int http_seek (UpnpWebFileHandle fh, off_t offset, int origin)
+   return 0;
+ }
+-int http_close (UpnpWebFileHandle fh)
++int http_close (UpnpWebFileHandle fh,
++                const void* cookie __attribute__((unused)),
++                const void* requestCookie __attribute__((unused)))
+ {
+   struct web_file_t *file = (struct web_file_t *) fh;
+diff --git a/src/http.h b/src/http.h
+index 32d6bcc..c912a7b 100644
+--- a/src/http.h
++++ b/src/http.h
+@@ -25,18 +25,30 @@
+ #include <upnp/upnp.h>
+ #include <upnp/upnptools.h>
+-int http_get_info (const char *filename, struct File_Info *info);
++int http_get_info (const char *filename, UpnpFileInfo *info,
++      const void* cookie __attribute__((unused)),
++      const void** requestCookie __attribute__((unused)));
+-UpnpWebFileHandle http_open (const char *filename, enum UpnpOpenFileMode mode);
++UpnpWebFileHandle http_open (const char *filename, enum UpnpOpenFileMode mode,
++      const void* cookie __attribute__((unused)),
++      const void* requestCookie __attribute__((unused)));
+-int http_read (UpnpWebFileHandle fh, char *buf, size_t buflen);
++int http_read (UpnpWebFileHandle fh, char *buf, size_t buflen,
++      const void* cookie __attribute__((unused)),
++      const void* requestCookie __attribute__((unused)));
+-int http_seek (UpnpWebFileHandle fh, off_t offset, int origin);
++int http_seek (UpnpWebFileHandle fh, off_t offset, int origin,
++      const void* cookie __attribute__((unused)),
++      const void* requestCookie __attribute__((unused)));
+ int http_write (UpnpWebFileHandle fh __attribute__((unused)),
+       char *buf __attribute__((unused)),
+-      size_t buflen __attribute__((unused)));
++      size_t buflen __attribute__((unused)),
++      const void* cookie __attribute__((unused)),
++      const void* requestCookie __attribute__((unused)));
+-int http_close (UpnpWebFileHandle fh);
++int http_close (UpnpWebFileHandle fh,
++      const void* cookie __attribute__((unused)),
++      const void* requestCookie __attribute__((unused)));
+ #endif /* _HTTP_H_ */
+diff --git a/src/services.c b/src/services.c
+index aec9cf8..287df55 100644
+--- a/src/services.c
++++ b/src/services.c
+@@ -62,25 +62,28 @@ static struct service_t services[] = {
+ };
+ bool
+-find_service_action (struct Upnp_Action_Request *request,
++find_service_action (UpnpActionRequest *request,
+                      struct service_t **service,
+                      struct service_action_t **action)
+ {
+   int c, d;
++  const char *actionName = NULL;
+   *service = NULL;
+   *action = NULL;
++  
++  actionName = UpnpActionRequest_get_ActionName_cstr(request);
+-  if (!request || !request->ActionName)
++  if (!request || !actionName)
+     return false;
+   for (c = 0; services[c].id != NULL; c++)
+-    if (!strcmp (services[c].id, request->ServiceID))
++    if (!strcmp (services[c].id, UpnpActionRequest_get_ServiceID_cstr(request)))
+     {
+       *service = &services[c];
+       for (d = 0; services[c].actions[d].name; d++)
+       {
+-        if (!strcmp (services[c].actions[d].name, request->ActionName))
++        if (!strcmp (services[c].actions[d].name, actionName))
+         {
+           *action = &services[c].actions[d];
+           return true;
+@@ -97,6 +100,7 @@ upnp_add_response (struct action_event_t *event, char *key, const char *value)
+ {
+   char *val;
+   int res;
++  IXML_Document* actionResult = NULL;
+   if (!event || !event->status || !key || !value)
+     return false;
+@@ -105,8 +109,9 @@ upnp_add_response (struct action_event_t *event, char *key, const char *value)
+   if (!val)
+     return false;
+-  res = UpnpAddToActionResponse (&event->request->ActionResult,
+-                                 event->request->ActionName,
++  actionResult = UpnpActionRequest_get_ActionResult(event->request);
++  res = UpnpAddToActionResponse (&actionResult,
++                                 UpnpActionRequest_get_ActionName_cstr(event->request),
+                                  event->service->type, key, val);
+   if (res != UPNP_E_SUCCESS)
+@@ -120,14 +125,17 @@ upnp_add_response (struct action_event_t *event, char *key, const char *value)
+ }
+ char *
+-upnp_get_string (struct Upnp_Action_Request *request, const char *key)
++upnp_get_string (UpnpActionRequest *request, const char *key)
+ {
+   IXML_Node *node = NULL;
++  IXML_Document *actionRequest = NULL;
+-  if (!request || !request->ActionRequest || !key)
++  actionRequest = UpnpActionRequest_get_ActionRequest(request);
++
++  if (!request || !actionRequest || !key)
+     return NULL;
+-  node = (IXML_Node *) request->ActionRequest;
++  node = (IXML_Node *) actionRequest;
+   if (!node)
+   {
+     log_verbose ("Invalid action request document\n");
+@@ -157,7 +165,7 @@ upnp_get_string (struct Upnp_Action_Request *request, const char *key)
+ }
+ int
+-upnp_get_ui4 (struct Upnp_Action_Request *request, const char *key)
++upnp_get_ui4 (UpnpActionRequest *request, const char *key)
+ {
+   char *value;
+   int val;
+diff --git a/src/services.h b/src/services.h
+index 89c072e..d5726b4 100644
+--- a/src/services.h
++++ b/src/services.h
+@@ -39,15 +39,15 @@ struct service_t {
+ #define SERVICE_CONTENT_TYPE "text/xml"
+-bool find_service_action (struct Upnp_Action_Request *request,
++bool find_service_action (UpnpActionRequest *request,
+                           struct service_t **service,
+                           struct service_action_t **action);
+ bool upnp_add_response (struct action_event_t *event,
+                         char *key, const char *value);
+-char * upnp_get_string (struct Upnp_Action_Request *request, const char *key);
++char * upnp_get_string (UpnpActionRequest *request, const char *key);
+-int upnp_get_ui4 (struct Upnp_Action_Request *request, const char *key);
++int upnp_get_ui4 (UpnpActionRequest *request, const char *key);
+ #endif /* _SERVICES_H_ */
+diff --git a/src/ushare.c b/src/ushare.c
+index 28fd67e..92e2345 100644
+--- a/src/ushare.c
++++ b/src/ushare.c
+@@ -177,7 +177,7 @@ ushare_signal_exit (void)
+ }
+ static void
+-handle_action_request (struct Upnp_Action_Request *request)
++handle_action_request (UpnpActionRequest *request)
+ {
+   struct service_t *service;
+   struct service_action_t *action;
+@@ -187,25 +187,25 @@ handle_action_request (struct Upnp_Action_Request *request)
+   if (!request || !ut)
+     return;
+-  if (request->ErrCode != UPNP_E_SUCCESS)
++  if (UpnpActionRequest_get_ErrCode(request) != UPNP_E_SUCCESS)
+     return;
+-  if (strcmp (request->DevUDN + 5, ut->udn))
++  if (strcmp (UpnpActionRequest_get_DevUDN_cstr(request) + 5, ut->udn))
+     return;
+-  ip = (*(struct sockaddr_in *)&request->CtrlPtIPAddr).sin_addr.s_addr;
++  ip = (*(struct sockaddr_in *)UpnpActionRequest_get_CtrlPtIPAddr(request)).sin_addr.s_addr;
+   ip = ntohl (ip);
+   sprintf (val, "%d.%d.%d.%d",
+            (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
+   if (ut->verbose)
+   {
+-    DOMString str = ixmlPrintDocument (request->ActionRequest);
++    DOMString str = ixmlPrintDocument (UpnpActionRequest_get_ActionRequest(request));
+     log_verbose ("***************************************************\n");
+     log_verbose ("**             New Action Request                **\n");
+     log_verbose ("***************************************************\n");
+-    log_verbose ("ServiceID: %s\n", request->ServiceID);
+-    log_verbose ("ActionName: %s\n", request->ActionName);
++    log_verbose ("ServiceID: %s\n", UpnpActionRequest_get_ServiceID_cstr(request));
++    log_verbose ("ActionName: %s\n", UpnpActionRequest_get_ActionName_cstr(request));
+     log_verbose ("CtrlPtIP: %s\n", val);
+     log_verbose ("Action Request:\n%s\n", str);
+     ixmlFreeDOMString (str);
+@@ -220,11 +220,11 @@ handle_action_request (struct Upnp_Action_Request *request)
+       event.service = service;
+       if (action->function (&event) && event.status)
+-        request->ErrCode = UPNP_E_SUCCESS;
++        UpnpActionRequest_set_ErrCode(request, UPNP_E_SUCCESS);
+       if (ut->verbose)
+       {
+-        DOMString str = ixmlPrintDocument (request->ActionResult);
++        DOMString str = ixmlPrintDocument (UpnpActionRequest_get_ActionResult(request));
+         log_verbose ("Action Result:\n%s", str);
+         log_verbose ("***************************************************\n");
+         log_verbose ("\n");
+@@ -235,22 +235,22 @@ handle_action_request (struct Upnp_Action_Request *request)
+     }
+   if (service) /* Invalid Action name */
+-    strcpy (request->ErrStr, "Unknown Service Action");
++    UpnpActionRequest_strcpy_ErrStr(request, "Unknown Service Action");
+   else /* Invalid Service name */
+-    strcpy (request->ErrStr, "Unknown Service ID");
++    UpnpActionRequest_strcpy_ErrStr(request, "Unknown Service ID");
+-  request->ActionResult = NULL;
+-  request->ErrCode = UPNP_SOAP_E_INVALID_ACTION;
++  UpnpActionRequest_set_ActionResult(request, NULL);
++  UpnpActionRequest_set_ErrCode(request, UPNP_SOAP_E_INVALID_ACTION);
+ }
+ static int
+-device_callback_event_handler (Upnp_EventType type, void *event,
++device_callback_event_handler (Upnp_EventType type, const void *event,
+                                void *cookie __attribute__((unused)))
+ {
+   switch (type)
+     {
+     case UPNP_CONTROL_ACTION_REQUEST:
+-      handle_action_request ((struct Upnp_Action_Request *) event);
++      handle_action_request ((UpnpActionRequest *) event);
+       break;
+     case UPNP_CONTROL_ACTION_COMPLETE:
+     case UPNP_EVENT_SUBSCRIPTION_REQUEST:
+@@ -323,7 +323,7 @@ init_upnp (struct ushare_t *ut)
+ #endif /* HAVE_DLNA */
+   log_info (_("Initializing UPnP subsystem ...\n"));
+-  res = UpnpInit (ut->ip, ut->port);
++  res = UpnpInit2 (ut->interface, ut->port);
+   if (res != UPNP_E_SUCCESS)
+   {
+     log_error (_("Cannot initialize UPnP subsystem\n"));
+@@ -351,7 +351,7 @@ init_upnp (struct ushare_t *ut)
+   log_info (_("UPnP MediaServer listening on %s:%d\n"),
+             UpnpGetServerIpAddress (), ut->port);
+-  UpnpEnableWebserver (TRUE);
++  UpnpEnableWebserver (1);
+ #define upnp_set_callback(cb, func) \
+   do {                                                            \
+@@ -371,7 +371,7 @@ init_upnp (struct ushare_t *ut)
+   upnp_set_callback(Write,   http_write);
+   upnp_set_callback(Close,   http_close);
+-  res = UpnpAddVirtualDir (VIRTUAL_DIR);
++  res = UpnpAddVirtualDir (VIRTUAL_DIR, NULL, NULL);
+   if (res != UPNP_E_SUCCESS)
+   {
+     log_error (_("Cannot add virtual directory for web server\n"));
+diff --git a/src/ushare.h b/src/ushare.h
+index a29da01..cd86cef 100644
+--- a/src/ushare.h
++++ b/src/ushare.h
+@@ -125,7 +125,7 @@ struct ushare_t {
+ };
+ struct action_event_t {
+-  struct Upnp_Action_Request *request;
++  UpnpActionRequest *request;
+   bool status;
+   struct service_t *service;
+ };