1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 #include "tool_setup.h"
23 
24 #ifdef HAVE_FSETXATTR
25 #  include <sys/xattr.h> /* header from libc, not from libattr */
26 #  define USE_XATTR
27 #elif (defined(__FreeBSD_version) && (__FreeBSD_version > 500000)) || \
28       defined(__MidnightBSD_version)
29 #  include <sys/types.h>
30 #  include <sys/extattr.h>
31 #  define USE_XATTR
32 #endif
33 
34 #include "tool_xattr.h"
35 
36 #include "memdebug.h" /* keep this as LAST include */
37 
38 #ifdef USE_XATTR
39 
40 /* mapping table of curl metadata to extended attribute names */
41 static const struct xattr_mapping {
42   const char *attr; /* name of the xattr */
43   CURLINFO info;
44 } mappings[] = {
45   /* mappings proposed by
46    * https://freedesktop.org/wiki/CommonExtendedAttributes/
47    */
48   { "user.xdg.referrer.url", CURLINFO_REFERER },
49   { "user.xdg.origin.url",   CURLINFO_EFFECTIVE_URL },
50   { "user.mime_type",        CURLINFO_CONTENT_TYPE },
51   { NULL,                    CURLINFO_NONE } /* last element, abort here */
52 };
53 
54 /* returns TRUE if a new URL is returned, that then needs to be freed */
55 /* @unittest: 1621 */
56 #ifdef UNITTESTS
57 bool stripcredentials(char **url);
58 #else
59 static
60 #endif
stripcredentials(char ** url)61 bool stripcredentials(char **url)
62 {
63   CURLU *u;
64   CURLUcode uc;
65   char *nurl;
66   u = curl_url();
67   if(u) {
68     uc = curl_url_set(u, CURLUPART_URL, *url, 0);
69     if(uc)
70       goto error;
71 
72     uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
73     if(uc)
74       goto error;
75 
76     uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
77     if(uc)
78       goto error;
79 
80     uc = curl_url_get(u, CURLUPART_URL, &nurl, 0);
81     if(uc)
82       goto error;
83 
84     curl_url_cleanup(u);
85 
86     *url = nurl;
87     return TRUE;
88   }
89   error:
90   curl_url_cleanup(u);
91   return FALSE;
92 }
93 
94 /* store metadata from the curl request alongside the downloaded
95  * file using extended attributes
96  */
fwrite_xattr(CURL * curl,int fd)97 int fwrite_xattr(CURL *curl, int fd)
98 {
99   int i = 0;
100   int err = 0;
101 
102   /* loop through all xattr-curlinfo pairs and abort on a set error */
103   while(err == 0 && mappings[i].attr != NULL) {
104     char *value = NULL;
105     CURLcode result = curl_easy_getinfo(curl, mappings[i].info, &value);
106     if(!result && value) {
107       bool freeptr = FALSE;
108       if(CURLINFO_EFFECTIVE_URL == mappings[i].info)
109         freeptr = stripcredentials(&value);
110       if(value) {
111 #ifdef HAVE_FSETXATTR_6
112         err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0);
113 #elif defined(HAVE_FSETXATTR_5)
114         err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0);
115 #elif defined(__FreeBSD_version) || defined(__MidnightBSD_version)
116         {
117           ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER,
118                                       mappings[i].attr, value, strlen(value));
119           /* FreeBSD's extattr_set_fd returns the length of the extended
120              attribute */
121           err = (rc < 0 ? -1 : 0);
122         }
123 #endif
124         if(freeptr)
125           curl_free(value);
126       }
127     }
128     i++;
129   }
130 
131   return err;
132 }
133 #else
fwrite_xattr(CURL * curl,int fd)134 int fwrite_xattr(CURL *curl, int fd)
135 {
136   (void)curl;
137   (void)fd;
138 
139   return 0;
140 }
141 #endif
142