/** * @brief Get supplementary groups given uid * * @param[in] uid The uid of the user * @param[out] group_data * * @return true if successful, false otherwise */ bool uid2grp(uid_t uid, struct group_data **gdata) { bool success = false; PTHREAD_RWLOCK_rdlock(&uid2grp_user_lock); success = uid2grp_lookup_by_uid(uid, gdata); /* Handle common case first */ if (success && !uid2grp_expired(*gdata)) { uid2grp_hold_group_data(*gdata); PTHREAD_RWLOCK_unlock(&uid2grp_user_lock); return success; } PTHREAD_RWLOCK_unlock(&uid2grp_user_lock); if (success) { /* Cache entry is expired */ PTHREAD_RWLOCK_wrlock(&uid2grp_user_lock); uid2grp_remove_by_uid(uid); PTHREAD_RWLOCK_unlock(&uid2grp_user_lock); } *gdata = uid2grp_allocate_by_uid(uid); PTHREAD_RWLOCK_wrlock(&uid2grp_user_lock); if (*gdata) uid2grp_add_user(*gdata); success = uid2grp_lookup_by_uid(uid, gdata); if (success) uid2grp_hold_group_data(*gdata); PTHREAD_RWLOCK_unlock(&uid2grp_user_lock); return success; }
/** * @brief Add a user entry to the cache * * @note The caller must hold uid2grp_user_lock for write. * * @param[in] group_data that has supplementary groups allocated * * @retval true on success. * @retval false if our reach exceeds our grasp. */ bool uid2grp_add_user(struct group_data *gdata) { struct avltree_node *name_node; struct avltree_node *id_node; struct avltree_node *name_node2 = NULL; struct avltree_node *id_node2 = NULL; struct cache_info *info; struct cache_info *tmp; info = gsh_malloc(sizeof(struct cache_info)); if (!info) { LogEvent(COMPONENT_IDMAPPER, "memory alloc failed"); return false; } info->uid = gdata->uid; info->uname.addr = gdata->uname.addr; info->uname.len = gdata->uname.len; info->gdata = gdata; /* The refcount on group_data should be 1 when we put it in * AVL trees. */ uid2grp_hold_group_data(gdata); /* We may have lost the race to insert. We remove existing * entry and insert this new entry if so! */ name_node = avltree_insert(&info->uname_node, &uname_tree); if (unlikely(name_node)) { tmp = avltree_container_of(name_node, struct cache_info, uname_node); uid2grp_remove_user(tmp); name_node2 = avltree_insert(&info->uname_node, &uname_tree); } id_node = avltree_insert(&info->uid_node, &uid_tree); if (unlikely(id_node)) { /* We should not come here unless someone changed uid of * a user. Remove old entry and re-insert the new * entry. */ tmp = avltree_container_of(id_node, struct cache_info, uid_node); uid2grp_remove_user(tmp); id_node2 = avltree_insert(&info->uid_node, &uid_tree); } uid_grplist_cache[info->uid % id_cache_size] = &info->uid_node; if (name_node && id_node) LogWarn(COMPONENT_IDMAPPER, "shouldn't happen, internal error"); if ((name_node && name_node2) || (id_node && id_node2)) LogWarn(COMPONENT_IDMAPPER, "shouldn't happen, internal error"); return true; }
int _9p_walk(struct _9p_request_data *req9p, void *worker_data, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; unsigned int i = 0; u16 *msgtag = NULL; u32 *fid = NULL; u32 *newfid = NULL; u16 *nwname = NULL; u16 *wnames_len; char *wnames_str; uint64_t fileid; cache_inode_status_t cache_status; cache_entry_t *pentry = NULL; char name[MAXNAMLEN]; u16 *nwqid; struct _9p_fid *pfid = NULL; struct _9p_fid *pnewfid = NULL; /* Now Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, newfid, u32); _9p_getptr(cursor, nwname, u16); LogDebug(COMPONENT_9P, "TWALK: tag=%u fid=%u newfid=%u nwname=%u", (u32) *msgtag, *fid, *newfid, *nwname); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); if (*newfid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout, preply); } op_ctx = &pfid->op_context; pnewfid = gsh_calloc(1, sizeof(struct _9p_fid)); if (pnewfid == NULL) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); /* Is this a lookup or a fid cloning operation ? */ if (*nwname == 0) { /* Cloning operation */ memcpy((char *)pnewfid, (char *)pfid, sizeof(struct _9p_fid)); /* Set the new fid id */ pnewfid->fid = *newfid; /* This is not a TATTACH fid */ pnewfid->from_attach = false; /* Increments refcount */ (void) cache_inode_lru_ref(pnewfid->pentry, LRU_REQ_STALE_OK); } else { /* the walk is in fact a lookup */ pentry = pfid->pentry; for (i = 0; i < *nwname; i++) { _9p_getstr(cursor, wnames_len, wnames_str); snprintf(name, MAXNAMLEN, "%.*s", *wnames_len, wnames_str); LogDebug(COMPONENT_9P, "TWALK (lookup): tag=%u fid=%u newfid=%u (component %u/%u :%s)", (u32) *msgtag, *fid, *newfid, i + 1, *nwname, name); if (pnewfid->pentry == pentry) pnewfid->pentry = NULL; /* refcount +1 */ cache_status = cache_inode_lookup(pentry, name, &pnewfid->pentry); if (pnewfid->pentry == NULL) { gsh_free(pnewfid); return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); } if (pentry != pfid->pentry) cache_inode_put(pentry); pentry = pnewfid->pentry; } pnewfid->fid = *newfid; pnewfid->op_context = pfid->op_context; pnewfid->ppentry = pfid->pentry; strncpy(pnewfid->name, name, MAXNAMLEN-1); /* gdata ref is not hold : the pfid, which use same gdata */ /* will be clunked after pnewfid */ /* This clunk release the gdata */ pnewfid->gdata = pfid->gdata; /* This is not a TATTACH fid */ pnewfid->from_attach = false; cache_status = cache_inode_fileid(pnewfid->pentry, &fileid); if (cache_status != CACHE_INODE_SUCCESS) { gsh_free(pnewfid); return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); } /* Build the qid */ /* No cache, we want the client to stay synchronous * with the server */ pnewfid->qid.version = 0; pnewfid->qid.path = fileid; pnewfid->specdata.xattr.xattr_id = 0; pnewfid->specdata.xattr.xattr_content = NULL; switch (pnewfid->pentry->type) { case REGULAR_FILE: case CHARACTER_FILE: case BLOCK_FILE: case SOCKET_FILE: case FIFO_FILE: pnewfid->qid.type = _9P_QTFILE; break; case SYMBOLIC_LINK: pnewfid->qid.type = _9P_QTSYMLINK; break; case DIRECTORY: pnewfid->qid.type = _9P_QTDIR; break; default: LogMajor(COMPONENT_9P, "implementation error, you should not see this message !!!!!!"); gsh_free(pnewfid); return _9p_rerror(req9p, worker_data, msgtag, EINVAL, plenout, preply); break; } } /* keep info on new fid */ req9p->pconn->fids[*newfid] = pnewfid; /* As much qid as requested fid */ nwqid = nwname; /* Hold refcount on gdata */ uid2grp_hold_group_data(pnewfid->gdata); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RWALK); _9p_setptr(cursor, msgtag, u16); _9p_setptr(cursor, nwqid, u16); for (i = 0; i < *nwqid; i++) { /** @todo: should be different qids * for each directory walked through */ _9p_setqid(cursor, pnewfid->qid); } _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RWALK: tag=%u fid=%u newfid=%u nwqid=%u fileid=%llu pentry=%p refcount=%i", (u32) *msgtag, *fid, *newfid, *nwqid, (unsigned long long)pnewfid->qid.path, pnewfid->pentry, pnewfid->pentry->lru.refcnt); return 1; }
int _9p_xattrwalk(struct _9p_request_data *req9p, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u32 *attrfid = NULL; u16 *name_len; char *name_str; size_t attrsize = 0; fsal_status_t fsal_status; char name[MAXNAMLEN]; fsal_xattrent_t xattrs_arr[XATTRS_ARRAY_LEN]; int eod_met = false; unsigned int nb_xattrs_read = 0; unsigned int i = 0; char *xattr_cursor = NULL; unsigned int tmplen = 0; struct _9p_fid *pfid = NULL; struct _9p_fid *pxattrfid = NULL; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, attrfid, u32); LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u", (u32) *msgtag, *fid, *attrfid); _9p_getstr(cursor, name_len, name_str); if (*name_len == 0) LogDebug(COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)", (u32) *msgtag, *fid, *attrfid); else LogDebug(COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s", (u32) *msgtag, *fid, *attrfid, *name_len, name_str); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); if (*attrfid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, msgtag, EIO, plenout, preply); } pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid)); if (pxattrfid == NULL) return _9p_rerror(req9p, msgtag, ENOMEM, plenout, preply); /* set op_ctx, it will be useful if FSAL is later called */ _9p_init_opctx(pfid, req9p); /* Initiate xattr's fid by copying file's fid in it */ memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid)); snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str); pxattrfid->specdata.xattr.xattr_content = gsh_malloc(XATTR_BUFFERSIZE); if (pxattrfid->specdata.xattr.xattr_content == NULL) { gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, ENOMEM, plenout, preply); } if (*name_len == 0) { /* xattrwalk is used with an empty name, * this is a listxattr request */ fsal_status = pxattrfid->pentry->obj_handle->obj_ops.list_ext_attrs( pxattrfid->pentry->obj_handle, FSAL_XATTR_RW_COOKIE, /* Start with RW cookie, * hiding RO ones */ xattrs_arr, XATTRS_ARRAY_LEN, /** @todo fix static length */ &nb_xattrs_read, &eod_met); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } /* if all xattrent are not read, * returns ERANGE as listxattr does */ if (eod_met != true) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); } xattr_cursor = pxattrfid->specdata.xattr.xattr_content; attrsize = 0; for (i = 0; i < nb_xattrs_read; i++) { tmplen = snprintf(xattr_cursor, MAXNAMLEN, "%s", xattrs_arr[i].xattr_name); xattr_cursor[tmplen] = '\0'; /* Just to be sure */ /* +1 for trailing '\0' */ xattr_cursor += tmplen + 1; attrsize += tmplen + 1; /* Make sure not to go beyond the buffer */ if (attrsize > XATTR_BUFFERSIZE) { gsh_free(pxattrfid->specdata.xattr. xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); } } } else { /* xattrwalk has a non-empty name, use regular setxattr */ fsal_status = pxattrfid->pentry->obj_handle->obj_ops. getextattr_id_by_name(pxattrfid->pentry->obj_handle, name, &pxattrfid->specdata.xattr.xattr_id); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); /* ENOENT for xattr is ENOATTR */ if (fsal_status.major == ERR_FSAL_NOENT) return _9p_rerror(req9p, msgtag, ENOATTR, plenout, preply); else return _9p_rerror(req9p, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } fsal_status = pxattrfid->pentry->obj_handle->obj_ops. getextattr_value_by_name(pxattrfid->pentry->obj_handle, name, pxattrfid->specdata.xattr. xattr_content, XATTR_BUFFERSIZE, &attrsize); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); /* fsal_status.minor is a valid errno code */ return _9p_rerror(req9p, msgtag, fsal_status.minor, plenout, preply); } } req9p->pconn->fids[*attrfid] = pxattrfid; /* Increments refcount as we're manually making a new copy */ (void) cache_inode_lru_ref(pfid->pentry, LRU_REQ_STALE_OK); /* hold reference on gdata */ uid2grp_hold_group_data(pxattrfid->gdata); get_gsh_export_ref(pfid->export); get_9p_user_cred_ref(pfid->ucred); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RXATTRWALK); _9p_setptr(cursor, msgtag, u16); _9p_setvalue(cursor, attrsize, u64); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu", (u32) *msgtag, *fid, *attrfid, *name_len, name_str, (unsigned long long)attrsize); return 1; } /* _9p_xattrwalk */