2 * Placed in the public domain
5 /* $OpenBSD: modpipe.c,v 1.6 2013/11/21 03:16:47 djm Exp $ */
23 fatal(const char *fmt
, ...)
28 vfprintf(stderr
, fmt
, args
);
33 /* Based on session.c. NB. keep tests in sync */
35 safely_chroot(const char *path
, uid_t uid
)
38 char component
[PATH_MAX
];
42 fatal("chroot path does not begin at root");
43 if (strlen(path
) >= sizeof(component
))
44 fatal("chroot path too long");
47 * Descend the path, checking that each component is a
48 * root-owned directory with strict permissions.
50 for (cp
= path
; cp
!= NULL
;) {
51 if ((cp
= strchr(cp
, '/')) == NULL
)
52 strlcpy(component
, path
, sizeof(component
));
55 memcpy(component
, path
, cp
- path
);
56 component
[cp
- path
] = '\0';
59 /* debug3("%s: checking '%s'", __func__, component); */
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 "
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
);
74 if (chdir(path
) == -1)
75 fatal("Unable to chdir to chroot path \"%s\": "
76 "%s", path
, strerror(errno
));
81 platform_sys_dir_uid(uid_t uid
)
85 #ifdef PLATFORM_SYS_DIR_UID
86 if (uid
== PLATFORM_SYS_DIR_UID
)
94 auth_secure_path(const char *name
, struct stat
*stp
, const char *pw_dir
,
95 uid_t uid
, char *err
, size_t errlen
)
97 char buf
[PATH_MAX
], homedir
[PATH_MAX
];
102 if (realpath(name
, buf
) == NULL
) {
103 snprintf(err
, errlen
, "realpath %s failed: %s", name
,
107 if (pw_dir
!= NULL
&& realpath(pw_dir
, homedir
) != NULL
)
110 if (!S_ISREG(stp
->st_mode
)) {
111 snprintf(err
, errlen
, "%s is not a regular file", buf
);
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",
121 /* for each component of the canonical path, walking upwards */
123 if ((cp
= dirname(buf
)) == NULL
) {
124 snprintf(err
, errlen
, "dirname() failed");
127 strlcpy(buf
, cp
, sizeof(buf
));
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
);
137 /* If are past the homedir then we can stop */
138 if (comparehome
&& strcmp(homedir
, buf
) == 0)
142 * dirname should always complete with a "/" path,
143 * but we can be paranoid and check for "." too
145 if ((strcmp("/", buf
) == 0) || (strcmp(".", buf
) == 0))
154 fprintf(stderr
, "check-perm -m [chroot | keys-command] [path]\n");
159 main(int argc
, char **argv
)
161 const char *path
= ".";
168 while ((ch
= getopt(argc
, argv
, "hm:")) != -1) {
171 if (strcasecmp(optarg
, "chroot") == 0)
173 else if (strcasecmp(optarg
, "keys-command") == 0)
176 fprintf(stderr
, "Invalid -m option\n"),
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
);
201 fprintf(stderr
, "Invalid mode\n");