1 /* 2 * Copyright (c) 1997,2007-8 Andrew G. Morgan <morgan (at) kernel.org> 3 * 4 * This sets/verifies the capabilities of a given file. 5 */ 6 7 #include <errno.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <stdlib.h> 11 #include <sys/capability.h> 12 #include <unistd.h> 13 14 static void usage(void) 15 { 16 fprintf(stderr, 17 "usage: setcap [-q] [-v] (-r|-|<caps>) <filename> " 18 "[ ... (-r|-|<capsN>) <filenameN> ]\n" 19 "\n" 20 " Note <filename> must be a regular (non-symlink) file.\n" 21 ); 22 exit(1); 23 } 24 25 #define MAXCAP 2048 26 27 static int read_caps(int quiet, const char *filename, char *buffer) 28 { 29 int i = MAXCAP; 30 31 if (!quiet) { 32 fprintf(stderr, "Please enter caps for file [empty line to end]:\n"); 33 } 34 while (i > 0) { 35 int j = read(STDIN_FILENO, buffer, i); 36 37 if (j < 0) { 38 fprintf(stderr, "\n[Error - aborting]\n"); 39 exit(1); 40 } 41 42 if (j==0 || buffer[0] == '\n') { 43 /* we're done */ 44 break; 45 } 46 47 /* move on... */ 48 49 i -= j; 50 buffer += j; 51 } 52 53 /* <NUL> terminate */ 54 buffer[0] = '\0'; 55 56 return (i < MAXCAP ? 0:-1); 57 } 58 59 int main(int argc, char **argv) 60 { 61 int tried_to_cap_setfcap = 0; 62 char buffer[MAXCAP+1]; 63 int retval, quiet=0, verify=0; 64 cap_t mycaps; 65 cap_value_t capflag; 66 67 if (argc < 3) { 68 usage(); 69 } 70 71 mycaps = cap_get_proc(); 72 if (mycaps == NULL) { 73 fprintf(stderr, "warning - unable to get process capabilities" 74 " (old libcap?)\n"); 75 } 76 77 while (--argc > 0) { 78 const char *text; 79 cap_t cap_d; 80 81 if (!strcmp(*++argv, "-q")) { 82 quiet = 1; 83 continue; 84 } 85 if (!strcmp(*argv, "-v")) { 86 verify = 1; 87 continue; 88 } 89 90 if (!strcmp(*argv, "-r")) { 91 cap_d = NULL; 92 } else { 93 if (!strcmp(*argv,"-")) { 94 retval = read_caps(quiet, *argv, buffer); 95 if (retval) 96 usage(); 97 text = buffer; 98 } else { 99 text = *argv; 100 } 101 102 cap_d = cap_from_text(text); 103 if (cap_d == NULL) { 104 perror("fatal error"); 105 usage(); 106 } 107 #ifdef DEBUG 108 { 109 ssize_t length; 110 const char *result; 111 112 result = cap_to_text(cap_d, &length); 113 fprintf(stderr, "caps set to: [%s]\n", result); 114 } 115 #endif 116 } 117 118 if (--argc <= 0) 119 usage(); 120 /* 121 * Set the filesystem capability for this file. 122 */ 123 if (verify) { 124 cap_t cap_on_file; 125 int cmp; 126 127 if (cap_d == NULL) { 128 cap_d = cap_from_text("="); 129 } 130 131 cap_on_file = cap_get_file(*++argv); 132 133 if (cap_on_file == NULL) { 134 cap_on_file = cap_from_text("="); 135 } 136 137 cmp = cap_compare(cap_on_file, cap_d); 138 cap_free(cap_on_file); 139 140 if (cmp != 0) { 141 if (!quiet) { 142 printf("%s differs in [%s%s%s]\n", *argv, 143 CAP_DIFFERS(cmp, CAP_PERMITTED) ? "p" : "", 144 CAP_DIFFERS(cmp, CAP_INHERITABLE) ? "i" : "", 145 CAP_DIFFERS(cmp, CAP_EFFECTIVE) ? "e" : ""); 146 } 147 exit(1); 148 } 149 if (!quiet) { 150 printf("%s: OK\n", *argv); 151 } 152 } else { 153 if (!tried_to_cap_setfcap) { 154 capflag = CAP_SETFCAP; 155 156 /* 157 * Raise the effective CAP_SETFCAP. 158 */ 159 if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET) 160 != 0) { 161 perror("unable to manipulate CAP_SETFCAP - " 162 "try a newer libcap?"); 163 exit(1); 164 } 165 if (cap_set_proc(mycaps) != 0) { 166 perror("unable to set CAP_SETFCAP effective capability"); 167 exit(1); 168 } 169 tried_to_cap_setfcap = 1; 170 } 171 retval = cap_set_file(*++argv, cap_d); 172 if (retval != 0) { 173 int explained = 0; 174 int oerrno = errno; 175 #ifdef linux 176 cap_value_t cap; 177 cap_flag_value_t per_state; 178 179 for (cap = 0; 180 cap_get_flag(cap_d, cap, CAP_PERMITTED, &per_state) != -1; 181 cap++) { 182 cap_flag_value_t inh_state, eff_state; 183 184 cap_get_flag(cap_d, cap, CAP_INHERITABLE, &inh_state); 185 cap_get_flag(cap_d, cap, CAP_EFFECTIVE, &eff_state); 186 if ((inh_state | per_state) != eff_state) { 187 fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n" 188 " exactly match the union of selected permitted and inheritable bits.\n"); 189 explained = 1; 190 break; 191 } 192 } 193 #endif /* def linux */ 194 195 fprintf(stderr, 196 "Failed to set capabilities on file `%s' (%s)\n", 197 argv[0], strerror(oerrno)); 198 if (!explained) { 199 usage(); 200 } 201 } 202 } 203 if (cap_d) { 204 cap_free(cap_d); 205 } 206 } 207 208 exit(0); 209 } 210