]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - crypto/openssh/regress/check-perm.c
MFS (r296781):
[FreeBSD/releng/10.3.git] / crypto / openssh / regress / check-perm.c
1 /*
2  * Placed in the public domain
3  */
4
5 /* $OpenBSD: modpipe.c,v 1.6 2013/11/21 03:16:47 djm Exp $ */
6
7 #include "includes.h"
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdarg.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <pwd.h>
18 #ifdef HAVE_LIBGEN_H
19 #include <libgen.h>
20 #endif
21
22 static void
23 fatal(const char *fmt, ...)
24 {
25         va_list args;
26
27         va_start(args, fmt);
28         vfprintf(stderr, fmt, args);
29         fputc('\n', stderr);
30         va_end(args);
31         exit(1);
32 }
33 /* Based on session.c. NB. keep tests in sync */
34 static void
35 safely_chroot(const char *path, uid_t uid)
36 {
37         const char *cp;
38         char component[PATH_MAX];
39         struct stat st;
40
41         if (*path != '/')
42                 fatal("chroot path does not begin at root");
43         if (strlen(path) >= sizeof(component))
44                 fatal("chroot path too long");
45
46         /*
47          * Descend the path, checking that each component is a
48          * root-owned directory with strict permissions.
49          */
50         for (cp = path; cp != NULL;) {
51                 if ((cp = strchr(cp, '/')) == NULL)
52                         strlcpy(component, path, sizeof(component));
53                 else {
54                         cp++;
55                         memcpy(component, path, cp - path);
56                         component[cp - path] = '\0';
57                 }
58
59                 /* debug3("%s: checking '%s'", __func__, component); */
60
61                 if (stat(component, &st) != 0)
62                         fatal("%s: stat(\"%s\"): %s", __func__,
63                             component, strerror(errno));
64                 if (st.st_uid != 0 || (st.st_mode & 022) != 0)
65                         fatal("bad ownership or modes for chroot "
66                             "directory %s\"%s\"",
67                             cp == NULL ? "" : "component ", component);
68                 if (!S_ISDIR(st.st_mode))
69                         fatal("chroot path %s\"%s\" is not a directory",
70                             cp == NULL ? "" : "component ", component);
71
72         }
73
74         if (chdir(path) == -1)
75                 fatal("Unable to chdir to chroot path \"%s\": "
76                     "%s", path, strerror(errno));
77 }
78
79 /* from platform.c */
80 int
81 platform_sys_dir_uid(uid_t uid)
82 {
83         if (uid == 0)
84                 return 1;
85 #ifdef PLATFORM_SYS_DIR_UID
86         if (uid == PLATFORM_SYS_DIR_UID)
87                 return 1;
88 #endif
89         return 0;
90 }
91
92 /* from auth.c */
93 int
94 auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
95     uid_t uid, char *err, size_t errlen)
96 {
97         char buf[PATH_MAX], homedir[PATH_MAX];
98         char *cp;
99         int comparehome = 0;
100         struct stat st;
101
102         if (realpath(name, buf) == NULL) {
103                 snprintf(err, errlen, "realpath %s failed: %s", name,
104                     strerror(errno));
105                 return -1;
106         }
107         if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
108                 comparehome = 1;
109
110         if (!S_ISREG(stp->st_mode)) {
111                 snprintf(err, errlen, "%s is not a regular file", buf);
112                 return -1;
113         }
114         if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
115             (stp->st_mode & 022) != 0) {
116                 snprintf(err, errlen, "bad ownership or modes for file %s",
117                     buf);
118                 return -1;
119         }
120
121         /* for each component of the canonical path, walking upwards */
122         for (;;) {
123                 if ((cp = dirname(buf)) == NULL) {
124                         snprintf(err, errlen, "dirname() failed");
125                         return -1;
126                 }
127                 strlcpy(buf, cp, sizeof(buf));
128
129                 if (stat(buf, &st) < 0 ||
130                     (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
131                     (st.st_mode & 022) != 0) {
132                         snprintf(err, errlen,
133                             "bad ownership or modes for directory %s", buf);
134                         return -1;
135                 }
136
137                 /* If are past the homedir then we can stop */
138                 if (comparehome && strcmp(homedir, buf) == 0)
139                         break;
140
141                 /*
142                  * dirname should always complete with a "/" path,
143                  * but we can be paranoid and check for "." too
144                  */
145                 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
146                         break;
147         }
148         return 0;
149 }
150
151 static void
152 usage(void)
153 {
154         fprintf(stderr, "check-perm -m [chroot | keys-command] [path]\n");
155         exit(1);
156 }
157
158 int
159 main(int argc, char **argv)
160 {
161         const char *path = ".";
162         char errmsg[256];
163         int ch, mode = -1;
164         extern char *optarg;
165         extern int optind;
166         struct stat st;
167
168         while ((ch = getopt(argc, argv, "hm:")) != -1) {
169                 switch (ch) {
170                 case 'm':
171                         if (strcasecmp(optarg, "chroot") == 0)
172                                 mode = 1;
173                         else if (strcasecmp(optarg, "keys-command") == 0)
174                                 mode = 2;
175                         else {
176                                 fprintf(stderr, "Invalid -m option\n"),
177                                 usage();
178                         }
179                         break;
180                 default:
181                         usage();
182                 }
183         }
184         argc -= optind;
185         argv += optind;
186
187         if (argc > 1)
188                 usage();
189         else if (argc == 1)
190                 path = argv[0];
191
192         if (mode == 1)
193                 safely_chroot(path, getuid());
194         else if (mode == 2) {
195                 if (stat(path, &st) < 0)
196                         fatal("Could not stat %s: %s", path, strerror(errno));
197                 if (auth_secure_path(path, &st, NULL, 0,
198                     errmsg, sizeof(errmsg)) != 0)
199                         fatal("Unsafe %s: %s", path, errmsg);
200         } else {
201                 fprintf(stderr, "Invalid mode\n");
202                 usage();
203         }
204         return 0;
205 }