summaryrefslogtreecommitdiff
path: root/lib9p/srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r--lib9p/srv.c156
1 files changed, 111 insertions, 45 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c
index e6a92ad..50e5dae 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -98,6 +98,7 @@ struct srv_pathinfo {
struct srv_fidinfo {
srv_path_t path;
+ struct lib9p_srv_authinfo *authinfo;
uint8_t flags;
enum srv_filetype type;
union {
@@ -109,6 +110,10 @@ struct srv_fidinfo {
size_t idx;
uint64_t off;
} dir;
+ struct {
+ struct lib9p_s aname;
+ bool completed;
+ } auth;
};
};
@@ -171,6 +176,35 @@ static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_stat *stat,
return mode & action;
}
+struct lib9p_srv_authinfo *srv_authinfo_new(struct lib9p_s uname, lib9p_nuid_t uid) {
+ struct lib9p_srv_authinfo *ret = malloc(sizeof(struct lib9p_srv_authinfo) + uname.len);
+ if (!ret)
+ return NULL;
+ ret->uid = uid;
+ ret->uname.len = uname.len;
+ ret->uname.utf8 = (void *)&ret[1];
+ memcpy(ret->uname.utf8, uname.utf8, uname.len);
+ ret->refcount = 1;
+ return ret;
+}
+
+struct lib9p_srv_authinfo *srv_authinfo_decref(struct lib9p_srv_authinfo *authinfo) {
+ assert(authinfo);
+ assert(authinfo->refcount);
+ authinfo->refcount--;
+ if (!authinfo->refcount) {
+ free(authinfo);
+ return NULL;
+ }
+ return authinfo;
+}
+
+struct lib9p_srv_authinfo *srv_authinfo_incref(struct lib9p_srv_authinfo *authinfo) {
+ assert(authinfo);
+ authinfo->refcount++;
+ return authinfo;
+}
+
/**
* Ensures that `file` is saved into the pathmap, and increments the
* gc_refcount by 1 (for presumptive insertion into the fidmap).
@@ -228,11 +262,7 @@ static inline void srv_path_decref(struct srv_req *ctx, srv_path_t path) {
static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove) {
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, fid);
- if (!fidinfo) {
- lib9p_errorf(&ctx->basectx,
- LINUX_EBADF, "bad file number %"PRIu32, fid);
- return;
- }
+ assert(fidinfo);
if (fidinfo->flags & FIDFLAG_RCLOSE)
remove = true;
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
@@ -270,7 +300,8 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove
}
pathinfo->io_refcount--;
}
- srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
+ fidinfo->authinfo = srv_authinfo_decref(fidinfo->authinfo);
+ srv_path_decref(ctx, fidinfo->path);
map_del(&ctx->parent_sess->fids, fid);
}
@@ -296,8 +327,9 @@ static struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t fid, s
}
}
struct srv_fidinfo *fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){
- .path = qid.path,
- .type = srv_qid_filetype(qid),
+ .path = qid.path,
+ .type = srv_qid_filetype(qid),
+ .authinfo = srv_authinfo_incref(ctx->authinfo),
});
assert(fidinfo);
return fidinfo;
@@ -443,13 +475,11 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) {
}
if (srv_read_exactly(conn.fd, buf, 7, &done))
break;
- struct lib9p_srv_authinfo authinfo = {};
struct srv_req req = {
.basectx = {
.version = sess.version,
.max_msg_size = sess.max_msg_size,
},
- .authinfo = &authinfo,
.parent_sess = &sess,
.tag = uint16le_decode(&buf[5]),
@@ -715,19 +745,22 @@ static void handle_Tauth(struct srv_req *ctx,
struct lib9p_msg_Rauth *resp) {
srv_handler_common(ctx, req, resp);
- ctx->authinfo->uid = req->n_uid;
- ctx->authinfo->uname = req->uname;
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
-
if (!srv->auth) {
lib9p_error(&ctx->basectx,
LINUX_EOPNOTSUPP, "authentication not required");
return;
}
+ ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid);
+
srv->auth(ctx, req->aname);
+
lib9p_error(&ctx->basectx,
LINUX_EOPNOTSUPP, "TODO: auth not implemented");
+
+ if (lib9p_ctx_has_error(&ctx->basectx))
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Tattach(struct srv_req *ctx,
@@ -735,58 +768,59 @@ static void handle_Tattach(struct srv_req *ctx,
struct lib9p_msg_Rattach *resp) {
srv_handler_common(ctx, req, resp);
- ctx->authinfo->uid = req->n_uid;
- ctx->authinfo->uname = req->uname;
- struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
+ if (req->fid == LIB9P_FID_NOFID) {
+ lib9p_error(&ctx->basectx,
+ LINUX_EBADF, "cannot assign to NOFID");
+ return;
+ }
+ struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (srv->auth) {
- /*
- struct lib9p_srv_filehandle *fh = map_get(req->afid);
- if (!fh)
+ struct srv_fidinfo *afid = map_load(&ctx->parent_sess->fids, req->afid);
+ if (!afid)
lib9p_error(&ctx->basectx,
LINUX_EACCES, "FID provided as auth-file is not a valid FID");
- else if (fh->type != FH_AUTH)
+ else if (afid->type != SRV_FILETYPE_AUTH)
lib9p_error(&ctx->basectx,
LINUX_EACCES, "FID provided as auth-file is not an auth-file");
- else if (!lib9p_str_eq(fh->data.auth.uname, req->uname))
+ else if (!lib9p_str_eq(afid->authinfo->uname, req->uname))
lib9p_errorf(&ctx->basectx,
LINUX_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"",
- fh->data.auth.uname.len, fh->data.auth.uname.utf8,
+ afid->authinfo->uname.len, afid->authinfo->uname.utf8,
req->uname.len, req->uname.utf8);
- else if (!lib9p_str_eq(fh->data.auth.aname, req->aname))
+#if CONFIG_9P_ENABLE_9P2000_u
+ else if (afid->authinfo->uid != req->n_uid)
+ lib9p_errorf(&ctx->basectx,
+ LINUX_EACCES, "FID provided as auth-file is for user=%"PRIu32" and cannot be used for user=%"PRIu32,
+ afid->authinfo->uid, req->n_uid);
+#endif
+ else if (!lib9p_str_eq(afid->auth.aname, req->aname))
lib9p_errorf(&ctx->basectx,
LINUX_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"",
- fh->data.auth.aname.len, fh->data.auth.aname.utf8,
+ afid->auth.aname.len, afid->auth.aname.utf8,
req->aname.len, req->aname.utf8);
- else if (!fh->data.auth.authenticated)
+ else if (!afid->auth.completed)
lib9p_error(&ctx->basectx,
LINUX_EACCES, "FID provided as auth-file has not completed authentication");
- fh->refcount--;
- if (lib9p_ctx_has_error(&ctx->ctx))
+ if (lib9p_ctx_has_error(&ctx->basectx))
return;
- */
- lib9p_error(&ctx->basectx,
- LINUX_EOPNOTSUPP, "TODO: auth not (yet?) implemented");
- return;
+ ctx->authinfo = srv_authinfo_incref(afid->authinfo);
} else {
if (req->afid != LIB9P_FID_NOFID) {
lib9p_error(&ctx->basectx,
LINUX_EACCES, "FID provided as auth-file, but no auth-file is required");
return;
}
- }
-
- if (req->fid == LIB9P_FID_NOFID) {
- lib9p_error(&ctx->basectx,
- LINUX_EBADF, "cannot assign to NOFID");
- return;
+ ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid);
}
/* 1. File object */
lo_interface lib9p_srv_file root_file = srv->rootdir(ctx, req->aname);
assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(&ctx->basectx));
- if (lib9p_ctx_has_error(&ctx->basectx))
+ if (lib9p_ctx_has_error(&ctx->basectx)) {
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
return;
+ }
struct lib9p_qid root_qid = LO_CALL(root_file, qid);
assert(srv_qid_filetype(root_qid) == SRV_FILETYPE_DIR);
@@ -797,9 +831,11 @@ static void handle_Tattach(struct srv_req *ctx,
/* 3. fidinfo */
if (!srv_fid_store(ctx, req->fid, root_pathinfo, false)) {
srv_path_decref(ctx, root_qid.path);
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
return;
}
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
resp->qid = root_qid;
return;
}
@@ -831,6 +867,7 @@ static void handle_Twalk(struct srv_req *ctx,
LINUX_EBADF, "bad file number %"PRIu32, req->fid);
return;
}
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
@@ -884,6 +921,7 @@ static void handle_Twalk(struct srv_req *ctx,
if (resp->nwqid > 0)
lib9p_ctx_clear_error(&ctx->basectx);
}
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Topen(struct srv_req *ctx,
@@ -912,6 +950,7 @@ static void handle_Topen(struct srv_req *ctx,
return;
}
}
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
/* Variables. */
lib9p_o_t reqmode = req->mode;
@@ -925,23 +964,23 @@ static void handle_Topen(struct srv_req *ctx,
assert(parent);
struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, ctx);
if (lib9p_ctx_has_error(&ctx->basectx))
- return;
+ goto topen_return;
lib9p_stat_assert(parent_stat);
if (!srv_check_perm(ctx, &parent_stat, 0b010)) {
lib9p_error(&ctx->basectx,
LINUX_EACCES, "permission denied to remove-on-close");
- return;
+ goto topen_return;
}
fidflags |= FIDFLAG_RCLOSE;
}
struct lib9p_stat stat = LO_CALL(pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(&ctx->basectx))
- return;
+ goto topen_return;
lib9p_stat_assert(stat);
if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
lib9p_error(&ctx->basectx,
LINUX_EEXIST, "exclusive file is already opened");
- return;
+ goto topen_return;
}
if (stat.file_mode & LIB9P_DM_APPEND)
reqmode = reqmode & ~LIB9P_O_TRUNC;
@@ -968,7 +1007,7 @@ static void handle_Topen(struct srv_req *ctx,
if (!srv_check_perm(ctx, &stat, perm_bits)) {
lib9p_error(&ctx->basectx,
LINUX_EACCES, "permission denied");
- return;
+ goto topen_return;
}
/* Actually make the call. */
@@ -979,7 +1018,7 @@ static void handle_Topen(struct srv_req *ctx,
fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, ctx);
assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->basectx));
if (lib9p_ctx_has_error(&ctx->basectx))
- return;
+ goto topen_return;
fidinfo->dir.idx = 0;
fidinfo->dir.off = 0;
qid = LO_CALL(fidinfo->dir.io, qid);
@@ -991,7 +1030,7 @@ static void handle_Topen(struct srv_req *ctx,
reqmode & LIB9P_O_TRUNC);
assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->basectx));
if (lib9p_ctx_has_error(&ctx->basectx))
- return;
+ goto topen_return;
qid = LO_CALL(fidinfo->file.io, qid);
iounit = LO_CALL(fidinfo->file.io, iounit);
break;
@@ -1012,6 +1051,8 @@ static void handle_Topen(struct srv_req *ctx,
fidinfo->flags = fidflags;
resp->qid = qid;
resp->iounit = iounit;
+ topen_return:
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Tcreate(struct srv_req *ctx,
@@ -1044,6 +1085,7 @@ static void handle_Tread(struct srv_req *ctx,
}
/* Do it. */
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
switch (fidinfo->type) {
case SRV_FILETYPE_DIR:
/* Translate byte-offset to object-index. */
@@ -1056,6 +1098,7 @@ static void handle_Tread(struct srv_req *ctx,
lib9p_errorf(&ctx->basectx,
LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64,
fidinfo->dir.off, req->offset);
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
return;
}
/* Do it. */
@@ -1087,6 +1130,7 @@ static void handle_Tread(struct srv_req *ctx,
assert_notreached("TODO: auth not yet implemented");
break;
}
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Twrite(struct srv_req *ctx,
@@ -1110,7 +1154,9 @@ static void handle_Twrite(struct srv_req *ctx,
}
/* Do it. */
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
resp->count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Tclunk(struct srv_req *ctx,
@@ -1118,7 +1164,16 @@ static void handle_Tclunk(struct srv_req *ctx,
struct lib9p_msg_Rclunk *resp) {
srv_handler_common(ctx, req, resp);
+ struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
+ if (!fidinfo) {
+ lib9p_errorf(&ctx->basectx,
+ LINUX_EBADF, "bad file number %"PRIu32, req->fid);
+ return;
+ }
+
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
srv_fid_del(ctx, req->fid, false);
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Tremove(struct srv_req *ctx,
@@ -1126,7 +1181,16 @@ static void handle_Tremove(struct srv_req *ctx,
struct lib9p_msg_Rremove *resp) {
srv_handler_common(ctx, req, resp);
+ struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
+ if (!fidinfo) {
+ lib9p_errorf(&ctx->basectx,
+ LINUX_EBADF, "bad file number %"PRIu32, req->fid);
+ return;
+ }
+
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
srv_fid_del(ctx, req->fid, true);
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Tstat(struct srv_req *ctx,
@@ -1143,9 +1207,11 @@ static void handle_Tstat(struct srv_req *ctx,
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
+ ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
resp->stat = LO_CALL(pathinfo->file, stat, ctx);
if (!lib9p_ctx_has_error(&ctx->basectx))
lib9p_stat_assert(resp->stat);
+ ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
}
static void handle_Twstat(struct srv_req *ctx,