1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24 #include "tool_setup.h"
25 #include "tool_xattr.h"
26
27 #include "memdebug.h" /* keep this as LAST include */
28
29 #ifdef USE_XATTR
30
31 /* mapping table of curl metadata to extended attribute names */
32 static const struct xattr_mapping {
33 const char *attr; /* name of the xattr */
34 CURLINFO info;
35 } mappings[] = {
36 /* mappings proposed by
37 * https://freedesktop.org/wiki/CommonExtendedAttributes/
38 */
39 { "user.xdg.referrer.url", CURLINFO_REFERER },
40 { "user.mime_type", CURLINFO_CONTENT_TYPE },
41 { NULL, CURLINFO_NONE } /* last element, abort here */
42 };
43
44 /* returns a new URL that needs to be freed */
45 /* @unittest: 1621 */
46 #ifdef UNITTESTS
47 char *stripcredentials(const char *url);
48 #else
49 static
50 #endif
stripcredentials(const char * url)51 char *stripcredentials(const char *url)
52 {
53 CURLU *u;
54 CURLUcode uc;
55 char *nurl;
56 u = curl_url();
57 if(u) {
58 uc = curl_url_set(u, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
59 if(uc)
60 goto error;
61
62 uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
63 if(uc)
64 goto error;
65
66 uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
67 if(uc)
68 goto error;
69
70 uc = curl_url_get(u, CURLUPART_URL, &nurl, 0);
71 if(uc)
72 goto error;
73
74 curl_url_cleanup(u);
75
76 return nurl;
77 }
78 error:
79 curl_url_cleanup(u);
80 return NULL;
81 }
82
xattr(int fd,const char * attr,const char * value)83 static int xattr(int fd,
84 const char *attr, /* name of the xattr */
85 const char *value)
86 {
87 int err = 0;
88 if(value) {
89 #ifdef DEBUGBUILD
90 if(getenv("CURL_FAKE_XATTR")) {
91 printf("%s => %s\n", attr, value);
92 return 0;
93 }
94 #endif
95 #ifdef HAVE_FSETXATTR_6
96 err = fsetxattr(fd, attr, value, strlen(value), 0, 0);
97 #elif defined(HAVE_FSETXATTR_5)
98 err = fsetxattr(fd, attr, value, strlen(value), 0);
99 #elif defined(__FreeBSD_version) || defined(__MidnightBSD_version)
100 {
101 ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER,
102 attr, value, strlen(value));
103 /* FreeBSD's extattr_set_fd returns the length of the extended
104 attribute */
105 err = (rc < 0 ? -1 : 0);
106 }
107 #endif
108 }
109 return err;
110 }
111 /* store metadata from the curl request alongside the downloaded
112 * file using extended attributes
113 */
fwrite_xattr(CURL * curl,const char * url,int fd)114 int fwrite_xattr(CURL *curl, const char *url, int fd)
115 {
116 int i = 0;
117 int err = xattr(fd, "user.creator", "curl");
118
119 /* loop through all xattr-curlinfo pairs and abort on a set error */
120 while(!err && mappings[i].attr) {
121 char *value = NULL;
122 CURLcode result = curl_easy_getinfo(curl, mappings[i].info, &value);
123 if(!result && value)
124 err = xattr(fd, mappings[i].attr, value);
125 i++;
126 }
127 if(!err) {
128 char *nurl = stripcredentials(url);
129 if(!nurl)
130 return 1;
131 err = xattr(fd, "user.xdg.origin.url", nurl);
132 curl_free(nurl);
133 }
134 return err;
135 }
136 #endif
137