Beispiel #1
0
int
deliver_mbox_deliver(struct deliver_ctx *dctx, struct actitem *ti)
{
    struct account			*a = dctx->account;
    struct mail			*m = dctx->mail;
    struct deliver_mbox_data	*data = ti->data;
    char				*path, *ptr, *lptr, *from = NULL;
    const char			*msg;
    size_t				 len, llen;
    int				 fd, saved_errno;
    FILE				*f;
    gzFile				 gzf;
    long long			 used;
    sigset_t			 set, oset;
    struct stat			 sb;

    f = gzf = NULL;
    fd = -1;

    path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home);
    if (path == NULL || *path == '\0') {
        log_warnx("%s: empty path", a->name);
        goto error;
    }
    if (data->compress) {
        len = strlen(path);
        if (len < 3 || strcmp(path + len - 3, ".gz") != 0) {
            path = xrealloc(path, 1, len + 4);
            strlcat(path, ".gz", len + 4);
        }
    }
    log_debug2("%s: saving to mbox %s", a->name, path);

    /* Save the mbox path. */
    add_tag(&m->tags, "mbox_file", "%s", path);

    /* Check permissions and ownership. */
    if (stat(path, &sb) != 0) {
        if (conf.no_create || errno != ENOENT)
            goto error_log;

        log_debug2("%s: creating %s", a->name, xdirname(path));
        if (xmkpath(xdirname(path), -1, conf.file_group, DIRMODE) != 0)
            goto error_log;
    } else {
        if ((msg = checkmode(&sb, UMASK(FILEMODE))) != NULL)
            log_warnx("%s: %s: %s", a->name, path, msg);
        if ((msg = checkowner(&sb, -1)) != NULL)
            log_warnx("%s: %s: %s", a->name, path, msg);
        if ((msg = checkgroup(&sb, conf.file_group)) != NULL)
            log_warnx("%s: %s: %s", a->name, path, msg);
    }

    /* Create or open the mbox. */
    used = 0;
    do {
        if (conf.no_create)
            fd = openlock(path, O_WRONLY|O_APPEND, conf.lock_types);
        else {
            fd = createlock(path, O_WRONLY|O_APPEND,
                            -1, conf.file_group, FILEMODE, conf.lock_types);
        }
        if (fd == -1 && errno == EEXIST)
            fd = openlock(path, O_WRONLY|O_APPEND, conf.lock_types);
        if (fd == -1) {
            if (errno == EAGAIN) {
                if (locksleep(a->name, path, &used) != 0)
                    goto error;
                continue;
            }
            goto error_log;
        }
    } while (fd < 0);

    /* Open gzFile or FILE * for writing. */
    if (data->compress) {
        if ((gzf = gzdopen(fd, "a")) == NULL) {
            errno = ENOMEM;
            goto error_log;
        }
    } else {
        if ((f = fdopen(fd, "a")) == NULL)
            goto error_log;
    }

    /*
     * mboxes are a pain: if we are interrupted after this we risk
     * having written a partial mail. So, block SIGTERM until we're
     * done.
     */
    sigemptyset(&set);
    sigaddset(&set, SIGTERM);
    if (sigprocmask(SIG_BLOCK, &set, &oset) < 0)
        fatal("sigprocmask failed");

    /* Write the from line. */
    from = make_from(m, dctx->udata->name);
    if (deliver_mbox_write(f, gzf, from, strlen(from)) < 0) {
        xfree(from);
        goto error_unblock;
    }
    if (deliver_mbox_write(f, gzf, "\n", 1) < 0) {
        xfree(from);
        goto error_unblock;
    }
    log_debug3("%s: using from line: %s", a->name, from);
    xfree(from);

    /* Write the mail, escaping from lines. */
    line_init(m, &ptr, &len);
    while (ptr != NULL) {
        if (ptr != m->data) {
            /* Skip leading >s. */
            lptr = ptr;
            llen = len;
            while (*lptr == '>' && llen > 0) {
                lptr++;
                llen--;
            }

            if (llen >= 5 && strncmp(lptr, "From ", 5) == 0) {
                log_debug2("%s: quoting from line: %.*s",
                           a->name, (int) len - 1, ptr);
                if (deliver_mbox_write(f, gzf, ">", 1) < 0)
                    goto error_unblock;
            }
        }

        if (deliver_mbox_write(f, gzf, ptr, len) < 0)
            goto error_unblock;

        line_next(m, &ptr, &len);
    }

    /* Append newlines. */
    if (m->data[m->size - 1] == '\n') {
        if (deliver_mbox_write(f, gzf, "\n", 1) < 0)
            goto error_unblock;
    } else {
        if (deliver_mbox_write(f, gzf, "\n\n", 2) < 0)
            goto error_unblock;
    }

    /* Flush buffers and sync. */
    if (gzf == NULL) {
        if (fflush(f) != 0)
            goto error_unblock;
    } else {
        if (gzflush(gzf, Z_FINISH) != Z_OK) {
            errno = EIO;
            goto error_unblock;
        }
    }
    if (fsync(fd) != 0)
        goto error_unblock;

    if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0)
        fatal("sigprocmask failed");

    if (gzf != NULL)
        gzclose(gzf);
    if (f != NULL)
        fclose(f);
    closelock(fd, path, conf.lock_types);

    xfree(path);
    return (DELIVER_SUCCESS);

error_unblock:
    saved_errno = errno;
    if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0)
        fatal("sigprocmask failed");
    errno = saved_errno;

error_log:
    log_warn("%s: %s", a->name, path);

error:
    if (gzf != NULL)
        gzclose(gzf);
    if (f != NULL)
        fclose(f);
    if (fd != -1)
        closelock(fd, path, conf.lock_types);

    if (path != NULL)
        xfree(path);
    return (DELIVER_FAILURE);
}
Beispiel #2
0
int parsefile(struct bb_frame** output, FILE* file) {
    int error = 0, linenum = 0;
    char filename = 0;
    char* line = NULL;
    ssize_t line_len;

    struct bb_frame* head = NULL;
    struct bb_frame* curframe = NULL;
    struct bb_frame** nextframeptr = &curframe;

    while ((line_len = readline(&line,file)) > 0) {
        ++linenum;

        config_debug("%s",line);

        char delim[] = {' ','\0'};
        char delim_endline[] = {'\n','\0'};
        char* tmp;
        char* cmd = strtok_r(line,delim,&tmp);

        if (strcmp(cmd,"txt") == 0) {

            char* mode = strtok_r(NULL,delim,&tmp);
            char* text = strtok_r(NULL,delim_endline,&tmp);
            if (checkmode(mode,text,linenum) < 0) {
                error = 1;
                break;
            }

            *nextframeptr = malloc(sizeof(struct bb_frame));
            curframe = *nextframeptr;
            curframe->next = NULL;

            curframe->mode = tolower(mode[0]);
            if (strlen(mode) > 1) {
                curframe->mode_special = toupper(mode[1]);
            } else {
                curframe->mode_special = NO_SPECIAL;
            }

            if (text == NULL) {
                curframe->data = NULL;
            } else {
                int is_trimmed = 0;

                int charsparsed = parse_inline_cmds(&curframe->data,&is_trimmed,
                        text,MAX_TEXTFILE_DATA_SIZE);

                if (is_trimmed) {
                    config_error("Warning, line %d: Data has been truncated at input index %d to fit %d available output bytes.",
                            linenum,charsparsed,MAX_TEXTFILE_DATA_SIZE);
                    config_error("Input vs output bytecount can vary if you used inline commands in your input.");
                }
            }

            curframe->frame_type = TEXT_FRAME_TYPE;

            filename = packet_next_filename(filename);
            if (filename <= 0) {
                error = 1;
                break;
            }
            curframe->filename = filename;

            nextframeptr = &curframe->next;

        } else if (strcmp(cmd,"cmd") == 0) {

            char* mode = strtok_r(NULL,delim,&tmp);
            char* command = strtok_r(NULL,delim_endline,&tmp);
            if (checkmode(mode,command,linenum) < 0) {
                error = 1;
                break;
            }

            char* raw_result;
            if (runcmd(&raw_result,command) < 0) {
                error = 1;
                break;
            }

            //data for the TEXT frame which will reference these STRING frames:
            char refchar = 0x10;//format for each reference is 2 bytes: "0x10, filename" (pg55)
            char* textrefs = (char*)calloc(2*MAX_STRINGFILE_GROUP_COUNT+1,sizeof(char));//include \0 in size
            textrefs[2*MAX_STRINGFILE_GROUP_COUNT] = 0;//set \0

            //Create and append STRING frames:
            int i, cumulative_parsed = 0;
            for (i = 0; i < MAX_STRINGFILE_GROUP_COUNT; i++) {
                *nextframeptr = malloc(sizeof(struct bb_frame));
                curframe = *nextframeptr;
                curframe->next = NULL;
                if (head == NULL) {
                    head = curframe;
                }

                int is_trimmed = 0;
                char* parsed_result;
                int charsparsed = parse_inline_cmds((char**)&parsed_result,&is_trimmed,
                        &raw_result[cumulative_parsed],
                        MAX_STRINGFILE_DATA_SIZE);
                cumulative_parsed += charsparsed;
                if (is_trimmed && i+1 == MAX_STRINGFILE_GROUP_COUNT) {
                    config_error("Warning, line %d: Data has been truncated at input index %d to fit %d available output bytes.",
                            linenum,cumulative_parsed,MAX_STRINGFILE_GROUP_COUNT*MAX_STRINGFILE_DATA_SIZE);
                    config_error("Input vs output bytecount can vary if you used inline commands in your input.");
                }

                curframe->data = malloc(MAX_STRINGFILE_DATA_SIZE+1);
                strncpy(curframe->data,parsed_result,
                        MAX_STRINGFILE_DATA_SIZE);
                curframe->data[MAX_STRINGFILE_DATA_SIZE] = 0;
                free(parsed_result);
                config_debug(">%d %s",i,curframe->data);

                filename = packet_next_filename(filename);
                if (filename <= 0) {
                    error = 1;
                    break;
                }
                curframe->filename = filename;
                //add a reference for ourselves to the TEXT frame:
                textrefs[2*i] = refchar;
                textrefs[2*i+1] = filename;

                curframe->frame_type = STRING_FRAME_TYPE;

                nextframeptr = &curframe->next;
            }
            free(raw_result);
            if (error == 1) {
                break;
            }

            //Append TEXT frame containing references to those STRINGs:
            *nextframeptr = malloc(sizeof(struct bb_frame));
            curframe = *nextframeptr;
            curframe->next = NULL;

            curframe->mode = mode[0];
            if (strlen(mode) > 1) {
                curframe->mode_special = mode[1];
            } else {
                curframe->mode_special = NO_SPECIAL;
            }

            curframe->data = textrefs;

            curframe->frame_type = TEXT_FRAME_TYPE;

            filename = packet_next_filename(filename);
            if (filename <= 0) {
                error = 1;
                break;
            }
            curframe->filename = filename;

            nextframeptr = &curframe->next;

        } else if ((strlen(cmd) >= 2 && cmd[0] == '/' && cmd[1] == '/') ||
                (strlen(cmd) >= 1 && cmd[0] == '#')) {

            //comment in input file, do nothing

        } else {

            config_error("Syntax error, line %d: Unknown command.",linenum);
            error = 1;
            break;

        }

        if (head == NULL) {
            head = curframe;
        }

        free(line);
        line = NULL;
    }

    if (line != NULL) {
        free(line);
        line = NULL;
    }

    *output = head;

    return (error == 0) ? 0 : -1;
}
Beispiel #3
0
/* returns 1 if used, 0 if not, so we can complain about bogus configs */
static int parse_conf_arg(int numargs, char **arg)
{
    /* using up to arg[1] below */
    if (numargs < 2)
        return 0;

    /* SHUTDOWNCMD <cmd> */
    if (!strcmp(arg[0], "SHUTDOWNCMD")) {
        checkmode(arg[0], shutdowncmd, arg[1], reload_flag);

        free(shutdowncmd);
        shutdowncmd = xstrdup(arg[1]);
        return 1;
    }

    /* POWERDOWNFLAG <fn> */
    if (!strcmp(arg[0], "POWERDOWNFLAG")) {
        checkmode(arg[0], powerdownflag, arg[1], reload_flag);

        free(powerdownflag);
        powerdownflag = xstrdup(arg[1]);

        if (!reload_flag)
            upslogx(LOG_INFO, "Using power down flag file %s",
                    arg[1]);

        return 1;
    }

    /* NOTIFYCMD <cmd> */
    if (!strcmp(arg[0], "NOTIFYCMD")) {
        free(notifycmd);
        notifycmd = xstrdup(arg[1]);
        return 1;
    }

    /* POLLFREQ <num> */
    if (!strcmp(arg[0], "POLLFREQ")) {
        pollfreq = atoi(arg[1]);
        return 1;
    }

    /* POLLFREQALERT <num> */
    if (!strcmp(arg[0], "POLLFREQALERT")) {
        pollfreqalert = atoi(arg[1]);
        return 1;
    }

    /* HOSTSYNC <num> */
    if (!strcmp(arg[0], "HOSTSYNC")) {
        hostsync = atoi(arg[1]);
        return 1;
    }

    /* DEADTIME <num> */
    if (!strcmp(arg[0], "DEADTIME")) {
        deadtime = atoi(arg[1]);
        return 1;
    }

    /* MINSUPPLIES <num> */
    if (!strcmp(arg[0], "MINSUPPLIES")) {
        minsupplies = atoi(arg[1]);
        return 1;
    }

    /* RBWARNTIME <num> */
    if (!strcmp(arg[0], "RBWARNTIME")) {
        rbwarntime = atoi(arg[1]);
        return 1;
    }

    /* NOCOMMWARNTIME <num> */
    if (!strcmp(arg[0], "NOCOMMWARNTIME")) {
        nocommwarntime = atoi(arg[1]);
        return 1;
    }

    /* FINALDELAY <num> */
    if (!strcmp(arg[0], "FINALDELAY")) {
        finaldelay = atoi(arg[1]);
        return 1;
    }

    /* RUN_AS_USER <userid> */
    if (!strcmp(arg[0], "RUN_AS_USER")) {
        free(run_as_user);
        run_as_user = xstrdup(arg[1]);
        return 1;
    }

    /* CERTPATH <path> */
    if (!strcmp(arg[0], "CERTPATH")) {
        free(certpath);
        certpath = xstrdup(arg[1]);
        return 1;
    }

    /* CERTVERIFY (0|1) */
    if (!strcmp(arg[0], "CERTVERIFY")) {
        certverify = atoi(arg[1]);
        return 1;
    }

    /* FORCESSL (0|1) */
    if (!strcmp(arg[0], "FORCESSL")) {
        forcessl = atoi(arg[1]);
        return 1;
    }

    /* using up to arg[2] below */
    if (numargs < 3)
        return 0;

    /* NOTIFYMSG <notify type> <replacement message> */
    if (!strcmp(arg[0], "NOTIFYMSG")) {
        set_notifymsg(arg[1], arg[2]);
        return 1;
    }

    /* NOTIFYFLAG <notify type> <flags> */
    if (!strcmp(arg[0], "NOTIFYFLAG")) {
        set_notifyflag(arg[1], arg[2]);
        return 1;
    }

    /* using up to arg[4] below */
    if (numargs < 5)
        return 0;

    if (!strcmp(arg[0], "MONITOR")) {

        /* original style: no username (only 5 args) */
        if (numargs == 5) {
            upslogx(LOG_ERR, "Unable to use old-style MONITOR line without a username");
            upslogx(LOG_ERR, "Convert it and add a username to upsd.users - see the documentation");

            fatalx(EXIT_FAILURE, "Fatal error: unusable configuration");
        }

        /* <sys> <pwrval> <user> <pw> ("master" | "slave") */
        addups(reload_flag, arg[1], arg[2], arg[3], arg[4], arg[5]);
        return 1;
    }

    /* didn't parse it at all */
    return 0;
}