Exemplo n.º 1
0
int
main(int argc, char *argv[])
{
    struct sigevent sev;
    mqd_t mqd;
    struct mq_attr attr;
    void *buffer;
    ssize_t numRead;
    sigset_t blockMask;
    siginfo_t si;

    if (argc != 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s mq-name\n", argv[0]);

    mqd = mq_open(argv[1], O_RDONLY | O_NONBLOCK);
    if (mqd == (mqd_t) -1)
        errExit("mq_open");

    /* Determine mq_msgsize for message queue, and allocate an input buffer
       of that size */

    if (mq_getattr(mqd, &attr) == -1)
        errExit("mq_getattr");
    buffer = malloc(attr.mq_msgsize);
    if (buffer == NULL)
        errExit("malloc");

    /* Block the signal that we'll accept using sigwaitinfo() */

    sigemptyset(&blockMask);
    sigaddset(&blockMask, NOTIFY_SIG);
    if (sigprocmask(SIG_BLOCK, &blockMask, NULL) == -1)
        errExit("sigprocmask");

    /* Set up message notification using the signal NOTIFY_SIG */

    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = NOTIFY_SIG;
    sev.sigev_value.sival_ptr = &mqd;
    /* This allows us to obtain a pointer to 'mqd' in the
       siginfo_t structure returned by sigwaitinfo() */

    if (mq_notify(mqd, &sev) == -1)
        errExit("mq_notify");

    for (;;) {

        /* Wait for a signal; when it is received, display associated
           information */

        if (sigwaitinfo(&blockMask, &si) == -1)errExit("sigwaitinfo");

        printf("Accepted signal:\n");
        printf("        si_signo   = %d\n", si.si_signo);
        printf("        si_pid     = %ld\n", (long) si.si_pid);
        printf("        si_uid     = %ld\n", (long) si.si_uid);
        printf("        si_code    = %d (%s)\n", si.si_code,
               (si.si_code == SI_MESGQ) ? "SI_MESGQ" : "???");
        printf("        *sival_ptr = %p\n\n", si.si_value.sival_ptr);

        /* Reestablish message notification */

        if (mq_notify(mqd, &sev) == -1)
            errExit("mq_notify");

        /* Although only one signal might have been queued (if NOTIFY_SIG
           is a standard signal) we might have received multiple messages,
           so use nonblocking mq_receive() calls inside a loop to read
           as many messages as possible. */

        while ((numRead = mq_receive(mqd, buffer, attr.mq_msgsize, NULL)) >= 0)
            printf("Read %ld bytes\n", (long) numRead);

        if (errno != EAGAIN)            /* Unexpected error */
            errExit("mq_receive");
    }
}
Exemplo n.º 2
0
int
main(int argc, char *argv[])
{
    sigset_t pending, blocked;
    const int numSecs = 5;
    struct sigaction sa;

    /* Set up a handler for SIGINT */

    printf("Setting up handler for SIGINT\n");
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = handler;
    if (sigaction(SIGINT, &sa, NULL) == -1)
        errExit("sigaction");

    /* Block SIGINT for a while */

    sigemptyset(&blocked);
    sigaddset(&blocked, SIGINT);
    if (sigprocmask(SIG_SETMASK, &blocked, NULL) == -1)
        errExit("sigprocmask");

    printf("BLOCKING SIGINT for %d seconds\n", numSecs);
    sleep(numSecs);

    /* Display mask of pending signals */

    if (sigpending(&pending) == -1)
        errExit("sigpending");
    printf("PENDING signals are: \n");
    printSigset(stdout, "\t\t", &pending);

    /* Now ignore SIGINT */

    sleep(2);
    printf("Ignoring SIGINT\n");
    if (signal(SIGINT, SIG_IGN) == SIG_ERR)     errExit("signal");

    /* Redisplay mask of pending signals */

    if (sigpending(&pending) == -1)
        errExit("sigpending");
    if (sigismember(&pending, SIGINT)) {
        printf("SIGINT is now pending\n");
    } else {
        printf("PENDING signals are: \n");
        printSigset(stdout, "\t\t", &pending);
    }
    sleep(2);

    /* Reestablish SIGINT handler */

    printf("Reestablishing handler for SIGINT\n");
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = handler;
    if (sigaction(SIGINT, &sa, NULL) == -1)
        errExit("sigaction");

    sleep(2);

    /* And unblock SIGINT */

    printf("UNBLOCKING SIGINT\n");
    sigemptyset(&blocked);
    if (sigprocmask(SIG_SETMASK, &blocked, NULL) == -1)
        errExit("sigprocmask");

    exit(EXIT_SUCCESS);
}
int
main(int argc, char *argv[])
{
    struct utmpx ut;
    char *devName;

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s username [sleep-time]\n", argv[0]);

    /* Initialize login record for utmp and wtmp files */

    memset(&ut, 0, sizeof(struct utmpx));
    ut.ut_type = USER_PROCESS;          /* This is a user login */
    strncpy(ut.ut_user, argv[1], sizeof(ut.ut_user));
    if (time((time_t *) &ut.ut_tv.tv_sec) == -1)
        errExit("time");                /* Stamp with current time */
    ut.ut_pid = getpid();

    /* Set ut_line and ut_id based on the terminal associated with
       'stdin'. This code assumes terminals named "/dev/[pt]t[sy]*".
       The "/dev/" dirname is 5 characters; the "[pt]t[sy]" filename
       prefix is 3 characters (making 8 characters in all). */

    devName = ttyname(STDIN_FILENO);
    if (devName == NULL)
        errExit("ttyname");
    if (strlen(devName) <= 8)           /* Should never happen */
        fatal("Terminal name is too short: %s", devName);

    strncpy(ut.ut_line, devName + 5, sizeof(ut.ut_line));
    strncpy(ut.ut_id, devName + 8, sizeof(ut.ut_id));

    printf("Creating login entries in utmp and wtmp\n");
    printf("        using pid %ld, line %.*s, id %.*s\n",
            (long) ut.ut_pid, (int) sizeof(ut.ut_line), ut.ut_line,
            (int) sizeof(ut.ut_id), ut.ut_id);

    setutxent();                        /* Rewind to start of utmp file */
    if (pututxline(&ut) == NULL)        /* Write login record to utmp */
        errExit("pututxline");
    updwtmpx(_PATH_WTMP, &ut);          /* Append login record to wtmp */

    /* Sleep a while, so we can examine utmp and wtmp files */

    sleep((argc > 2) ? getInt(argv[2], GN_NONNEG, "sleep-time") : 15);

    /* Now do a "logout"; use values from previously initialized 'ut',
       except for changes below */

    ut.ut_type = DEAD_PROCESS;          /* Required for logout record */
    time((time_t *) &ut.ut_tv.tv_sec);  /* Stamp with logout time */
    memset(&ut.ut_user, 0, sizeof(ut.ut_user));
                                        /* Logout record has null username */

    printf("Creating logout entries in utmp and wtmp\n");
    setutxent();                        /* Rewind to start of utmp file */
    if (pututxline(&ut) == NULL)        /* Overwrite previous utmp record */
        errExit("pututxline");
    updwtmpx(_PATH_WTMP, &ut);          /* Append logout record to wtmp */

    endutxent();
    exit(EXIT_SUCCESS);
}
Exemplo n.º 4
0
// mon_pid: pid of sandbox to be monitored, 0 if all sandboxes are included
void pid_read(pid_t mon_pid) {
	if (pids == NULL) {
		FILE *fp = fopen("/proc/sys/kernel/pid_max", "r");
		if (fp) {
			int val;
			if (fscanf(fp, "%d", &val) == 1) {
				if (val >= max_pids)
					max_pids = val + 1;
			}
			fclose(fp);
		}
		pids = malloc(sizeof(Process) * max_pids);
		if (pids == NULL)
			errExit("malloc");
	}
	memset(pids, 0, sizeof(Process) * max_pids);
	pid_t mypid = getpid();

	DIR *dir;
	if (!(dir = opendir("/proc"))) {
		// sleep 2 seconds and try again
		sleep(2);
		if (!(dir = opendir("/proc"))) {
			fprintf(stderr, "Error: cannot open /proc directory\n");
			exit(1);
		}
	}
	
	pid_t child = -1;
	struct dirent *entry;
	char *end;
	while (child < 0 && (entry = readdir(dir))) {
		pid_t pid = strtol(entry->d_name, &end, 10);
		pid %= max_pids;
		if (end == entry->d_name || *end)
			continue;
		if (pid == mypid)
			continue;
		
		// open stat file
		char *file;
		if (asprintf(&file, "/proc/%u/status", pid) == -1) {
			perror("asprintf");
			exit(1);
		}
		FILE *fp = fopen(file, "r");
		if (!fp) {
			free(file);
			continue;
		}

		// look for firejail executable name
		char buf[PIDS_BUFLEN];
		while (fgets(buf, PIDS_BUFLEN - 1, fp)) {
			if (strncmp(buf, "Name:", 5) == 0) {
				char *ptr = buf + 5;
				while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
					ptr++;
				}
				if (*ptr == '\0') {
					fprintf(stderr, "Error: cannot read /proc file\n");
					exit(1);
				}

				if (mon_pid == 0 && strncmp(ptr, "firejail", 8) == 0) {
					pids[pid].level = 1;
				}
				else if (mon_pid == pid && strncmp(ptr, "firejail", 8) == 0) {
					pids[pid].level = 1;
				}
//				else if (mon_pid == 0 && strncmp(ptr, "lxc-execute", 11) == 0) {
//					pids[pid].level = 1;
//				}
//				else if (mon_pid == pid && strncmp(ptr, "lxc-execute", 11) == 0) {
//					pids[pid].level = 1;
//				}
				else
					pids[pid].level = -1;
			}
			if (strncmp(buf, "State:", 6) == 0) {
				if (strstr(buf, "(zombie)"))
					pids[pid].zombie = 1;
			}
			else if (strncmp(buf, "PPid:", 5) == 0) {
				char *ptr = buf + 5;
				while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
					ptr++;
				}
				if (*ptr == '\0') {
					fprintf(stderr, "Error: cannot read /proc file\n");
					exit(1);
				}
				unsigned parent = atoi(ptr);
				parent %= max_pids;
				if (pids[parent].level > 0) {
					pids[pid].level = pids[parent].level + 1;
				}
				pids[pid].parent = parent;
			}
			else if (strncmp(buf, "Uid:", 4) == 0) {
				char *ptr = buf + 5;
				while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
					ptr++;
				}
				if (*ptr == '\0') {
					fprintf(stderr, "Error: cannot read /proc file\n");
					exit(1);
				}
				pids[pid].uid = atoi(ptr);
				break;
			}
		}
		fclose(fp);
		free(file);
	}
	closedir(dir);

	pid_t pid;
	for (pid = 0; pid < max_pids; pid++) {
		int parent = pids[pid].parent;
		if (pids[parent].level > 0) {
			pids[pid].level = pids[parent].level + 1;
		}
	}
}
Exemplo n.º 5
0
int main(int argc,char *argv[])
{
    char cmd[CMD_SIZE];
    pid_t childPid;
    sigset_t blockMask,emptyMask;
    struct sigaction sa;

    setbuf(stdout,NULL);    /* Disable buffering of stdout */

    memset(cmd,0,CMD_SIZE);
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigHandler;
    if (sigaction(SIGCHLD,&sa,NULL) == -1)
    {
        errExit("sigaction");
    }

    /* Block SIGCHLD to prevent its delivery if a child terminates
       before the parent commences the sigsupsend() */
    sigemptyset(&blockMask);
    sigaddset(&blockMask,SIGCHLD);
    if (sigprocmask(SIG_SETMASK,&blockMask,NULL) == -1)
    {
        errExit("sigprocmask");
    }
    
    printf("Parent PID=%ld\n",(long)getpid());

    switch(childPid = fork())
    {
    case -1:
        errExit("fork");
    case 0:   /* Child: immediately exits to become zombie */
        printf("Child (PID=%ld) exiting\n",(long)getpid());
        _exit(EXIT_SUCCESS);
    default:  /* Parent */

        sigemptyset(&emptyMask);
        if (sigsuspend(&emptyMask) == -1 && errno != EINTR)
        {
            errExit("sigsuspend");
        }
        
        snprintf(cmd,CMD_SIZE,"ps -c | grep %s",basename(argv[0]));
        cmd[CMD_SIZE - 1] = '\0';   /* Ensure string is null-terminated */
        system(cmd);               /* View zombie child */
        
        /* Now send the "sure kill" signal to the zombie */

        if (kill(childPid,SIGKILL) == -1)
        {
            errMsg("kill");
        }

        sleep(10);   /* Give child a chance to react to signal */
        printf("After sending SIGKILL to zombie (PID=%ld):\n",(long)childPid);
        system(cmd);   /* View zombie child again */
        
        exit(EXIT_SUCCESS);
    }
}
Exemplo n.º 6
0
int
main(int argc, char *argv[])
{
    char buf[BUF_SIZE];
    int outbound[2];            /* Pipe to send data from parent to child */
    int inbound[2];             /* Pipe to send data from child to parent */
    int j;
    ssize_t cnt;

    if (pipe(outbound) == -1)
        errExit("pipe");
    if (pipe(inbound) == -1)
        errExit("pipe");

    switch (fork()) {
    case -1:
        errExit("fork");

    case 0: /* Child */

        /* Close unused pipe descriptors */

        if (close(outbound[1]) == -1)
            errExit("close");
        if (close(inbound[0]) == -1)
            errExit("close");

        /* Read data from outbound pipe, convert to uppercase,
           and send back to parent on inbound pipe */

        while ((cnt = read(outbound[0], buf, BUF_SIZE)) > 0) {
            for (j = 0; j < cnt; j++)
                buf[j] = toupper((unsigned char) buf[j]);
            if (write(inbound[1], buf, cnt) == -1)
                errExit("write");
        }

        if (cnt == -1)
            errExit("read");
        _exit(EXIT_SUCCESS);

    default:

        /* Close unused pipe descriptors */

        if (close(outbound[0]) == -1)
            errExit("close");
        if (close(inbound[1]) == -1)
            errExit("close");

        /* Read data from stdin, send to the child via the
           outbound pipe, read the results back from the child
           on the inbound pipe, and print them on stdout */

        while ((cnt = read(STDIN_FILENO, buf, BUF_SIZE)) > 0) {
            if (write(outbound[1], buf, cnt) == -1)
                errExit("write");

            cnt = read(inbound[0], buf, BUF_SIZE);
            if (cnt == -1)
                errExit("read");
            if (cnt > 0)
                if (write(STDOUT_FILENO, buf, cnt) == -1)
                    errExit("write");
        }

        if (cnt == -1)
            errExit("read");

        /* Exiting will close write end of outbound pipe, so that
           child see EOF */

        exit(EXIT_SUCCESS);
    }
}
int
main(int argc, char *argv[])
{
	int epfd,ready,fd,s,j,numOpenFds;
	struct epoll_event ev;
	struct epoll_event evlist[MAX_EVENTS];
	char buf[MAX_BUF];
	
	//使用说明
	if(argc < 2|| strcmp(argv[1], "--help") == 0)
		usageErr("%s file ..\n",argv[0]);

	epfd = epoll_create(argc - 1);
	if(epfd==-1)
		errExit("epoll_create");

	//open each file on command line, and add it to the "interest list" for the epoll instance
	for(j = 1;j<argc; ++j)
	{
		fd = open(argv[j],O_RDONLY);
		if(fd == -1)
			errExit("open");
		printf("Opened \"%s\" on fd %d\n",argv[j],fd);

		ev.events = EPOLLIN; //Only interested in input events
		ev.data.fd = fd;
		if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev) == -1)
			errExit("epoll_ctl");
	}

	numOpenFds = argc -1;
	while(numOpenFds > 0)
	{
		//fetch up to MAX_EVENTS items from the ready list
		printf("About to epoll_wait()\n");
		ready = epoll_wait(epfd,evlist,MAX_EVENTS, -1);
		if(ready == -1)
		{
			if(errno == EINTR)
				continue;
			else
				errExit("epoll_wait");
		}


		printf("Ready: %d\n",ready);

		//deal with returned list of events

		for(j=0;j<ready;++j)
		{
			printf("   fd=%d;events: %s%s%s\n",evlist[j].data.fd,
					(evlist[j].events & EPOLLIN) ? "EPOLLIN" :"",
					(evlist[j].events & EPOLLHUP)? "EPOLLHUP":"",
					(evlist[j].events & EPOLLERR)? "EPOLLERR":"");

			if(evlist[j].events & EPOLLIN)
			{
				s = read(evlist[j].data.fd, buf ,MAX_BUF);
				if(s == -1)
					errExit("read");
				printf("   read %d bytes:%.*s\n",s,s,buf);
			}
			else if(evlist[j].events & (EPOLLHUP | EPOLLERR))
			{
				/*if EPOLLIN and EPOLLHUP were both set,
				then there might be more than MAX_BUF bytes to read.
				Therefore, we close the file descriptor only if EPOLLIN wsa not set.
				We'll read further bytes after the next epoll_wait().*/

				printf("   closing fd %d\n",evlist[j].data.fd);
				if(close(evlist[j].data.fd) == -1)
					errExit("close");
				numOpenFds--;
			}
		}
	}

	printf("All file descriptors closed,bye!\n");
	exit(EXIT_SUCCESS);
}
Exemplo n.º 8
0
static void sanitize_group(void) {
	struct stat s;
	if (stat("/etc/group", &s) == -1)
		return;
	assert(gid_min);
	if (arg_debug)
		printf("Sanitizing /etc/group, GID_MIN %d\n", gid_min);
	if (is_link("/etc/group")) {
		fprintf(stderr, "Error: invalid /etc/group\n");
		exit(1);
	}

	FILE *fpin = NULL;
	FILE *fpout = NULL;

	// open files
	/* coverity[toctou] */
	fpin = fopen("/etc/group", "r");
	if (!fpin)
		goto errout;
	fpout = fopen(RUN_GROUP_FILE, "w");
	if (!fpout)
		goto errout;

	// read the file line by line
	char buf[MAXBUF];
	gid_t mygid = getgid();
	while (fgets(buf, MAXBUF, fpin)) {
		// comments and empty lines
		if (*buf == '\0' || *buf == '#')
			continue;

		// sample line:
		// 	pulse:x:115:netblue,bingo
		// drop lines with uid > 1000 and not the current user group
		char *ptr = buf;

		// advance to uid
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		ptr++;
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		ptr++;
		if (*ptr == '\0')
			goto errout;

		// process uid
		int gid;
		int rv = sscanf(ptr, "%d:", &gid);
		if (rv == 0 || gid < 0)
			goto errout;
		assert(gid_min);
		if (gid < gid_min || gid == 65534) { // on Debian platforms 65534 is group nogroup
			if (copy_line(fpout, buf, ptr))
				goto errout;
			continue;
		}
		if ((gid_t) gid != mygid) {
			continue; // skip line
		}
		if (copy_line(fpout, buf, ptr))
			goto errout;
	}
	fclose(fpin);
	SET_PERMS_STREAM(fpout, 0, 0, 0644);
	fclose(fpout);

	// mount-bind tne new group file
	if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0)
		errExit("mount");
	fs_logger("create /etc/group");

	return;

errout:
	fwarning("failed to clean up /etc/group\n");
	if (fpin)
		fclose(fpin);
	if (fpout)
		fclose(fpout);
}
Exemplo n.º 9
0
static void
processInotifyEvents(int *inotifyFd)
{
    char buf[INOTIFY_READ_BUF_LEN]
        __attribute__ ((aligned(__alignof__(struct inotify_event))));
    ssize_t numRead, nr;
    char *evp;
    size_t cnt;
    int evLen;
    int firstTry;
    int j;
    struct sigaction sa;

    /* SIGALRM handler is designed simply to interrupt read() */

    sigemptyset(&sa.sa_mask);
    sa.sa_handler = alarmHandler;
    sa.sa_flags = 0;
    if (sigaction(SIGALRM, &sa, NULL) == -1)
        errExit("sigaction");

    firstTry = 1;

    /* Read some events from inotify file descriptor */

    cnt = (readBufferSize > 0) ? readBufferSize : INOTIFY_READ_BUF_LEN;
    numRead = read(*inotifyFd, buf, cnt);
    if (numRead == -1)
        errExit("read");
    if (numRead == 0) {
        fprintf(stderr, "read() from inotify fd returned 0!");
        exit(EXIT_FAILURE);
    }

    inotifyReadCnt++;

    logMessage(VB_NOISY,
               "\n==========> Read %d: got %zd bytes\n",
               inotifyReadCnt, numRead);

    /* Process each event in the buffer returned by read() */

    for (evp = buf; evp < buf + numRead; ) {
        evLen = processNextInotifyEvent(inotifyFd, evp,
                                 buf + numRead - evp, firstTry);

        if (evLen > 0) {
            evp += evLen;
            firstTry = 1;
        } else {

            /* We got here because an IN_MOVED_FROM event was found at
               the end of a previously read buffer and that event may be
               part of an "intra-tree" rename(), meaning that we should
               check if there is a subsequent IN_MOVED_TO event with the
               same cookie value. We left that event unprocessed and we
               will now try to read some more events, delaying for a
               short time, to give the associated IN_MOVED_IN event (if
               there is one) a chance to arrive. However, we only want
               to do this once: if the read() below fails to gather
               further events, then when we reprocess the IN_MOVED_FROM
               we should treat it as though this is an out-of-tree
               rename(). Thus, we set 'firstTry' to 0 for the next
               processNextInotifyEvent() call. */

            struct sigaction sa;
            int savedErrno;

            firstTry = 0;

            numRead = buf + numRead - evp;

            /* Shuffle remaining bytes to start of buffer */

            for (j = 0; j < numRead; j++)
                buf[j] = evp[j];

            /* Do a read with timeout, to allow next events
               (if any) to arrive */

            sa.sa_flags = 0;
            sigemptyset(&sa.sa_mask);
            sa.sa_handler = alarmHandler;

            /* Set a timeout for read(). Some rough testing suggests
               that a 2-millisecond timeout is sufficient to ensure
               that, in around 99.8% of cases, we get the IN_MOVED_TO
               event (if there is one) that matched an IN_MOVED_FROM
               event, even in a highly dynamic directory tree. This
               number may, of course, warrant tuning on different
               hardware and in environments with different filesystem
               activity levels. */

            ualarm(2000, 0);

            nr = read(*inotifyFd, buf + numRead,
                      INOTIFY_READ_BUF_LEN - numRead);

            savedErrno = errno; /* In case ualarm() should change errno */
            ualarm(0, 0);       /* Cancel alarm */
            errno = savedErrno;

            if (nr == -1 && errno != EINTR)
                errExit("read");
            if (nr == 0) {
                fprintf(stderr, "read() from inotify fd returned 0!");
                exit(EXIT_FAILURE);
            }

            if (errno != -1) {
                numRead += nr;
                inotifyReadCnt++;

                logMessage(VB_NOISY,
                       "\n==========> SECONDARY Read %d: got %zd bytes\n",
                       inotifyReadCnt, nr);

            } else {                    /* EINTR */
                logMessage(VB_NOISY,
                       "\n==========> SECONDARY Read got nothing\n");
            }

            evp = buf;          /* Start again at beginning of buffer */
        }
    }
}
Exemplo n.º 10
0
// check profile line; if line == 0, this was generated from a command line option
// return 1 if the command is to be added to the linked list of profile commands
// return 0 if the command was already executed inside the function
int profile_check_line(char *ptr, int lineno, const char *fname) {
	EUID_ASSERT();
	
	// check ignore list
	int i;
	for (i = 0; i < MAX_PROFILE_IGNORE; i++) {
		if (cfg.profile_ignore[i] == NULL)
			break;
		
		if (strncmp(ptr, cfg.profile_ignore[i], strlen(cfg.profile_ignore[i])) == 0)
			return 0;	// ignore line
	}
	
	if (strncmp(ptr, "ignore ", 7) == 0) {
		char *str = strdup(ptr + 7);
		if (*str == '\0') {
			fprintf(stderr, "Error: invalid ignore option\n");
			exit(1);
		}
		// find an empty entry in profile_ignore array
		int j;
		for (j = 0; j < MAX_PROFILE_IGNORE; j++) {
			if (cfg.profile_ignore[j] == NULL) 
				break;
		}
		if (j >= MAX_PROFILE_IGNORE) {
			fprintf(stderr, "Error: maximum %d --ignore options are permitted\n", MAX_PROFILE_IGNORE);
			exit(1);
		}
		// ... and configure it
		else 
			cfg.profile_ignore[j] = str;

		return 0;
	}

	// mkdir 
	if (strncmp(ptr, "mkdir ", 6) == 0) {
		fs_mkdir(ptr + 6);
		return 0;
	}
	// sandbox name
	else if (strncmp(ptr, "name ", 5) == 0) {
		cfg.name = ptr + 5;
		if (strlen(cfg.name) == 0) {
			fprintf(stderr, "Error: invalid sandbox name\n");
			exit(1);
		}
		return 0;
	}
	else if (strcmp(ptr, "ipc-namespace") == 0) {
		arg_ipc = 1;
		return 0;
	}
	// seccomp, caps, private, user namespace
	else if (strcmp(ptr, "noroot") == 0) {
#if HAVE_USERNS
		if (checkcfg(CFG_USERNS))
			check_user_namespace();
		else
			fprintf(stderr, "Warning: user namespace feature is disabled in Firejail configuration file\n");
#endif

		return 0;
	}
	else if (strcmp(ptr, "nonewprivs") == 0) {
		arg_nonewprivs = 1;
		return 0;
	}
	else if (strcmp(ptr, "seccomp") == 0) {
#ifdef HAVE_SECCOMP
		if (checkcfg(CFG_SECCOMP))
			arg_seccomp = 1;
		else
			fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	else if (strcmp(ptr, "caps") == 0) {
		arg_caps_default_filter = 1;
		return 0;
	}
	else if (strcmp(ptr, "caps.drop all") == 0) {
		arg_caps_drop_all = 1;
		return 0;
	}
	else if (strcmp(ptr, "shell none") == 0) {
		arg_shell_none = 1;
		return 0;
	}	
	else if (strcmp(ptr, "tracelog") == 0) {
		arg_tracelog = 1;
		return 0;
	}
	else if (strcmp(ptr, "private") == 0) {
		arg_private = 1;
		return 0;
	}
	else if (strcmp(ptr, "private-dev") == 0) {
		arg_private_dev = 1;
		return 0;
	}
	else if (strcmp(ptr, "private-tmp") == 0) {
		arg_private_tmp = 1;
		return 0;
	}
	else if (strcmp(ptr, "nogroups") == 0) {
		arg_nogroups = 1;
		return 0;
	}
	else if (strcmp(ptr, "nosound") == 0) {
		arg_nosound = 1;
		arg_private_dev = 1;
		return 0;
	}
	else if (strcmp(ptr, "netfilter") == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK))
			arg_netfilter = 1;
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	else if (strncmp(ptr, "netfilter ", 10) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			arg_netfilter = 1;
			arg_netfilter_file = strdup(ptr + 10);
			if (!arg_netfilter_file)
				errExit("strdup");
			check_netfilter_file(arg_netfilter_file);
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	else if (strncmp(ptr, "netfilter6 ", 11) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			arg_netfilter6 = 1;
			arg_netfilter6_file = strdup(ptr + 11);
			if (!arg_netfilter6_file)
				errExit("strdup");
			check_netfilter_file(arg_netfilter6_file);
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	else if (strcmp(ptr, "net none") == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			arg_nonetwork  = 1;
			cfg.bridge0.configured = 0;
			cfg.bridge1.configured = 0;
			cfg.bridge2.configured = 0;
			cfg.bridge3.configured = 0;
			cfg.interface0.configured = 0;
			cfg.interface1.configured = 0;
			cfg.interface2.configured = 0;
			cfg.interface3.configured = 0;
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	else if (strncmp(ptr, "net ", 4) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
#ifdef HAVE_NETWORK_RESTRICTED
			// compile time restricted networking
			if (getuid() != 0) {
				fprintf(stderr, "Error: only \"net none\" is allowed to non-root users\n");
				exit(1);
			}
#endif
			// run time restricted networking
			if (checkcfg(CFG_RESTRICTED_NETWORK) && getuid() != 0) {
				fprintf(stderr, "Error: only \"net none\" is allowed to non-root users\n");
				exit(1);
			}
			
			if (strcmp(ptr + 4, "lo") == 0) {
				fprintf(stderr, "Error: cannot attach to lo device\n");
				exit(1);
			}

			Bridge *br;
			if (cfg.bridge0.configured == 0)
				br = &cfg.bridge0;
			else if (cfg.bridge1.configured == 0)
				br = &cfg.bridge1;
			else if (cfg.bridge2.configured == 0)
				br = &cfg.bridge2;
			else if (cfg.bridge3.configured == 0)
				br = &cfg.bridge3;
			else {
				fprintf(stderr, "Error: maximum 4 network devices are allowed\n");
				exit(1);
			}
			net_configure_bridge(br, ptr + 4);
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	
	else if (strncmp(ptr, "iprange ", 8) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			Bridge *br = last_bridge_configured();
			if (br == NULL) {
				fprintf(stderr, "Error: no network device configured\n");
				exit(1);
			}
			if (br->iprange_start || br->iprange_end) {
				fprintf(stderr, "Error: cannot configure the IP range twice for the same interface\n");
				exit(1);
			}

			// parse option arguments
			char *firstip = ptr + 8;
			char *secondip = firstip;
			while (*secondip != '\0') {
				if (*secondip == ',')
					break;
				secondip++;
			}
			if (*secondip == '\0') {
				fprintf(stderr, "Error: invalid IP range\n");
				exit(1);
			}
			*secondip = '\0';
			secondip++;
			
			// check addresses
			if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) ||
			    br->iprange_start >= br->iprange_end) {
				fprintf(stderr, "Error: invalid IP range\n");
				exit(1);
			}
			if (in_netrange(br->iprange_start, br->ip, br->mask) || in_netrange(br->iprange_end, br->ip, br->mask)) {
				fprintf(stderr, "Error: IP range addresses not in network range\n");
				exit(1);
			}
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}


// from here
	else if (strncmp(ptr, "mac ", 4) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			Bridge *br = last_bridge_configured();
			if (br == NULL) {
				fprintf(stderr, "Error: no network device configured\n");
				exit(1);
			}
			
			if (mac_not_zero(br->macsandbox)) {
				fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n");
				exit(1);
			}

			// read the address
			if (atomac(ptr + 4, br->macsandbox)) {
				fprintf(stderr, "Error: invalid MAC address\n");
				exit(1);
			}
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}

	else if (strncmp(ptr, "mtu ", 4) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			Bridge *br = last_bridge_configured();
			if (br == NULL) {
				fprintf(stderr, "Error: no network device configured\n");
				exit(1);
			}
			
			if (sscanf(ptr + 4, "%d", &br->mtu) != 1 || br->mtu < 576 || br->mtu > 9198) {
				fprintf(stderr, "Error: invalid mtu value\n");
				exit(1);
			}
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}

	else if (strncmp(ptr, "ip ", 3) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			Bridge *br = last_bridge_configured();
			if (br == NULL) {
				fprintf(stderr, "Error: no network device configured\n");
				exit(1);
			}
			if (br->arg_ip_none || br->ipsandbox) {
				fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n");
				exit(1);
			}

			// configure this IP address for the last bridge defined
			if (strcmp(ptr + 3, "none") == 0)
				br->arg_ip_none = 1;
			else {
				if (atoip(ptr + 3, &br->ipsandbox)) {
					fprintf(stderr, "Error: invalid IP address\n");
					exit(1);
				}
			}
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}

	else if (strncmp(ptr, "ip6 ", 4) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			Bridge *br = last_bridge_configured();
			if (br == NULL) {
				fprintf(stderr, "Error: no network device configured\n");
				exit(1);
			}
			if (br->arg_ip_none || br->ip6sandbox) {
				fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n");
				exit(1);
			}

			// configure this IP address for the last bridge defined
			// todo: verify ipv6 syntax
			br->ip6sandbox = ptr + 4;
//			if (atoip(argv[i] + 5, &br->ipsandbox)) {
//				fprintf(stderr, "Error: invalid IP address\n");
//				exit(1);
//			}
			
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}

	else if (strncmp(ptr, "defaultgw ", 10) == 0) {
#ifdef HAVE_NETWORK
		if (checkcfg(CFG_NETWORK)) {
			if (atoip(ptr + 10, &cfg.defaultgw)) {
				fprintf(stderr, "Error: invalid IP address\n");
				exit(1);
			}
		}
		else
			fprintf(stderr, "Warning: networking features are disabled in Firejail configuration file\n");
#endif
		return 0;
	}

	if (strncmp(ptr, "protocol ", 9) == 0) {
#ifdef HAVE_SECCOMP
		if (checkcfg(CFG_SECCOMP))
			protocol_store(ptr + 9);
		else
			fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
#endif
		return 0;
	}
	
	if (strncmp(ptr, "env ", 4) == 0) {
		env_store(ptr + 4);
		return 0;
	}
	
	// seccomp drop list on top of default list
	if (strncmp(ptr, "seccomp ", 8) == 0) {
#ifdef HAVE_SECCOMP
		if (checkcfg(CFG_SECCOMP)) {
			arg_seccomp = 1;
			cfg.seccomp_list = strdup(ptr + 8);
			if (!cfg.seccomp_list)
				errExit("strdup");
		}
		else
			fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
#endif

		return 0;
	}
	
	// seccomp drop list without default list
	if (strncmp(ptr, "seccomp.drop ", 13) == 0) {
#ifdef HAVE_SECCOMP
		if (checkcfg(CFG_SECCOMP)) {
			arg_seccomp = 1;
			cfg.seccomp_list_drop = strdup(ptr + 13);
			if (!cfg.seccomp_list_drop)
				errExit("strdup");
		}
		else
			fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
#endif		
		return 0;
	}

	// seccomp keep list
	if (strncmp(ptr, "seccomp.keep ", 13) == 0) {
#ifdef HAVE_SECCOMP
		if (checkcfg(CFG_SECCOMP)) {
			arg_seccomp = 1;
			cfg.seccomp_list_keep= strdup(ptr + 13);
			if (!cfg.seccomp_list_keep)
				errExit("strdup");
		}
		else
			fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
#endif		
		return 0;
	}
	
	// caps drop list
	if (strncmp(ptr, "caps.drop ", 10) == 0) {
		arg_caps_drop = 1;
		arg_caps_list = strdup(ptr + 10);
		if (!arg_caps_list)
			errExit("strdup");
		// verify seccomp list and exit if problems
		if (caps_check_list(arg_caps_list, NULL))
			exit(1);
		return 0;
	}
	
	// caps keep list
	if (strncmp(ptr, "caps.keep ", 10) == 0) {
		arg_caps_keep = 1;
		arg_caps_list = strdup(ptr + 10);
		if (!arg_caps_list)
			errExit("strdup");
		// verify seccomp list and exit if problems
		if (caps_check_list(arg_caps_list, NULL))
			exit(1);
		return 0;
	}

	// hostname
	if (strncmp(ptr, "hostname ", 9) == 0) {
		cfg.hostname = ptr + 9;
		return 0;
	}
	
	// dns
	if (strncmp(ptr, "dns ", 4) == 0) {
		uint32_t dns;
		if (atoip(ptr + 4, &dns)) {
			fprintf(stderr, "Error: invalid DNS server IP address\n");
			return 1;
		}
		
		if (cfg.dns1 == 0)
			cfg.dns1 = dns;
		else if (cfg.dns2 == 0)
			cfg.dns2 = dns;
		else if (cfg.dns3 == 0)
			cfg.dns3 = dns;
		else {
			fprintf(stderr, "Error: up to 3 DNS servers can be specified\n");
			return 1;
		}
		return 0;
	}
	
	// cpu affinity
	if (strncmp(ptr, "cpu ", 4) == 0) {
		read_cpu_list(ptr + 4);
		return 0;
	}
	
	// nice value
	if (strncmp(ptr, "nice ", 4) == 0) {
		cfg.nice = atoi(ptr + 5);
		if (getuid() != 0 &&cfg.nice < 0)
			cfg.nice = 0;
		arg_nice = 1;
		return 0;
	}

	// cgroup
	if (strncmp(ptr, "cgroup ", 7) == 0) {
		set_cgroup(ptr + 7);
		return 0;
	}
	
	// writable-etc
	if (strcmp(ptr, "writable-etc") == 0) {
		if (cfg.etc_private_keep) {
			fprintf(stderr, "Error: private-etc and writable-etc are mutually exclusive\n");
			exit(1);
		}
		arg_writable_etc = 1;
		return 0;
	}
	
	// writable-var
	if (strcmp(ptr, "writable-var") == 0) {
		arg_writable_var = 1;
		return 0;
	}
	
	// private directory
	if (strncmp(ptr, "private ", 8) == 0) {
		cfg.home_private = ptr + 8;
		fs_check_private_dir();
		arg_private = 1;
		return 0;
	}

	// private /etc list of files and directories
	if (strncmp(ptr, "private-etc ", 12) == 0) {
		if (arg_writable_etc) {
			fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
			exit(1);
		}
		cfg.etc_private_keep = ptr + 12;
		fs_check_etc_list();
		arg_private_etc = 1;
		
		return 0;
	}

	// private /bin list of files
	if (strncmp(ptr, "private-bin ", 12) == 0) {
		cfg.bin_private_keep = ptr + 12;
		arg_private_bin = 1;
		fs_check_bin_list();
		return 0;
	}

	// filesystem bind
	if (strncmp(ptr, "bind ", 5) == 0) {
#ifdef HAVE_BIND		
		if (checkcfg(CFG_BIND)) {
			if (getuid() != 0) {
				fprintf(stderr, "Error: --bind option is available only if running as root\n");
				exit(1);
			}
	
			// extract two directories
			char *dname1 = ptr + 5;
			char *dname2 = split_comma(dname1); // this inserts a '0 to separate the two dierctories
			if (dname2 == NULL) {
				fprintf(stderr, "Error: missing second directory for bind\n");
				exit(1);
			}
			
			// check directories
			invalid_filename(dname1);
			invalid_filename(dname2);
			if (strstr(dname1, "..") || strstr(dname2, "..")) {
				fprintf(stderr, "Error: invalid file name.\n");
				exit(1);
			}
			if (is_link(dname1) || is_link(dname2)) {
				fprintf(stderr, "Symbolic links are not allowed for bind command\n");
				exit(1);
			}
			
			// insert comma back
			*(dname2 - 1) = ',';
			return 1;
		}
		else {
			fprintf(stderr, "Warning: bind feature is disabled in Firejail configuration file\n");
			return 0;			
		}
#else
		return 0;
#endif		
	}

	// rlimit
	if (strncmp(ptr, "rlimit", 6) == 0) {
		if (strncmp(ptr, "rlimit-nofile ", 14) == 0) {
			ptr += 14;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_nofile);
			arg_rlimit_nofile = 1;
		}
		else if (strncmp(ptr, "rlimit-nproc ", 13) == 0) {
			ptr += 13;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_nproc);
			arg_rlimit_nproc = 1;
		}
		else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) {
			ptr += 13;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_fsize);
			arg_rlimit_fsize = 1;
		}
		else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) {
			ptr += 18;
			if (not_unsigned(ptr)) {
				fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
				exit(1);
			}
			sscanf(ptr, "%u", &cfg.rlimit_sigpending);
			arg_rlimit_sigpending = 1;
		}
		else {
			fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
			exit(1);
		}
		
		return 0;		
	}

	// read-write
	if (strncmp(ptr, "read-write ", 11) == 0) {
		if (getuid() != 0) {
			fprintf(stderr, "Error: read-write command is available only for root user\n");
			exit(1);
		}
		fs_rdwr_add(ptr + 11);
		return 0;
	}

	// rest of filesystem
	if (strncmp(ptr, "blacklist ", 10) == 0)
		ptr += 10;
	else if (strncmp(ptr, "blacklist-nolog ", 16) == 0)
		ptr += 16;
	else if (strncmp(ptr, "noblacklist ", 12) == 0)
		ptr += 12;
	else if (strncmp(ptr, "whitelist ", 10) == 0) {
#ifdef HAVE_WHITELIST		
		if (checkcfg(CFG_WHITELIST)) {
			arg_whitelist = 1;
			ptr += 10;
		}
		else
			return 0;
#else		
		return 0;
#endif
	}
	else if (strncmp(ptr, "read-only ", 10) == 0)
		ptr += 10;
	else if (strncmp(ptr, "tmpfs ", 6) == 0) {
		if (getuid() != 0) {
			fprintf(stderr, "Error: tmpfs available only when running the sandbox as root\n");
			exit(1);
		}
		ptr += 6;
	}
	else {
		if (lineno == 0)
			fprintf(stderr, "Error: \"%s\" as a command line option is invalid\n", ptr);
		else if (fname != NULL)
			fprintf(stderr, "Error: line %d in %s is invalid\n", lineno, fname);
		else
			fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno);
		exit(1);
	}

	// some characters just don't belong in filenames
	invalid_filename(ptr);
	if (strstr(ptr, "..")) {
		if (lineno == 0)
			fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
		else if (fname != NULL)
			fprintf(stderr, "Error: line %d in %s is invalid\n", lineno, fname);
		else
			fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno);
		exit(1);
	}
	return 1;
}
Exemplo n.º 11
0
static void sanitize_passwd(void) {
	struct stat s;
	if (stat("/etc/passwd", &s) == -1)
		return;
	assert(uid_min);
	if (arg_debug)
		printf("Sanitizing /etc/passwd, UID_MIN %d\n", uid_min);
	if (is_link("/etc/passwd")) {
		fprintf(stderr, "Error: invalid /etc/passwd\n");
		exit(1);
	}

	FILE *fpin = NULL;
	FILE *fpout = NULL;

	// open files
	/* coverity[toctou] */
	fpin = fopen("/etc/passwd", "r");
	if (!fpin)
		goto errout;
	fpout = fopen(RUN_PASSWD_FILE, "w");
	if (!fpout)
		goto errout;

	// read the file line by line
	char buf[MAXBUF];
	uid_t myuid = getuid();
	while (fgets(buf, MAXBUF, fpin)) {
		// comments and empty lines
		if (*buf == '\0' || *buf == '#')
			continue;

		// sample line:
		// 	www-data:x:33:33:www-data:/var/www:/bin/sh
		// drop lines with uid > 1000 and not the current user
		char *ptr = buf;

		// advance to uid
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		char *ptr1 = ptr;
		ptr++;
		while (*ptr != ':' && *ptr != '\0')
			ptr++;
		if (*ptr == '\0')
			goto errout;
		ptr++;
		if (*ptr == '\0')
			goto errout;

		// process uid
		int uid;
		int rv = sscanf(ptr, "%d:", &uid);
		if (rv == 0 || uid < 0)
			goto errout;
		assert(uid_min);
		if (uid < uid_min || uid == 65534) { // on Debian platforms user nobody is 65534
			fprintf(fpout, "%s", buf);
			continue;
		}
		if ((uid_t) uid != myuid) {
			// store user name - necessary to process /etc/group
			*ptr1 = '\0';
			char *user = strdup(buf);
			if (!user)
				errExit("malloc");
			ulist_add(user);
			continue; // skip line
		}
		fprintf(fpout, "%s", buf);
	}
	fclose(fpin);
	SET_PERMS_STREAM(fpout, 0, 0, 0644);
	fclose(fpout);

	// mount-bind tne new password file
	if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0)
		errExit("mount");
	fs_logger("create /etc/passwd");

	return;

errout:
	fwarning("failed to clean up /etc/passwd\n");
	if (fpin)
		fclose(fpin);
	if (fpout)
		fclose(fpout);
}
Exemplo n.º 12
0
int
main(int argc, char *argv[])
{
    struct timeval start, finish;
    struct timespec request, remain;
    struct sigaction sa;
    int s, flags;

    if (argc < 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s secs nanosecs [a]\n", argv[0]);

    /* Allow SIGINT handler to interrupt clock_nanosleep() */

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigintHandler;
    if (sigaction(SIGINT, &sa, NULL) == -1)
        errExit("sigaction");

    /* If more than three command-line arguments, use TIMER_ABSTIME flag */

    flags = (argc > 3) ? TIMER_ABSTIME : 0;

    if (flags == TIMER_ABSTIME) {
        if (clock_gettime(CLOCK_REALTIME, &request) == -1)
            errExit("clock_gettime");
        printf("Initial CLOCK_REALTIME value: %ld.%09ld\n",
                (long) request.tv_sec, (long) request.tv_nsec);

        request.tv_sec  += getLong(argv[1], 0, "secs");
        request.tv_nsec += getLong(argv[2], 0, "nanosecs");
        if (request.tv_nsec >= 1000000000) {
            request.tv_sec += request.tv_nsec / 1000000000;
            request.tv_nsec %= 1000000000;
        }

    } else {                    /* Relative sleep */
        request.tv_sec  = getLong(argv[1], 0, "secs");
        request.tv_nsec = getLong(argv[2], 0, "nanosecs");
    }

    if (gettimeofday(&start, NULL) == -1)
        errExit("gettimeofday");

    for (;;) {
        s = clock_nanosleep(CLOCK_REALTIME, flags, &request, &remain);
        if (s != 0 && s != EINTR)
            errExitEN(s, "clock_nanosleep");

        if (s == EINTR)
            printf("Interrupted... ");

        if (gettimeofday(&finish, NULL) == -1)
            errExit("gettimeofday");
        printf("Slept: %.6f secs", finish.tv_sec - start.tv_sec +
                        (finish.tv_usec - start.tv_usec) / 1000000.0);

        if (s == 0)
            break;                      /* sleep completed */

        if (flags != TIMER_ABSTIME) {
            printf("... Remaining: %ld.%09ld",
                    (long) remain.tv_sec, remain.tv_nsec);

            request = remain;
        }

        printf("... Restarting\n");
    }

    printf("\nSleep complete\n");
    exit(EXIT_SUCCESS);
}
Exemplo n.º 13
0
int
main(int argc, char *argv[])
{
    char *username, *password, *encrypted, *p;
    struct passwd *pwd;
    struct spwd *spwd;
    Boolean authOk;
    size_t len;
    long lnmax;

    /* Determine size of buffer required for a username, and allocate it */

    lnmax = sysconf(_SC_LOGIN_NAME_MAX);
    if (lnmax == -1)                    /* If limit is indeterminate */
        lnmax = 256;                    /* make a guess */

    username = malloc(lnmax);
    if (username == NULL)
        errExit("malloc");

    printf("Username: "******"couldn't get password record");
    spwd = getspnam(username);
    if (spwd == NULL && errno == EACCES)
        fatal("no permission to read shadow password file");

    if (spwd != NULL)           /* If there is a shadow password record */
        pwd->pw_passwd = spwd->sp_pwdp;     /* Use the shadow password */

    password = getpass("Password: "******"crypt");

    authOk = strcmp(encrypted, pwd->pw_passwd) == 0;
    if (!authOk) {
        printf("Incorrect password\n");
        exit(EXIT_FAILURE);
    }

    printf("Successfully authenticated: UID=%ld\n", (long) pwd->pw_uid);

    /* Now do authenticated work... */

    exit(EXIT_SUCCESS);
}
Exemplo n.º 14
0
int
main(int argc, char *argv[])
{
    int semid, key, perms;
    struct sembuf sops[2];

    if (argc != 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s sem-op\n", argv[0]);

    key = 12345;
    perms = S_IRUSR | S_IWUSR;

    semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms);

    if (semid != -1) {                  /* Successfully created the semaphore */
        union semun arg;
        struct sembuf sop;

        sleep(5);
        printf("%ld: created semaphore\n", (long) getpid());

        arg.val = 0;                    /* So initialize it to 0 */
        if (semctl(semid, 0, SETVAL, arg) == -1)
            errExit("semctl 1");
        printf("%ld: initialized semaphore\n", (long) getpid());

        /* Perform a "no-op" semaphore operation - changes sem_otime
           so other processes can see we've initialized the set. */

        sop.sem_num = 0;                /* Operate on semaphore 0 */
        sop.sem_op = 0;                 /* Wait for value to equal 0 */
        sop.sem_flg = 0;
        if (semop(semid, &sop, 1) == -1)
            errExit("semop");
        printf("%ld: completed dummy semop()\n", (long) getpid());

    } else {                            /* We didn't create the semaphore set */

        if (errno != EEXIST) {          /* Unexpected error from semget() */
            errExit("semget 1");

        } else {                        /* Someone else already created it */
            const int MAX_TRIES = 10;
            int j;
            union semun arg;
            struct semid_ds ds;

            semid = semget(key, 1, perms);      /* So just get ID */
            if (semid == -1)
                errExit("semget 2");

            printf("%ld: got semaphore key\n", (long) getpid());
            /* Wait until another process has called semop() */

            arg.buf = &ds;
            for (j = 0; j < MAX_TRIES; j++) {
                printf("Try %d\n", j);
                if (semctl(semid, 0, IPC_STAT, arg) == -1)
                    errExit("semctl 2");

                if (ds.sem_otime != 0)          /* Semop() performed? */
                    break;                      /* Yes, quit loop */
                sleep(1);                       /* If not, wait and retry */
            }

            if (ds.sem_otime == 0)              /* Loop ran to completion! */
                fatal("Existing semaphore not initialized");
        }
    }

    /* Now perform some operation on the semaphore */

    sops[0].sem_num = 0;                        /* Operate on semaphore 0... */
    sops[0].sem_op = getInt(argv[1], 0, "sem-op");
    sops[0].sem_flg = 0;
    if (semop(semid, sops, 1) == -1)
        errExit("semop");

    exit(EXIT_SUCCESS);
}
Exemplo n.º 15
0
int
main(int argc, char *argv[])
{
    int epfd, ready, fd, s, j, numOpenFds;
    struct epoll_event ev;
    struct epoll_event evlist[MAX_EVENTS];
    char buf[MAX_BUF];

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s file...\n", argv[0]);

    epfd = epoll_create(argc - 1);
    if (epfd == -1)
        errExit("epoll_create");

    /* Open each file on command line, and add it to the "interest
       list" for the epoll instance */

    for (j = 1; j < argc; j++) {
        fd = open(argv[j], O_RDONLY);
        if (fd == -1)
            errExit("open");
        printf("Opened \"%s\" on fd %d\n", argv[j], fd);

        ev.events = EPOLLIN;            /* Only interested in input events */
        ev.data.fd = fd;
        if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
            errExit("epoll_ctl");
    }

    numOpenFds = argc - 1;

    while (numOpenFds > 0) {

        /* Fetch up to MAX_EVENTS items from the ready list of the
           epoll instance */

        printf("About to epoll_wait()\n");
        ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1);
        if (ready == -1) {
            if (errno == EINTR)
                continue;               /* Restart if interrupted by signal */
            else
                errExit("epoll_wait");
        }

        printf("Ready: %d\n", ready);

        /* Deal with returned list of events */

        for (j = 0; j < ready; j++) {
            printf("  fd=%d; events: %s%s%s\n", evlist[j].data.fd,
                    (evlist[j].events & EPOLLIN)  ? "EPOLLIN "  : "",
                    (evlist[j].events & EPOLLHUP) ? "EPOLLHUP " : "",
                    (evlist[j].events & EPOLLERR) ? "EPOLLERR " : "");

            if (evlist[j].events & EPOLLIN) {
                s = read(evlist[j].data.fd, buf, MAX_BUF);
                if (s == -1)
                    errExit("read");
                printf("    read %d bytes: %.*s\n", s, s, buf);

            } else if (evlist[j].events & (EPOLLHUP | EPOLLERR)) {

                /* After the epoll_wait(), EPOLLIN and EPOLLHUP may both have
                   been set. But we'll only get here, and thus close the file
                   descriptor, if EPOLLIN was not set. This ensures that all
                   outstanding input (possibly more than MAX_BUF bytes) is
                   consumed (by further loop iterations) before the file
                   descriptor is closed. */

                printf("    closing fd %d\n", evlist[j].data.fd);
                if (close(evlist[j].data.fd) == -1)
                    errExit("close");
                numOpenFds--;
            }
        }
    }

    printf("All file descriptors closed; bye\n");
    exit(EXIT_SUCCESS);
}
Exemplo n.º 16
0
int
main(int argc, char *argv[])
{
    fd_set rfds;
    int opt;
    int inotifyFd;

    /* Parse command-line options */

    verboseMask = 0;
    checkCache = 0;
    dumpCache = 0;
    stopFile = NULL;
    abortOnCacheProblem = 0;

    while ((opt = getopt(argc, argv, "a:dxl:v:b:")) != -1) {
        switch (opt) {

        case 'a':
            abortOnCacheProblem = 1;
            stopFile = optarg;
            break;

        case 'x':
            checkCache = 1;
            break;

        case 'd':
            dumpCache = 1;
            break;

        case 'v':
            verboseMask = atoi(optarg);
            break;

        case 'b':
            readBufferSize = atoi(optarg);
            break;

        case 'l':
            logfp = fopen(optarg, "w+");
            if (logfp == NULL)
                errExit("fopen");
            setbuf(logfp, NULL);
            break;

        default:
            usageError(argv[0]);
        }
    }

    if (optind >= argc)
        usageError(argv[0]);

    /* Save a copy of the directories on the command line */

    copyRootDirPaths(&argv[optind]);

    /* Create an inotify instance and populate it with entries for
       directory named on command line */

    inotifyFd = reinitialize(-1);

    /* Loop to handle inotify events and keyboard commands */

    printf("%s> ", argv[0]);
    fflush(stdout);

    for (;;) {
        FD_ZERO(&rfds);
        FD_SET(STDIN_FILENO, &rfds);
        FD_SET(inotifyFd, &rfds);
        if (select(inotifyFd + 1, &rfds, NULL, NULL, NULL) == -1)
            errExit("select");

        if (FD_ISSET(STDIN_FILENO, &rfds)) {
            executeCommand(&inotifyFd);

            printf("%s> ", argv[0]);
            fflush(stdout);
        }

        if (FD_ISSET(inotifyFd, &rfds))
            processInotifyEvents(&inotifyFd);
    }

    exit(EXIT_SUCCESS);
}
Exemplo n.º 17
0
/******************** gettCmdList **************************************
int getCmdList(Cmd cmdM[], Token tokenM[], int iTokenCnt)
Purpose:
    Parse through the token array to determine the commands.  It
    saves the beginning and ending subscripts for each command's arguments.
    It also determines whether the command has a redirected stdin 
    and/or stdout.
Parameters:
    O Cmd cmdM[]     array of commands
    I Token tokenM[] array of tokens for the input test
    I int iTokenCnt  number of entries in tokenM
Returns:
    Count of number of entries in cmdM. 
Notes:
    - commands are separated by commas
**************************************************************************/
int getCmdList(Cmd cmdM[], Token tokenM[], int iTokenCnt)
{
    int i;              // subscript to current token
    char cChar;         // current character in input text
    int iCmdCnt = 0;    // count of number of entries in cmdM
    // Iterate through the array of tokens.  We actually 
    // go to one item beyond the end so that we can process 
    // the last token normally.  (We pretend there is an 
    // ending token after the last token.)
    for (i = 1; i <= iTokenCnt; i += 1)
    {
        Cmd *pCmd = &(cmdM[iCmdCnt]); 
        if (i == iTokenCnt)
            cChar = ',';  // pretend an ending delim
        else
            cChar = tokenM[i][0];
        switch(cChar)
        {
            case ',':  // delimiter between commands
                if (pCmd->iBeginIdx == 0)
                    errExit("no command, cmd arg: %d\n", i);
                // If we haven't yet marked the end of the command's
                // arguments, assume it is right before the comma.
                // Note that redirection also set the iEndIdx.
                if (pCmd->iEndIdx == 0)
                     pCmd->iEndIdx = i-1;
                // Check for no command arguments
                if (pCmd->iBeginIdx > pCmd->iEndIdx)
                {   // no args
                    pCmd->iBeginIdx = 0;
                    pCmd->iEndIdx = -1;
                }
                iCmdCnt += 1;
                break;
            case '<':  // stdin redirection
                if (i+1 >= iTokenCnt)  // need another arg
                    errExit("redirect requires additional arg, cmd arg: %d\n", i);
                pCmd->iStdinRedirectIdx = i+1;
                // If we haven't yet marked the end of the command's
                // arguments, assume it is right before the <.
                if (pCmd->iEndIdx == 0)
                     pCmd->iEndIdx = i-1;
                break;
            case '>':
                if (i+1 >= iTokenCnt)  // need another arg
                    errExit("redirect requires additional arg, cmd arg: %d\n", i);
                pCmd->iStdoutRedirectIdx = i+1;
                // If we haven't yet marked the end of the command's
                // arguments, assume it is right before the >.
                if (pCmd->iEndIdx == 0)
                     pCmd->iEndIdx = i-1;
                break;
            default:
                // check if at the beginning of the command
                if (pCmd->iBeginIdx == 0)
                {   // not comma, <, > if iBeginIdx is 0, we need to record
                    // where the arguments might begin
                    strcpy(pCmd->szCmdNm, tokenM[i]);
                    pCmd->iBeginIdx = i+1;
                }
        }
    }
    return iCmdCnt;
}
Exemplo n.º 18
0
static void
copyRootDirPaths(char *argv[])
{
    char **p;
    int j, k;
    struct stat sb;

    p = argv;
    numRootDirs = 0;

    /* Count the number of root paths, and check that the paths are valid */

    for (p = argv; *p != NULL; p++) {

        /* Check that command-line arguments are directories */

        if (lstat(*p, &sb) == -1) {
            fprintf(stderr, "lstat() failed on '%s'\n", *p);
            exit(EXIT_FAILURE);
        }

        if (! S_ISDIR(sb.st_mode)) {
            fprintf(stderr, "'%s' is not a directory\n", *p);
            exit(EXIT_FAILURE);
        }

        numRootDirs++;
    }

    /* Create a copy of the root directory pathnames */

    rootDirPaths = calloc(numRootDirs, sizeof(char *));
    if (rootDirPaths == NULL)
        errExit("calloc");

    rootDirStat = calloc(numRootDirs, sizeof(struct stat));
    if (rootDirPaths == NULL)
        errExit("calloc");

    for (j = 0; j < numRootDirs; j++) {
        rootDirPaths[j] = strdup(argv[j]);
        if (rootDirPaths[j] == NULL)
            errExit("strdup");

        /* If the same filesystem object appears more than once in the
           command line, this will cause confusion if we later try to zap
           an object from the set of root paths. So, reject such
           duplicates now. Note that we can't just do simple string
           comparisons of the arguments, since different pathname strings
           may refer to the same filesystem object (e.g., "mydir" and
           "./mydir"). So, we use stat() to compare i-node numbers and
           containing device IDs. */

        if (lstat(argv[j], &rootDirStat[j]) == -1)
            errExit("lstat");

        for (k = 0; k < j; k++) {
            if ((rootDirStat[j].st_ino == rootDirStat[k].st_ino) &&
                (rootDirStat[j].st_dev == rootDirStat[k].st_dev)) {

                fprintf(stderr, "Duplicate filesystem objects: %s, %s\n",
                        argv[j], argv[k]);
                exit(EXIT_FAILURE);
            }
        }
    }

    ignoreRootDirs = 0;
}
Exemplo n.º 19
0
int
main(int argc, char *argv[])
{
    fd_set readfds;
    int ready, nfds, flags;
    struct timeval timeout;
    struct timeval *pto;
    struct sigaction sa;
    char ch;
    int fd, j;

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s {timeout|-} fd...\n"
                "\t\t('-' means infinite timeout)\n", argv[0]);

    /* Initialize 'timeout', 'readfds', and 'nfds' for select() */

    if (strcmp(argv[1], "-") == 0) {
        pto = NULL;                     /* Infinite timeout */
    } else {
        pto = &timeout;
        timeout.tv_sec = getLong(argv[1], 0, "timeout");
        timeout.tv_usec = 0;            /* No microseconds */
    }

    nfds = 0;

    /* Build the 'readfds' from the fd numbers given in command line */

    FD_ZERO(&readfds);
    for (j = 2; j < argc; j++) {
        fd = getInt(argv[j], 0, "fd");
        if (fd >= FD_SETSIZE)
            cmdLineErr("file descriptor exceeds limit (%d)\n", FD_SETSIZE);

        if (fd >= nfds)
            nfds = fd + 1;              /* Record maximum fd + 1 */
        FD_SET(fd, &readfds);
    }

    /* Create pipe before establishing signal handler to prevent race */

    if (pipe(pfd) == -1)
        errExit("pipe");

    FD_SET(pfd[0], &readfds);           /* Add read end of pipe to 'readfds' */
    nfds = max(nfds, pfd[0] + 1);       /* And adjust 'nfds' if required */

    /* Make read and write ends of pipe nonblocking */

    flags = fcntl(pfd[0], F_GETFL);
    if (flags == -1)
        errExit("fcntl-F_GETFL");
    flags |= O_NONBLOCK;                /* Make read end nonblocking */
    if (fcntl(pfd[0], F_SETFL, flags) == -1)
        errExit("fcntl-F_SETFL");

    flags = fcntl(pfd[1], F_GETFL);
    if (flags == -1)
        errExit("fcntl-F_GETFL");
    flags |= O_NONBLOCK;                /* Make write end nonblocking */
    if (fcntl(pfd[1], F_SETFL, flags) == -1)
        errExit("fcntl-F_SETFL");

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;           /* Restart interrupted reads()s */
    sa.sa_handler = handler;
    if (sigaction(SIGINT, &sa, NULL) == -1)
        errExit("sigaction");

    while ((ready = select(nfds, &readfds, NULL, NULL, pto)) == -1 &&
            errno == EINTR)
        continue;                       /* Restart if interrupted by signal */
    if (ready == -1)                    /* Unexpected error */
        errExit("select");

    if (FD_ISSET(pfd[0], &readfds)) {   /* Handler was called */
        printf("A signal was caught\n");

        for (;;) {                      /* Consume bytes from pipe */
            if (read(pfd[0], &ch, 1) == -1) {
                if (errno == EAGAIN)
                    break;              /* No more bytes */
                else
                    errExit("read");    /* Some other error */
            }

            /* Perform any actions that should be taken in response to signal */
        }
    }

    /* Examine file descriptor sets returned by select() to see
       which other file descriptors are ready */

    printf("ready = %d\n", ready);
    for (j = 2; j < argc; j++) {
        fd = getInt(argv[j], 0, "fd");
        printf("%d: %s\n", fd, FD_ISSET(fd, &readfds) ? "r" : "");
    }

    /* And check if read end of pipe is ready */

    printf("%d: %s   (read end of pipe)\n", pfd[0],
            FD_ISSET(pfd[0], &readfds) ? "r" : "");

    if (pto != NULL)
        printf("timeout after select(): %ld.%03ld\n",
               (long) timeout.tv_sec, (long) timeout.tv_usec / 1000);

    exit(EXIT_SUCCESS);
}
Exemplo n.º 20
0
static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) {
	(void) st;
	(void) sftw;
	assert(infname);
	assert(*infname != '\0');
	assert(outpath);
	assert(*outpath != '\0');
	assert(inpath);
	
	// check size limit
	if (size_limit_reached)
		return 0;


	char *outfname;
	if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1)
		errExit("asprintf");

//printf("outpaht %s\n", outpath);
//printf("inpath %s\n", inpath);
//printf("infname %s\n", infname);
//printf("outfname %s\n\n", outfname);

	// don't copy it if we already have the file
	struct stat s;
	if (stat(outfname, &s) == 0) {
		if (first)
			first = 0;
		else	
		    	fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname);
		free(outfname);
		return 0;
	}
	
	// extract mode and ownership
	if (stat(infname, &s) != 0) {
	    	fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname);
		free(outfname);
		return 0;
	}
	uid_t uid = s.st_uid;
	gid_t gid = s.st_gid;
	mode_t mode = s.st_mode;

	// recalculate size
	if ((s.st_size + size_cnt) > COPY_LIMIT) {
		fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024);
		size_limit_reached = 1;
		free(outfname);
		return 0;
	}

	file_cnt++;
	size_cnt += s.st_size;

	if(ftype == FTW_F) {
		copy_file(infname, outfname, mode, uid, gid);
	}
	else if (ftype == FTW_D) {
		mkdir_attr(outfname, mode, uid, gid);
	}		
	else if (ftype == FTW_SL) {
		copy_link(infname, outfname, mode, uid, gid);
	}		

	return(0);
}
Exemplo n.º 21
0
static void
install_filter(void)
{
    struct sock_filter filter[] = {
        /* Load architecture */

        BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
                (offsetof(struct seccomp_data, arch))),

        /* Kill process if the architecture is not what we expect */

        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),

        /* Load system call number */

        BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
                 (offsetof(struct seccomp_data, nr))),

        /* Allow system calls other than open() */

        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 1, 0),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),

        /* Kill process on open() */

        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL)
    };

    struct sock_fprog prog = {
        .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
        .filter = filter,
    };

    if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) == -1)
        errExit("seccomp");
}

int
main(int argc, char *argv[])
{
    int j, nloops;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <num-loops> [x]\n", argv[0]);
        fprintf(stderr, "       (use 'x' to run with BPF filter applied)\n");
        exit(EXIT_FAILURE);
    }

    if (argc > 2) {
        printf("Appling BPF filter\n");

        if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
            errExit("prctl");

        install_filter();
    }

    nloops = atoi(argv[1]);

    for (j = 0; j < nloops; j++)
        getppid();

    exit(EXIT_SUCCESS);
}
Exemplo n.º 22
0
// scan interface (--scan option)
void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
    assert(dev);
    assert(ifip);

//	printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
//		dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));

    if (strlen(dev) > IFNAMSIZ) {
        fprintf(stderr, "Error: invalid network device name %s\n", dev);
        exit(1);
    }

    // find interface mac address
    int sock;
    if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
        errExit("socket");
    struct ifreq ifr;
    memset(&ifr, 0, sizeof (ifr));
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
        errExit("ioctl");
    close(sock);
    uint8_t mac[6];
    memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);

    // open layer2 socket
    if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
        errExit("socket");

    // try all possible ip addresses in ascending order
    uint32_t range = ~ifmask + 1; // the number of potential addresses
    // this software is not supported for /31 networks
    if (range < 4) {
        fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
        close(sock);
        return;
    }

    uint32_t dest = (ifip & ifmask) + 1;
    uint32_t last = dest + range - 1;
    uint32_t src = htonl(ifip);

    // wait not more than one second for an answer
    int header_printed = 0;
    uint32_t last_ip = 0;
    struct timeval ts;
    ts.tv_sec = 2; // 2 seconds receive timeout
    ts.tv_usec = 0;

    while (1) {
        fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(sock, &rfds);
        fd_set wfds;
        FD_ZERO(&wfds);
        FD_SET(sock, &wfds);
        int maxfd = sock;

        uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
        memset(frame, 0, ETH_FRAME_LEN);

        int nready;
        if (dest < last)
            nready = select(maxfd + 1,  &rfds, &wfds, (fd_set *) 0, NULL);
        else
            nready = select(maxfd + 1,  &rfds,  (fd_set *) 0, (fd_set *) 0, &ts);

        if (nready < 0)
            errExit("select");

        if (nready == 0) { // timeout
            break;
        }

        if (FD_ISSET(sock, &wfds) && dest < last) {
            // configure layer2 socket address information
            struct sockaddr_ll addr;
            memset(&addr, 0, sizeof(addr));
            if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
                errExit("if_nametoindex");
            addr.sll_family = AF_PACKET;
            memcpy (addr.sll_addr, mac, 6);
            addr.sll_halen = htons(6);

            // build the arp packet header
            ArpHdr hdr;
            memset(&hdr, 0, sizeof(hdr));
            hdr.htype = htons(1);
            hdr.ptype = htons(ETH_P_IP);
            hdr.hlen = 6;
            hdr.plen = 4;
            hdr.opcode = htons(1); //ARPOP_REQUEST
            memcpy(hdr.sender_mac, mac, 6);
            memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
            uint32_t dst = htonl(dest);
            memcpy(hdr.target_ip, (uint8_t *)&dst, 4);

            // buiild ethernet frame
            uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
            memset(frame, 0, sizeof(frame));
            frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
            memcpy(frame + 6, mac, 6);
            frame[12] = ETH_P_ARP / 256;
            frame[13] = ETH_P_ARP % 256;
            memcpy (frame + 14, &hdr, sizeof(hdr));

            // send packet
            int len;
            if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
                errExit("send");
//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
            fflush(0);
            dest++;
        }

        if (FD_ISSET(sock, &rfds)) {
            // read the incoming packet
            int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
            if (len < 0) {
                perror("recvfrom");
            }

            // parse the incomming packet
            if ((unsigned int) len < 14 + sizeof(ArpHdr))
                continue;

            // look only at ARP packets
            if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
                continue;

            ArpHdr hdr;
            memcpy(&hdr, frame + 14, sizeof(ArpHdr));

            if (hdr.opcode == htons(2)) {
                // check my mac and my address
                if (memcmp(mac, hdr.target_mac, 6) != 0)
                    continue;
                uint32_t ip;
                memcpy(&ip, hdr.target_ip, 4);
                if (ip != src)
                    continue;
                memcpy(&ip, hdr.sender_ip, 4);
                ip = ntohl(ip);

                if (ip == last_ip) // filter duplicates
                    continue;
                last_ip = ip;

                // printing
                if (header_printed == 0) {
                    printf("   Network scan:\n");

                    // print parent interface
                    if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan &&
                            (cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask))
                        printf("   %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
                               PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip));

                    if (cfg.bridge1.configured && cfg.bridge1.ip &&  cfg.bridge1.macvlan &&
                            (cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask))
                        printf("   %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
                               PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip));

                    if (cfg.bridge2.configured && cfg.bridge2.ip &&  cfg.bridge2.macvlan &&
                            (cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask))
                        printf("   %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
                               PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip));

                    if (cfg.bridge3.configured && cfg.bridge3.ip &&  cfg.bridge3.macvlan &&
                            (cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask))
                        printf("   %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
                               PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip));

                    header_printed = 1;
                }
                printf("   %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
                       PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
            }
        }
    }

    close(sock);
}
int
main(int argc, char *argv[])
{
    struct msghdr msgh;
    struct iovec iov;
    struct ucred *ucredp, ucred;
    int data, lfd, sfd, optval, opt;
    ssize_t nr;
    Boolean useDatagramSocket;
    union {
        struct cmsghdr cmh;
        char   control[CMSG_SPACE(sizeof(struct ucred))];
                        /* Space large enough to hold a ucred structure */
    } control_un;
    struct cmsghdr *cmhp;
    socklen_t len;

    /* Parse command-line arguments */

    useDatagramSocket = FALSE;

    while ((opt = getopt(argc, argv, "d")) != -1) {
        switch (opt) {
        case 'd':
            useDatagramSocket = TRUE;
            break;

        default:
            usageErr("%s [-d]\n"
                    "        -d    use datagram socket\n", argv[0]);
        }
    }

    /* Create socket bound to well-known address */

    if (remove(SOCK_PATH) == -1 && errno != ENOENT)
        errExit("remove-%s", SOCK_PATH);

    if (useDatagramSocket) {
        printf("Receiving via datagram socket\n");
        sfd = unixBind(SOCK_PATH, SOCK_DGRAM);
        if (sfd == -1)
            errExit("unixBind");

    } else {
        printf("Receiving via stream socket\n");
        lfd = unixListen(SOCK_PATH, 5);
        if (lfd == -1)
            errExit("unixListen");

        sfd = accept(lfd, NULL, 0);
        if (sfd == -1)
            errExit("accept");
    }

    /* We must set the SO_PASSCRED socket option in order to receive
       credentials */

    optval = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1)
        errExit("setsockopt");

    /* Set 'control_un' to describe ancillary data that we want to receive */

    control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred));
    control_un.cmh.cmsg_level = SOL_SOCKET;
    control_un.cmh.cmsg_type = SCM_CREDENTIALS;

    /* Set 'msgh' fields to describe 'control_un' */

    msgh.msg_control = control_un.control;
    msgh.msg_controllen = sizeof(control_un.control);

    /* Set fields of 'msgh' to point to buffer used to receive (real)
       data read by recvmsg() */

    msgh.msg_iov = &iov;
    msgh.msg_iovlen = 1;
    iov.iov_base = &data;
    iov.iov_len = sizeof(int);

    msgh.msg_name = NULL;               /* We don't need address of peer */
    msgh.msg_namelen = 0;

    /* Receive real plus ancillary data */

    nr = recvmsg(sfd, &msgh, 0);
    if (nr == -1)
        errExit("recvmsg");
    printf("recvmsg() returned %ld\n", (long) nr);

    if (nr > 0)
        printf("Received data = %d\n", data);

    /* Extract credentials information from received ancillary data */

    cmhp = CMSG_FIRSTHDR(&msgh);
    if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
        fatal("bad cmsg header / message length");
    if (cmhp->cmsg_level != SOL_SOCKET)
        fatal("cmsg_level != SOL_SOCKET");
    if (cmhp->cmsg_type != SCM_CREDENTIALS)
        fatal("cmsg_type != SCM_CREDENTIALS");

    ucredp = (struct ucred *) CMSG_DATA(cmhp);
    printf("Received credentials pid=%ld, uid=%ld, gid=%ld\n",
                (long) ucredp->pid, (long) ucredp->uid, (long) ucredp->gid);

    /* The Linux-specific, read-only SO_PEERCRED socket option returns
       credential information about the peer, as described in socket(7) */

    len = sizeof(struct ucred);
    if (getsockopt(sfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
        errExit("getsockopt");

    printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n",
            (long) ucred.pid, (long) ucred.uid, (long) ucred.gid);

    exit(EXIT_SUCCESS);
}
Exemplo n.º 24
0
// returns 0 if the address is not in use, -1 otherwise
int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) {
    if (strlen(dev) > IFNAMSIZ) {
        fprintf(stderr, "Error: invalid network device name %s\n", dev);
        exit(1);
    }

    if (arg_debug)
        printf("Trying %d.%d.%d.%d ...\n", PRINT_IP(destaddr));

    // find interface address
    int sock;
    if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
        errExit("socket");

    srcaddr = htonl(srcaddr);
    destaddr = htonl(destaddr);

    // Find interface MAC address
    struct ifreq ifr;
    memset(&ifr, 0, sizeof (ifr));
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
        errExit("ioctl");
    close(sock);

    // configure layer2 socket address information
    struct sockaddr_ll addr;
    memset(&addr, 0, sizeof(addr));
    if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
        errExit("if_nametoindex");
    addr.sll_family = AF_PACKET;
    memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6);
    addr.sll_halen = htons(6);

    // build the arp packet header
    ArpHdr hdr;
    memset(&hdr, 0, sizeof(hdr));
    hdr.htype = htons(1);
    hdr.ptype = htons(ETH_P_IP);
    hdr.hlen = 6;
    hdr.plen = 4;
    hdr.opcode = htons(1); //ARPOP_REQUEST
    memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6);
    memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4);
    memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4);

    // buiild ethernet frame
    uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
    memset(frame, 0, sizeof(frame));
    frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
    memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6);
    frame[12] = ETH_P_ARP / 256;
    frame[13] = ETH_P_ARP % 256;
    memcpy (frame + 14, &hdr, sizeof(hdr));

    // open layer2 socket
    if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
        errExit("socket");

    int len;
    if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
        errExit("send");
    fflush(0);

    // wait not more than one second for an answer
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(sock, &fds);
    int maxfd = sock;
    struct timeval ts;
    ts.tv_sec = 1; // 1 second wait time
    ts.tv_usec = 0;
    while (1) {
        int nready = select(maxfd + 1,  &fds, (fd_set *) 0, (fd_set *) 0, &ts);
        if (nready < 0)
            errExit("select");
        else if (nready == 0) { // timeout
            close(sock);
            return 0;
        }
        else {
            // read the incoming packet
            int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
            if (len < 0) {
                perror("recvfrom");
                close(sock);
                return -1;
            }

            // parse the incomming packet
            if ((unsigned int) len < 14 + sizeof(ArpHdr))
                continue;
            if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
                continue;
            memcpy(&hdr, frame + 14, sizeof(ArpHdr));
            if (hdr.opcode == htons(1))
                continue;
            if (hdr.opcode == htons(2)) {
                // check my mac and my address
                if (memcmp(ifr.ifr_hwaddr.sa_data, hdr.target_mac, 6) != 0)
                    continue;
                uint32_t ip;
                memcpy(&ip, hdr.target_ip, 4);
                if (ip != srcaddr) {
                    continue;
                }
                close(sock);
                return -1;
            }
        }
    }

    // it will never get here!
    close(sock);
    return -1;
}
Exemplo n.º 25
0
void netfilter(const char *fname) {
	// default filter
	char *filter = client_filter;

	// custom filter
	int allocated = 0;
	if (fname) {
		// buffer the filter
		struct stat s;
		if (stat(fname, &s) == -1) {
			fprintf(stderr, "Error: cannot find network filter file\n");
			exit(1);
		}
				
		filter = malloc(s.st_size + 1);	// + '\0'
		memset(filter, 0, s.st_size + 1);
		if (!filter)
			errExit("malloc");
		
		FILE *fp = fopen(fname, "r");
		if (!fp) {
			fprintf(stderr, "Error: cannot open network filter file\n");
			exit(1);
		}

		size_t sz = fread(filter, 1, s.st_size, fp);
		if (sz != s.st_size) {
			fprintf(stderr, "Error: cannot read network filter file\n");
			exit(1);
		}
		fclose(fp);
		allocated = 1;
	}
		
	// mount a tempfs on top of /tmp directory
	if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
		errExit("mounting /tmp");

	// create the filter file
	FILE *fp = fopen("/tmp/netfilter", "w");
	if (!fp) {
		fprintf(stderr, "Error: cannot open /tmp/netfilter file\n");
		exit(1);
	}
	fprintf(fp, "%s\n", filter);
	fclose(fp);

	// push filter
	int rv;
	if (arg_debug)
		printf("Installing network filter:\n%s\n", filter);

	rv = system("/sbin/iptables-restore < /tmp/netfilter");
	if (rv == -1) {
		fprintf(stderr, "Error: failed to configure network filter.\n");
		exit(1);
	}
	if (arg_debug)
		rv = system("/sbin/iptables -vL");
	
	// unmount /tmp
	umount("/tmp");
	
	if (allocated)
		free(filter);
}
Exemplo n.º 26
0
void fs_private_dev(void){
	// install a new /dev directory
	if (arg_debug)
		printf("Mounting tmpfs on /dev\n");

	// create DRI_DIR
	fs_build_mnt_dir();
	
	// keep a copy of dev directory
	if (mkdir(RUN_DEV_DIR, 0755) == -1)
		errExit("mkdir");
	if (chmod(RUN_DEV_DIR, 0755) == -1)
		errExit("chmod");
	ASSERT_PERMS(RUN_DEV_DIR, 0, 0, 0755);
	if (mount("/dev", RUN_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mounting /dev/dri");

	// create DEVLOG_FILE
	int have_devlog = 0;
	struct stat s;
	if (stat("/dev/log", &s) == 0) {
		have_devlog = 1;
		FILE *fp = fopen(RUN_DEVLOG_FILE, "w");
		if (!fp)
			have_devlog = 0;
		else {
			fprintf(fp, "\n");
			fclose(fp);
			if (mount("/dev/log", RUN_DEVLOG_FILE, NULL, MS_BIND|MS_REC, NULL) < 0)
				errExit("mounting /dev/log");
		}
	}

	// mount tmpfs on top of /dev
	if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
		errExit("mounting /dev");
	fs_logger("tmpfs /dev");
	
	deventry_mount();

	// bring back /dev/log
	if (have_devlog) {
		FILE *fp = fopen("/dev/log", "w");
		if (fp) {
			fprintf(fp, "\n");
			fclose(fp);
			if (mount(RUN_DEVLOG_FILE, "/dev/log", NULL, MS_BIND|MS_REC, NULL) < 0)
				errExit("mounting /dev/log");
			fs_logger("clone /dev/log");
		}
	}		
	if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0)
		errExit("disable /dev/snd");

	
	// create /dev/shm
	if (arg_debug)
		printf("Create /dev/shm directory\n");
	if (mkdir("/dev/shm", 01777) == -1)
		errExit("mkdir");
	// mkdir sets only the file permission bits
	if (chmod("/dev/shm", 01777) < 0)
		errExit("chmod");
	ASSERT_PERMS("/dev/shm", 0, 0, 01777);
	fs_logger("mkdir /dev/shm");

	// create devices
	create_char_dev("/dev/zero", 0666, 1, 5); // mknod -m 666 /dev/zero c 1 5
	fs_logger("mknod /dev/zero");
	create_char_dev("/dev/null", 0666, 1, 3); // mknod -m 666 /dev/null c 1 3
	fs_logger("mknod /dev/null");
	create_char_dev("/dev/full", 0666, 1, 7); // mknod -m 666 /dev/full c 1 7
	fs_logger("mknod /dev/full");
	create_char_dev("/dev/random", 0666, 1, 8); // Mknod -m 666 /dev/random c 1 8
	fs_logger("mknod /dev/random");
	create_char_dev("/dev/urandom", 0666, 1, 9); // mknod -m 666 /dev/urandom c 1 9
	fs_logger("mknod /dev/urandom");
	create_char_dev("/dev/tty", 0666,  5, 0); // mknod -m 666 /dev/tty c 5 0
	fs_logger("mknod /dev/tty");
#if 0
	create_dev("/dev/tty0", "mknod -m 666 /dev/tty0 c 4 0");
	create_dev("/dev/console", "mknod -m 622 /dev/console c 5 1");
#endif

	// pseudo-terminal
	if (mkdir("/dev/pts", 0755) == -1)
		errExit("mkdir");
	if (chmod("/dev/pts", 0755) == -1)
		errExit("chmod");
	ASSERT_PERMS("/dev/pts", 0, 0, 0755);
	fs_logger("mkdir /dev/pts");
	create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2");
	fs_logger("mknod /dev/pts/ptmx");
	create_link("/dev/pts/ptmx", "/dev/ptmx");

// code before github issue #351
	// mount -vt devpts -o newinstance -o ptmxmode=0666 devpts //dev/pts
//	if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,  "newinstance,ptmxmode=0666") < 0)
//		errExit("mounting /dev/pts");


	// mount /dev/pts
	gid_t ttygid = get_tty_gid();
	char *data;
	if (asprintf(&data, "newinstance,gid=%d,mode=620,ptmxmode=0666", (int) ttygid) == -1)
		errExit("asprintf");
	if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,  data) < 0)
		errExit("mounting /dev/pts");
	free(data);
	fs_logger("clone /dev/pts");

#if 0
	// stdin, stdout, stderr
	create_link("/proc/self/fd", "/dev/fd");
	create_link("/proc/self/fd/0", "/dev/stdin");
	create_link("/proc/self/fd/1", "/dev/stdout");
	create_link("/proc/self/fd/2", "/dev/stderr");
#endif
}
Exemplo n.º 27
0
Arquivo: dnotify.c Projeto: nipra/see
int
main(int argc, char *argv[])
{
    struct sigaction sa;
    int fd, events, fnum;
    const int NOTIFY_SIG = SIGRTMIN;
    char *p;

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageError(argv[0], NULL);

    /* Establish handler for notification signal */

    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;           /* So handler gets siginfo_t arg. */
    if (sigaction(NOTIFY_SIG, &sa, NULL) == -1)
        errExit("sigaction");

    for (fnum = 1; fnum < argc; fnum++) {
        p = strchr(argv[fnum], ':');    /* Look for optional ':' */

        if (p == NULL) {                /* Default is all events + multishot */
            events = DN_ACCESS | DN_ATTRIB | DN_CREATE | DN_DELETE |
                     DN_MODIFY | DN_RENAME | DN_MULTISHOT;
        } else {                        /* ':' present, parse event chars */
            *p = '\0';                  /* Terminates directory component */
            events = 0;
            for (p++; *p != '\0'; p++) {
                switch (*p) {
                case 'a': events |= DN_ACCESS;          break;
                case 'A': events |= DN_ATTRIB;          break;
                case 'c': events |= DN_CREATE;          break;
                case 'd': events |= DN_DELETE;          break;
                case 'm': events |= DN_MODIFY;          break;
                case 'r': events |= DN_RENAME;          break;
                case 'M': events |= DN_MULTISHOT;       break;
                default:  usageError(argv[0], "Bad event character\n");
                }
            }
        }

        /* Obtain a file descriptor for the directory to be monitored */

        fd = open(argv[fnum], O_RDONLY);
        if (fd == -1)
            errExit("open");
        printf("opened '%s' as file descriptor %d\n", argv[fnum], fd);

        /* Use alternate signal instead of SIGIO for dnotify events */

        if (fcntl(fd, F_SETSIG, NOTIFY_SIG) == -1)
            errExit("fcntl - F_SETSIG");

        /* Enable directory change notifications */

        if (fcntl(fd, F_NOTIFY, events) == -1)
            errExit("fcntl-F_NOTIFY");
        printf("events: %o\n", (unsigned int) events);
    }

    for (;;)
        pause();                        /* Wait for events */
}
Exemplo n.º 28
0
void join(pid_t pid, int argc, char **argv, int index) {
	EUID_ASSERT();
	char *homedir = cfg.homedir;
	
	extract_command(argc, argv, index);

	// if the pid is that of a firejail  process, use the pid of the first child process
	EUID_ROOT();
	char *comm = pid_proc_comm(pid);
	EUID_USER();
	if (comm) {
		if (strcmp(comm, "firejail") == 0) {
			pid_t child;
			if (find_child(pid, &child) == 0) {
				pid = child;
				printf("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) pid);
			}
		}
		free(comm);
	}

	// check privileges for non-root users
	uid_t uid = getuid();
	if (uid != 0) {
		uid_t sandbox_uid = pid_get_uid(pid);
		if (uid != sandbox_uid) {
			fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n");
			exit(1);
		}
	}

	EUID_ROOT();
	// in user mode set caps seccomp, cpu, cgroup, etc
	if (getuid() != 0) {
		extract_caps_seccomp(pid);
		extract_cpu(pid);
		extract_cgroup(pid);
		extract_nogroups(pid);
		extract_user_namespace(pid);
	}
	
	// set cgroup
	if (cfg.cgroup)	// not available for uid 0
		set_cgroup(cfg.cgroup);
		
	// join namespaces
	if (arg_join_network) {
		if (join_namespace(pid, "net"))
			exit(1);
	}
	else if (arg_join_filesystem) {
		if (join_namespace(pid, "mnt"))
			exit(1);
	}
	else {
		if (join_namespace(pid, "ipc"))
			exit(1);
		if (join_namespace(pid, "net"))
			exit(1);
		if (join_namespace(pid, "pid"))
			exit(1);
		if (join_namespace(pid, "uts"))
			exit(1);
		if (join_namespace(pid, "mnt"))
			exit(1);
	}

	pid_t child = fork();
	if (child < 0)
		errExit("fork");
	if (child == 0) {
		// chroot into /proc/PID/root directory
		char *rootdir;
		if (asprintf(&rootdir, "/proc/%d/root", pid) == -1)
			errExit("asprintf");
			
		int rv;
		if (!arg_join_network) {
			rv = chroot(rootdir); // this will fail for processes in sandboxes not started with --chroot option
			if (rv == 0)
				printf("changing root to %s\n", rootdir);
		}
		
		prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died
		if (chdir("/") < 0)
			errExit("chdir");
		if (homedir) {
			struct stat s;
			if (stat(homedir, &s) == 0) {
				/* coverity[toctou] */
				if (chdir(homedir) < 0)
					errExit("chdir");
			}
		}
		
		// set cpu affinity
		if (cfg.cpus)	// not available for uid 0
			set_cpu_affinity();
					
		// set caps filter
		if (apply_caps == 1)	// not available for uid 0
			caps_set(caps);
#ifdef HAVE_SECCOMP
		// set protocol filter
		if (getuid() != 0)
			protocol_filter_load(RUN_PROTOCOL_CFG);
		if (cfg.protocol) {	// not available for uid 0
			protocol_filter();
		}
				
		// set seccomp filter
		if (apply_seccomp == 1)	// not available for uid 0
			seccomp_set();
		
#endif
		
		// fix qt 4.8
		if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0)
			errExit("setenv");
		if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc,
			errExit("setenv");

		// mount user namespace or drop privileges
		if (arg_noroot) {	// not available for uid 0
			if (arg_debug)
				printf("Joining user namespace\n");
			if (join_namespace(1, "user"))
				exit(1);
		}
		else 
			drop_privs(arg_nogroups);	// nogroups not available for uid 0

		// set prompt color to green
		//export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] '
		if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0)
			errExit("setenv");

		// run cmdline trough /bin/bash
		if (cfg.command_line == NULL) {
			struct stat s;

			// replace the process with a shell
			if (stat("/bin/bash", &s) == 0)
				execlp("/bin/bash", "/bin/bash", NULL);
			else if (stat("/usr/bin/zsh", &s) == 0)
				execlp("/usr/bin/zsh", "/usr/bin/zsh", NULL);
			else if (stat("/bin/csh", &s) == 0)
				execlp("/bin/csh", "/bin/csh", NULL);
			else if (stat("/bin/sh", &s) == 0)
				execlp("/bin/sh", "/bin/sh", NULL);
			
			// no shell found, print an error and exit
			fprintf(stderr, "Error: no POSIX shell found\n");
			sleep(5);
			exit(1);
		}
		else {
			// run the command supplied by the user
			int cwd = 0;
			if (cfg.cwd) {
				if (chdir(cfg.cwd) == 0)
					cwd = 1;
			}
			
			if (!cwd) {
				if (chdir("/") < 0)
					errExit("chdir");
				if (cfg.homedir) {
					struct stat s;
					if (stat(cfg.homedir, &s) == 0) {
						if (chdir(cfg.homedir) < 0)
							errExit("chdir");
					}
				}
			}

			char *arg[5];
			arg[0] = "/bin/bash";
			arg[1] = "-c";
			if (arg_debug)
				printf("Starting %s\n", cfg.command_line);
			if (!arg_doubledash) {
				arg[2] = cfg.command_line;
				arg[3] = NULL;
			}
			else {
				arg[2] = "--";
				arg[3] = cfg.command_line;
				arg[4] = NULL;
			}
			execvp("/bin/bash", arg);
		}

		// it will never get here!!!
	}

	// wait for the child to finish
	waitpid(child, NULL, 0);
	exit(0);
}
Exemplo n.º 29
0
int
main(int argc, char *argv[])
{
    uint32_t seqNum;
    char reqLenStr[INT_LEN];            /* Length of requested sequence */
    char seqNumStr[INT_LEN];            /* Start of granted sequence */
    struct sockaddr_storage claddr;
    int lfd, cfd, optval, reqLen;
    socklen_t addrlen;
    struct addrinfo hints;
    struct addrinfo *result, *rp;
#define ADDRSTRLEN (NI_MAXHOST + NI_MAXSERV + 10)
    char addrStr[ADDRSTRLEN];
    char host[NI_MAXHOST];
    char service[NI_MAXSERV];

    if (argc > 1 && strcmp(argv[1], "--help") == 0)
        usageErr("%s [init-seq-num]\n", argv[0]);

    seqNum = (argc > 1) ? getInt(argv[1], 0, "init-seq-num") : 0;

    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        errExit("signal");

    /* Call getaddrinfo() to obtain a list of addresses that
       we can try binding to */

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_family = AF_UNSPEC;        /* Allows IPv4 or IPv6 */
    hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
                        /* Wildcard IP address; service name is numeric */

    if (getaddrinfo(NULL, PORT_NUM, &hints, &result) != 0)
        errExit("getaddrinfo");

    /* Walk through returned list until we find an address structure
       that can be used to successfully create and bind a socket */

    optval = 1;
    for (rp = result; rp != NULL; rp = rp->ai_next) {
        lfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (lfd == -1)
            continue;                   /* On error, try next address */

        if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))
                == -1)
             errExit("setsockopt");

        if (bind(lfd, rp->ai_addr, rp->ai_addrlen) == 0)
            break;                      /* Success */

        /* bind() failed: close this socket and try next address */

        close(lfd);
    }

    if (rp == NULL)
        fatal("Could not bind socket to any address");

    if (listen(lfd, BACKLOG) == -1)
        errExit("listen");

    freeaddrinfo(result);

    for (;;) {                  /* Handle clients iteratively */

        /* Accept a client connection, obtaining client's address */

        addrlen = sizeof(struct sockaddr_storage);
        cfd = accept(lfd, (struct sockaddr *) &claddr, &addrlen);
        if (cfd == -1) {
            errMsg("accept");
            continue;
        }

        if (getnameinfo((struct sockaddr *) &claddr, addrlen,
                    host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
            snprintf(addrStr, ADDRSTRLEN, "(%s, %s)", host, service);
        else
            snprintf(addrStr, ADDRSTRLEN, "(?UNKNOWN?)");
        printf("Connection from %s\n", addrStr);

        /* Read client request, send sequence number back */

        if (readLine(cfd, reqLenStr, INT_LEN) <= 0) {
            close(cfd);
            continue;                   /* Failed read; skip request */
        }

        reqLen = atoi(reqLenStr);
        if (reqLen <= 0) {              /* Watch for misbehaving clients */
            close(cfd);
            continue;                   /* Bad request; skip it */
        }

        snprintf(seqNumStr, INT_LEN, "%d\n", seqNum);
        if (write(cfd, &seqNumStr, strlen(seqNumStr)) != strlen(seqNumStr))
            fprintf(stderr, "Error on write");

        seqNum += reqLen;               /* Update sequence number */

        if (close(cfd) == -1)           /* Close connection */
            errMsg("close");
    }
}
Exemplo n.º 30
0
// disable shm in pulseaudio
void pulseaudio_init(void) {
	struct stat s;

	// do we have pulseaudio in the system?
	if (stat("/etc/pulse/client.conf", &s) == -1) {
		if (arg_debug)
			printf("/etc/pulse/client.conf not found\n");
		return;
	}

	// create the new user pulseaudio directory
	if (mkdir(RUN_PULSE_DIR, 0700) == -1)
		errExit("mkdir");
	// make it a mount point and add mount flags
	if (mount(RUN_PULSE_DIR, RUN_PULSE_DIR, NULL, MS_BIND, NULL) < 0 ||
	    mount(NULL, RUN_PULSE_DIR, NULL, MS_NOEXEC|MS_NODEV|MS_NOSUID|MS_BIND|MS_REMOUNT, NULL) < 0)
		errExit("mount RUN_PULSE_DIR");

	// create the new client.conf file
	char *pulsecfg = NULL;
	if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1)
		errExit("asprintf");
	if (copy_file("/etc/pulse/client.conf", pulsecfg, -1, -1, 0644)) // root needed
		errExit("copy_file");
	FILE *fp = fopen(pulsecfg, "a+");
	if (!fp)
		errExit("fopen");
	fprintf(fp, "%s", "\nenable-shm = no\n");
	SET_PERMS_STREAM(fp, getuid(), getgid(), 0644);
	fclose(fp);
	// hand over the directory to the user
	if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700))
		errExit("set_perms");

	// create ~/.config/pulse directory if not present
	char *dir1;
	if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1)
		errExit("asprintf");
	if (lstat(dir1, &s) == -1) {
		pid_t child = fork();
		if (child < 0)
			errExit("fork");
		if (child == 0) {
			// drop privileges
			drop_privs(0);

			int rv = mkdir(dir1, 0755);
			if (rv == 0) {
				if (set_perms(dir1, getuid(), getgid(), 0755))
					{;} // do nothing
			}
#ifdef HAVE_GCOV
			__gcov_flush();
#endif
			_exit(0);
		}
		// wait for the child to finish
		waitpid(child, NULL, 0);
		fs_logger2("create", dir1);
	}
	else {
		// we expect a user owned directory
		if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
			if (S_ISLNK(s.st_mode))
				fprintf(stderr, "Error: user .config is a symbolic link\n");
			else
				fprintf(stderr, "Error: user .config is not a directory owned by the current user\n");
			exit(1);
		}
	}
	free(dir1);

	if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1)
		errExit("asprintf");
	if (lstat(dir1, &s) == -1) {
		pid_t child = fork();
		if (child < 0)
			errExit("fork");
		if (child == 0) {
			// drop privileges
			drop_privs(0);

			int rv = mkdir(dir1, 0700);
			if (rv == 0) {
				if (set_perms(dir1, getuid(), getgid(), 0700))
					{;} // do nothing
			}
#ifdef HAVE_GCOV
			__gcov_flush();
#endif
			_exit(0);
		}
		// wait for the child to finish
		waitpid(child, NULL, 0);
		fs_logger2("create", dir1);
	}
	else {
		// we expect a user owned directory
		if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
			if (S_ISLNK(s.st_mode))
				fprintf(stderr, "Error: user .config/pulse is a symbolic link\n");
			else
				fprintf(stderr, "Error: user .config/pulse is not a directory owned by the current user\n");
			exit(1);
		}
	}
	free(dir1);

	// if we have ~/.config/pulse mount the new directory, else set environment variable.
	char *homeusercfg;
	if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
		errExit("asprintf");
	if (stat(homeusercfg, &s) == 0) {
		// get a file descriptor for ~/.config/pulse, fails if there is any symlink
		int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
		if (fd == -1)
			errExit("safe_fd");
		// confirm the actual mount destination is owned by the user
		if (fstat(fd, &s) == -1 || s.st_uid != getuid())
			errExit("fstat");

		// mount via the link in /proc/self/fd
		char *proc;
		if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
			errExit("asprintf");
		if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
			errExit("mount pulseaudio");
		fs_logger2("tmpfs", homeusercfg);
		free(proc);
		close(fd);
		// check /proc/self/mountinfo to confirm the mount is ok
		MountData *mptr = get_last_mount();
		if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
			errLogExit("invalid pulseaudio mount");

		char *p;
		if (asprintf(&p, "%s/client.conf", homeusercfg) == -1)
			errExit("asprintf");
		fs_logger2("create", p);
		free(p);
	}

	else {
		// set environment
		if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0)
			errExit("setenv");
	}

	free(pulsecfg);
	free(homeusercfg);
}