chiark
/
gitweb
/
~mdw
/
checkpath
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
checkpath.c: Allocate the state from a resource pool.
[checkpath]
/
checkpath.c
diff --git
a/checkpath.c
b/checkpath.c
index e5942018a8194bef60d45f800aa504b482dd9f6f..95524ae24f34c3b9fc01d670c9c1585cd029b32a 100644
(file)
--- a/
checkpath.c
+++ b/
checkpath.c
@@
-44,6
+44,7
@@
#include <mLib/alloc.h>
#include <mLib/dstr.h>
#include <mLib/macros.h>
#include <mLib/alloc.h>
#include <mLib/dstr.h>
#include <mLib/macros.h>
+#include <mLib/pool.h>
#include "checkpath.h"
#include "checkpath.h"
@@
-59,18
+60,19
@@
struct elt {
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 */
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 */
};
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 */
+struct state {
+ pool *p; /* Allocation pool */
+ struct elt *sp; /* Stack pointer for list */
+ dstr path; /* Current path string */
+};
/*----- Static variables --------------------------------------------------*/
/*----- Static variables --------------------------------------------------*/
-static 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 */
+static const struct elt rootnode = { 0, 0, 0 }; /* Root of the list */
/*----- Main code ---------------------------------------------------------*/
/*----- Main code ---------------------------------------------------------*/
@@
-89,9
+91,9
@@
static dstr d = DSTR_INIT; /* Current path string */
static struct elt *splitpath(const char *path, struct elt *tail)
{
struct elt *head, **ee = &head, *e;
static struct elt *splitpath(const char *path, struct elt *tail)
{
struct elt *head, **ee = &head, *e;
+ size_t n;
while (*path) {
while (*path) {
- size_t n;
/* --- Either a leading `/', or a doubled one --- *
*
/* --- Either a leading `/', or a doubled one --- *
*
@@
-126,56
+128,59
@@
static struct elt *splitpath(const char *path, struct elt *tail)
/* --- @pop@ --- *
*
/* --- @pop@ --- *
*
- * Arguments:
---
+ * Arguments:
@struct state *state@ = working state
*
* Returns: ---
*
* Use: Removes the top item from the directory stack.
*/
*
* Returns: ---
*
* Use: Removes the top item from the directory stack.
*/
-static void pop(
void
)
+static void pop(
struct state *state
)
{
{
+ struct elt *sp = state->sp, *e;
+
if (sp->e_link) {
if (sp->e_link) {
-
struct elt *
e = sp->e_link;
-
d
.len = sp->e_offset;
- DPUTZ(&
d
);
- sp = e;
+ e = sp->e_link;
+
state->path
.len = sp->e_offset;
+ DPUTZ(&
state->path
);
+
xfree(state->sp); state->
sp = e;
}
}
/* --- @popall@ --- *
*
}
}
/* --- @popall@ --- *
*
- * Arguments:
---
+ * Arguments:
@struct state *state@ = working state
*
* Returns: ---
*
* Use: Removes all the items from the directory stack.
*/
*
* Returns: ---
*
* Use: Removes all the items from the directory stack.
*/
-static void popall(
void
)
- { while (s
p->e_link) pop(
); }
+static void popall(
struct state *state
)
+ { while (s
tate->sp->e_link) pop(state
); }
/* --- @push@ --- *
*
/* --- @push@ --- *
*
- * Arguments: @struct elt *e@ = pointer to directory element
+ * Arguments: @struct state *state@ = working state
+ * @struct elt *e@ = pointer to directory element
*
* Returns: ---
*
* Use: Pushes a new subdirectory onto the stack.
*/
*
* Returns: ---
*
* Use: Pushes a new subdirectory onto the stack.
*/
-static void push(struct elt *e)
+static void push(struct
state *state, struct
elt *e)
{
{
- e->e_link = sp;
- e->e_offset =
d
.len;
- DPUTC(&
d
, '/');
- DPUTS(&
d
, e->e_name);
- sp = e;
+ e->e_link = s
tate->s
p;
+ e->e_offset =
state->path
.len;
+ DPUTC(&
state->path
, '/');
+ DPUTS(&
state->path
, e->e_name);
+ s
tate->s
p = e;
}
/* --- @report@ --- *
*
}
/* --- @report@ --- *
*
- * Arguments: @const struct checkpath *cp@ = pointer to
context
+ * Arguments: @const struct checkpath *cp@ = pointer to
query
* @unsigned what@ = what sort of report is this?
* @int verbose@ = how verbose is this?
* @const char *p@ = what path does it refer to?
* @unsigned what@ = what sort of report is this?
* @int verbose@ = how verbose is this?
* @const char *p@ = what path does it refer to?
@@
-271,14
+276,18
@@
static void report(const struct checkpath *cp, unsigned what, int verbose,
*
* Arguments: @const char *p@ = name of directory to check
* @struct stat *st@ = pointer to @stat@(2) block for it
*
* 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
+ * @const struct checkpath *cp@ = pointer to
query
+ * @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.
*
* 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)
{
static unsigned sanity(const char *p, struct stat *st,
const struct checkpath *cp, unsigned f)
{
@@
-288,13
+297,13
@@
static unsigned sanity(const char *p, struct stat *st,
unsigned b;
if (S_ISDIR(st->st_mode) &&
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) &&
/* --- 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 **");
}
bad |= CP_WRWORLD;
report(cp, CP_WRWORLD, 1, p, "** world writable **");
}
@@
-302,7
+311,7
@@
static unsigned sanity(const char *p, struct stat *st,
/* --- Check for group-writability --- */
if ((cp->cp_what & (CP_WRGRP | CP_WROTHGRP)) &&
/* --- 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) {
b = CP_WRGRP;
if (cp->cp_what & CP_WROTHGRP) {
@@
-348,13
+357,20
@@
unsigned checkpath(const char *p, const struct checkpath *cp)
{
char cwd[PATH_MAX];
struct elt *e, *ee;
{
char cwd[PATH_MAX];
struct elt *e, *ee;
+ struct state *state;
+ pool *pp;
struct stat st;
unsigned bad = 0;
struct stat st;
unsigned bad = 0;
+ dstr buf = DSTR_INIT;
+ int i;
- /* --- Initialize
stack pointer and path string
--- */
+ /* --- Initialize
the state
--- */
- sp = &rootnode;
- dstr_destroy(&d);
+ pp = pool_create(arena_global);
+ state = pool_alloc(pp, sizeof(*state));
+ state->p = pp;
+ state->sp = (/*unconst*/ struct elt *)&rootnode;
+ dstr_create(&state->path);
/* --- Try to find the current directory --- */
/* --- Try to find the current directory --- */
@@
-387,7
+403,7
@@
unsigned checkpath(const char *p, const struct checkpath *cp)
/* --- Strip off simple `.' elements --- */
if (strcmp(ee->e_name, ".") == 0) {
/* --- Strip off simple `.' elements --- */
if (strcmp(ee->e_name, ".") == 0) {
- free(ee);
+
x
free(ee);
ee = e;
continue;
}
ee = e;
continue;
}
@@
-395,21
+411,21
@@
unsigned checkpath(const char *p, const struct checkpath *cp)
/* --- Backtrack on `..' elements --- */
else if (strcmp(ee->e_name, "..") == 0) {
/* --- Backtrack on `..' elements --- */
else if (strcmp(ee->e_name, "..") == 0) {
- pop();
- free(ee);
+ pop(
state
);
+
x
free(ee);
ee = e;
continue;
}
/* --- Everything else gets pushed on the end --- */
ee = e;
continue;
}
/* --- Everything else gets pushed on the end --- */
- push(ee);
+ push(
state,
ee);
ee = e;
/* --- Find out what sort of a thing this is --- */
ee = e;
/* --- Find out what sort of a thing this is --- */
- if (lstat(
d
.buf, &st)) {
- report(cp, CP_ERROR, 0,
d
.buf, "can't stat: %e");
+ if (lstat(
state->path
.buf, &st)) {
+ report(cp, CP_ERROR, 0,
state->path
.buf, "can't stat: %e");
bad |= CP_ERROR;
break;
}
bad |= CP_ERROR;
break;
}
@@
-417,19
+433,18
@@
unsigned checkpath(const char *p, const struct checkpath *cp)
/* --- Handle symbolic links specially --- */
if (S_ISLNK(st.st_mode)) {
/* --- Handle symbolic links specially --- */
if (S_ISLNK(st.st_mode)) {
- dstr buf = DSTR_INIT;
- int i;
/* --- Resolve the link --- */
/* --- Resolve the link --- */
+ dstr_reset(&buf);
dstr_ensure(&buf, st.st_size + 1);
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 ((i = readlink(
state->path
.buf, buf.buf, buf.sz)) < 0) {
+ report(cp, CP_ERROR, 0,
state->path
.buf, "can't readlink: %e");
bad |= CP_ERROR;
break;
}
buf.buf[i] = 0;
bad |= CP_ERROR;
break;
}
buf.buf[i] = 0;
- report(cp, CP_SYMLINK, 2,
d
.buf, "symlink -> `%s'", buf.buf);
+ report(cp, CP_SYMLINK, 2,
state->path
.buf, "symlink -> `%s'", buf.buf);
/* --- Handle sticky parents --- *
*
/* --- Handle sticky parents --- *
*
@@
-439,32
+454,31
@@
unsigned checkpath(const char *p, const struct checkpath *cp)
*/
if ((cp->cp_what & CP_WROTHUSR) &&
*/
if ((cp->cp_what & CP_WROTHUSR) &&
- (s
p->e_link->e_flags & f_sticky
) &&
+ (s
tate->sp->e_link->e_flags & EF_STICKY
) &&
st.st_uid != cp->cp_uid && st.st_uid != 0) {
bad |= CP_WROTHUSR;
st.st_uid != cp->cp_uid && st.st_uid != 0) {
bad |= CP_WROTHUSR;
- report(cp, CP_WROTHUSR, 1,
d
.buf,
+ report(cp, CP_WROTHUSR, 1,
state->path
.buf,
"symlink modifiable by user %u", st.st_uid);
}
/* --- Sort out what to do from here --- */
if (buf.buf[0] == '/')
"symlink modifiable by user %u", st.st_uid);
}
/* --- Sort out what to do from here --- */
if (buf.buf[0] == '/')
- popall();
+ popall(
state
);
else
else
- pop();
+ pop(
state
);
ee = splitpath(buf.buf, ee);
ee = splitpath(buf.buf, ee);
- dstr_destroy(&buf);
continue;
}
/* --- Run the sanity check on this path element --- */
continue;
}
/* --- Run the sanity check on this path element --- */
- bad |= sanity(
d.buf, &st, cp, ee ? 0 : f_last
);
+ bad |= sanity(
state->path.buf, &st, cp, ee ? 0 : SF_LAST
);
if (S_ISDIR(st.st_mode)) {
if (S_ISDIR(st.st_mode)) {
- if (st.st_mode &
01000
)
- s
p->e_flags |= f_sticky
;
- report(cp, CP_REPORT, 4,
d
.buf, "directory");
+ if (st.st_mode &
S_ISVTX
)
+ s
tate->sp->e_flags |= EF_STICKY
;
+ report(cp, CP_REPORT, 4,
state->path
.buf, "directory");
continue;
}
continue;
}
@@
-480,12
+494,15
@@
unsigned checkpath(const char *p, const struct checkpath *cp)
report(cp, CP_ERROR, 0, 0, "junk left over after reaching leaf");
while (ee) {
e = ee->e_link;
report(cp, CP_ERROR, 0, 0, "junk left over after reaching leaf");
while (ee) {
e = ee->e_link;
- free(ee);
+
x
free(ee);
ee = e;
}
}
ee = e;
}
}
- popall();
+ popall(state);
+ dstr_destroy(&state->path);
+ dstr_destroy(&buf);
+ pool_destroy(state->p);
return (bad);
}
return (bad);
}