1 /*
2 * pickystat.c
3 *
4 * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
5 * All rights reserved.
6 *
7 * $Id: pickystat.c,v 1.11 2015/03/14 06:11:27 marc Exp marc $
8 *
9 */
10
11 #include "headers.h"
12
13 static const char rcsid[] __attribute__ ((used)) = "$Id: pickystat.c,v 1.11 2015/03/14 06:11:27 marc Exp marc $";
14
pickystat_one(struct context * ctx,struct stat * st,char * file)15 static int pickystat_one(struct context *ctx, struct stat *st, char *file)
16 {
17 struct stat lst;
18
19 Debug((DEBUG_PROC, "+ %s(%s)\n", __func__, file));
20
21 if (lstat(file, &lst)) {
22 /* file doesn't exist */
23
24 Debug((DEBUG_PROC, "- %s FAILURE (no such file)\n", __func__));
25 return -1;
26 }
27
28 if (S_ISLNK(lst.st_mode)) {
29 /* symbolic link */
30
31 if (stat(file, st)) {
32 Debug((DEBUG_PROC, "- %s FAILURE (broken link)\n", __func__));
33 return -1;
34 }
35
36 if (!(((ctx->allow_symlinks & SYMLINKS_YES)) ||
37 ((ctx->allow_symlinks & SYMLINKS_REAL) && !ctx->anonymous) ||
38 ((ctx->allow_symlinks & SYMLINKS_ROOT) && lst.st_uid == 0) || ((ctx->allow_symlinks & SYMLINKS_SAME)
39 && lst.st_uid == st->st_uid))) {
40 Debug((DEBUG_PROC, "- %s FAILURE (unsafe symlink)\n", __func__));
41 return -1;
42 }
43 } else
44 *st = lst;
45
46 if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) {
47 Debug((DEBUG_PROC, "- %s FAILURE (not a plain file or directory)\n", __func__));
48 return -1;
49 }
50
51 if (ctx->picky_uidcheck && !ctx->picky_gidcheck && (st->st_uid != ctx->uid)) {
52 Debug((DEBUG_PROC, "- %s FAILURE (UID check)\n", __func__));
53 return -1;
54 }
55
56 if (ctx->picky_gidcheck && !check_gids(ctx, st->st_gid)) {
57 Debug((DEBUG_PROC, "- %s FAILURE (GID check)\n", __func__));
58 return -1;
59 }
60
61 if (ctx->picky_permcheck && !(st->st_mode & S_IROTH)) {
62 Debug((DEBUG_PROC, "- %s FAILURE (not world readable)\n", __func__));
63 return -1;
64 }
65
66 Debug((DEBUG_PROC, "- %s SUCCESS\n", __func__));
67 return 0;
68 }
69
pickystat(struct context * ctx,struct stat * st,char * path)70 int pickystat(struct context *ctx, struct stat *st, char *path)
71 {
72 int r;
73
74 Debug((DEBUG_PROC, "+ %s (%s)\n", __func__, path));
75
76 if (*path == '/') {
77 int offset;
78 char *t;
79
80 if (strncmp(path, ctx->cwd, ctx->cwdlen) || (path[ctx->cwdlen] && path[ctx->cwdlen] != '/'))
81 offset = ctx->rootlen;
82 else
83 offset = ctx->cwdlen;
84
85 offset = offset ? offset : 1;
86
87 for (t = path + offset; *t; t++)
88 if (*t == '/') {
89 *t = 0;
90 r = pickystat_one(ctx, st, path);
91 *t = '/';
92 if (r) {
93 DebugOut(DEBUG_PROC);
94 return r;
95 }
96 }
97 }
98
99 r = pickystat_one(ctx, st, path);
100 DebugOut(DEBUG_PROC);
101 return r;
102 }
103
pickystat_path(struct context * ctx,struct stat * st,char * path)104 int pickystat_path(struct context *ctx, struct stat *st, char *path)
105 {
106 char *t;
107 int r;
108
109 t = strrchr(path, '/');
110 if (t)
111 *t = 0;
112 r = pickystat(ctx, st, path);
113 if (t)
114 *t = '/';
115 return r;
116 }
117