-
-
Save sbz/1090868 to your computer and use it in GitHub Desktop.
| #include <sys/capability.h> | |
| #include <sys/types.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| #define nitems(x) (sizeof(x) / sizeof(x[0])) | |
| int | |
| main(void) { | |
| pid_t pid; | |
| cap_t cap; | |
| cap_value_t cap_list[CAP_LAST_CAP+1]; | |
| cap_flag_t cap_flags; | |
| cap_flag_value_t cap_flags_value; | |
| // | |
| // generated list with command line below: | |
| // sed -n 's/^#define \(CAP_.*\) .*/\1/p' /usr/include/linux/capability.h | tr A-Z a-z | |
| // don't take cap_last_cap which is the same as the last cap_audit_read capability | |
| // | |
| const char *cap_name[CAP_LAST_CAP+1] = { | |
| "cap_chown", | |
| "cap_dac_override", | |
| "cap_dac_read_search", | |
| "cap_fowner", | |
| "cap_fsetid", | |
| "cap_kill", | |
| "cap_setgid", | |
| "cap_setuid", | |
| "cap_setpcap", | |
| "cap_linux_immutable", | |
| "cap_net_bind_service", | |
| "cap_net_broadcast", | |
| "cap_net_admin", | |
| "cap_net_raw", | |
| "cap_ipc_lock", | |
| "cap_ipc_owner", | |
| "cap_sys_module", | |
| "cap_sys_rawio", | |
| "cap_sys_chroot", | |
| "cap_sys_ptrace", | |
| "cap_sys_pacct", | |
| "cap_sys_admin", | |
| "cap_sys_boot", | |
| "cap_sys_nice", | |
| "cap_sys_resource", | |
| "cap_sys_time", | |
| "cap_sys_tty_config", | |
| "cap_mknod", | |
| "cap_lease", | |
| "cap_audit_write", | |
| "cap_audit_control", | |
| "cap_setfcap", | |
| "cap_mac_override", | |
| "cap_mac_admin", | |
| "cap_syslog", | |
| "cap_wake_alarm", | |
| "cap_block_suspend", | |
| "cap_audit_read", | |
| }; | |
| int i, j; | |
| /* temporary use for cap_get_flag calls */ | |
| struct { | |
| const char *str; | |
| cap_flag_t flag; | |
| } const flags[3] = { | |
| {"EFFECTIVE", CAP_EFFECTIVE}, | |
| {"PERMITTED", CAP_PERMITTED}, | |
| {"INHERITABLE", CAP_INHERITABLE} | |
| }; | |
| pid = getpid(); | |
| cap = cap_get_pid(pid); | |
| if (cap == NULL) { | |
| perror("cap_get_pid"); | |
| exit(-1); | |
| } | |
| /* set effective cap */ | |
| cap_list[0] = CAP_CHOWN; | |
| if (cap_set_flag(cap, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) { | |
| perror("cap_set_flag cap_chown"); | |
| cap_free(cap); | |
| exit(-1); | |
| } | |
| /* set permitted cap */ | |
| cap_list[0] = CAP_MAC_ADMIN; | |
| if (cap_set_flag(cap, CAP_PERMITTED, 1, cap_list, CAP_SET) == -1) { | |
| perror("cap_set_flag cap_mac_admin"); | |
| cap_free(cap); | |
| exit(-1); | |
| } | |
| /* set inherit cap */ | |
| cap_list[0] = CAP_SETFCAP; | |
| if (cap_set_flag(cap, CAP_INHERITABLE, 1, cap_list, CAP_SET) == -1) { | |
| perror("cap_set_flag cap_setfcap"); | |
| cap_free(cap); | |
| exit(-1); | |
| } | |
| /* dump them */ | |
| for (i=0; i < cap_max_bits(); i++) { | |
| cap_from_name(cap_name[i], &cap_list[i]); | |
| printf("%-20s %d\t\t", cap_to_name(cap_list[i]), cap_list[i]); | |
| printf("flags: \t\t"); | |
| for (j=0; j < nitems(flags); j++) { | |
| cap_get_flag(cap, cap_list[i], flags[j].flag, &cap_flags_value); | |
| printf(" %s %-4s ", flags[j].str, (cap_flags_value == CAP_SET) ? "OK" : "NOK"); | |
| } | |
| printf("\n"); | |
| } | |
| cap_free(cap); | |
| return 0; | |
| } |
Thank you very much
Very helpful
For compiling, I had to use gcc lcap.c -lcap -g -o lcap instead of the command you provided due to some undefined reference error to [libcap function] according to this stackoverflow answer
I also encountered a segmentation fault (core dumped) that I'm trying to fix ...
I'm using ubuntu 16.04 with the corresponding repository libcap-dev package.
Once again thank you
Sigsegv because new capabilities were added and you are initializing remaining names with NULL values:
Update start of the for block
for (i=0; i < CAP_LAST_CAP + 1; i++) {
if (!cap_name[i]) {
break;
}
"continue" could be used but as they are not empty spots in the array "break" makes more sense.
FWIW There is a function called cap_to_name() in libcap that pretty much does what you are doing with cap_name[i]. Also, libcap provides the function cap_max_bits() which returns the number of capabilities known to the running kernel which doesn't require you rely having access to the kernel header for your running kernel to build.
@AndrewGMorgan Thanks, it's great to have a feedback from the original author of libcap. I wrote this gist 11 years ago so it definitely need an update I guess.
From a quick look cap_to_name() is existing for a long time and cap_max_bits() seems to have been added last year with release 2.30 apparently.
If you remove the cap_name array and replace the final loop with the following It would work as @AndrewGMorgan stated:
int i;
char* cap_name;
for (i=0; i < CAP_LAST_CAP + 1; i++) {
cap_name = cap_to_name(i);
cap_from_name(cap_name, &cap_list[i]);
printf("%-20s %d\t\t", cap_name, cap_list[i]);
cap_free(cap_name);
printf("flags: \t\t");
cap_get_flag(cap, cap_list[i], CAP_EFFECTIVE, &cap_flags_value);
printf(" EFFECTIVE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_PERMITTED, &cap_flags_value);
printf(" PERMITTED %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_INHERITABLE, &cap_flags_value);
printf(" INHERITABLE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
printf("\n");
}```
% make lcap CFLAGS+="-lcap -g"
cc -lcap -g lcap.c -o lcap
% ./lcap
cap_chown 0 flags: EFFECTIVE OK PERMITTED NOK INHERITABLE NOK
...
cap_syslog 34 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK