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); }
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; }
/* 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; }