This repository is to contain libraries that will let privilege-demanding application...
[vsys-wrappers.git] / fuse / stolen_from_fuse.c
1 #include <assert.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/mount.h>
7 #include <sys/socket.h>
8 #include <sys/un.h>
9 #include "stolen_from_fuse.h"
10
11 // Most of this code is stolen from FUSE 2.7.4
12
13 /** Function to pass a file descriptor over a UNIX socket.
14   * 
15   * Sends the file descriptor fd over the channel sock_fd.
16   *
17   ***/
18 int rrm_send_fd(int sock_fd, int fd)
19 {
20         int retval;
21         struct msghdr msg;
22         struct cmsghdr *p_cmsg;
23         struct iovec vec;
24         size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
25         int *p_fds;
26         char sendchar = 0;
27
28         msg.msg_control = cmsgbuf;
29         msg.msg_controllen = sizeof(cmsgbuf);
30         p_cmsg = CMSG_FIRSTHDR(&msg);
31         p_cmsg->cmsg_level = SOL_SOCKET;
32         p_cmsg->cmsg_type = SCM_RIGHTS;
33         p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
34         p_fds = (int *) CMSG_DATA(p_cmsg);
35         *p_fds = fd;
36         msg.msg_controllen = p_cmsg->cmsg_len;
37         msg.msg_name = NULL;
38         msg.msg_namelen = 0;
39         msg.msg_iov = &vec;
40         msg.msg_iovlen = 1;
41         msg.msg_flags = 0;
42         /* "To pass file descriptors or credentials you need to send/read at
43          * least one byte" (man 7 unix) */
44         vec.iov_base = &sendchar;
45         vec.iov_len = sizeof(sendchar);
46         while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
47         if (retval != 1) {
48                 perror("sending file descriptor");
49                 return -1;
50         }
51         return 0;
52 }
53
54
55 /* return value:
56  * >= 0  => fd
57  * -1    => error
58  */
59 int rrm_receive_fd(int fd)
60 {
61         struct msghdr msg;
62         struct iovec iov;
63         char buf[1];
64         int rv;
65         size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
66         struct cmsghdr *cmsg;
67
68         iov.iov_base = buf;
69         iov.iov_len = 1;
70
71         msg.msg_name = 0;
72         msg.msg_namelen = 0;
73         msg.msg_iov = &iov;
74         msg.msg_iovlen = 1;
75         /* old BSD implementations should use msg_accrights instead of
76          * msg_control; the interface is different. */
77         msg.msg_control = ccmsg;
78         msg.msg_controllen = sizeof(ccmsg);
79
80         while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
81         if (rv == -1) {
82                 perror("recvmsg");
83                 return -1;
84         }
85         if(!rv) {
86                 /* EOF */
87                 return -1;
88         }
89
90         cmsg = CMSG_FIRSTHDR(&msg);
91         if (!cmsg->cmsg_type == SCM_RIGHTS) {
92                 fprintf(stderr, "got control message of unknown type %d\n",
93                         cmsg->cmsg_type);
94                 return -1;
95         }
96         return *(int*)CMSG_DATA(cmsg);
97 }
98
99 int rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
100 {
101         int res;
102         int status;
103         
104         res = umount2(mnt, lazy ? 2 : 0);
105         if (res == -1)
106           fprintf(stderr, "%s: failed to unmount %s: %s\n",
107                   progname, mnt, strerror(errno));
108         return res;
109
110 }
111
112 static int rrm_try_open(const char *dev, char **devp, int silent)
113 {
114         int fd = open(dev, O_RDWR);
115         if (fd != -1) {
116                 *devp = strdup(dev);
117                 if (*devp == NULL) {
118                   fprintf(stderr, "failed to allocate memory\n" );
119                                 
120                         close(fd);
121                         fd = -1;
122                 }
123         } else if (errno == ENODEV ||
124                    errno == ENOENT)/* check for ENOENT too, for the udev case */
125                 return -2;
126         else if (!silent) {
127                 fprintf(stderr, "failed to open %s: %s\n", dev,
128                         strerror(errno));
129         }
130         return fd;
131 }
132
133 static int rrm_try_open_fuse_device(char **devp)
134 {
135         int fd;
136         int err;
137
138         //drop_privs();
139         fd = rrm_try_open(FUSE_DEV_NEW, devp, 0);
140         //restore_privs();
141         if (fd >= 0)
142                 return fd;
143
144         err = fd;
145         fd = rrm_try_open(FUSE_DEV_OLD, devp, 1);
146         if (fd >= 0)
147                 return fd;
148
149         return err;
150 }
151
152 int rrm_open_fuse_device(char **devp)
153 {
154         int fd = rrm_try_open_fuse_device(devp);
155         if (fd >= -1)
156                 return fd;
157
158         fprintf(stderr,
159                 "fuse device not found, try 'modprobe fuse' first\n");
160
161         return -1;
162 }