174 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <sys/capability.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/wait.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| /*
 | |
|  * tests for cap_launch.
 | |
|  */
 | |
| 
 | |
| #define MORE_THAN_ENOUGH 20
 | |
| #define NO_MORE 1
 | |
| 
 | |
| struct test_case_s {
 | |
|     int pass_on;
 | |
|     const char *chroot;
 | |
|     uid_t uid;
 | |
|     gid_t gid;
 | |
|     int ngroups;
 | |
|     const gid_t groups[MORE_THAN_ENOUGH];
 | |
|     const char *args[MORE_THAN_ENOUGH];
 | |
|     const char **envp;
 | |
|     const char *iab;
 | |
|     cap_mode_t mode;
 | |
|     int result;
 | |
| };
 | |
| 
 | |
| #ifdef WITH_PTHREADS
 | |
| #include <pthread.h>
 | |
| #else /* WITH_PTHREADS */
 | |
| #endif /* WITH_PTHREADS */
 | |
| 
 | |
| int main(int argc, char **argv) {
 | |
|     static struct test_case_s vs[] = {
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--", "-c", "echo hello" },
 | |
| 	    .result = 0
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--is-uid=123" },
 | |
| 	    .result = 256
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--is-uid=123" },
 | |
| 	    .result = 0,
 | |
| 	    .uid = 123,
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--is-gid=123" },
 | |
| 	    .result = 0,
 | |
| 	    .gid = 123,
 | |
| 	    .ngroups = 1,
 | |
| 	    .groups = { 456 },
 | |
| 	    .iab = "",
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--dropped=cap_chown",
 | |
| 		      "--has-i=cap_chown" },
 | |
| 	    .result = 0,
 | |
| 	    .iab = "!%cap_chown"
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--dropped=cap_chown",
 | |
| 		      "--has-i=cap_chown", "--is-uid=234",
 | |
| 		      "--has-a=cap_chown", "--has-p=cap_chown" },
 | |
| 	    .uid = 234,
 | |
| 	    .result = 0,
 | |
| 	    .iab = "!^cap_chown"
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "../progs/tcapsh-static", "--inmode=NOPRIV",
 | |
| 		      "--has-no-new-privs" },
 | |
| 	    .result = 0,
 | |
| 	    .mode = CAP_MODE_NOPRIV
 | |
| 	},
 | |
| 	{
 | |
| 	    .args = { "/noop" },
 | |
| 	    .result = 0,
 | |
| 	    .chroot = ".",
 | |
| 	},
 | |
| 	{
 | |
| 	    .pass_on = NO_MORE
 | |
| 	},
 | |
|     };
 | |
| 
 | |
|     cap_t orig = cap_get_proc();
 | |
| 
 | |
|     int success = 1, i;
 | |
|     for (i=0; vs[i].pass_on != NO_MORE; i++) {
 | |
| 	const struct test_case_s *v = &vs[i];
 | |
| 	printf("[%d] test should %s\n", i,
 | |
| 	       v->result ? "generate error" : "work");
 | |
| 	cap_launch_t attr = cap_new_launcher(v->args[0], v->args, v->envp);
 | |
| 	if (v->chroot) {
 | |
| 	    cap_launcher_set_chroot(attr, v->chroot);
 | |
| 	}
 | |
| 	if (v->uid) {
 | |
| 	    cap_launcher_setuid(attr, v->uid);
 | |
| 	}
 | |
| 	if (v->gid) {
 | |
| 	    cap_launcher_setgroups(attr, v->gid, v->ngroups, v->groups);
 | |
| 	}
 | |
| 	if (v->iab) {
 | |
| 	    cap_iab_t iab = cap_iab_from_text(v->iab);
 | |
| 	    if (iab == NULL) {
 | |
| 		fprintf(stderr, "[%d] failed to decode iab [%s]", i, v->iab);
 | |
| 		perror(":");
 | |
| 		success = 0;
 | |
| 		continue;
 | |
| 	    }
 | |
| 	    cap_iab_t old = cap_launcher_set_iab(attr, iab);
 | |
| 	    if (cap_free(old)) {
 | |
| 		fprintf(stderr, "[%d] failed to decode iab [%s]", i, v->iab);
 | |
| 		perror(":");
 | |
| 		success = 0;
 | |
| 		continue;
 | |
| 	    }
 | |
| 	}
 | |
| 	if (v->mode) {
 | |
| 	    cap_launcher_set_mode(attr, v->mode);
 | |
| 	}
 | |
| 
 | |
| 	pid_t child = cap_launch(attr, NULL);
 | |
| 
 | |
| 	if (child <= 0) {
 | |
| 	    fprintf(stderr, "[%d] failed to launch", i);
 | |
| 	    perror(":");
 | |
| 	    success = 0;
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (cap_free(attr)) {
 | |
| 	    fprintf(stderr, "[%d] failed to free launcher", i);
 | |
| 	    perror(":");
 | |
| 	    success = 0;
 | |
| 	}
 | |
| 	int result;
 | |
| 	int ret = waitpid(child, &result, 0);
 | |
| 	if (ret != child) {
 | |
| 	    fprintf(stderr, "[%d] failed to wait", i);
 | |
| 	    perror(":");
 | |
| 	    success = 0;
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (result != v->result) {
 | |
| 	    fprintf(stderr, "[%d] bad result: got=%d want=%d", i, result,
 | |
| 		    v->result);
 | |
| 	    perror(":");
 | |
| 	    success = 0;
 | |
| 	    continue;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     cap_t final = cap_get_proc();
 | |
|     if (cap_compare(orig, final)) {
 | |
| 	char *was = cap_to_text(orig, NULL);
 | |
| 	char *is = cap_to_text(final, NULL);
 | |
| 	printf("cap_launch_test: orig:'%s' != final:'%s'\n", was, is);
 | |
| 	cap_free(is);
 | |
| 	cap_free(was);
 | |
| 	success = 0;
 | |
|     }
 | |
|     cap_free(final);
 | |
|     cap_free(orig);
 | |
| 
 | |
|     if (success) {
 | |
| 	printf("cap_launch_test: PASSED\n");
 | |
|     } else {
 | |
| 	printf("cap_launch_test: FAILED\n");
 | |
| 	exit(1);
 | |
|     }
 | |
| }
 |