struct elt *e_link; /* Pointer to the next one along */
size_t e_offset; /* Offset of name in path string */
unsigned e_flags; /* Various useful flags */
+#define EF_STICKY 1u /* Directory has sticky bit set */
char e_name[1]; /* Name of the directory */
};
-#define f_sticky 1u /* Directory has sticky bit set */
-
-#define f_last 1u /* This is the final item to check */
/*----- Static variables --------------------------------------------------*/
-static struct elt rootnode = { 0, 0, 0 }; /* Root of the list */
+static const struct elt rootnode = { 0, 0, 0 }; /* Root of the list */
static struct elt *sp; /* Stack pointer for list */
static dstr d = DSTR_INIT; /* Current path string */
struct elt *e = sp->e_link;
d.len = sp->e_offset;
DPUTZ(&d);
- free(sp); sp = e;
+ xfree(sp); sp = e;
}
}
* Arguments: @const char *p@ = name of directory to check
* @struct stat *st@ = pointer to @stat@(2) block for it
* @const struct checkpath *cp@ = pointer to caller parameters
- * @unsigned f@ = various flags
+ * @unsigned f@ = various flags (@SF_...@)
*
* Returns: Zero if everything's OK, else bitmask of problems.
*
* Use: Performs the main load of sanity-checking on a directory.
+ * If @SF_LAST@ is not set then sticky directories are always
+ * acceptable.
*/
+#define SF_LAST 1u /* This is the final item to check */
+
static unsigned sanity(const char *p, struct stat *st,
const struct checkpath *cp, unsigned f)
{
unsigned b;
if (S_ISDIR(st->st_mode) &&
- (!(f & f_last) || (cp->cp_what & CP_STICKYOK)))
- stickyok = 01000;
+ (!(f & SF_LAST) || (cp->cp_what & CP_STICKYOK)))
+ stickyok = S_ISVTX;
/* --- Check for world-writability --- */
if ((cp->cp_what & CP_WRWORLD) &&
- (st->st_mode & (0002 | stickyok)) == 0002) {
+ (st->st_mode & (S_IWOTH | stickyok)) == S_IWOTH) {
bad |= CP_WRWORLD;
report(cp, CP_WRWORLD, 1, p, "** world writable **");
}
/* --- Check for group-writability --- */
if ((cp->cp_what & (CP_WRGRP | CP_WROTHGRP)) &&
- (st->st_mode & (0020 | stickyok)) == 0020) {
+ (st->st_mode & (S_IWGRP | stickyok)) == S_IWGRP) {
b = CP_WRGRP;
if (cp->cp_what & CP_WROTHGRP) {
struct elt *e, *ee;
struct stat st;
unsigned bad = 0;
+ dstr buf = DSTR_INIT;
/* --- Initialize stack pointer and path string --- */
- sp = &rootnode;
+ sp = (/*unconst*/ struct elt *)&rootnode;
dstr_destroy(&d);
/* --- Try to find the current directory --- */
/* --- Strip off simple `.' elements --- */
if (strcmp(ee->e_name, ".") == 0) {
- free(ee);
+ xfree(ee);
ee = e;
continue;
}
else if (strcmp(ee->e_name, "..") == 0) {
pop();
- free(ee);
+ xfree(ee);
ee = e;
continue;
}
/* --- Handle symbolic links specially --- */
if (S_ISLNK(st.st_mode)) {
- dstr buf = DSTR_INIT;
int i;
/* --- Resolve the link --- */
+ dstr_reset(&buf);
dstr_ensure(&buf, st.st_size + 1);
if ((i = readlink(d.buf, buf.buf, buf.sz)) < 0) {
report(cp, CP_ERROR, 0, d.buf, "can't readlink: %e");
*/
if ((cp->cp_what & CP_WROTHUSR) &&
- (sp->e_link->e_flags & f_sticky) &&
+ (sp->e_link->e_flags & EF_STICKY) &&
st.st_uid != cp->cp_uid && st.st_uid != 0) {
bad |= CP_WROTHUSR;
report(cp, CP_WROTHUSR, 1, d.buf,
else
pop();
ee = splitpath(buf.buf, ee);
- dstr_destroy(&buf);
continue;
}
/* --- Run the sanity check on this path element --- */
- bad |= sanity(d.buf, &st, cp, ee ? 0 : f_last);
+ bad |= sanity(d.buf, &st, cp, ee ? 0 : SF_LAST);
if (S_ISDIR(st.st_mode)) {
- if (st.st_mode & 01000)
- sp->e_flags |= f_sticky;
+ if (st.st_mode & S_ISVTX)
+ sp->e_flags |= EF_STICKY;
report(cp, CP_REPORT, 4, d.buf, "directory");
continue;
}
report(cp, CP_ERROR, 0, 0, "junk left over after reaching leaf");
while (ee) {
e = ee->e_link;
- free(ee);
+ xfree(ee);
ee = e;
}
}
popall();
+ dstr_destroy(&buf);
return (bad);
}