xref: /aosp_15_r20/external/curl/src/tool_doswin.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker 
26*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(MSDOS)
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
29*6236dae4SAndroid Build Coastguard Worker #  include <libgen.h>
30*6236dae4SAndroid Build Coastguard Worker #endif
31*6236dae4SAndroid Build Coastguard Worker 
32*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
33*6236dae4SAndroid Build Coastguard Worker #  include <stdlib.h>
34*6236dae4SAndroid Build Coastguard Worker #  include <tlhelp32.h>
35*6236dae4SAndroid Build Coastguard Worker #  include "tool_cfgable.h"
36*6236dae4SAndroid Build Coastguard Worker #  include "tool_libinfo.h"
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker 
39*6236dae4SAndroid Build Coastguard Worker #include "tool_bname.h"
40*6236dae4SAndroid Build Coastguard Worker #include "tool_doswin.h"
41*6236dae4SAndroid Build Coastguard Worker 
42*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
43*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
44*6236dae4SAndroid Build Coastguard Worker 
45*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
46*6236dae4SAndroid Build Coastguard Worker #  undef  PATH_MAX
47*6236dae4SAndroid Build Coastguard Worker #  define PATH_MAX MAX_PATH
48*6236dae4SAndroid Build Coastguard Worker #endif
49*6236dae4SAndroid Build Coastguard Worker 
50*6236dae4SAndroid Build Coastguard Worker #ifndef S_ISCHR
51*6236dae4SAndroid Build Coastguard Worker #  ifdef S_IFCHR
52*6236dae4SAndroid Build Coastguard Worker #    define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
53*6236dae4SAndroid Build Coastguard Worker #  else
54*6236dae4SAndroid Build Coastguard Worker #    define S_ISCHR(m) (0) /* cannot tell if file is a device */
55*6236dae4SAndroid Build Coastguard Worker #  endif
56*6236dae4SAndroid Build Coastguard Worker #endif
57*6236dae4SAndroid Build Coastguard Worker 
58*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
59*6236dae4SAndroid Build Coastguard Worker #  define _use_lfn(f) (1)   /* long filenames always available */
60*6236dae4SAndroid Build Coastguard Worker #elif !defined(__DJGPP__) || (__DJGPP__ < 2)  /* DJGPP 2.0 has _use_lfn() */
61*6236dae4SAndroid Build Coastguard Worker #  define _use_lfn(f) (0)  /* long filenames never available */
62*6236dae4SAndroid Build Coastguard Worker #elif defined(__DJGPP__)
63*6236dae4SAndroid Build Coastguard Worker #  include <fcntl.h>                /* _use_lfn(f) prototype */
64*6236dae4SAndroid Build Coastguard Worker #endif
65*6236dae4SAndroid Build Coastguard Worker 
66*6236dae4SAndroid Build Coastguard Worker #ifdef MSDOS
67*6236dae4SAndroid Build Coastguard Worker /* only used by msdosify() */
68*6236dae4SAndroid Build Coastguard Worker static SANITIZEcode truncate_dryrun(const char *path,
69*6236dae4SAndroid Build Coastguard Worker                                     const size_t truncate_pos);
70*6236dae4SAndroid Build Coastguard Worker static SANITIZEcode msdosify(char **const sanitized, const char *file_name,
71*6236dae4SAndroid Build Coastguard Worker                              int flags);
72*6236dae4SAndroid Build Coastguard Worker #endif
73*6236dae4SAndroid Build Coastguard Worker static SANITIZEcode rename_if_reserved_dos(char **const sanitized,
74*6236dae4SAndroid Build Coastguard Worker                                            const char *file_name,
75*6236dae4SAndroid Build Coastguard Worker                                            int flags);
76*6236dae4SAndroid Build Coastguard Worker 
77*6236dae4SAndroid Build Coastguard Worker 
78*6236dae4SAndroid Build Coastguard Worker /*
79*6236dae4SAndroid Build Coastguard Worker Sanitize a file or path name.
80*6236dae4SAndroid Build Coastguard Worker 
81*6236dae4SAndroid Build Coastguard Worker All banned characters are replaced by underscores, for example:
82*6236dae4SAndroid Build Coastguard Worker f?*foo => f__foo
83*6236dae4SAndroid Build Coastguard Worker f:foo::$DATA => f_foo__$DATA
84*6236dae4SAndroid Build Coastguard Worker f:\foo:bar => f__foo_bar
85*6236dae4SAndroid Build Coastguard Worker f:\foo:bar => f:\foo:bar   (flag SANITIZE_ALLOW_PATH)
86*6236dae4SAndroid Build Coastguard Worker 
87*6236dae4SAndroid Build Coastguard Worker This function was implemented according to the guidelines in 'Naming Files,
88*6236dae4SAndroid Build Coastguard Worker Paths, and Namespaces' section 'Naming Conventions'.
89*6236dae4SAndroid Build Coastguard Worker https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
90*6236dae4SAndroid Build Coastguard Worker 
91*6236dae4SAndroid Build Coastguard Worker Flags
92*6236dae4SAndroid Build Coastguard Worker -----
93*6236dae4SAndroid Build Coastguard Worker SANITIZE_ALLOW_PATH:       Allow path separators and colons.
94*6236dae4SAndroid Build Coastguard Worker Without this flag path separators and colons are sanitized.
95*6236dae4SAndroid Build Coastguard Worker 
96*6236dae4SAndroid Build Coastguard Worker SANITIZE_ALLOW_RESERVED:   Allow reserved device names.
97*6236dae4SAndroid Build Coastguard Worker Without this flag a reserved device name is renamed (COM1 => _COM1) unless it
98*6236dae4SAndroid Build Coastguard Worker is in a UNC prefixed path.
99*6236dae4SAndroid Build Coastguard Worker 
100*6236dae4SAndroid Build Coastguard Worker Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
101*6236dae4SAndroid Build Coastguard Worker Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
102*6236dae4SAndroid Build Coastguard Worker */
sanitize_file_name(char ** const sanitized,const char * file_name,int flags)103*6236dae4SAndroid Build Coastguard Worker SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
104*6236dae4SAndroid Build Coastguard Worker                                 int flags)
105*6236dae4SAndroid Build Coastguard Worker {
106*6236dae4SAndroid Build Coastguard Worker   char *p, *target;
107*6236dae4SAndroid Build Coastguard Worker   size_t len;
108*6236dae4SAndroid Build Coastguard Worker   SANITIZEcode sc;
109*6236dae4SAndroid Build Coastguard Worker   size_t max_sanitized_len;
110*6236dae4SAndroid Build Coastguard Worker 
111*6236dae4SAndroid Build Coastguard Worker   if(!sanitized)
112*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
113*6236dae4SAndroid Build Coastguard Worker 
114*6236dae4SAndroid Build Coastguard Worker   *sanitized = NULL;
115*6236dae4SAndroid Build Coastguard Worker 
116*6236dae4SAndroid Build Coastguard Worker   if(!file_name)
117*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
118*6236dae4SAndroid Build Coastguard Worker 
119*6236dae4SAndroid Build Coastguard Worker   if(flags & SANITIZE_ALLOW_PATH) {
120*6236dae4SAndroid Build Coastguard Worker #ifndef MSDOS
121*6236dae4SAndroid Build Coastguard Worker     if(file_name[0] == '\\' && file_name[1] == '\\')
122*6236dae4SAndroid Build Coastguard Worker       /* UNC prefixed path \\ (eg \\?\C:\foo) */
123*6236dae4SAndroid Build Coastguard Worker       max_sanitized_len = 32767-1;
124*6236dae4SAndroid Build Coastguard Worker     else
125*6236dae4SAndroid Build Coastguard Worker #endif
126*6236dae4SAndroid Build Coastguard Worker       max_sanitized_len = PATH_MAX-1;
127*6236dae4SAndroid Build Coastguard Worker   }
128*6236dae4SAndroid Build Coastguard Worker   else
129*6236dae4SAndroid Build Coastguard Worker     /* The maximum length of a filename. FILENAME_MAX is often the same as
130*6236dae4SAndroid Build Coastguard Worker        PATH_MAX, in other words it is 260 and does not discount the path
131*6236dae4SAndroid Build Coastguard Worker        information therefore we should not use it. */
132*6236dae4SAndroid Build Coastguard Worker     max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;
133*6236dae4SAndroid Build Coastguard Worker 
134*6236dae4SAndroid Build Coastguard Worker   len = strlen(file_name);
135*6236dae4SAndroid Build Coastguard Worker   if(len > max_sanitized_len)
136*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_INVALID_PATH;
137*6236dae4SAndroid Build Coastguard Worker 
138*6236dae4SAndroid Build Coastguard Worker   target = strdup(file_name);
139*6236dae4SAndroid Build Coastguard Worker   if(!target)
140*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_OUT_OF_MEMORY;
141*6236dae4SAndroid Build Coastguard Worker 
142*6236dae4SAndroid Build Coastguard Worker #ifndef MSDOS
143*6236dae4SAndroid Build Coastguard Worker   if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4))
144*6236dae4SAndroid Build Coastguard Worker     /* Skip the literal path prefix \\?\ */
145*6236dae4SAndroid Build Coastguard Worker     p = target + 4;
146*6236dae4SAndroid Build Coastguard Worker   else
147*6236dae4SAndroid Build Coastguard Worker #endif
148*6236dae4SAndroid Build Coastguard Worker     p = target;
149*6236dae4SAndroid Build Coastguard Worker 
150*6236dae4SAndroid Build Coastguard Worker   /* replace control characters and other banned characters */
151*6236dae4SAndroid Build Coastguard Worker   for(; *p; ++p) {
152*6236dae4SAndroid Build Coastguard Worker     const char *banned;
153*6236dae4SAndroid Build Coastguard Worker 
154*6236dae4SAndroid Build Coastguard Worker     if((1 <= *p && *p <= 31) ||
155*6236dae4SAndroid Build Coastguard Worker        (!(flags & SANITIZE_ALLOW_PATH) && *p == ':') ||
156*6236dae4SAndroid Build Coastguard Worker        (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) {
157*6236dae4SAndroid Build Coastguard Worker       *p = '_';
158*6236dae4SAndroid Build Coastguard Worker       continue;
159*6236dae4SAndroid Build Coastguard Worker     }
160*6236dae4SAndroid Build Coastguard Worker 
161*6236dae4SAndroid Build Coastguard Worker     for(banned = "|<>\"?*"; *banned; ++banned) {
162*6236dae4SAndroid Build Coastguard Worker       if(*p == *banned) {
163*6236dae4SAndroid Build Coastguard Worker         *p = '_';
164*6236dae4SAndroid Build Coastguard Worker         break;
165*6236dae4SAndroid Build Coastguard Worker       }
166*6236dae4SAndroid Build Coastguard Worker     }
167*6236dae4SAndroid Build Coastguard Worker   }
168*6236dae4SAndroid Build Coastguard Worker 
169*6236dae4SAndroid Build Coastguard Worker   /* remove trailing spaces and periods if not allowing paths */
170*6236dae4SAndroid Build Coastguard Worker   if(!(flags & SANITIZE_ALLOW_PATH) && len) {
171*6236dae4SAndroid Build Coastguard Worker     char *clip = NULL;
172*6236dae4SAndroid Build Coastguard Worker 
173*6236dae4SAndroid Build Coastguard Worker     p = &target[len];
174*6236dae4SAndroid Build Coastguard Worker     do {
175*6236dae4SAndroid Build Coastguard Worker       --p;
176*6236dae4SAndroid Build Coastguard Worker       if(*p != ' ' && *p != '.')
177*6236dae4SAndroid Build Coastguard Worker         break;
178*6236dae4SAndroid Build Coastguard Worker       clip = p;
179*6236dae4SAndroid Build Coastguard Worker     } while(p != target);
180*6236dae4SAndroid Build Coastguard Worker 
181*6236dae4SAndroid Build Coastguard Worker     if(clip) {
182*6236dae4SAndroid Build Coastguard Worker       *clip = '\0';
183*6236dae4SAndroid Build Coastguard Worker       len = clip - target;
184*6236dae4SAndroid Build Coastguard Worker     }
185*6236dae4SAndroid Build Coastguard Worker   }
186*6236dae4SAndroid Build Coastguard Worker 
187*6236dae4SAndroid Build Coastguard Worker #ifdef MSDOS
188*6236dae4SAndroid Build Coastguard Worker   sc = msdosify(&p, target, flags);
189*6236dae4SAndroid Build Coastguard Worker   free(target);
190*6236dae4SAndroid Build Coastguard Worker   if(sc)
191*6236dae4SAndroid Build Coastguard Worker     return sc;
192*6236dae4SAndroid Build Coastguard Worker   target = p;
193*6236dae4SAndroid Build Coastguard Worker   len = strlen(target);
194*6236dae4SAndroid Build Coastguard Worker 
195*6236dae4SAndroid Build Coastguard Worker   if(len > max_sanitized_len) {
196*6236dae4SAndroid Build Coastguard Worker     free(target);
197*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_INVALID_PATH;
198*6236dae4SAndroid Build Coastguard Worker   }
199*6236dae4SAndroid Build Coastguard Worker #endif
200*6236dae4SAndroid Build Coastguard Worker 
201*6236dae4SAndroid Build Coastguard Worker   if(!(flags & SANITIZE_ALLOW_RESERVED)) {
202*6236dae4SAndroid Build Coastguard Worker     sc = rename_if_reserved_dos(&p, target, flags);
203*6236dae4SAndroid Build Coastguard Worker     free(target);
204*6236dae4SAndroid Build Coastguard Worker     if(sc)
205*6236dae4SAndroid Build Coastguard Worker       return sc;
206*6236dae4SAndroid Build Coastguard Worker     target = p;
207*6236dae4SAndroid Build Coastguard Worker     len = strlen(target);
208*6236dae4SAndroid Build Coastguard Worker 
209*6236dae4SAndroid Build Coastguard Worker     if(len > max_sanitized_len) {
210*6236dae4SAndroid Build Coastguard Worker       free(target);
211*6236dae4SAndroid Build Coastguard Worker       return SANITIZE_ERR_INVALID_PATH;
212*6236dae4SAndroid Build Coastguard Worker     }
213*6236dae4SAndroid Build Coastguard Worker   }
214*6236dae4SAndroid Build Coastguard Worker 
215*6236dae4SAndroid Build Coastguard Worker   *sanitized = target;
216*6236dae4SAndroid Build Coastguard Worker   return SANITIZE_ERR_OK;
217*6236dae4SAndroid Build Coastguard Worker }
218*6236dae4SAndroid Build Coastguard Worker 
219*6236dae4SAndroid Build Coastguard Worker #if defined(MSDOS)
220*6236dae4SAndroid Build Coastguard Worker /*
221*6236dae4SAndroid Build Coastguard Worker Test if truncating a path to a file will leave at least a single character in
222*6236dae4SAndroid Build Coastguard Worker the filename. Filenames suffixed by an alternate data stream cannot be
223*6236dae4SAndroid Build Coastguard Worker truncated. This performs a dry run, nothing is modified.
224*6236dae4SAndroid Build Coastguard Worker 
225*6236dae4SAndroid Build Coastguard Worker Good truncate_pos 9:    C:\foo\bar  =>  C:\foo\ba
226*6236dae4SAndroid Build Coastguard Worker Good truncate_pos 6:    C:\foo      =>  C:\foo
227*6236dae4SAndroid Build Coastguard Worker Good truncate_pos 5:    C:\foo      =>  C:\fo
228*6236dae4SAndroid Build Coastguard Worker Bad* truncate_pos 5:    C:foo       =>  C:foo
229*6236dae4SAndroid Build Coastguard Worker Bad truncate_pos 5:     C:\foo:ads  =>  C:\fo
230*6236dae4SAndroid Build Coastguard Worker Bad truncate_pos 9:     C:\foo:ads  =>  C:\foo:ad
231*6236dae4SAndroid Build Coastguard Worker Bad truncate_pos 5:     C:\foo\bar  =>  C:\fo
232*6236dae4SAndroid Build Coastguard Worker Bad truncate_pos 5:     C:\foo\     =>  C:\fo
233*6236dae4SAndroid Build Coastguard Worker Bad truncate_pos 7:     C:\foo\     =>  C:\foo\
234*6236dae4SAndroid Build Coastguard Worker Error truncate_pos 7:   C:\foo      =>  (pos out of range)
235*6236dae4SAndroid Build Coastguard Worker Bad truncate_pos 1:     C:\foo\     =>  C
236*6236dae4SAndroid Build Coastguard Worker 
237*6236dae4SAndroid Build Coastguard Worker * C:foo is ambiguous, C could end up being a drive or file therefore something
238*6236dae4SAndroid Build Coastguard Worker   like C:superlongfilename cannot be truncated.
239*6236dae4SAndroid Build Coastguard Worker 
240*6236dae4SAndroid Build Coastguard Worker Returns
241*6236dae4SAndroid Build Coastguard Worker SANITIZE_ERR_OK: Good -- 'path' can be truncated
242*6236dae4SAndroid Build Coastguard Worker SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated
243*6236dae4SAndroid Build Coastguard Worker != SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error
244*6236dae4SAndroid Build Coastguard Worker */
truncate_dryrun(const char * path,const size_t truncate_pos)245*6236dae4SAndroid Build Coastguard Worker SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)
246*6236dae4SAndroid Build Coastguard Worker {
247*6236dae4SAndroid Build Coastguard Worker   size_t len;
248*6236dae4SAndroid Build Coastguard Worker 
249*6236dae4SAndroid Build Coastguard Worker   if(!path)
250*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
251*6236dae4SAndroid Build Coastguard Worker 
252*6236dae4SAndroid Build Coastguard Worker   len = strlen(path);
253*6236dae4SAndroid Build Coastguard Worker 
254*6236dae4SAndroid Build Coastguard Worker   if(truncate_pos > len)
255*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
256*6236dae4SAndroid Build Coastguard Worker 
257*6236dae4SAndroid Build Coastguard Worker   if(!len || !truncate_pos)
258*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_INVALID_PATH;
259*6236dae4SAndroid Build Coastguard Worker 
260*6236dae4SAndroid Build Coastguard Worker   if(strpbrk(&path[truncate_pos - 1], "\\/:"))
261*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_INVALID_PATH;
262*6236dae4SAndroid Build Coastguard Worker 
263*6236dae4SAndroid Build Coastguard Worker   /* C:\foo can be truncated but C:\foo:ads cannot */
264*6236dae4SAndroid Build Coastguard Worker   if(truncate_pos > 1) {
265*6236dae4SAndroid Build Coastguard Worker     const char *p = &path[truncate_pos - 1];
266*6236dae4SAndroid Build Coastguard Worker     do {
267*6236dae4SAndroid Build Coastguard Worker       --p;
268*6236dae4SAndroid Build Coastguard Worker       if(*p == ':')
269*6236dae4SAndroid Build Coastguard Worker         return SANITIZE_ERR_INVALID_PATH;
270*6236dae4SAndroid Build Coastguard Worker     } while(p != path && *p != '\\' && *p != '/');
271*6236dae4SAndroid Build Coastguard Worker   }
272*6236dae4SAndroid Build Coastguard Worker 
273*6236dae4SAndroid Build Coastguard Worker   return SANITIZE_ERR_OK;
274*6236dae4SAndroid Build Coastguard Worker }
275*6236dae4SAndroid Build Coastguard Worker 
276*6236dae4SAndroid Build Coastguard Worker /* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function
277*6236dae4SAndroid Build Coastguard Worker  * were taken with modification from the DJGPP port of tar 1.12. They use
278*6236dae4SAndroid Build Coastguard Worker  * algorithms originally from DJTAR.
279*6236dae4SAndroid Build Coastguard Worker  */
280*6236dae4SAndroid Build Coastguard Worker 
281*6236dae4SAndroid Build Coastguard Worker /*
282*6236dae4SAndroid Build Coastguard Worker Extra sanitization MS-DOS for file_name.
283*6236dae4SAndroid Build Coastguard Worker 
284*6236dae4SAndroid Build Coastguard Worker This is a supporting function for sanitize_file_name.
285*6236dae4SAndroid Build Coastguard Worker 
286*6236dae4SAndroid Build Coastguard Worker Warning: This is an MS-DOS legacy function and was purposely written in a way
287*6236dae4SAndroid Build Coastguard Worker that some path information may pass through. For example drive letter names
288*6236dae4SAndroid Build Coastguard Worker (C:, D:, etc) are allowed to pass through. For sanitizing a filename use
289*6236dae4SAndroid Build Coastguard Worker sanitize_file_name.
290*6236dae4SAndroid Build Coastguard Worker 
291*6236dae4SAndroid Build Coastguard Worker Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
292*6236dae4SAndroid Build Coastguard Worker Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
293*6236dae4SAndroid Build Coastguard Worker */
msdosify(char ** const sanitized,const char * file_name,int flags)294*6236dae4SAndroid Build Coastguard Worker SANITIZEcode msdosify(char **const sanitized, const char *file_name,
295*6236dae4SAndroid Build Coastguard Worker                       int flags)
296*6236dae4SAndroid Build Coastguard Worker {
297*6236dae4SAndroid Build Coastguard Worker   char dos_name[PATH_MAX];
298*6236dae4SAndroid Build Coastguard Worker   static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
299*6236dae4SAndroid Build Coastguard Worker     "|<>/\\\":?*"; /* illegal in DOS & W95 */
300*6236dae4SAndroid Build Coastguard Worker   static const char *illegal_chars_w95 = &illegal_chars_dos[8];
301*6236dae4SAndroid Build Coastguard Worker   int idx, dot_idx;
302*6236dae4SAndroid Build Coastguard Worker   const char *s = file_name;
303*6236dae4SAndroid Build Coastguard Worker   char *d = dos_name;
304*6236dae4SAndroid Build Coastguard Worker   const char *const dlimit = dos_name + sizeof(dos_name) - 1;
305*6236dae4SAndroid Build Coastguard Worker   const char *illegal_aliens = illegal_chars_dos;
306*6236dae4SAndroid Build Coastguard Worker   size_t len = sizeof(illegal_chars_dos) - 1;
307*6236dae4SAndroid Build Coastguard Worker 
308*6236dae4SAndroid Build Coastguard Worker   if(!sanitized)
309*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
310*6236dae4SAndroid Build Coastguard Worker 
311*6236dae4SAndroid Build Coastguard Worker   *sanitized = NULL;
312*6236dae4SAndroid Build Coastguard Worker 
313*6236dae4SAndroid Build Coastguard Worker   if(!file_name)
314*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
315*6236dae4SAndroid Build Coastguard Worker 
316*6236dae4SAndroid Build Coastguard Worker   if(strlen(file_name) > PATH_MAX-1)
317*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_INVALID_PATH;
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker   /* Support for Windows 9X VFAT systems, when available. */
320*6236dae4SAndroid Build Coastguard Worker   if(_use_lfn(file_name)) {
321*6236dae4SAndroid Build Coastguard Worker     illegal_aliens = illegal_chars_w95;
322*6236dae4SAndroid Build Coastguard Worker     len -= (illegal_chars_w95 - illegal_chars_dos);
323*6236dae4SAndroid Build Coastguard Worker   }
324*6236dae4SAndroid Build Coastguard Worker 
325*6236dae4SAndroid Build Coastguard Worker   /* Get past the drive letter, if any. */
326*6236dae4SAndroid Build Coastguard Worker   if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
327*6236dae4SAndroid Build Coastguard Worker     *d++ = *s++;
328*6236dae4SAndroid Build Coastguard Worker     *d = ((flags & SANITIZE_ALLOW_PATH)) ? ':' : '_';
329*6236dae4SAndroid Build Coastguard Worker     ++d; ++s;
330*6236dae4SAndroid Build Coastguard Worker   }
331*6236dae4SAndroid Build Coastguard Worker 
332*6236dae4SAndroid Build Coastguard Worker   for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
333*6236dae4SAndroid Build Coastguard Worker     if(memchr(illegal_aliens, *s, len)) {
334*6236dae4SAndroid Build Coastguard Worker 
335*6236dae4SAndroid Build Coastguard Worker       if((flags & SANITIZE_ALLOW_PATH) && *s == ':')
336*6236dae4SAndroid Build Coastguard Worker         *d = ':';
337*6236dae4SAndroid Build Coastguard Worker       else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
338*6236dae4SAndroid Build Coastguard Worker         *d = *s;
339*6236dae4SAndroid Build Coastguard Worker       /* Dots are special: DOS does not allow them as the leading character,
340*6236dae4SAndroid Build Coastguard Worker          and a filename cannot have more than a single dot. We leave the
341*6236dae4SAndroid Build Coastguard Worker          first non-leading dot alone, unless it comes too close to the
342*6236dae4SAndroid Build Coastguard Worker          beginning of the name: we want sh.lex.c to become sh_lex.c, not
343*6236dae4SAndroid Build Coastguard Worker          sh.lex-c.  */
344*6236dae4SAndroid Build Coastguard Worker       else if(*s == '.') {
345*6236dae4SAndroid Build Coastguard Worker         if((flags & SANITIZE_ALLOW_PATH) && idx == 0 &&
346*6236dae4SAndroid Build Coastguard Worker            (s[1] == '/' || s[1] == '\\' ||
347*6236dae4SAndroid Build Coastguard Worker             (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) {
348*6236dae4SAndroid Build Coastguard Worker           /* Copy "./" and "../" verbatim.  */
349*6236dae4SAndroid Build Coastguard Worker           *d++ = *s++;
350*6236dae4SAndroid Build Coastguard Worker           if(d == dlimit)
351*6236dae4SAndroid Build Coastguard Worker             break;
352*6236dae4SAndroid Build Coastguard Worker           if(*s == '.') {
353*6236dae4SAndroid Build Coastguard Worker             *d++ = *s++;
354*6236dae4SAndroid Build Coastguard Worker             if(d == dlimit)
355*6236dae4SAndroid Build Coastguard Worker               break;
356*6236dae4SAndroid Build Coastguard Worker           }
357*6236dae4SAndroid Build Coastguard Worker           *d = *s;
358*6236dae4SAndroid Build Coastguard Worker         }
359*6236dae4SAndroid Build Coastguard Worker         else if(idx == 0)
360*6236dae4SAndroid Build Coastguard Worker           *d = '_';
361*6236dae4SAndroid Build Coastguard Worker         else if(dot_idx >= 0) {
362*6236dae4SAndroid Build Coastguard Worker           if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
363*6236dae4SAndroid Build Coastguard Worker             d[dot_idx - idx] = '_'; /* replace previous dot */
364*6236dae4SAndroid Build Coastguard Worker             *d = '.';
365*6236dae4SAndroid Build Coastguard Worker           }
366*6236dae4SAndroid Build Coastguard Worker           else
367*6236dae4SAndroid Build Coastguard Worker             *d = '-';
368*6236dae4SAndroid Build Coastguard Worker         }
369*6236dae4SAndroid Build Coastguard Worker         else
370*6236dae4SAndroid Build Coastguard Worker           *d = '.';
371*6236dae4SAndroid Build Coastguard Worker 
372*6236dae4SAndroid Build Coastguard Worker         if(*s == '.')
373*6236dae4SAndroid Build Coastguard Worker           dot_idx = idx;
374*6236dae4SAndroid Build Coastguard Worker       }
375*6236dae4SAndroid Build Coastguard Worker       else if(*s == '+' && s[1] == '+') {
376*6236dae4SAndroid Build Coastguard Worker         if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
377*6236dae4SAndroid Build Coastguard Worker           *d++ = 'x';
378*6236dae4SAndroid Build Coastguard Worker           if(d == dlimit)
379*6236dae4SAndroid Build Coastguard Worker             break;
380*6236dae4SAndroid Build Coastguard Worker           *d   = 'x';
381*6236dae4SAndroid Build Coastguard Worker         }
382*6236dae4SAndroid Build Coastguard Worker         else {
383*6236dae4SAndroid Build Coastguard Worker           /* libg++ etc.  */
384*6236dae4SAndroid Build Coastguard Worker           if(dlimit - d < 4) {
385*6236dae4SAndroid Build Coastguard Worker             *d++ = 'x';
386*6236dae4SAndroid Build Coastguard Worker             if(d == dlimit)
387*6236dae4SAndroid Build Coastguard Worker               break;
388*6236dae4SAndroid Build Coastguard Worker             *d   = 'x';
389*6236dae4SAndroid Build Coastguard Worker           }
390*6236dae4SAndroid Build Coastguard Worker           else {
391*6236dae4SAndroid Build Coastguard Worker             memcpy(d, "plus", 4);
392*6236dae4SAndroid Build Coastguard Worker             d += 3;
393*6236dae4SAndroid Build Coastguard Worker           }
394*6236dae4SAndroid Build Coastguard Worker         }
395*6236dae4SAndroid Build Coastguard Worker         s++;
396*6236dae4SAndroid Build Coastguard Worker         idx++;
397*6236dae4SAndroid Build Coastguard Worker       }
398*6236dae4SAndroid Build Coastguard Worker       else
399*6236dae4SAndroid Build Coastguard Worker         *d = '_';
400*6236dae4SAndroid Build Coastguard Worker     }
401*6236dae4SAndroid Build Coastguard Worker     else
402*6236dae4SAndroid Build Coastguard Worker       *d = *s;
403*6236dae4SAndroid Build Coastguard Worker     if(*s == '/' || *s == '\\') {
404*6236dae4SAndroid Build Coastguard Worker       idx = 0;
405*6236dae4SAndroid Build Coastguard Worker       dot_idx = -1;
406*6236dae4SAndroid Build Coastguard Worker     }
407*6236dae4SAndroid Build Coastguard Worker     else
408*6236dae4SAndroid Build Coastguard Worker       idx++;
409*6236dae4SAndroid Build Coastguard Worker   }
410*6236dae4SAndroid Build Coastguard Worker   *d = '\0';
411*6236dae4SAndroid Build Coastguard Worker 
412*6236dae4SAndroid Build Coastguard Worker   if(*s) {
413*6236dae4SAndroid Build Coastguard Worker     /* dos_name is truncated, check that truncation requirements are met,
414*6236dae4SAndroid Build Coastguard Worker        specifically truncating a filename suffixed by an alternate data stream
415*6236dae4SAndroid Build Coastguard Worker        or truncating the entire filename is not allowed. */
416*6236dae4SAndroid Build Coastguard Worker     if(strpbrk(s, "\\/:") || truncate_dryrun(dos_name, d - dos_name))
417*6236dae4SAndroid Build Coastguard Worker       return SANITIZE_ERR_INVALID_PATH;
418*6236dae4SAndroid Build Coastguard Worker   }
419*6236dae4SAndroid Build Coastguard Worker 
420*6236dae4SAndroid Build Coastguard Worker   *sanitized = strdup(dos_name);
421*6236dae4SAndroid Build Coastguard Worker   return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
422*6236dae4SAndroid Build Coastguard Worker }
423*6236dae4SAndroid Build Coastguard Worker #endif /* MSDOS */
424*6236dae4SAndroid Build Coastguard Worker 
425*6236dae4SAndroid Build Coastguard Worker /*
426*6236dae4SAndroid Build Coastguard Worker Rename file_name if it is a reserved dos device name.
427*6236dae4SAndroid Build Coastguard Worker 
428*6236dae4SAndroid Build Coastguard Worker This is a supporting function for sanitize_file_name.
429*6236dae4SAndroid Build Coastguard Worker 
430*6236dae4SAndroid Build Coastguard Worker Warning: This is an MS-DOS legacy function and was purposely written in a way
431*6236dae4SAndroid Build Coastguard Worker that some path information may pass through. For example drive letter names
432*6236dae4SAndroid Build Coastguard Worker (C:, D:, etc) are allowed to pass through. For sanitizing a filename use
433*6236dae4SAndroid Build Coastguard Worker sanitize_file_name.
434*6236dae4SAndroid Build Coastguard Worker 
435*6236dae4SAndroid Build Coastguard Worker Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
436*6236dae4SAndroid Build Coastguard Worker Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
437*6236dae4SAndroid Build Coastguard Worker */
rename_if_reserved_dos(char ** const sanitized,const char * file_name,int flags)438*6236dae4SAndroid Build Coastguard Worker static SANITIZEcode rename_if_reserved_dos(char **const sanitized,
439*6236dae4SAndroid Build Coastguard Worker                                            const char *file_name,
440*6236dae4SAndroid Build Coastguard Worker                                            int flags)
441*6236dae4SAndroid Build Coastguard Worker {
442*6236dae4SAndroid Build Coastguard Worker   /* We could have a file whose name is a device on MS-DOS. Trying to
443*6236dae4SAndroid Build Coastguard Worker    * retrieve such a file would fail at best and wedge us at worst. We need
444*6236dae4SAndroid Build Coastguard Worker    * to rename such files. */
445*6236dae4SAndroid Build Coastguard Worker   char *p, *base;
446*6236dae4SAndroid Build Coastguard Worker   char fname[PATH_MAX];
447*6236dae4SAndroid Build Coastguard Worker #ifdef MSDOS
448*6236dae4SAndroid Build Coastguard Worker   struct_stat st_buf;
449*6236dae4SAndroid Build Coastguard Worker #endif
450*6236dae4SAndroid Build Coastguard Worker   size_t len;
451*6236dae4SAndroid Build Coastguard Worker 
452*6236dae4SAndroid Build Coastguard Worker   if(!sanitized || !file_name)
453*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_BAD_ARGUMENT;
454*6236dae4SAndroid Build Coastguard Worker 
455*6236dae4SAndroid Build Coastguard Worker   *sanitized = NULL;
456*6236dae4SAndroid Build Coastguard Worker   len = strlen(file_name);
457*6236dae4SAndroid Build Coastguard Worker 
458*6236dae4SAndroid Build Coastguard Worker   /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */
459*6236dae4SAndroid Build Coastguard Worker #ifndef MSDOS
460*6236dae4SAndroid Build Coastguard Worker   if((flags & SANITIZE_ALLOW_PATH) &&
461*6236dae4SAndroid Build Coastguard Worker      file_name[0] == '\\' && file_name[1] == '\\') {
462*6236dae4SAndroid Build Coastguard Worker     *sanitized = strdup(file_name);
463*6236dae4SAndroid Build Coastguard Worker     if(!*sanitized)
464*6236dae4SAndroid Build Coastguard Worker       return SANITIZE_ERR_OUT_OF_MEMORY;
465*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_OK;
466*6236dae4SAndroid Build Coastguard Worker   }
467*6236dae4SAndroid Build Coastguard Worker #endif
468*6236dae4SAndroid Build Coastguard Worker 
469*6236dae4SAndroid Build Coastguard Worker   if(len > PATH_MAX-1)
470*6236dae4SAndroid Build Coastguard Worker     return SANITIZE_ERR_INVALID_PATH;
471*6236dae4SAndroid Build Coastguard Worker 
472*6236dae4SAndroid Build Coastguard Worker   memcpy(fname, file_name, len);
473*6236dae4SAndroid Build Coastguard Worker   fname[len] = '\0';
474*6236dae4SAndroid Build Coastguard Worker   base = basename(fname);
475*6236dae4SAndroid Build Coastguard Worker 
476*6236dae4SAndroid Build Coastguard Worker   /* Rename reserved device names that are known to be accessible without \\.\
477*6236dae4SAndroid Build Coastguard Worker      Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS
478*6236dae4SAndroid Build Coastguard Worker      https://support.microsoft.com/en-us/kb/74496
479*6236dae4SAndroid Build Coastguard Worker      https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
480*6236dae4SAndroid Build Coastguard Worker      */
481*6236dae4SAndroid Build Coastguard Worker   for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) {
482*6236dae4SAndroid Build Coastguard Worker     size_t p_len;
483*6236dae4SAndroid Build Coastguard Worker     int x = (curl_strnequal(p, "CON", 3) ||
484*6236dae4SAndroid Build Coastguard Worker              curl_strnequal(p, "PRN", 3) ||
485*6236dae4SAndroid Build Coastguard Worker              curl_strnequal(p, "AUX", 3) ||
486*6236dae4SAndroid Build Coastguard Worker              curl_strnequal(p, "NUL", 3)) ? 3 :
487*6236dae4SAndroid Build Coastguard Worker             (curl_strnequal(p, "CLOCK$", 6)) ? 6 :
488*6236dae4SAndroid Build Coastguard Worker             (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ?
489*6236dae4SAndroid Build Coastguard Worker               (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0;
490*6236dae4SAndroid Build Coastguard Worker 
491*6236dae4SAndroid Build Coastguard Worker     if(!x)
492*6236dae4SAndroid Build Coastguard Worker       continue;
493*6236dae4SAndroid Build Coastguard Worker 
494*6236dae4SAndroid Build Coastguard Worker     /* the devices may be accessible with an extension or ADS, for
495*6236dae4SAndroid Build Coastguard Worker        example CON.AIR and 'CON . AIR' and CON:AIR access console */
496*6236dae4SAndroid Build Coastguard Worker 
497*6236dae4SAndroid Build Coastguard Worker     for(; p[x] == ' '; ++x)
498*6236dae4SAndroid Build Coastguard Worker       ;
499*6236dae4SAndroid Build Coastguard Worker 
500*6236dae4SAndroid Build Coastguard Worker     if(p[x] == '.') {
501*6236dae4SAndroid Build Coastguard Worker       p[x] = '_';
502*6236dae4SAndroid Build Coastguard Worker       continue;
503*6236dae4SAndroid Build Coastguard Worker     }
504*6236dae4SAndroid Build Coastguard Worker     else if(p[x] == ':') {
505*6236dae4SAndroid Build Coastguard Worker       if(!(flags & SANITIZE_ALLOW_PATH)) {
506*6236dae4SAndroid Build Coastguard Worker         p[x] = '_';
507*6236dae4SAndroid Build Coastguard Worker         continue;
508*6236dae4SAndroid Build Coastguard Worker       }
509*6236dae4SAndroid Build Coastguard Worker       ++x;
510*6236dae4SAndroid Build Coastguard Worker     }
511*6236dae4SAndroid Build Coastguard Worker     else if(p[x]) /* no match */
512*6236dae4SAndroid Build Coastguard Worker       continue;
513*6236dae4SAndroid Build Coastguard Worker 
514*6236dae4SAndroid Build Coastguard Worker     /* p points to 'CON' or 'CON ' or 'CON:', etc */
515*6236dae4SAndroid Build Coastguard Worker     p_len = strlen(p);
516*6236dae4SAndroid Build Coastguard Worker 
517*6236dae4SAndroid Build Coastguard Worker     /* Prepend a '_' */
518*6236dae4SAndroid Build Coastguard Worker     if(strlen(fname) == PATH_MAX-1)
519*6236dae4SAndroid Build Coastguard Worker       return SANITIZE_ERR_INVALID_PATH;
520*6236dae4SAndroid Build Coastguard Worker     memmove(p + 1, p, p_len + 1);
521*6236dae4SAndroid Build Coastguard Worker     p[0] = '_';
522*6236dae4SAndroid Build Coastguard Worker     ++p_len;
523*6236dae4SAndroid Build Coastguard Worker 
524*6236dae4SAndroid Build Coastguard Worker     /* if fname was just modified then the basename pointer must be updated */
525*6236dae4SAndroid Build Coastguard Worker     if(p == fname)
526*6236dae4SAndroid Build Coastguard Worker       base = basename(fname);
527*6236dae4SAndroid Build Coastguard Worker   }
528*6236dae4SAndroid Build Coastguard Worker 
529*6236dae4SAndroid Build Coastguard Worker   /* This is the legacy portion from rename_if_dos_device_name that checks for
530*6236dae4SAndroid Build Coastguard Worker      reserved device names. It only works on MS-DOS. On Windows XP the stat
531*6236dae4SAndroid Build Coastguard Worker      check errors with EINVAL if the device name is reserved. On Windows
532*6236dae4SAndroid Build Coastguard Worker      Vista/7/8 it sets mode S_IFREG (regular file or device). According to
533*6236dae4SAndroid Build Coastguard Worker      MSDN stat doc the latter behavior is correct, but that does not help us
534*6236dae4SAndroid Build Coastguard Worker      identify whether it is a reserved device name and not a regular
535*6236dae4SAndroid Build Coastguard Worker      filename. */
536*6236dae4SAndroid Build Coastguard Worker #ifdef MSDOS
537*6236dae4SAndroid Build Coastguard Worker   if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
538*6236dae4SAndroid Build Coastguard Worker     /* Prepend a '_' */
539*6236dae4SAndroid Build Coastguard Worker     size_t blen = strlen(base);
540*6236dae4SAndroid Build Coastguard Worker     if(blen) {
541*6236dae4SAndroid Build Coastguard Worker       if(strlen(fname) >= PATH_MAX-1)
542*6236dae4SAndroid Build Coastguard Worker         return SANITIZE_ERR_INVALID_PATH;
543*6236dae4SAndroid Build Coastguard Worker       memmove(base + 1, base, blen + 1);
544*6236dae4SAndroid Build Coastguard Worker       base[0] = '_';
545*6236dae4SAndroid Build Coastguard Worker     }
546*6236dae4SAndroid Build Coastguard Worker   }
547*6236dae4SAndroid Build Coastguard Worker #endif
548*6236dae4SAndroid Build Coastguard Worker 
549*6236dae4SAndroid Build Coastguard Worker   *sanitized = strdup(fname);
550*6236dae4SAndroid Build Coastguard Worker   return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
551*6236dae4SAndroid Build Coastguard Worker }
552*6236dae4SAndroid Build Coastguard Worker 
553*6236dae4SAndroid Build Coastguard Worker #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
554*6236dae4SAndroid Build Coastguard Worker 
555*6236dae4SAndroid Build Coastguard Worker /*
556*6236dae4SAndroid Build Coastguard Worker  * Disable program default argument globbing. We do it on our own.
557*6236dae4SAndroid Build Coastguard Worker  */
__crt0_glob_function(char * arg)558*6236dae4SAndroid Build Coastguard Worker char **__crt0_glob_function(char *arg)
559*6236dae4SAndroid Build Coastguard Worker {
560*6236dae4SAndroid Build Coastguard Worker   (void)arg;
561*6236dae4SAndroid Build Coastguard Worker   return (char **)0;
562*6236dae4SAndroid Build Coastguard Worker }
563*6236dae4SAndroid Build Coastguard Worker 
564*6236dae4SAndroid Build Coastguard Worker #endif /* MSDOS && (__DJGPP__ || __GO32__) */
565*6236dae4SAndroid Build Coastguard Worker 
566*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
567*6236dae4SAndroid Build Coastguard Worker 
568*6236dae4SAndroid Build Coastguard Worker #if !defined(CURL_WINDOWS_UWP) && \
569*6236dae4SAndroid Build Coastguard Worker   !defined(CURL_DISABLE_CA_SEARCH) && !defined(CURL_CA_SEARCH_SAFE)
570*6236dae4SAndroid Build Coastguard Worker /* Search and set the CA cert file for Windows.
571*6236dae4SAndroid Build Coastguard Worker  *
572*6236dae4SAndroid Build Coastguard Worker  * Do not call this function if Schannel is the selected SSL backend. We allow
573*6236dae4SAndroid Build Coastguard Worker  * setting CA location for Schannel only when explicitly specified by the user
574*6236dae4SAndroid Build Coastguard Worker  * via CURLOPT_CAINFO / --cacert.
575*6236dae4SAndroid Build Coastguard Worker  *
576*6236dae4SAndroid Build Coastguard Worker  * Function to find CACert bundle on a Win32 platform using SearchPath.
577*6236dae4SAndroid Build Coastguard Worker  * (SearchPath is already declared via inclusions done in setup header file)
578*6236dae4SAndroid Build Coastguard Worker  * (Use the ASCII version instead of the Unicode one!)
579*6236dae4SAndroid Build Coastguard Worker  * The order of the directories it searches is:
580*6236dae4SAndroid Build Coastguard Worker  *  1. application's directory
581*6236dae4SAndroid Build Coastguard Worker  *  2. current working directory
582*6236dae4SAndroid Build Coastguard Worker  *  3. Windows System directory (e.g. C:\Windows\System32)
583*6236dae4SAndroid Build Coastguard Worker  *  4. Windows Directory (e.g. C:\Windows)
584*6236dae4SAndroid Build Coastguard Worker  *  5. all directories along %PATH%
585*6236dae4SAndroid Build Coastguard Worker  *
586*6236dae4SAndroid Build Coastguard Worker  * For WinXP and later search order actually depends on registry value:
587*6236dae4SAndroid Build Coastguard Worker  * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
588*6236dae4SAndroid Build Coastguard Worker  */
FindWin32CACert(struct OperationConfig * config,const TCHAR * bundle_file)589*6236dae4SAndroid Build Coastguard Worker CURLcode FindWin32CACert(struct OperationConfig *config,
590*6236dae4SAndroid Build Coastguard Worker                          const TCHAR *bundle_file)
591*6236dae4SAndroid Build Coastguard Worker {
592*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
593*6236dae4SAndroid Build Coastguard Worker   DWORD res_len;
594*6236dae4SAndroid Build Coastguard Worker   TCHAR buf[PATH_MAX];
595*6236dae4SAndroid Build Coastguard Worker   TCHAR *ptr = NULL;
596*6236dae4SAndroid Build Coastguard Worker 
597*6236dae4SAndroid Build Coastguard Worker   buf[0] = TEXT('\0');
598*6236dae4SAndroid Build Coastguard Worker 
599*6236dae4SAndroid Build Coastguard Worker   res_len = SearchPath(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr);
600*6236dae4SAndroid Build Coastguard Worker   if(res_len > 0) {
601*6236dae4SAndroid Build Coastguard Worker     char *mstr = curlx_convert_tchar_to_UTF8(buf);
602*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(config->cacert);
603*6236dae4SAndroid Build Coastguard Worker     if(mstr)
604*6236dae4SAndroid Build Coastguard Worker       config->cacert = strdup(mstr);
605*6236dae4SAndroid Build Coastguard Worker     curlx_unicodefree(mstr);
606*6236dae4SAndroid Build Coastguard Worker     if(!config->cacert)
607*6236dae4SAndroid Build Coastguard Worker       result = CURLE_OUT_OF_MEMORY;
608*6236dae4SAndroid Build Coastguard Worker   }
609*6236dae4SAndroid Build Coastguard Worker 
610*6236dae4SAndroid Build Coastguard Worker   return result;
611*6236dae4SAndroid Build Coastguard Worker }
612*6236dae4SAndroid Build Coastguard Worker #endif
613*6236dae4SAndroid Build Coastguard Worker 
614*6236dae4SAndroid Build Coastguard Worker /* Get a list of all loaded modules with full paths.
615*6236dae4SAndroid Build Coastguard Worker  * Returns slist on success or NULL on error.
616*6236dae4SAndroid Build Coastguard Worker  */
GetLoadedModulePaths(void)617*6236dae4SAndroid Build Coastguard Worker struct curl_slist *GetLoadedModulePaths(void)
618*6236dae4SAndroid Build Coastguard Worker {
619*6236dae4SAndroid Build Coastguard Worker   HANDLE hnd = INVALID_HANDLE_VALUE;
620*6236dae4SAndroid Build Coastguard Worker   MODULEENTRY32 mod = {0};
621*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *slist = NULL;
622*6236dae4SAndroid Build Coastguard Worker 
623*6236dae4SAndroid Build Coastguard Worker   mod.dwSize = sizeof(MODULEENTRY32);
624*6236dae4SAndroid Build Coastguard Worker 
625*6236dae4SAndroid Build Coastguard Worker   do {
626*6236dae4SAndroid Build Coastguard Worker     hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
627*6236dae4SAndroid Build Coastguard Worker   } while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH);
628*6236dae4SAndroid Build Coastguard Worker 
629*6236dae4SAndroid Build Coastguard Worker   if(hnd == INVALID_HANDLE_VALUE)
630*6236dae4SAndroid Build Coastguard Worker     goto error;
631*6236dae4SAndroid Build Coastguard Worker 
632*6236dae4SAndroid Build Coastguard Worker   if(!Module32First(hnd, &mod))
633*6236dae4SAndroid Build Coastguard Worker     goto error;
634*6236dae4SAndroid Build Coastguard Worker 
635*6236dae4SAndroid Build Coastguard Worker   do {
636*6236dae4SAndroid Build Coastguard Worker     char *path; /* points to stack allocated buffer */
637*6236dae4SAndroid Build Coastguard Worker     struct curl_slist *temp;
638*6236dae4SAndroid Build Coastguard Worker 
639*6236dae4SAndroid Build Coastguard Worker #ifdef UNICODE
640*6236dae4SAndroid Build Coastguard Worker     /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
641*6236dae4SAndroid Build Coastguard Worker        bytes of multibyte chars will not be more than twice that. */
642*6236dae4SAndroid Build Coastguard Worker     char buffer[sizeof(mod.szExePath) * 2];
643*6236dae4SAndroid Build Coastguard Worker     if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
644*6236dae4SAndroid Build Coastguard Worker                             buffer, sizeof(buffer), NULL, NULL))
645*6236dae4SAndroid Build Coastguard Worker       goto error;
646*6236dae4SAndroid Build Coastguard Worker     path = buffer;
647*6236dae4SAndroid Build Coastguard Worker #else
648*6236dae4SAndroid Build Coastguard Worker     path = mod.szExePath;
649*6236dae4SAndroid Build Coastguard Worker #endif
650*6236dae4SAndroid Build Coastguard Worker     temp = curl_slist_append(slist, path);
651*6236dae4SAndroid Build Coastguard Worker     if(!temp)
652*6236dae4SAndroid Build Coastguard Worker       goto error;
653*6236dae4SAndroid Build Coastguard Worker     slist = temp;
654*6236dae4SAndroid Build Coastguard Worker   } while(Module32Next(hnd, &mod));
655*6236dae4SAndroid Build Coastguard Worker 
656*6236dae4SAndroid Build Coastguard Worker   goto cleanup;
657*6236dae4SAndroid Build Coastguard Worker 
658*6236dae4SAndroid Build Coastguard Worker error:
659*6236dae4SAndroid Build Coastguard Worker   curl_slist_free_all(slist);
660*6236dae4SAndroid Build Coastguard Worker   slist = NULL;
661*6236dae4SAndroid Build Coastguard Worker cleanup:
662*6236dae4SAndroid Build Coastguard Worker   if(hnd != INVALID_HANDLE_VALUE)
663*6236dae4SAndroid Build Coastguard Worker     CloseHandle(hnd);
664*6236dae4SAndroid Build Coastguard Worker   return slist;
665*6236dae4SAndroid Build Coastguard Worker }
666*6236dae4SAndroid Build Coastguard Worker 
667*6236dae4SAndroid Build Coastguard Worker bool tool_term_has_bold;
668*6236dae4SAndroid Build Coastguard Worker 
669*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_WINDOWS_UWP
670*6236dae4SAndroid Build Coastguard Worker /* The terminal settings to restore on exit */
671*6236dae4SAndroid Build Coastguard Worker static struct TerminalSettings {
672*6236dae4SAndroid Build Coastguard Worker   HANDLE hStdOut;
673*6236dae4SAndroid Build Coastguard Worker   DWORD dwOutputMode;
674*6236dae4SAndroid Build Coastguard Worker   LONG valid;
675*6236dae4SAndroid Build Coastguard Worker } TerminalSettings;
676*6236dae4SAndroid Build Coastguard Worker 
677*6236dae4SAndroid Build Coastguard Worker #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
678*6236dae4SAndroid Build Coastguard Worker #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
679*6236dae4SAndroid Build Coastguard Worker #endif
680*6236dae4SAndroid Build Coastguard Worker 
restore_terminal(void)681*6236dae4SAndroid Build Coastguard Worker static void restore_terminal(void)
682*6236dae4SAndroid Build Coastguard Worker {
683*6236dae4SAndroid Build Coastguard Worker   if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
684*6236dae4SAndroid Build Coastguard Worker     SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
685*6236dae4SAndroid Build Coastguard Worker }
686*6236dae4SAndroid Build Coastguard Worker 
687*6236dae4SAndroid Build Coastguard Worker /* This is the console signal handler.
688*6236dae4SAndroid Build Coastguard Worker  * The system calls it in a separate thread.
689*6236dae4SAndroid Build Coastguard Worker  */
signal_handler(DWORD type)690*6236dae4SAndroid Build Coastguard Worker static BOOL WINAPI signal_handler(DWORD type)
691*6236dae4SAndroid Build Coastguard Worker {
692*6236dae4SAndroid Build Coastguard Worker   if(type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
693*6236dae4SAndroid Build Coastguard Worker     restore_terminal();
694*6236dae4SAndroid Build Coastguard Worker   return FALSE;
695*6236dae4SAndroid Build Coastguard Worker }
696*6236dae4SAndroid Build Coastguard Worker 
init_terminal(void)697*6236dae4SAndroid Build Coastguard Worker static void init_terminal(void)
698*6236dae4SAndroid Build Coastguard Worker {
699*6236dae4SAndroid Build Coastguard Worker   TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
700*6236dae4SAndroid Build Coastguard Worker 
701*6236dae4SAndroid Build Coastguard Worker   /*
702*6236dae4SAndroid Build Coastguard Worker    * Enable VT (Virtual Terminal) output.
703*6236dae4SAndroid Build Coastguard Worker    * Note: VT mode flag can be set on any version of Windows, but VT
704*6236dae4SAndroid Build Coastguard Worker    * processing only performed on Win10 >= version 1709 (OS build 16299)
705*6236dae4SAndroid Build Coastguard Worker    * Creator's Update. Also, ANSI bold on/off supported since then.
706*6236dae4SAndroid Build Coastguard Worker    */
707*6236dae4SAndroid Build Coastguard Worker   if(TerminalSettings.hStdOut == INVALID_HANDLE_VALUE ||
708*6236dae4SAndroid Build Coastguard Worker      !GetConsoleMode(TerminalSettings.hStdOut,
709*6236dae4SAndroid Build Coastguard Worker                      &TerminalSettings.dwOutputMode) ||
710*6236dae4SAndroid Build Coastguard Worker      !curlx_verify_windows_version(10, 0, 16299, PLATFORM_WINNT,
711*6236dae4SAndroid Build Coastguard Worker                                    VERSION_GREATER_THAN_EQUAL))
712*6236dae4SAndroid Build Coastguard Worker     return;
713*6236dae4SAndroid Build Coastguard Worker 
714*6236dae4SAndroid Build Coastguard Worker   if((TerminalSettings.dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
715*6236dae4SAndroid Build Coastguard Worker     tool_term_has_bold = true;
716*6236dae4SAndroid Build Coastguard Worker   else {
717*6236dae4SAndroid Build Coastguard Worker     /* The signal handler is set before attempting to change the console mode
718*6236dae4SAndroid Build Coastguard Worker        because otherwise a signal would not be caught after the change but
719*6236dae4SAndroid Build Coastguard Worker        before the handler was installed. */
720*6236dae4SAndroid Build Coastguard Worker     (void)InterlockedExchange(&TerminalSettings.valid, (LONG)TRUE);
721*6236dae4SAndroid Build Coastguard Worker     if(SetConsoleCtrlHandler(signal_handler, TRUE)) {
722*6236dae4SAndroid Build Coastguard Worker       if(SetConsoleMode(TerminalSettings.hStdOut,
723*6236dae4SAndroid Build Coastguard Worker                         (TerminalSettings.dwOutputMode |
724*6236dae4SAndroid Build Coastguard Worker                          ENABLE_VIRTUAL_TERMINAL_PROCESSING))) {
725*6236dae4SAndroid Build Coastguard Worker         tool_term_has_bold = true;
726*6236dae4SAndroid Build Coastguard Worker         atexit(restore_terminal);
727*6236dae4SAndroid Build Coastguard Worker       }
728*6236dae4SAndroid Build Coastguard Worker       else {
729*6236dae4SAndroid Build Coastguard Worker         SetConsoleCtrlHandler(signal_handler, FALSE);
730*6236dae4SAndroid Build Coastguard Worker         (void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE);
731*6236dae4SAndroid Build Coastguard Worker       }
732*6236dae4SAndroid Build Coastguard Worker     }
733*6236dae4SAndroid Build Coastguard Worker   }
734*6236dae4SAndroid Build Coastguard Worker }
735*6236dae4SAndroid Build Coastguard Worker #endif
736*6236dae4SAndroid Build Coastguard Worker 
737*6236dae4SAndroid Build Coastguard Worker LARGE_INTEGER tool_freq;
738*6236dae4SAndroid Build Coastguard Worker bool tool_isVistaOrGreater;
739*6236dae4SAndroid Build Coastguard Worker 
win32_init(void)740*6236dae4SAndroid Build Coastguard Worker CURLcode win32_init(void)
741*6236dae4SAndroid Build Coastguard Worker {
742*6236dae4SAndroid Build Coastguard Worker   /* curlx_verify_windows_version must be called during init at least once
743*6236dae4SAndroid Build Coastguard Worker      because it has its own initialization routine. */
744*6236dae4SAndroid Build Coastguard Worker   if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
745*6236dae4SAndroid Build Coastguard Worker                                   VERSION_GREATER_THAN_EQUAL))
746*6236dae4SAndroid Build Coastguard Worker     tool_isVistaOrGreater = true;
747*6236dae4SAndroid Build Coastguard Worker   else
748*6236dae4SAndroid Build Coastguard Worker     tool_isVistaOrGreater = false;
749*6236dae4SAndroid Build Coastguard Worker 
750*6236dae4SAndroid Build Coastguard Worker   QueryPerformanceFrequency(&tool_freq);
751*6236dae4SAndroid Build Coastguard Worker 
752*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_WINDOWS_UWP
753*6236dae4SAndroid Build Coastguard Worker   init_terminal();
754*6236dae4SAndroid Build Coastguard Worker #endif
755*6236dae4SAndroid Build Coastguard Worker 
756*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
757*6236dae4SAndroid Build Coastguard Worker }
758*6236dae4SAndroid Build Coastguard Worker 
759*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 */
760*6236dae4SAndroid Build Coastguard Worker 
761*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 || MSDOS */
762