sfakeroot

manipulate files faking root privileges
git clone git://git.vx21.xyz/sfakeroot
Log | Files | Refs | README | LICENSE

libsfakeroot.c (7043B)


      1 /* sfakeroot
      2  *
      3  * Copyright © 2020 Richard Ipsum
      4  *
      5  * This file is part of sfakeroot.
      6  *
      7  * sfakeroot is free software: you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License as published by
      9  * the Free Software Foundation, version 3 of the License.
     10  *
     11  * sfakeroot is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with sfakeroot.  If not, see <http://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <stdbool.h>
     23 #include <fcntl.h>
     24 #include <unistd.h>
     25 #include <string.h>
     26 #include <errno.h>
     27 #include <sys/stat.h>
     28 #include <sys/types.h>
     29 #include <sys/socket.h>
     30 #include <sys/wait.h>
     31 #include <sys/un.h>
     32 
     33 #include "sfakeroot.h"
     34 
     35 int sfakeroot_readwriten(int fd, char bytes[], size_t len, bool is_write)
     36 {
     37     ssize_t n;
     38     size_t remaining = len;
     39 
     40     while (remaining > 0) {
     41         n = is_write ? write(fd, bytes, remaining) : read(fd, bytes, remaining);
     42         switch (n) {
     43             case 0:
     44                 if (is_write) {
     45                     /* not necessarily an error if we're writing... */
     46                     continue;
     47                 }
     48                 fprintf(stderr, "sfakeroot: %s: data truncated, remaining: %zu\n",
     49                         is_write ? "write" : "read", remaining);
     50                 return -1;
     51             case -1:
     52                 if (errno == EINTR) {
     53                     continue;
     54                 }
     55                 fprintf(stderr, "sfakeroot: %s: %s\n",
     56                         is_write ? "write" : "read", strerror(errno));
     57                 return -1;
     58             default:
     59                 remaining -= n;
     60                 bytes += n;
     61         }
     62     }
     63 
     64     return len - remaining;
     65 }
     66 
     67 int sfakeroot_recvmsg(int fd, struct sfakeroot_msg *m)
     68 {
     69     if (sfakeroot_readwriten(fd, (char *) m, sizeof (*m), false) != sizeof (*m)) {
     70         fprintf(stderr, "sfakeroot_recvmsg: error reading message\n");
     71         return -1;
     72     }
     73 
     74     return 0;
     75 }
     76 
     77 int sfakeroot_sendmsg(int fd, struct sfakeroot_msg *m)
     78 {
     79     if (sfakeroot_readwriten(fd, (char *) m, sizeof (*m), true) != sizeof (*m)) {
     80         fprintf(stderr, "sfakeroot_sendmsg: error writing message\n");
     81         return -1;
     82     }
     83 
     84     return 0;
     85 }
     86 
     87 static int sfakeroot__session_open_internal(bool session_expected)
     88 {
     89     struct sockaddr_un sa = {.sun_family = AF_UNIX};
     90     int sockfd;
     91     socklen_t socklen;
     92     char *sockpath = getenv("SFAKEROOT_SOCKET_PATH");
     93 
     94     if (sockpath == NULL) {
     95         fprintf(stderr, "environment variable SFAKEROOT_SOCKET_PATH not set!\n");
     96         return -1;
     97     }
     98 
     99     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    100     if (sockfd == -1) {
    101         fprintf(stderr, "socket: %s\n", strerror(errno));
    102         return -1;
    103     }
    104 
    105     strlcpy(sa.sun_path, sockpath, sizeof (sa.sun_path));
    106     socklen = strlen(sa.sun_path) + 1 + sizeof (sa.sun_family);
    107 
    108     if (connect(sockfd, (struct sockaddr *) &sa, socklen) == -1) {
    109         if (session_expected) {
    110             fprintf(stderr, "connect: %s\n", strerror(errno));
    111         }
    112         return -1;
    113     }
    114 
    115     return sockfd;
    116 }
    117 
    118 int sfakeroot_session_open(void)
    119 {
    120     return sfakeroot__session_open_internal(true);
    121 }
    122 
    123 bool sfakeroot_daemon_running(void)
    124 {
    125     int sockfd = sfakeroot__session_open_internal(false);
    126     close(sockfd);
    127     return sockfd != -1;
    128 }
    129 
    130 static int sfakeroot__call(struct sfakeroot_msg *m)
    131 {
    132     int sockfd;
    133     char *wd;
    134 
    135     sockfd = sfakeroot_session_open();
    136     if (sockfd == -1) {
    137         return -1;
    138     }
    139 
    140     if ((wd = getcwd(NULL, 0)) == NULL) {
    141         return -1;
    142     }
    143 
    144     strlcpy(m->working_dir, wd, sizeof (m->working_dir));
    145     free(wd);
    146 
    147     if (sfakeroot_sendmsg(sockfd, m) == -1) {
    148         return -1;
    149     }
    150     if (sfakeroot_recvmsg(sockfd, m) == -1) {
    151         return -1;
    152     }
    153 
    154     close(sockfd);
    155     errno = m->reterrno;
    156     return m->retcode;
    157 }
    158 
    159 int chmod(const char *path, mode_t mode)
    160 {
    161     struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_CHMOD, .mode = mode};
    162     debug("chmod %s %o\n", path, mode);
    163     strlcpy(m.path, path, sizeof (m.path));
    164     return sfakeroot__call(&m);
    165 }
    166 
    167 int chown(const char *path, uid_t uid, gid_t gid)
    168 {
    169     struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_CHOWN, .uid = uid, .gid = gid};
    170     strlcpy(m.path, path, sizeof (m.path));
    171     debug("chown: path: %s, uid: %d, gid: %d\n", path, (int) uid, (int) gid);
    172     return sfakeroot__call(&m);
    173 }
    174 
    175 int lchown(const char *path, uid_t uid, gid_t gid)
    176 {
    177     struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_LCHOWN, .uid = uid, .gid = gid};
    178     strlcpy(m.path, path, sizeof (m.path));
    179     debug("lchown: path: %s, uid: %d, gid: %d\n", path, (int) uid, (int) gid);
    180     return sfakeroot__call(&m);
    181 }
    182 
    183 int fchown(int fd, uid_t uid, gid_t gid)
    184 {
    185     struct sfakeroot_msg m = {
    186         .type = SFAKEROOT_MSG_FCHOWN,
    187         .fd = fd,
    188         .uid = uid,
    189         .gid = gid
    190     };
    191     return sfakeroot__call(&m);
    192 }
    193 
    194 int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag)
    195 {
    196     struct sfakeroot_msg m = {
    197         .type = SFAKEROOT_MSG_FCHOWNAT,
    198         .fd = fd,
    199         .flag = flag,
    200         .uid = uid,
    201         .gid = gid
    202     };
    203     debug("fchownat %d %s %u %u %u\n", fd, path, uid, gid, flag);
    204     strlcpy(m.path, path, sizeof (m.path));
    205     return sfakeroot__call(&m);
    206 }
    207 
    208 static int sfakeroot__stat(struct sfakeroot_msg *m, struct stat *s)
    209 {
    210     int ret;
    211     if ((ret = sfakeroot__call(m)) == -1) {
    212         return -1;
    213     }
    214     *s = m->st;
    215     return ret;
    216 }
    217 
    218 int stat(const char *path, struct stat *s)
    219 {
    220     struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_STAT};
    221     debug("stat\n");
    222     strlcpy(m.path, path, sizeof (m.path));
    223     return sfakeroot__stat(&m, s);
    224 }
    225 
    226 int __xstat(int ver, const char *path, struct stat *s)
    227 {
    228     (void) ver;
    229     return stat(path, s);
    230 }
    231 
    232 int lstat(const char *path, struct stat *s)
    233 {
    234     struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_LSTAT};
    235     debug("lstat\n");
    236     strlcpy(m.path, path, sizeof (m.path));
    237     return sfakeroot__stat(&m, s);
    238 }
    239 
    240 int __lxstat(int ver, const char *path, struct stat *s)
    241 {
    242     (void) ver;
    243     return lstat(path, s);
    244 }
    245 
    246 int fstat(int fd, struct stat *s)
    247 {
    248     struct sfakeroot_msg m = {.type = SFAKEROOT_MSG_FSTAT, .fd = fd};
    249     return sfakeroot__stat(&m, s);
    250 }
    251 
    252 int __fxstat(int ver, int fd, struct stat *sb)
    253 {
    254     (void) ver;
    255     return fstat(fd, sb);
    256 }
    257 
    258 int fstatat(int fd, const char *path, struct stat *s, int flag)
    259 {
    260     struct sfakeroot_msg m = {
    261         .type = SFAKEROOT_MSG_FSTATAT,
    262         .fd = fd,
    263         .flag = flag,
    264     };
    265     strlcpy(m.path, path, sizeof (m.path));
    266     return sfakeroot__stat(&m, s);
    267 }
    268 
    269 #undef __xstat
    270 #undef __fxstat
    271 #undef __lxstat
    272 #undef __xstat64
    273 #undef __fxstat64
    274 #undef __lxstat64
    275 #undef _FILE_OFFSET_BITS
    276 
    277 // TODO:
    278 // int
    279 // utimes(const char *path, const struct timeval *times);
    280 //
    281 // int
    282 // futimes(int fd, const struct timeval *times);