1363da138SBaptiste Daroussin /*- 2363da138SBaptiste Daroussin * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> 3363da138SBaptiste Daroussin * All rights reserved. 4363da138SBaptiste Daroussin * 5363da138SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 6363da138SBaptiste Daroussin * modification, are permitted provided that the following conditions 7363da138SBaptiste Daroussin * are met: 8363da138SBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 9363da138SBaptiste Daroussin * notice, this list of conditions and the following disclaimer 10363da138SBaptiste Daroussin * in this position and unchanged. 11363da138SBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 12363da138SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 13363da138SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 14363da138SBaptiste Daroussin * 15363da138SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16363da138SBaptiste Daroussin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17363da138SBaptiste Daroussin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18363da138SBaptiste Daroussin * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19363da138SBaptiste Daroussin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20363da138SBaptiste Daroussin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21363da138SBaptiste Daroussin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22363da138SBaptiste Daroussin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23363da138SBaptiste Daroussin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24363da138SBaptiste Daroussin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25363da138SBaptiste Daroussin */ 26363da138SBaptiste Daroussin 27363da138SBaptiste Daroussin #include <sys/cdefs.h> 28363da138SBaptiste Daroussin __FBSDID("$FreeBSD$"); 29363da138SBaptiste Daroussin 30224d9e3eSBaptiste Daroussin #include <sys/capsicum.h> 31b704d1f2SBaptiste Daroussin #include <sys/types.h> 32b704d1f2SBaptiste Daroussin 330330f102SBaptiste Daroussin #include <ctype.h> 340330f102SBaptiste Daroussin #include <err.h> 35224d9e3eSBaptiste Daroussin #include <errno.h> 36224d9e3eSBaptiste Daroussin #include <fcntl.h> 3746cc6349SBaptiste Daroussin #include <limits.h> 38363da138SBaptiste Daroussin #include <stdio.h> 39363da138SBaptiste Daroussin #include <stdlib.h> 40363da138SBaptiste Daroussin #include <string.h> 41363da138SBaptiste Daroussin #include <stringlist.h> 42224d9e3eSBaptiste Daroussin #include <termios.h> 430330f102SBaptiste Daroussin #include <unistd.h> 44363da138SBaptiste Daroussin 45b4a0618cSBaptiste Daroussin #define C_OPTION 0x1 46b4a0618cSBaptiste Daroussin 47363da138SBaptiste Daroussin static StringList *includes; 48363da138SBaptiste Daroussin 49363da138SBaptiste Daroussin static void 50363da138SBaptiste Daroussin usage(void) 51363da138SBaptiste Daroussin { 52363da138SBaptiste Daroussin 53363da138SBaptiste Daroussin fprintf(stderr, "usage: soelim [-Crtv] [-I dir] [files]\n"); 54363da138SBaptiste Daroussin 55363da138SBaptiste Daroussin exit(EXIT_FAILURE); 56363da138SBaptiste Daroussin } 57363da138SBaptiste Daroussin 58224d9e3eSBaptiste Daroussin static const char * 59224d9e3eSBaptiste Daroussin relpath(const char *path) 60363da138SBaptiste Daroussin { 61b2c71bceSBaptiste Daroussin 62224d9e3eSBaptiste Daroussin while (*path == '/' && *path != '\0') 63224d9e3eSBaptiste Daroussin path++; 64224d9e3eSBaptiste Daroussin 65224d9e3eSBaptiste Daroussin return (path); 66224d9e3eSBaptiste Daroussin } 67224d9e3eSBaptiste Daroussin 68224d9e3eSBaptiste Daroussin static FILE * 69224d9e3eSBaptiste Daroussin soelim_fopen(int rootfd, const char *name) 70224d9e3eSBaptiste Daroussin { 71*160af931SBaptiste Daroussin FILE *f = NULL; 7246cc6349SBaptiste Daroussin char path[PATH_MAX]; 73363da138SBaptiste Daroussin size_t i; 74224d9e3eSBaptiste Daroussin int fd; 75363da138SBaptiste Daroussin 766f32f49cSXin LI if (strcmp(name, "-") == 0) 776f32f49cSXin LI return (stdin); 786f32f49cSXin LI 79*160af931SBaptiste Daroussin if ((fd = openat(rootfd, relpath(name), O_RDONLY)) != -1) { 80*160af931SBaptiste Daroussin f = fdopen(fd, "r"); 81*160af931SBaptiste Daroussin goto out; 82*160af931SBaptiste Daroussin } 83363da138SBaptiste Daroussin 84363da138SBaptiste Daroussin if (*name == '/') { 85363da138SBaptiste Daroussin warn("can't open '%s'", name); 86363da138SBaptiste Daroussin return (NULL); 87363da138SBaptiste Daroussin } 88363da138SBaptiste Daroussin 89363da138SBaptiste Daroussin for (i = 0; i < includes->sl_cur; i++) { 90363da138SBaptiste Daroussin snprintf(path, sizeof(path), "%s/%s", includes->sl_str[i], 91363da138SBaptiste Daroussin name); 92*160af931SBaptiste Daroussin if ((fd = openat(rootfd, relpath(path), O_RDONLY)) != -1) { 93*160af931SBaptiste Daroussin f = fdopen(fd, "r"); 94*160af931SBaptiste Daroussin break; 95*160af931SBaptiste Daroussin } 96363da138SBaptiste Daroussin } 97363da138SBaptiste Daroussin 98*160af931SBaptiste Daroussin out: 99*160af931SBaptiste Daroussin if (f == NULL) 100363da138SBaptiste Daroussin warn("can't open '%s'", name); 101363da138SBaptiste Daroussin 102*160af931SBaptiste Daroussin return (f); 103363da138SBaptiste Daroussin } 104363da138SBaptiste Daroussin 105363da138SBaptiste Daroussin static int 106224d9e3eSBaptiste Daroussin soelim_file(int rootfd, FILE *f, int flag) 107363da138SBaptiste Daroussin { 108363da138SBaptiste Daroussin char *line = NULL; 109b4a0618cSBaptiste Daroussin char *walk, *cp; 110363da138SBaptiste Daroussin size_t linecap = 0; 111363da138SBaptiste Daroussin ssize_t linelen; 112363da138SBaptiste Daroussin 113363da138SBaptiste Daroussin if (f == NULL) 114363da138SBaptiste Daroussin return (1); 115363da138SBaptiste Daroussin 116363da138SBaptiste Daroussin while ((linelen = getline(&line, &linecap, f)) > 0) { 117363da138SBaptiste Daroussin if (strncmp(line, ".so", 3) != 0) { 118363da138SBaptiste Daroussin printf("%s", line); 119363da138SBaptiste Daroussin continue; 120363da138SBaptiste Daroussin } 121b4a0618cSBaptiste Daroussin 122363da138SBaptiste Daroussin walk = line + 3; 123b4a0618cSBaptiste Daroussin if (!isspace(*walk) && ((flag & C_OPTION) == 0)) { 124b4a0618cSBaptiste Daroussin printf("%s", line); 125b4a0618cSBaptiste Daroussin continue; 126b4a0618cSBaptiste Daroussin } 127b4a0618cSBaptiste Daroussin 128363da138SBaptiste Daroussin while (isspace(*walk)) 129363da138SBaptiste Daroussin walk++; 130363da138SBaptiste Daroussin 1312b30fb26SBaptiste Daroussin cp = walk; 1322b30fb26SBaptiste Daroussin while (*cp != '\0' && !isspace(*cp)) 1332b30fb26SBaptiste Daroussin cp++; 134b4a0618cSBaptiste Daroussin *cp = 0; 1352b30fb26SBaptiste Daroussin if (cp < line + linelen) 1362b30fb26SBaptiste Daroussin cp++; 137b4a0618cSBaptiste Daroussin 138b4a0618cSBaptiste Daroussin if (*walk == '\0') { 139b4a0618cSBaptiste Daroussin printf("%s", line); 140b4a0618cSBaptiste Daroussin continue; 141b4a0618cSBaptiste Daroussin } 142224d9e3eSBaptiste Daroussin if (soelim_file(rootfd, soelim_fopen(rootfd, walk), flag) == 1) { 143363da138SBaptiste Daroussin free(line); 144363da138SBaptiste Daroussin return (1); 145363da138SBaptiste Daroussin } 1462b30fb26SBaptiste Daroussin if (*cp != '\0') 1472b30fb26SBaptiste Daroussin printf("%s", cp); 148363da138SBaptiste Daroussin } 149363da138SBaptiste Daroussin 150363da138SBaptiste Daroussin free(line); 151363da138SBaptiste Daroussin fclose(f); 152363da138SBaptiste Daroussin 153363da138SBaptiste Daroussin return (0); 154363da138SBaptiste Daroussin } 155363da138SBaptiste Daroussin 156363da138SBaptiste Daroussin int 157363da138SBaptiste Daroussin main(int argc, char **argv) 158363da138SBaptiste Daroussin { 159224d9e3eSBaptiste Daroussin int ch, i, rootfd; 160363da138SBaptiste Daroussin int ret = 0; 161b4a0618cSBaptiste Daroussin int flags = 0; 162224d9e3eSBaptiste Daroussin unsigned long cmd; 163224d9e3eSBaptiste Daroussin char cwd[MAXPATHLEN]; 164224d9e3eSBaptiste Daroussin cap_rights_t rights; 165363da138SBaptiste Daroussin 166363da138SBaptiste Daroussin includes = sl_init(); 167*160af931SBaptiste Daroussin if (getcwd(cwd, sizeof(cwd)) != NULL) 168*160af931SBaptiste Daroussin sl_add(includes, cwd); 169*160af931SBaptiste Daroussin 170363da138SBaptiste Daroussin if (includes == NULL) 171363da138SBaptiste Daroussin err(EXIT_FAILURE, "sl_init()"); 172363da138SBaptiste Daroussin 173363da138SBaptiste Daroussin while ((ch = getopt(argc, argv, "CrtvI:")) != -1) { 174363da138SBaptiste Daroussin switch (ch) { 175363da138SBaptiste Daroussin case 'C': 176b4a0618cSBaptiste Daroussin flags |= C_OPTION; 177b4a0618cSBaptiste Daroussin break; 178363da138SBaptiste Daroussin case 'r': 179363da138SBaptiste Daroussin case 'v': 180363da138SBaptiste Daroussin case 't': 181363da138SBaptiste Daroussin /* stub compatibility with groff's soelim */ 182363da138SBaptiste Daroussin break; 183363da138SBaptiste Daroussin case 'I': 184363da138SBaptiste Daroussin sl_add(includes, optarg); 185363da138SBaptiste Daroussin break; 186363da138SBaptiste Daroussin default: 187363da138SBaptiste Daroussin sl_free(includes, 0); 188363da138SBaptiste Daroussin usage(); 189363da138SBaptiste Daroussin } 190363da138SBaptiste Daroussin } 191363da138SBaptiste Daroussin 192363da138SBaptiste Daroussin argc -= optind; 193363da138SBaptiste Daroussin argv += optind; 194363da138SBaptiste Daroussin 195224d9e3eSBaptiste Daroussin cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_IOCTL); 196224d9e3eSBaptiste Daroussin /* 197224d9e3eSBaptiste Daroussin * EBADF in case stdin is closed by the caller 198224d9e3eSBaptiste Daroussin */ 199224d9e3eSBaptiste Daroussin if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS 200224d9e3eSBaptiste Daroussin && errno != EBADF) 201224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit rights for stdin"); 202224d9e3eSBaptiste Daroussin cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT, CAP_IOCTL); 203224d9e3eSBaptiste Daroussin if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) 204224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit rights for stdout"); 205224d9e3eSBaptiste Daroussin if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) 206224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit rights for stderr"); 207224d9e3eSBaptiste Daroussin rootfd = open("/", O_DIRECTORY | O_RDONLY); 208*160af931SBaptiste Daroussin if (rootfd == -1) 209*160af931SBaptiste Daroussin err(EXIT_FAILURE, "unable to open '/'"); 210224d9e3eSBaptiste Daroussin cap_rights_init(&rights, CAP_READ, CAP_LOOKUP, CAP_FSTAT, CAP_FCNTL); 211224d9e3eSBaptiste Daroussin if (cap_rights_limit(rootfd, &rights) < 0 && errno != ENOSYS) 212224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit rights"); 213224d9e3eSBaptiste Daroussin 214224d9e3eSBaptiste Daroussin cmd = TIOCGETA; 215224d9e3eSBaptiste Daroussin if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS) 216224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit ioctls for stdout"); 217224d9e3eSBaptiste Daroussin if (cap_ioctls_limit(STDERR_FILENO, &cmd, 1) < 0 && errno != ENOSYS) 218224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit ioctls for stderr"); 219224d9e3eSBaptiste Daroussin if (cap_ioctls_limit(STDIN_FILENO, &cmd, 1) < 0 && errno != ENOSYS) 220224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to limit ioctls for stdin"); 221224d9e3eSBaptiste Daroussin 222224d9e3eSBaptiste Daroussin if (cap_enter() < 0 && errno != ENOSYS) 223224d9e3eSBaptiste Daroussin err(EXIT_FAILURE, "unable to enter capability mode"); 224224d9e3eSBaptiste Daroussin 225363da138SBaptiste Daroussin if (argc == 0) 226224d9e3eSBaptiste Daroussin ret = soelim_file(rootfd, stdin, flags); 227363da138SBaptiste Daroussin 228363da138SBaptiste Daroussin for (i = 0; i < argc; i++) 229224d9e3eSBaptiste Daroussin ret = soelim_file(rootfd, soelim_fopen(rootfd, argv[i]), flags); 230363da138SBaptiste Daroussin 231363da138SBaptiste Daroussin sl_free(includes, 0); 232224d9e3eSBaptiste Daroussin close(rootfd); 233363da138SBaptiste Daroussin 234363da138SBaptiste Daroussin return (ret); 235363da138SBaptiste Daroussin } 236