/* Retrieve export flags for the given aname. * Don't set np_uerror() here, just return 1 on match, 0 otherwise. */ int diod_fetch_xflags (Npstr *aname, int *xfp) { List exports = diod_conf_get_exports (); ListIterator itr = NULL; Export *x; char *path = NULL; int res = 0; if (!(path = np_strdup (aname))) goto done; NP_ASSERT (exports != NULL); if (strstr (path, "/..") != NULL) goto done; if (!(itr = list_iterator_create (exports))) goto done; while ((x = list_next (itr))) { if (_match_export_path (x, path)) { if (xfp) *xfp = x->oflags; res = 1; break; } } done: if (itr) list_iterator_destroy (itr); if (path) free (path); return res; }
static Xattr _xattr_create (Npstr *name, size_t size, int flags, u32 setflags) { Xattr x; x = malloc (sizeof (struct xattr_struct)); if (!x) goto nomem; memset (x, 0, sizeof (struct xattr_struct)); x->flags = flags; x->setflags = setflags; if (name && name->len > 0) { x->name = np_strdup (name); if (!x->name) goto nomem; } if (size > 0) { x->buf = malloc (size); if (!x->buf) goto nomem; x->len = size; } return x; nomem: _xattr_destroy (&x); np_uerror (ENOMEM); return NULL; }
Npfcall* diod_symlink(Npfid *fid, Npstr *name, Npstr *symtgt, u32 gid) { Fid *f = fid->aux; Npfcall *ret = NULL; char *target = NULL, *npath = NULL; Npqid qid; struct stat sb; mode_t saved_umask; int created = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = _mkpath(f->path, name))) { np_uerror (ENOMEM); goto error; } if (!(target = np_strdup (symtgt))) { np_uerror (ENOMEM); goto error; } saved_umask = umask(0); if (symlink (target, npath) < 0) { np_uerror (errno); goto error_quiet; } created = 1; umask(saved_umask); if (lstat (npath, &sb) < 0) { np_uerror (errno); goto error; /* shouldn't happen? */ } _ustat2qid (&sb, &qid); if (!((ret = np_create_rsymlink (&qid)))) { np_uerror (ENOMEM); goto error; } free (npath); free (target); return ret; error: errn (np_rerror (), "diod_symlink %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, name->len, name->str); error_quiet: if (created && npath) (void)unlink (npath); if (npath) free (npath); if (target) free (target); if (ret) free (ret); return NULL; }
Path path_create (Npsrv *srv, Npstr *ns) { char *s; if (!(s = np_strdup (ns))) return NULL; return _path_alloc (srv, s, ns->len); }
Npfcall* diod_symlink(Npfid *fid, Npstr *name, Npstr *symtgt, u32 gid) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Npfcall *ret; char *target = NULL; Path npath = NULL; Npqid qid; struct stat sb; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, f->path, name))) { np_uerror (ENOMEM); goto error; } if (!(target = np_strdup (symtgt))) { np_uerror (ENOMEM); goto error; } if (symlink (target, path_s (npath)) < 0 || lstat (path_s (npath), &sb) < 0) { np_uerror (errno); goto error_quiet; } diod_ustat2qid (&sb, &qid); if (!((ret = np_create_rsymlink (&qid)))) { (void)unlink (path_s (npath)); np_uerror (ENOMEM); goto error; } path_decref (srv, npath); free (target); return ret; error: errn (np_rerror (), "diod_symlink %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), name->len, name->str); error_quiet: if (npath) path_decref (srv, npath); if (target) free (target); return NULL; }
/* Tattach - attach a new user (fid->user) to aname. * diod_auth.c::diod_checkauth first authenticates/authorizes user */ Npfcall* diod_attach (Npfid *fid, Npfid *afid, Npstr *aname) { Npfcall* ret = NULL; Fid *f = NULL; Npqid qid; struct stat sb; if (aname->len == 0 || *aname->str != '/') { np_uerror (EPERM); goto error; } if (!(f = _fidalloc ()) || !(f->path = np_strdup (aname))) { np_uerror (ENOMEM); goto error; } if (diod_conf_opt_runasuid ()) { if (fid->user->uid != diod_conf_get_runasuid ()) { np_uerror (EPERM); goto error; } } if (!diod_match_exports (f->path, fid->conn, fid->user, &f->xflags)) goto error; if (stat (f->path, &sb) < 0) { /* OK to follow symbolic links */ np_uerror (errno); goto error; } if (!S_ISDIR (sb.st_mode)) { np_uerror (ENOTDIR); goto error; } _ustat2qid (&sb, &qid); if ((ret = np_create_rattach (&qid)) == NULL) { np_uerror (ENOMEM); goto error; } fid->aux = f; np_fid_incref (fid); return ret; error: errn (np_rerror (), "diod_attach %s@%s:%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), aname->len, aname->str); if (f) _fidfree (f); return NULL; }
Npfcall* diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, Npstr *client_id) { Fid *f = fid->aux; Npfcall *ret; char *cid = NULL; int ftype; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!f->ioctx) { msg ("diod_getlock: fid is not open"); np_uerror (EBADF); goto error; } if (!(cid = np_strdup (client_id))) { np_uerror (ENOMEM); goto error; } if (type != P9_LOCK_TYPE_RDLCK && type != P9_LOCK_TYPE_WRLCK) { np_uerror (EINVAL); goto error; } ftype = (type == P9_LOCK_TYPE_RDLCK) ? LOCK_SH : LOCK_EX; ftype = ioctx_testlock (f->ioctx, ftype); type = (ftype == LOCK_EX) ? P9_LOCK_TYPE_WRLCK : P9_LOCK_TYPE_UNLCK; if (!((ret = np_create_rgetlock(type, start, length, proc_id, cid)))) { np_uerror (ENOMEM); goto error; } free (cid); return ret; error: errn (np_rerror (), "diod_getlock %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: if (cid) free (cid); return NULL; }
Npuser * np_attach2user (Npsrv *srv, Npstr *uname, u32 n_uname) { Npuser *u = NULL; char *s; if (n_uname != P9_NONUNAME) { u = np_uid2user (srv, n_uname); } else { if (uname->len == 0) { np_uerror (EIO); goto done; } s = np_strdup (uname); if (!s) { np_uerror (ENOMEM); goto done; } u = np_uname2user (srv, s); free (s); } done: return u; }
Npfcall* diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, Npstr *client_id) { Fid *f = fid->aux; Npfcall *ret; char *cid = NULL; struct stat sb; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(cid = np_strdup (client_id))) { np_uerror (ENOMEM); goto error; } if (fstat(f->fd, &sb) < 0) { np_uerror (errno); goto error_quiet; } switch (type) { case P9_LOCK_TYPE_RDLCK: switch (f->lock_type) { case LOCK_EX: case LOCK_SH: type = P9_LOCK_TYPE_UNLCK; break; case LOCK_UN: if (flock (f->fd, LOCK_SH | LOCK_NB) >= 0) { (void)flock (f->fd, LOCK_UN); type = P9_LOCK_TYPE_UNLCK; } else type = P9_LOCK_TYPE_WRLCK; break; } break; case P9_LOCK_TYPE_WRLCK: switch (f->lock_type) { case LOCK_EX: type = P9_LOCK_TYPE_UNLCK; break; case LOCK_SH: /* Rather than upgrade the lock to LOCK_EX and risk * not reacquiring the LOCK_SH afterwards, lie about * the lock being available. Getlock is racy anyway. */ type = P9_LOCK_TYPE_UNLCK; break; case LOCK_UN: if (flock (f->fd, LOCK_EX | LOCK_NB) >= 0) { (void)flock (f->fd, LOCK_UN); type = P9_LOCK_TYPE_UNLCK; } else type = P9_LOCK_TYPE_WRLCK; /* could also be LOCK_SH actually */ } break; default: np_uerror (EINVAL); goto error; } if (type != P9_LOCK_TYPE_UNLCK && type != F_UNLCK) { /* FIXME: need to fake up start, length, proc_id, cid? */ } if (!((ret = np_create_rgetlock(type, start, length, proc_id, cid)))) { np_uerror (ENOMEM); goto error; } free (cid); return ret; error: errn (np_rerror (), "diod_getlock %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: if (cid) free (cid); return NULL; }
/* Look up operation's fid and assign it to req->fid. * This is done before the request is handed off to a worker, with * the plan of using fid data in scheduling work. * The fid refcount is incremented here, then decremented in * np_process_request (). */ static void np_preprocess_request(Npreq *req) { Npfcall *tc = req->tcall; Npconn *conn = req->conn; switch (tc->type) { case P9_TSTATFS: req->fid = np_fid_find (conn, tc->u.tstatfs.fid); break; case P9_TLOPEN: req->fid = np_fid_find (conn, tc->u.tlopen.fid); break; case P9_TLCREATE: req->fid = np_fid_find (conn, tc->u.tlcreate.fid); break; case P9_TSYMLINK: req->fid = np_fid_find (conn, tc->u.tsymlink.fid); break; case P9_TMKNOD: req->fid = np_fid_find (conn, tc->u.tmknod.fid); break; case P9_TRENAME: req->fid = np_fid_find (conn, tc->u.trename.fid); break; case P9_TREADLINK: req->fid = np_fid_find (conn, tc->u.treadlink.fid); break; case P9_TGETATTR: req->fid = np_fid_find (conn, tc->u.tgetattr.fid); break; case P9_TSETATTR: req->fid = np_fid_find (conn, tc->u.tsetattr.fid); break; case P9_TXATTRWALK: req->fid = np_fid_find (conn, tc->u.txattrwalk.fid); break; case P9_TXATTRCREATE: req->fid = np_fid_find (conn, tc->u.txattrcreate.fid); break; case P9_TREADDIR: req->fid = np_fid_find (conn, tc->u.treaddir.fid); break; case P9_TFSYNC: req->fid = np_fid_find (conn, tc->u.tfsync.fid); break; case P9_TLOCK: req->fid = np_fid_find (conn, tc->u.tlock.fid); break; case P9_TGETLOCK: req->fid = np_fid_find (conn, tc->u.tgetlock.fid); break; case P9_TLINK: req->fid = np_fid_find (conn, tc->u.tlink.dfid); break; case P9_TMKDIR: req->fid = np_fid_find (conn, tc->u.tmkdir.fid); break; case P9_TVERSION: break; case P9_TAUTH: req->fid = np_fid_create (conn, tc->u.tauth.afid); if (!req->fid) break; req->fid->aname = np_strdup (&tc->u.tauth.aname); if (!req->fid->aname) np_fid_decref (&req->fid); /* XXX leave fid->tpool NULL for now as auth * can be handled in the default thread pool * without risk of deadlock. */ break; case P9_TATTACH: req->fid = np_fid_create (conn, tc->u.tattach.fid); if (!req->fid) break; req->fid->aname = np_strdup (&tc->u.tattach.aname); if (!req->fid->aname) np_fid_decref (&req->fid); /* Here we select the tpool that will handle this * request and requests on fids walked from this fid. */ np_tpool_select (req); break; case P9_TFLUSH: break; case P9_TWALK: req->fid = np_fid_find (conn, tc->u.twalk.fid); break; case P9_TREAD: req->fid = np_fid_find (conn, tc->u.tread.fid); break; case P9_TWRITE: req->fid = np_fid_find (conn, tc->u.twrite.fid); break; case P9_TCLUNK: req->fid = np_fid_find (conn, tc->u.tclunk.fid); break; case P9_TREMOVE: req->fid = np_fid_find (conn, tc->u.tremove.fid); break; case P9_TRENAMEAT: req->fid = np_fid_find (conn, tc->u.trenameat.olddirfid); break; case P9_TUNLINKAT: req->fid = np_fid_find (conn, tc->u.tunlinkat.dirfid); break; default: break; } }