Ejemplo n.º 1
0
queue_err_t queue_open(void *p, const char *filename, int flags)
{
    int omask;
    mode_t oldmask;
    posix_queue_t *q;

    q = (posix_queue_t *) p;
    if (HAS_FLAG(flags, QUEUE_FL_SENDER)) {
        omask = O_WRONLY;
    } else {
        omask = O_RDONLY;
    }
    if (HAS_FLAG(flags, QUEUE_FL_OWNER)) {
        omask |= O_CREAT | O_EXCL;
        oldmask = umask(0);
        if (NULL == (q->filename = strdup(filename))) {
            // TODO: error
            return QUEUE_ERR_GENERAL_FAILURE;
        }
    }
    if (NOT_MQD_T == (q->mq = mq_open(filename, omask, 0660, &q->attr))) {
        if (HAS_FLAG(flags, QUEUE_FL_OWNER)) {
            umask(oldmask);
#ifdef __FreeBSD__
            if (ENOSYS == errno) {
                // please load mqueuefs module with kldload or recompile your kernel to include "options P1003_1B_MQUEUE"
            }
#endif
        }
        // TODO: error
        return QUEUE_ERR_GENERAL_FAILURE;
    }
    if (!HAS_FLAG(flags, QUEUE_FL_SENDER)) {
        // mq_setattr implies CAP_EVENT?
        CAP_RIGHTS_LIMIT(__mq_oshandle(q->mq), CAP_READ, CAP_EVENT);
#if 0
    } else {
        CAP_RIGHTS_LIMIT(__mq_oshandle(q->mq), CAP_WRITE, CAP_EVENT);
#endif
    }
    if (HAS_FLAG(flags, QUEUE_FL_OWNER)) {
        umask(oldmask);
    } else {
        if (0 != mq_getattr(q->mq, &q->attr)) {
            // TODO: error
            return QUEUE_ERR_GENERAL_FAILURE;
        }
    }

    return QUEUE_ERR_OK;
}
Ejemplo n.º 2
0
Archivo: systemv.c Proyecto: julp/banip
queue_err_t queue_open(void *p, const char *name, int flags)
{
    int id;
    FILE *fp;
    key_t key;
    mode_t oldmask;
    systemv_queue_t *q;
    struct msqid_ds buf;
    char *s, filename[MAXPATHLEN];

    q = (systemv_queue_t *) p;
    if (HAS_FLAG(flags, QUEUE_FL_OWNER)) {
        if (NULL == (s = strchr(name, ':')) || '\0' == *s) {
            id = 'b';
            if (strlcpy(filename, name, STR_SIZE(filename)) >= STR_SIZE(filename)) {
                errno = E2BIG;
                return QUEUE_ERR_GENERAL_FAILURE;
            }
        } else {
            id = s[1];
            if (s - name >= STR_SIZE(filename)) {
                errno = E2BIG;
                return QUEUE_ERR_GENERAL_FAILURE;
            }
            strncpy(filename, name, s - name);
        }
        if (NULL == (fp = fopen(filename, "wx"))) {
            // TODO: error
            debug("");
            return QUEUE_ERR_GENERAL_FAILURE;
        }
        if (1 != fwrite(&id, sizeof(id), 1, fp)) {
            // TODO: error
            debug("");
            return QUEUE_ERR_GENERAL_FAILURE;
        }
        fflush(fp);
    } else {
        if (strlcpy(filename, name, STR_SIZE(filename)) >= STR_SIZE(filename)) {
            errno = E2BIG;
            return QUEUE_ERR_GENERAL_FAILURE;
        }
        if (NULL == (fp = fopen(filename, "r"))) {
            // TODO: error
            debug("");
            return QUEUE_ERR_GENERAL_FAILURE;
        }
        if (1 != fread(&id, sizeof(id), 1, fp) < sizeof(id)) {
            // TODO: error
            debug("");
            return QUEUE_ERR_GENERAL_FAILURE;
        }
    }
    fclose(fp);
    if (-1 == (key = ftok(filename, id))) {
        // NOTE: errno is not set by ftok
        // TODO: error
        debug("");
        return QUEUE_ERR_GENERAL_FAILURE;
    }
    if (HAS_FLAG(flags, QUEUE_FL_OWNER)) {
        if (NULL == (q->filename = strdup(filename))) {
            // TODO: error
            debug("");
            return QUEUE_ERR_GENERAL_FAILURE;
        }
        oldmask = umask(0);
        q->qid = msgget(key, 0660 | IPC_CREAT | IPC_EXCL);
        umask(oldmask);
    } else {
        q->qid = msgget(key, 0660);
    }
    if (-1 == q->qid) {
        // TODO: error
        debug("");
        return QUEUE_ERR_GENERAL_FAILURE;
    }
    if (!HAS_FLAG(flags, QUEUE_FL_SENDER)) {
#if 0
https://svnweb.freebsd.org/base/head/sys/kern/sysv_msg.c?revision=282213&view=markup

#define IPCID_TO_IX(id)         ((id) & 0xffff)
#define IPCID_TO_SEQ(id)        (((id) >> 16) & 0xffff)
#define IXSEQ_TO_IPCID(ix,perm) (((perm.seq) << 16) | (ix & 0xffff))
#endif
        CAP_RIGHTS_LIMIT(q->qid, CAP_READ);
#if 0
    } else {
        CAP_RIGHTS_LIMIT(q->qid, CAP_WRITE);
#endif
    }
    if (0 != msgctl(q->qid, IPC_STAT, &buf)) {
        // TODO: error
        debug("");
        return QUEUE_ERR_GENERAL_FAILURE;
    }
    q->buffer_size = buf.msg_qbytes / 8;
    if (NULL == (q->buffer = malloc(sizeof(long) + sizeof(q->buffer) * q->buffer_size))) {
        // TODO: error
        debug("");
        return QUEUE_ERR_GENERAL_FAILURE;
    }
    *(long *) q->buffer = 1; /* mtype is an integer greater than 0 */

    return QUEUE_ERR_OK;
}
Ejemplo n.º 3
0
Archivo: banipd.c Proyecto: julp/banip
int main(int argc, char **argv)
{
    gid_t gid;
    addr_t addr;
    struct sigaction sa;
    int c, dFlag, vFlag;
    unsigned long max_message_size;
    const char *queuename, *tablename;

    ctxt = NULL;
    gid = (gid_t) -1;
    vFlag = dFlag = 0;
    tablename = queuename = NULL;
    if (NULL == (queue = queue_init())) {
        errx("queue_init failed"); // TODO: better
    }
    atexit(cleanup);
    sa.sa_handler = &on_signal;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    sa.sa_flags = SA_RESTART;
    sigaction(SIGUSR1, &sa, NULL);
    if (NULL == (engine = get_default_engine())) {
        errx("no engine available for your system");
    }
    while (-1 != (c = getopt_long(argc, argv, optstr, long_options, NULL))) {
        switch (c) {
            case 'b':
            {
                unsigned long val;

                if (parse_ulong(optarg, &val)) {
                    queue_set_attribute(queue, QUEUE_ATTR_MAX_MESSAGE_SIZE, val); // TODO: check returned value
                }
                break;
            }
            case 'd':
                dFlag = 1;
                break;
            case 'e':
            {
                if (NULL == (engine = get_engine_by_name(optarg))) {
                    errx("unknown engine '%s'", optarg);
                }
                break;
            }
            case 'g':
            {
                struct group *grp;

                if (NULL == (grp = getgrnam(optarg))) {
                    errc("getgrnam failed");
                }
                gid = grp->gr_gid;
                break;
            }
            case 'l':
            {
                logfilename = optarg;
                if (NULL == (err_file = fopen(logfilename, "a"))) {
                    err_file = NULL;
                    warnc("fopen '%s' failed, falling back to stderr", logfilename);
                }
                break;
            }
            case 'p':
                pidfilename = optarg;
                break;
            case 'q':
                queuename = optarg;
                break;
            case 's':
            {
                unsigned long val;

                if (parse_ulong(optarg, &val)) {
                    queue_set_attribute(queue, QUEUE_ATTR_MAX_MESSAGE_IN_QUEUE, val); // TODO: check returned value
                }
                break;
            }
            case 't':
                tablename = optarg;
                break;
            case 'v':
                vFlag++;
                break;
            case 'h':
            default:
                usage();
        }
    }
    argc -= optind;
    argv += optind;

    if (0 != argc || NULL == queuename || NULL == tablename) {
        usage();
    }

    if (dFlag) {
        if (0 != daemon(0, !vFlag)) {
            errc("daemon failed");
        }
    }
    if (NULL != pidfilename) {
        FILE *fp;

        if (NULL == (fp = fopen(pidfilename, "w"))) {
            warnc("can't create pid file '%s'", pidfilename);
        } else {
            fprintf(fp, "%ld\n", (long) getpid());
            fclose(fp);
        }
    }

    if (((gid_t) -1) != gid) {
        if (0 != setgid(gid)) {
            errc("setgid failed");
        }
        if (0 != setgroups(1, &gid)) {
            errc("setgroups failed");
        }
    }
    CAP_RIGHTS_LIMIT(STDOUT_FILENO, CAP_WRITE);
    CAP_RIGHTS_LIMIT(STDERR_FILENO, CAP_WRITE);
    if (NULL != err_file/* && fileno(err_file) > 2*/) {
        CAP_RIGHTS_LIMIT(fileno(err_file), CAP_WRITE);
    }
    if (QUEUE_ERR_OK != queue_open(queue, queuename, QUEUE_FL_OWNER)) {
        errx("queue_open failed"); // TODO: better
    }
    if (QUEUE_ERR_OK != queue_get_attribute(queue, QUEUE_ATTR_MAX_MESSAGE_SIZE, &max_message_size)) {
        errx("queue_get_attribute failed"); // TODO: better
    }
    if (NULL == (buffer = calloc(++max_message_size, sizeof(*buffer)))) {
        errx("calloc failed");
    }
    if (NULL != engine->open) {
        ctxt = engine->open(tablename);
    }
    if (0 == getuid() && engine->drop_privileges) {
        struct passwd *pwd;

        if (NULL == (pwd = getpwnam("nobody"))) {
            if (NULL == (pwd = getpwnam("daemon"))) {
                errx("no nobody or daemon user accounts found on this system");
            }
        }
        if (0 != setuid(pwd->pw_uid)) {
            errc("setuid failed");
        }
    }
    CAP_ENTER();
    while (1) {
        ssize_t read;

        if (-1 == (read = queue_receive(queue, buffer, max_message_size))) {
            errc("queue_receive failed"); // TODO: better
        } else {
            if (!parse_addr(buffer, &addr)) {
                errx("parsing of '%s' failed", buffer); // TODO: better
            } else {
                engine->handle(ctxt, tablename, addr);
            }
        }
    }
    /* not reached */

    return BANIPD_EXIT_SUCCESS;
}