|
|
1.1 root 1: /*
2: * Virtio 9p Posix callback
3: *
4: * Copyright IBM, Corp. 2010
5: *
6: * Authors:
7: * Anthony Liguori <[email protected]>
8: *
9: * This work is licensed under the terms of the GNU GPL, version 2. See
10: * the COPYING file in the top-level directory.
11: *
12: */
13: #include "virtio.h"
14: #include "virtio-9p.h"
15: #include <arpa/inet.h>
16: #include <pwd.h>
17: #include <grp.h>
18: #include <sys/socket.h>
19: #include <sys/un.h>
20: #include <attr/xattr.h>
21:
22: static const char *rpath(FsContext *ctx, const char *path)
23: {
24: /* FIXME: so wrong... */
25: static char buffer[4096];
26: snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
27: return buffer;
28: }
29:
30:
31: static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
32: {
33: int err;
34: err = lstat(rpath(fs_ctx, path), stbuf);
35: if (err) {
36: return err;
37: }
38: if (fs_ctx->fs_sm == SM_MAPPED) {
39: /* Actual credentials are part of extended attrs */
40: uid_t tmp_uid;
41: gid_t tmp_gid;
42: mode_t tmp_mode;
43: dev_t tmp_dev;
44: if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid,
45: sizeof(uid_t)) > 0) {
46: stbuf->st_uid = tmp_uid;
47: }
48: if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid,
49: sizeof(gid_t)) > 0) {
50: stbuf->st_gid = tmp_gid;
51: }
52: if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode,
53: sizeof(mode_t)) > 0) {
54: stbuf->st_mode = tmp_mode;
55: }
56: if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev,
57: sizeof(dev_t)) > 0) {
58: stbuf->st_rdev = tmp_dev;
59: }
60: }
61: return err;
62: }
63:
64: static int local_set_xattr(const char *path, FsCred *credp)
65: {
66: int err;
67: if (credp->fc_uid != -1) {
68: err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
69: 0);
70: if (err) {
71: return err;
72: }
73: }
74: if (credp->fc_gid != -1) {
75: err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
76: 0);
77: if (err) {
78: return err;
79: }
80: }
81: if (credp->fc_mode != -1) {
82: err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
83: sizeof(mode_t), 0);
84: if (err) {
85: return err;
86: }
87: }
88: if (credp->fc_rdev != -1) {
89: err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
90: sizeof(dev_t), 0);
91: if (err) {
92: return err;
93: }
94: }
95: return 0;
96: }
97:
98: static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
99: FsCred *credp)
100: {
101: if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
102: return -1;
103: }
104: if (chown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
105: return -1;
106: }
107: return 0;
108: }
109:
110: static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
111: char *buf, size_t bufsz)
112: {
113: ssize_t tsize = -1;
114: if (fs_ctx->fs_sm == SM_MAPPED) {
115: int fd;
116: fd = open(rpath(fs_ctx, path), O_RDONLY);
117: if (fd == -1) {
118: return -1;
119: }
120: do {
121: tsize = read(fd, (void *)buf, bufsz);
122: } while (tsize == -1 && errno == EINTR);
123: close(fd);
124: return tsize;
125: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
126: tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
127: }
128: return tsize;
129: }
130:
131: static int local_close(FsContext *ctx, int fd)
132: {
133: return close(fd);
134: }
135:
136: static int local_closedir(FsContext *ctx, DIR *dir)
137: {
138: return closedir(dir);
139: }
140:
141: static int local_open(FsContext *ctx, const char *path, int flags)
142: {
143: return open(rpath(ctx, path), flags);
144: }
145:
146: static DIR *local_opendir(FsContext *ctx, const char *path)
147: {
148: return opendir(rpath(ctx, path));
149: }
150:
151: static void local_rewinddir(FsContext *ctx, DIR *dir)
152: {
153: return rewinddir(dir);
154: }
155:
156: static off_t local_telldir(FsContext *ctx, DIR *dir)
157: {
158: return telldir(dir);
159: }
160:
161: static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
162: {
163: return readdir(dir);
164: }
165:
166: static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
167: {
168: return seekdir(dir, off);
169: }
170:
171: static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov,
172: int iovcnt)
173: {
174: return readv(fd, iov, iovcnt);
175: }
176:
177: static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence)
178: {
179: return lseek(fd, offset, whence);
180: }
181:
182: static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov,
183: int iovcnt)
184: {
185: return writev(fd, iov, iovcnt);
186: }
187:
188: static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
189: {
190: if (fs_ctx->fs_sm == SM_MAPPED) {
191: return local_set_xattr(rpath(fs_ctx, path), credp);
192: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
193: return chmod(rpath(fs_ctx, path), credp->fc_mode);
194: }
195: return -1;
196: }
197:
198: static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
199: {
200: int err = -1;
201: int serrno = 0;
202:
203: /* Determine the security model */
204: if (fs_ctx->fs_sm == SM_MAPPED) {
205: err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
206: if (err == -1) {
207: return err;
208: }
209: local_set_xattr(rpath(fs_ctx, path), credp);
210: if (err == -1) {
211: serrno = errno;
212: goto err_end;
213: }
214: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
215: err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
216: if (err == -1) {
217: return err;
218: }
219: err = local_post_create_passthrough(fs_ctx, path, credp);
220: if (err == -1) {
221: serrno = errno;
222: goto err_end;
223: }
224: }
225: return err;
226:
227: err_end:
228: remove(rpath(fs_ctx, path));
229: errno = serrno;
230: return err;
231: }
232:
233: static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
234: {
235: int err = -1;
236: int serrno = 0;
237:
238: /* Determine the security model */
239: if (fs_ctx->fs_sm == SM_MAPPED) {
240: err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
241: if (err == -1) {
242: return err;
243: }
244: credp->fc_mode = credp->fc_mode|S_IFDIR;
245: err = local_set_xattr(rpath(fs_ctx, path), credp);
246: if (err == -1) {
247: serrno = errno;
248: goto err_end;
249: }
250: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
251: err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
252: if (err == -1) {
253: return err;
254: }
255: err = local_post_create_passthrough(fs_ctx, path, credp);
256: if (err == -1) {
257: serrno = errno;
258: goto err_end;
259: }
260: }
261: return err;
262:
263: err_end:
264: remove(rpath(fs_ctx, path));
265: errno = serrno;
266: return err;
267: }
268:
269: static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
270: {
271: int err;
272: err = fstat(fd, stbuf);
273: if (err) {
274: return err;
275: }
276: if (fs_ctx->fs_sm == SM_MAPPED) {
277: /* Actual credentials are part of extended attrs */
278: uid_t tmp_uid;
279: gid_t tmp_gid;
280: mode_t tmp_mode;
281: dev_t tmp_dev;
282:
283: if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
284: stbuf->st_uid = tmp_uid;
285: }
286: if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
287: stbuf->st_gid = tmp_gid;
288: }
289: if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
290: stbuf->st_mode = tmp_mode;
291: }
292: if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
293: stbuf->st_rdev = tmp_dev;
294: }
295: }
296: return err;
297: }
298:
299: static int local_open2(FsContext *fs_ctx, const char *path, int flags,
300: FsCred *credp)
301: {
302: int fd = -1;
303: int err = -1;
304: int serrno = 0;
305:
306: /* Determine the security model */
307: if (fs_ctx->fs_sm == SM_MAPPED) {
308: fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
309: if (fd == -1) {
310: return fd;
311: }
312: credp->fc_mode = credp->fc_mode|S_IFREG;
313: /* Set cleint credentials in xattr */
314: err = local_set_xattr(rpath(fs_ctx, path), credp);
315: if (err == -1) {
316: serrno = errno;
317: goto err_end;
318: }
319: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
320: fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
321: if (fd == -1) {
322: return fd;
323: }
324: err = local_post_create_passthrough(fs_ctx, path, credp);
325: if (err == -1) {
326: serrno = errno;
327: goto err_end;
328: }
329: }
330: return fd;
331:
332: err_end:
333: close(fd);
334: remove(rpath(fs_ctx, path));
335: errno = serrno;
336: return err;
337: }
338:
339:
340: static int local_symlink(FsContext *fs_ctx, const char *oldpath,
341: const char *newpath, FsCred *credp)
342: {
343: int err = -1;
344: int serrno = 0;
345:
346: /* Determine the security model */
347: if (fs_ctx->fs_sm == SM_MAPPED) {
348: int fd;
349: ssize_t oldpath_size, write_size;
350: fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
351: SM_LOCAL_MODE_BITS);
352: if (fd == -1) {
353: return fd;
354: }
355: /* Write the oldpath (target) to the file. */
356: oldpath_size = strlen(oldpath) + 1;
357: do {
358: write_size = write(fd, (void *)oldpath, oldpath_size);
359: } while (write_size == -1 && errno == EINTR);
360:
361: if (write_size != oldpath_size) {
362: serrno = errno;
363: close(fd);
364: err = -1;
365: goto err_end;
366: }
367: close(fd);
368: /* Set cleint credentials in symlink's xattr */
369: credp->fc_mode = credp->fc_mode|S_IFLNK;
370: err = local_set_xattr(rpath(fs_ctx, newpath), credp);
371: if (err == -1) {
372: serrno = errno;
373: goto err_end;
374: }
375: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
376: err = symlink(oldpath, rpath(fs_ctx, newpath));
377: if (err) {
378: return err;
379: }
380: err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
381: if (err == -1) {
382: serrno = errno;
383: goto err_end;
384: }
385: }
386: return err;
387:
388: err_end:
389: remove(rpath(fs_ctx, newpath));
390: errno = serrno;
391: return err;
392: }
393:
394: static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
395: {
396: char *tmp = qemu_strdup(rpath(ctx, oldpath));
397: int err, serrno = 0;
398:
399: if (tmp == NULL) {
400: return -ENOMEM;
401: }
402:
403: err = link(tmp, rpath(ctx, newpath));
404: if (err == -1) {
405: serrno = errno;
406: }
407:
408: qemu_free(tmp);
409:
410: if (err == -1) {
411: errno = serrno;
412: }
413:
414: return err;
415: }
416:
417: static int local_truncate(FsContext *ctx, const char *path, off_t size)
418: {
419: return truncate(rpath(ctx, path), size);
420: }
421:
422: static int local_rename(FsContext *ctx, const char *oldpath,
423: const char *newpath)
424: {
425: char *tmp;
426: int err;
427:
428: tmp = qemu_strdup(rpath(ctx, oldpath));
429: if (tmp == NULL) {
430: return -1;
431: }
432:
433: err = rename(tmp, rpath(ctx, newpath));
434: if (err == -1) {
435: int serrno = errno;
436: qemu_free(tmp);
437: errno = serrno;
438: } else {
439: qemu_free(tmp);
440: }
441:
442: return err;
443:
444: }
445:
446: static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
447: {
448: if (fs_ctx->fs_sm == SM_MAPPED) {
449: return local_set_xattr(rpath(fs_ctx, path), credp);
450: } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
451: return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
452: }
453: return -1;
454: }
455:
456: static int local_utime(FsContext *ctx, const char *path,
457: const struct utimbuf *buf)
458: {
459: return utime(rpath(ctx, path), buf);
460: }
461:
462: static int local_remove(FsContext *ctx, const char *path)
463: {
464: return remove(rpath(ctx, path));
465: }
466:
467: static int local_fsync(FsContext *ctx, int fd)
468: {
469: return fsync(fd);
470: }
471:
472: FileOperations local_ops = {
473: .lstat = local_lstat,
474: .readlink = local_readlink,
475: .close = local_close,
476: .closedir = local_closedir,
477: .open = local_open,
478: .opendir = local_opendir,
479: .rewinddir = local_rewinddir,
480: .telldir = local_telldir,
481: .readdir = local_readdir,
482: .seekdir = local_seekdir,
483: .readv = local_readv,
484: .lseek = local_lseek,
485: .writev = local_writev,
486: .chmod = local_chmod,
487: .mknod = local_mknod,
488: .mkdir = local_mkdir,
489: .fstat = local_fstat,
490: .open2 = local_open2,
491: .symlink = local_symlink,
492: .link = local_link,
493: .truncate = local_truncate,
494: .rename = local_rename,
495: .chown = local_chown,
496: .utime = local_utime,
497: .remove = local_remove,
498: .fsync = local_fsync,
499: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.