Coverage Report

Created: 2023-08-07 06:59

/src/p11-kit/common/path.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2005 Stefan Walter
3
 * Copyright (c) 2011 Collabora Ltd.
4
 * Copyright (c) 2013 Red Hat Inc.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 *     * Redistributions of source code must retain the above
11
 *       copyright notice, this list of conditions and the
12
 *       following disclaimer.
13
 *     * Redistributions in binary form must reproduce the
14
 *       above copyright notice, this list of conditions and
15
 *       the following disclaimer in the documentation and/or
16
 *       other materials provided with the distribution.
17
 *     * The names of contributors to this software may not be
18
 *       used to endorse or promote products derived from this
19
 *       software without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32
 * DAMAGE.
33
 *
34
 *
35
 * CONTRIBUTORS
36
 *  Stef Walter <stefw@redhat.com>
37
 */
38
39
#include "config.h"
40
41
#include "buffer.h"
42
#include "debug.h"
43
#include "message.h"
44
#include "path.h"
45
#include "url.h"
46
47
#include <assert.h>
48
#include <errno.h>
49
#include <stdarg.h>
50
#include <stdlib.h>
51
#include <string.h>
52
53
#ifdef OS_UNIX
54
#include <pwd.h>
55
#include <unistd.h>
56
#endif
57
58
#ifdef OS_WIN32
59
#include <shlobj.h>
60
#endif
61
62
63
char *
64
p11_path_base (const char *path)
65
0
{
66
#ifdef OS_WIN32
67
  const char *delims = "/\\";
68
#else
69
0
  const char *delims = "/";
70
0
#endif
71
72
0
  const char *end;
73
0
  const char *beg;
74
75
0
  return_val_if_fail (path != NULL, NULL);
76
77
  /* Any trailing slashes */
78
0
  end = path + strlen (path);
79
0
  while (end != path) {
80
0
    if (!strchr (delims, *(end - 1)))
81
0
      break;
82
0
    end--;
83
0
  }
84
85
  /* Find the last slash after those */
86
0
  beg = end;
87
0
  while (beg != path) {
88
0
    if (strchr (delims, *(beg - 1)))
89
0
      break;
90
0
    beg--;
91
0
  }
92
93
0
  return strndup (beg, end - beg);
94
0
}
95
96
static inline bool
97
is_path_separator (char ch)
98
0
{
99
0
  return (ch == '/'
100
#ifdef OS_WIN32
101
      || ch == '\\'
102
#endif
103
0
    );
104
0
}
105
106
static inline bool
107
is_path_separator_or_null (char ch)
108
0
{
109
0
  return is_path_separator (ch) || ch == '\0';
110
0
}
111
112
static char *
113
expand_homedir (const char *remainder)
114
0
{
115
0
  const char *env;
116
117
0
  if (getauxval (AT_SECURE)) {
118
0
    errno = EPERM;
119
0
    return NULL;
120
0
  }
121
122
0
  while (is_path_separator (remainder[0]))
123
0
    remainder++;
124
0
  if (remainder[0] == '\0')
125
0
    remainder = NULL;
126
127
  /* Expand $XDG_CONFIG_HOME */
128
0
  if (remainder != NULL &&
129
0
      strncmp (remainder, ".config", 7) == 0 &&
130
0
      is_path_separator_or_null (remainder[7])) {
131
0
    env = getenv ("XDG_CONFIG_HOME");
132
0
    if (env && env[0])
133
0
      return p11_path_build (env, remainder + 8, NULL);
134
0
  }
135
136
0
  env = getenv ("HOME");
137
0
  if (env && env[0]) {
138
0
    return p11_path_build (env, remainder, NULL);
139
140
0
  } else {
141
0
#ifdef OS_UNIX
142
0
    char buf[1024];
143
0
    struct passwd pws;
144
0
    struct passwd *pwd = NULL;
145
0
    int error;
146
0
    int ret;
147
148
0
    errno = 0;
149
0
    ret = getpwuid_r (getuid (), &pws, buf, sizeof (buf), &pwd);
150
0
    if (pwd == NULL) {
151
0
      if (ret == 0)
152
0
        error = ESRCH;
153
0
      else
154
0
        error = errno;
155
0
      p11_message_err (error, "couldn't lookup home directory for user %d", getuid ());
156
0
      errno = error;
157
0
      return NULL;
158
0
    }
159
160
0
    return p11_path_build (pwd->pw_dir, remainder, NULL);
161
162
#else /* OS_WIN32 */
163
    char directory[MAX_PATH + 1];
164
165
    if (!SHGetSpecialFolderPathA (NULL, directory, CSIDL_PROFILE, TRUE)) {
166
      p11_message ("couldn't lookup home directory for user");
167
      errno = ENOTDIR;
168
      return NULL;
169
    }
170
171
    return p11_path_build (directory, remainder, NULL);
172
173
#endif /* OS_WIN32 */
174
0
  }
175
0
}
176
177
char *
178
p11_path_expand (const char *path)
179
0
{
180
0
  return_val_if_fail (path != NULL, NULL);
181
182
0
  if (strncmp (path, "~", 1) == 0 &&
183
0
      is_path_separator_or_null (path[1])) {
184
0
    return expand_homedir (path + 1);
185
186
0
  } else {
187
0
    return strdup (path);
188
0
  }
189
0
}
190
191
bool
192
p11_path_absolute (const char *path)
193
0
{
194
0
  return_val_if_fail (path != NULL, false);
195
196
0
  return (path[0] == '/')
197
#ifdef OS_WIN32
198
  || (path[0] != '\0' && path[1] == ':' && path[2] == '\\')
199
#endif
200
0
  ;
201
0
}
202
203
char *
204
p11_path_build (const char *path,
205
                ...)
206
0
{
207
#ifdef OS_WIN32
208
  const char delim = '\\';
209
#else
210
0
  const char delim = '/';
211
0
#endif
212
0
  const char *first = path;
213
0
  char *built;
214
0
  size_t len;
215
0
  size_t at;
216
0
  size_t num;
217
0
  size_t until;
218
0
  va_list va;
219
220
0
  return_val_if_fail (path != NULL, NULL);
221
222
0
  len = 1;
223
0
  va_start (va, path);
224
0
  while (path != NULL) {
225
0
    size_t old_len = len;
226
0
    len += strlen (path) + 1;
227
0
    if (len < old_len) {
228
0
      va_end (va);
229
0
      return_val_if_reached (NULL);
230
0
    }
231
0
    path = va_arg (va, const char *);
232
0
  }
233
0
  va_end (va);
234
235
0
  built = malloc (len + 1);
236
0
  return_val_if_fail (built != NULL, NULL);
237
238
0
  at = 0;
239
0
  path = first;
240
0
  va_start (va, path);
241
0
  while (path != NULL) {
242
0
    num = strlen (path);
243
244
    /* Trim beginning of path */
245
0
    while (is_path_separator (path[0])) {
246
      /* But preserve the leading path component */
247
0
      if (!at && !is_path_separator (path[1]))
248
0
        break;
249
0
      path++;
250
0
      num--;
251
0
    }
252
253
    /* Trim end of the path */
254
0
    until = (at > 0) ? 0 : 1;
255
0
    while (num > until && is_path_separator_or_null (path[num - 1]))
256
0
      num--;
257
258
0
    if (at != 0) {
259
0
      if (num == 0) {
260
0
        path = va_arg (va, const char *);
261
0
        continue;
262
0
      }
263
0
      if (built[at - 1] != delim)
264
0
        built[at++] = delim;
265
0
    }
266
267
0
    assert (at + num < len);
268
0
    memcpy (built + at, path, num);
269
0
    at += num;
270
271
0
    path = va_arg (va, const char *);
272
0
  }
273
0
  va_end (va);
274
275
0
  assert (at < len);
276
0
  built[at] = '\0';
277
0
  return built;
278
0
}
279
280
char *
281
p11_path_parent (const char *path)
282
0
{
283
0
  const char *e;
284
0
  char *parent;
285
0
  bool had = false;
286
287
0
  return_val_if_fail (path != NULL, NULL);
288
289
  /* Find the end of the last component */
290
0
  e = path + strlen (path);
291
0
  while (e != path && is_path_separator_or_null (*e))
292
0
    e--;
293
294
  /* Find the beginning of the last component */
295
0
  while (e != path && !is_path_separator_or_null (*e)) {
296
0
    had = true;
297
0
    e--;
298
0
  }
299
300
  /* Find the end of the last component */
301
0
  while (e != path && is_path_separator_or_null (*e))
302
0
    e--;
303
304
0
  if (e == path) {
305
0
    if (!had)
306
0
      return NULL;
307
0
    parent = strdup ("/");
308
0
  } else {
309
0
    parent = strndup (path, (e - path) + 1);
310
0
  }
311
312
0
  return_val_if_fail (parent != NULL, NULL);
313
0
  return parent;
314
0
}
315
316
bool
317
p11_path_prefix (const char *string,
318
                 const char *prefix)
319
0
{
320
0
  int a, b;
321
322
0
  return_val_if_fail (string != NULL, false);
323
0
  return_val_if_fail (prefix != NULL, false);
324
325
0
  a = strlen (string);
326
0
  b = strlen (prefix);
327
328
0
  return a > b &&
329
0
         strncmp (string, prefix, b) == 0 &&
330
0
         is_path_separator_or_null (string[b]);
331
0
}
332
333
void
334
p11_path_canon (char *name)
335
0
{
336
0
  static const char *VALID =
337
0
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_";
338
0
  int i;
339
340
0
  return_if_fail (name != NULL);
341
342
0
  for (i = 0; name[i] != '\0'; i++) {
343
0
    if (strchr (VALID, name[i]) == NULL)
344
0
      name[i] = '_';
345
0
  }
346
0
}
347
348
char *
349
p11_path_encode (const char *path)
350
0
{
351
0
  static const char *VALID =
352
0
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/\\";
353
0
  p11_buffer buf;
354
0
  char *result;
355
356
0
  return_val_if_fail (path != NULL, NULL);
357
358
0
  if (!p11_buffer_init_null (&buf, strlen (path)))
359
0
    return_val_if_reached (NULL);
360
361
0
  p11_url_encode ((unsigned char *)path,
362
0
      (unsigned char *)path + strlen (path),
363
0
      VALID,
364
0
      &buf);
365
0
  return_val_if_fail (p11_buffer_ok (&buf), NULL);
366
367
0
  result = p11_buffer_steal (&buf, NULL);
368
0
  p11_buffer_uninit (&buf);
369
370
0
  return result;
371
0
}
372
373
char *
374
p11_path_decode (const char *path)
375
0
{
376
0
  return (char *) p11_url_decode (path, path + strlen (path), "", NULL);
377
0
}