/* * Parse a line 'src' from an /etc/krb.equiv file. * Sets the buffer pointed to by 'principal' to be the kerberos * identity and sets the buffer pointed to by 'localuser' to * be the local user. Both buffers must be of size one larger than * MAX_K_NAME_SZ. Returns 1 on success, 0 on failure. */ static int parse_krbequiv_line(const char *src, char *principal, char *localuser) { int i; while (Uisspace(*src)) src++; if (!*src) return 0; for (i = 0; *src && !Uisspace(*src); i++) { if (i >= MAX_K_NAME_SZ) return 0; *principal++ = *src++; } *principal = 0; if (!Uisspace(*src)) return 0; /* Need at least one separator */ while (Uisspace(*src)) src++; if (!*src) return 0; for (i = 0; *src && !Uisspace(*src); i++) { if (i >= MAX_K_NAME_SZ) return 0; *localuser++ = *src++; } *localuser = 0; return 1; }
/* * Given a line buffer @buf, find the IMAP response code named by @code, * isolate it and return the start of it, or NULL if not found. */ static char *find_response_code(char *buf, const char *code) { char *start; char *end; int codelen = strlen(code); /* Try to find the first response code */ start = strchr(buf, '['); if (!start) return NULL; /* no response codes */ start++; for (;;) { while (*start && Uisspace(*start)) start++; if (!*start) break; /* nothing to see here */ /* response codes are delineated by [] */ if (!(end = strchr(start, ']'))) break; /* unbalanced [response code] */ if (!strncasecmp(start, code, codelen) && Uisspace(start[codelen])) { *end = '\0'; start += codelen+1; return start; } else { start = end+1; } } return NULL; }
int is_local_realm(const char *realm) { const char *val = localrealms; if(!val || !realm) return 0; while (*val) { char buf[1024]; size_t len; char *p; for (p = (char *) val; *p && !Uisspace(*p); p++); len = p-val; if(len >= sizeof(buf)) len = sizeof(buf) - 1; memcpy(buf, val, len); buf[len] = '\0'; if (!strcasecmp(realm,buf)) { return 1; } val = p; while (*val && Uisspace(*val)) val++; } return 0; }
static void split_args(struct entry *e, char *buf) { char *p = buf, *q; char *key, *value; for (;;) { /* skip whitespace before arg */ while (Uisspace(*p)) p++; if (!*p) return; key = p; /* parse the key */ for (q = p ; Uisalnum(*q) ; q++) ; if (*q != '=') fatalf(EX_CONFIG, "configuration file %s: " "bad character '%c' in argument on line %d", MASTER_CONFIG_FILENAME, *q, e->lineno); *q++ = '\0'; /* parse the value */ if (*q == '"') { /* quoted string */ value = ++q; q = strchr(q, '"'); if (!q) fatalf(EX_CONFIG, "configuration file %s: missing \" on line %d", MASTER_CONFIG_FILENAME, e->lineno); *q++ = '\0'; } else { /* simple word */ value = q; while (*q && !Uisspace(*q)) q++; if (*q) *q++ = '\0'; } if (e->nargs == MAXARGS) fatalf(EX_CONFIG, "configuration file %s: too many arguments on line %d", MASTER_CONFIG_FILENAME, e->lineno); e->args[e->nargs].key = key; e->args[e->nargs].value = value; e->nargs++; p = q; } }
static void process_section(FILE *f, int *lnptr, masterconf_process *func, void *rock) { struct entry e; char buf[4096]; int lineno = *lnptr; while (fgets(buf, sizeof(buf), f)) { char *p, *q; lineno++; /* remove EOL character */ if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; /* remove starting whitespace */ for (p = buf; *p && Uisspace(*p); p++); /* remove comments */ q = strchr(p, '#'); if (q) *q = '\0'; /* skip empty lines or all comment lines */ if (!*p) continue; if (*p == '}') break; for (q = p; Uisalnum(*q); q++) ; if (*q) { if (q > p && !Uisspace(*q)) fatalf(EX_CONFIG, "configuration file %s: " "bad character '%c' in name on line %d", MASTER_CONFIG_FILENAME, *q, lineno); *q++ = '\0'; } if (q - p > 0) { /* there's a value on this line */ memset(&e, 0, sizeof(e)); e.lineno = lineno; split_args(&e, q); func(p, &e, rock); } /* end of section? */ if (strchr(q, '}')) break; } *lnptr = lineno; }
/* * Parse a source route (at-domain-list) */ static int parseaddr_route(char **inp, char **routep) { int c; char *src = *inp; char *dst; SKIPWHITESPACE(src); *routep = dst = src; for (;;) { c = *src++; if (Uisalnum(c) || c == '-' || c == '[' || c == ']' || c == ',' || c == '@') { *dst++ = c; } else if (c == '.') { if (dst > *routep && dst[-1] != '.') *dst++ = c; } else if (Uisspace(c) || c == '(') { src--; SKIPWHITESPACE(src); } else { while (dst > *routep && (dst[-1] == '.' || dst[-1] == ',' || dst[-1] == '@')) dst--; *dst = '\0'; *inp = src; return c; } } }
/* * Parse an RFC 822 "phrase", stopping at 'specials' */ static int parseaddr_phrase(char **inp, char **phrasep, const char *specials) { int c; char *src = *inp; char *dst; SKIPWHITESPACE(src); *phrasep = dst = src; for (;;) { c = *src++; if (c == '"') { while ((c = *src)) { src++; if (c == '\r' && *src == '\n') { /* CR+LF combination */ src++; if (*src == ' ' || *src == '\t') { /* CR+LF+WSP - folded header field, * unfold it by skipping ONLY the CR+LF */ continue; } /* otherwise we have CR+LF at the end of a header * field, which means we have an unbalanced " */ goto fail; } if (c == '\r' || c == '\n') goto fail; /* invalid chars */ if (c == '"') break; /* end of quoted string */ if (c == '\\') { if (!(c = *src)) goto fail; src++; } *dst++ = c; } if (c != '"') goto fail; /* unbalanced " */ } else if (Uisspace(c) || c == '(') { src--; SKIPWHITESPACE(src); *dst++ = ' '; } else if (!c || strchr(specials, c)) { if (dst > *phrasep && dst[-1] == ' ') dst--; *dst = '\0'; *inp = src; return c; } else { *dst++ = c; } } fail: /* simulate end-of-string */ *phrasep = ""; return 0; }
/* * Parse a domain. If 'commentp' is non-nil, parses any trailing comment. * If the domain is invalid, set invalid to non-zero. */ static int parseaddr_domain(char **inp, char **domainp, char **commentp, int *invalid) { int c; char *src = *inp; char *dst; char *cdst; int comment; if (commentp) *commentp = 0; SKIPWHITESPACE(src); *domainp = dst = src; for (;;) { c = *src++; if (Uisalnum(c) || c == '-' || c == '[' || c == ']' || c == ':') { *dst++ = c; if (commentp) *commentp = 0; } else if (c == '.') { if (dst > *domainp && dst[-1] != '.') *dst++ = c; if (commentp) *commentp = 0; } else if (c == '(') { if (commentp) { *commentp = cdst = src; comment = 1; while (comment && (c = *src)) { src++; if (c == '(') comment++; else if (c == ')') comment--; else if (c == '\\' && (c = *src)) src++; if (comment) *cdst++ = c; } *cdst = '\0'; } else { src--; SKIPWHITESPACE(src); } } else if (c == '@') { /* This domain name is garbage. Continue eating up the characters * until we get to a sane state. */ *invalid = 1; *dst++ = c; if (commentp) *commentp = 0; } else if (!Uisspace(c)) { if (dst > *domainp && dst[-1] == '.') dst--; *dst = '\0'; *inp = src; return c; } } }
/* * Parse a word from the string starting at the pointer pointed to by 's'. * Places a pointer to the parsed word in the pointer at 'retval', * returns the character following the word, and modifies the pointer at * 's' to point after the returned character. Modifies the input buffer. */ EXPORTED int imparse_word(char **s, char **retval) { int c; *retval = *s; for (;;) { c = *(*s)++; if (!c || Uisspace(c) || c == '(' || c == ')' || c == '\"') { (*s)[-1] = '\0'; return c; } } }
/* * Parse a domain. If 'commentp' is non-nil, parses any trailing comment */ static int parseaddr_domain(char **inp, char **domainp, char **commentp) { int c; char *src = *inp; char *dst; char *cdst; int comment; if (commentp) *commentp = 0; SKIPWHITESPACE(src); *domainp = dst = src; for (;;) { c = *src++; if (Uisalnum(c) || c == '-' || c == '[' || c == ']' || c == ':') { *dst++ = c; if (commentp) *commentp = 0; } else if (c == '.') { if (dst > *domainp && dst[-1] != '.') *dst++ = c; if (commentp) *commentp = 0; } else if (c == '(') { if (commentp) { *commentp = cdst = src; comment = 1; while (comment && (c = *src)) { src++; if (c == '(') comment++; else if (c == ')') comment--; else if (c == '\\' && (c = *src)) src++; if (comment) *cdst++ = c; } *cdst = '\0'; } else { src--; SKIPWHITESPACE(src); } } else if (!Uisspace(c)) { if (dst > *domainp && dst[-1] == '.') dst--; *dst = '\0'; *inp = src; return c; } } }
/* * Skip RFC822 FWS = Folding White Space. This is the white * space that can be inserted harmlessly into structured * RFC822 headers, including splitting them over multiple lines. * * Note that RFC822 isn't entirely clear about whether such * space may be present in date-times, but it's successor * RFC2822 is quite clear and explicit. Note also that * neither RFC allows for (comments) inside a date-time, * so we don't attempt to handle that here. */ static const char *skip_fws(const char *p) { if (!p) return NULL; while (*p && Uisspace(*p)) { /* check for end of an RFC822 header line */ if (*p == '\n') { p++; if (*p != ' ' && *p != '\t') return NULL; } else p++; } return (*p ? p : NULL); }
static void parse_data(const char *data, int datalen, struct seendata *sd) { /* remember that 'data' may not be null terminated ! */ const char *dend = data + datalen; char *p; int uidlen; int version; memset(sd, 0, sizeof(struct seendata)); version = strtol(data, &p, 10); data = p; assert(version == SEEN_VERSION); sd->lastread = strtol(data, &p, 10); data = p; sd->lastuid = strtoll(data, &p, 10); data = p; sd->lastchange = strtol(data, &p, 10); data = p; while (p < dend && Uisspace(*p)) p++; data = p; uidlen = dend - data; sd->seenuids = xmalloc(uidlen + 1); memcpy(sd->seenuids, data, uidlen); sd->seenuids[uidlen] = '\0'; }
char *find_free_server(void) { const char *servers = config_getstring(IMAPOPT_SERVERLIST); unsigned long max_avail = 0; char *server = NULL; if (servers) { char *tmpbuf, *cur_server, *next_server; char mytag[128]; struct backend *be; /* make a working copy of the list */ cur_server = tmpbuf = xstrdup(servers); while (cur_server) { /* eat any leading whitespace */ while (Uisspace(*cur_server)) cur_server++; if (!*cur_server) break; /* find end of server */ if ((next_server = strchr(cur_server, ' ')) || (next_server = strchr(cur_server, '\t'))) *next_server++ = '\0'; syslog(LOG_DEBUG, "checking free space on server '%s'", cur_server); /* connect to server */ be = proxy_findserver(cur_server, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); if (be) { unsigned avail = 0; int c; /* fetch annotation from remote */ proxy_gentag(mytag, sizeof(mytag)); prot_printf(be->out, "%s GETANNOTATION \"\" " "\"/vendor/cmu/cyrus-imapd/freespace\" " "\"value.shared\"\r\n", mytag); prot_flush(be->out); for (/* each annotation response */;;) { /* read a line */ c = prot_getc(be->in); if (c != '*') break; c = prot_getc(be->in); if (c != ' ') { /* protocol error */ c = EOF; break; } c = chomp(be->in, "ANNOTATION \"\" " "\"/vendor/cmu/cyrus-imapd/freespace\" " "(\"value.shared\" \""); if (c == EOF) { /* we don't care about this response */ eatline(be->in, c); continue; } /* read uidvalidity */ c = getuint32(be->in, &avail); if (c != '\"') { c = EOF; break; } eatline(be->in, c); /* we don't care about the rest of the line */ } if (c != EOF) { prot_ungetc(c, be->in); /* we should be looking at the tag now */ eatline(be->in, c); } if (c == EOF) { /* uh oh, we're not happy */ fatal("Lost connection to backend", EC_UNAVAILABLE); } if (avail > max_avail) { server = cur_server; max_avail = avail; } } /* move to next server */ cur_server = next_server; } if (server) server = xstrdup(server); free(tmpbuf); } return server; }
/* Determine if we should respond to a vacation message */ static int shouldRespond(void * m, sieve_interp_t *interp, int numaddresses, bytecode_input_t* bc, int i, char **from, char **to) { const char **body; char buf[128]; char *myaddr = NULL; int l = SIEVE_OK, j; int curra, x; char *found = NULL; char *reply_to = NULL; /* Implementations SHOULD NOT respond to any message that contains a "List-Id" [RFC2919], "List-Help", "List-Subscribe", "List- Unsubscribe", "List-Post", "List-Owner" or "List-Archive" [RFC2369] header field. */ for (j = 0; list_fields[j]; j++) { strcpy(buf, list_fields[j]); if (interp->getheader(m, buf, &body) == SIEVE_OK) { l = SIEVE_DONE; break; } } /* Implementations SHOULD NOT respond to any message that has an "Auto-submitted" header field with a value other than "no". This header field is described in [RFC3834]. */ strcpy(buf, "auto-submitted"); if (interp->getheader(m, buf, &body) == SIEVE_OK) { /* we don't deal with comments, etc. here */ /* skip leading white-space */ while (*body[0] && Uisspace(*body[0])) body[0]++; if (strcasecmp(body[0], "no")) l = SIEVE_DONE; } /* is there a Precedence keyword of "junk | bulk | list"? */ /* XXX non-standard header, but worth checking */ strcpy(buf, "precedence"); if (interp->getheader(m, buf, &body) == SIEVE_OK) { /* we don't deal with comments, etc. here */ /* skip leading white-space */ while (*body[0] && Uisspace(*body[0])) body[0]++; if (!strcasecmp(body[0], "junk") || !strcasecmp(body[0], "bulk") || !strcasecmp(body[0], "list")) l = SIEVE_DONE; } /* Note: the domain-part of all addresses are canonicalized */ /* grab my address from the envelope */ if (l == SIEVE_OK) { strcpy(buf, "to"); l = interp->getenvelope(m, buf, &body); if (body[0]) myaddr = address_canonicalise(body[0]); } if (l == SIEVE_OK) { strcpy(buf, "from"); l = interp->getenvelope(m, buf, &body); } if (l == SIEVE_OK && body[0]) { /* we have to parse this address & decide whether we want to respond to it */ reply_to = address_canonicalise(body[0]); /* first, is there a reply-to address? */ if (reply_to == NULL) { l = SIEVE_DONE; } /* first, is it from me? */ if (l == SIEVE_OK && myaddr && !strcmp(myaddr, reply_to)) { l = SIEVE_DONE; } /* ok, is it any of the other addresses i've specified? */ if (l == SIEVE_OK) { curra=i; for(x=0; x<numaddresses; x++) { const char *address; curra = unwrap_string(bc, curra, &address, NULL); if (!strcmp(address, reply_to)) l = SIEVE_DONE; } } /* ok, is it a system address? */ if (l == SIEVE_OK && sysaddr(reply_to)) { l = SIEVE_DONE; } } if (l == SIEVE_OK) { /* ok, we're willing to respond to the sender. but is this message to me? that is, is my address in the [Resent]-To, [Resent]-Cc or [Resent]-Bcc fields? */ if (strcpy(buf, "to"), interp->getheader(m, buf, &body) == SIEVE_OK) found = look_for_me(myaddr, numaddresses ,bc, i, body); if (!found && (strcpy(buf, "cc"), (interp->getheader(m, buf, &body) == SIEVE_OK))) found = look_for_me(myaddr, numaddresses, bc, i, body); if (!found && (strcpy(buf, "bcc"), (interp->getheader(m, buf, &body) == SIEVE_OK))) found = look_for_me(myaddr, numaddresses, bc, i, body); if (!found && (strcpy(buf, "resent-to"), (interp->getheader(m, buf, &body) == SIEVE_OK))) found = look_for_me(myaddr, numaddresses ,bc, i, body); if (!found && (strcpy(buf, "resent-cc"), (interp->getheader(m, buf, &body) == SIEVE_OK))) found = look_for_me(myaddr, numaddresses, bc, i, body); if (!found && (strcpy(buf, "resent-bcc"), (interp->getheader(m, buf, &body) == SIEVE_OK))) found = look_for_me(myaddr, numaddresses, bc, i, body); if (!found) l = SIEVE_DONE; } /* ok, ok, if we got here maybe we should reply */ if (myaddr) free(myaddr); *from = found; *to = reply_to; return l; }
void masterconf_getsection(const char *section, masterconf_process *f, void *rock) { FILE *infile = NULL; int seclen = strlen(section); int level = 0; int lineno = 0; char buf[4096]; const char *cyrus_path; /* try loading the copy inside CYRUS_PREFIX first */ cyrus_path = getenv("CYRUS_PREFIX"); if (cyrus_path) { strlcpy(buf, cyrus_path, sizeof(buf)); strlcat(buf, MASTER_CONFIG_FILENAME, sizeof(buf)); infile = fopen(buf, "r"); } if (!infile) infile = fopen(MASTER_CONFIG_FILENAME, "r"); if (!infile) fatalf(EX_CONFIG, "can't open configuration file %s: %m", MASTER_CONFIG_FILENAME); while (fgets(buf, sizeof(buf), infile)) { char *p, *q; lineno++; if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; for (p = buf; *p && Uisspace(*p); p++); /* remove comments */ q = strchr(p, '#'); if (q) *q = '\0'; /* skip empty lines or all comment lines */ if (!*p) continue; if (level == 0 && *p == *section && !strncasecmp(p, section, seclen) && !Uisalnum(p[seclen])) { for (p += seclen; *p; p++) { if (*p == '{') level++; if (*p == '}') level--; } /* valid opening; process the section */ if (level == 1) process_section(infile, &lineno, f, rock); continue; } for (; *p; p++) { if (*p == '{') level++; if (*p == '}') level--; } } fclose(infile); }
static char next_nonspace(struct protstream *in, char c) { while (Uisspace(c)) c = prot_getc(in); return c; }
/* ** Parse the expiration control file. Return TRUE if okay. */ BOOL EXPreadfile(FILE *F) { char *p; int i; int j; int k; char mod; NEWSGROUP v; BOOL SawDefault; char buff[BUFSIZ]; char *fields[7]; char **patterns; /* Scan all lines. */ EXPremember = -1; SawDefault = FALSE; patterns = NEW(char*, nGroups); for (i = 0; i < NUM_STORAGE_CLASSES; i++) EXPclasses[i].ReportedMissing = EXPclasses[i].Missing = TRUE; for (i = 1; fgets(buff, sizeof buff, F) != NULL; i++) { if ((p = strchr(buff, '\n')) == NULL) { (void)fprintf(stderr, "Line %d too long\n", i); return FALSE; } *p = '\0'; p = strchr(buff, '#'); if (p) *p = '\0'; else p = buff + strlen(buff); while (--p >= buff) { if (Uisspace(*p)) *p = '\0'; else break; } if (buff[0] == '\0') continue; if ((j = EXPsplit(buff, ':', fields, SIZEOF(fields))) == -1) { (void)fprintf(stderr, "Line %d too many fields\n", i); return FALSE; } /* Expired-article remember line? */ if (EQ(fields[0], "/remember/")) { if (j != 2) { (void)fprintf(stderr, "Line %d bad format\n", i); return FALSE; } if (EXPremember != -1) { (void)fprintf(stderr, "Line %d duplicate /remember/\n", i); return FALSE; } if (!EXPgetnum(i, fields[1], &EXPremember, "remember")) return FALSE; continue; } /* Storage class line? */ if (j == 4) { j = atoi(fields[0]); if ((j < 0) || (j > NUM_STORAGE_CLASSES)) { fprintf(stderr, "Line %d bad storage class %d\n", i, j); } if (!EXPgetnum(i, fields[1], &EXPclasses[j].Keep, "keep") || !EXPgetnum(i, fields[2], &EXPclasses[j].Default, "default") || !EXPgetnum(i, fields[3], &EXPclasses[j].Purge, "purge")) return FALSE; /* These were turned into offsets, so the test is the opposite * of what you think it should be. If Purge isn't forever, * make sure it's greater then the other two fields. */ if (EXPclasses[j].Purge) { /* Some value not forever; make sure other values are in range. */ if (EXPclasses[j].Keep && EXPclasses[j].Keep < EXPclasses[j].Purge) { (void)fprintf(stderr, "Line %d keep>purge\n", i); return FALSE; } if (EXPclasses[j].Default && EXPclasses[j].Default < EXPclasses[j].Purge) { (void)fprintf(stderr, "Line %d default>purge\n", i); return FALSE; } } EXPclasses[j].Missing = FALSE; continue; } /* Regular expiration line -- right number of fields? */ if (j != 5) { (void)fprintf(stderr, "Line %d bad format\n", i); return FALSE; } /* Parse the fields. */ if (strchr(fields[1], 'M') != NULL) mod = 'm'; else if (strchr(fields[1], 'U') != NULL) mod = 'u'; else if (strchr(fields[1], 'A') != NULL) mod = 'a'; else { (void)fprintf(stderr, "Line %d bad modflag\n", i); return FALSE; } v.Poison = (strchr(fields[1], 'X') != NULL); if (!EXPgetnum(i, fields[2], &v.Keep, "keep") || !EXPgetnum(i, fields[3], &v.Default, "default") || !EXPgetnum(i, fields[4], &v.Purge, "purge")) return FALSE; /* These were turned into offsets, so the test is the opposite * of what you think it should be. If Purge isn't forever, * make sure it's greater then the other two fields. */ if (v.Purge) { /* Some value not forever; make sure other values are in range. */ if (v.Keep && v.Keep < v.Purge) { (void)fprintf(stderr, "Line %d keep>purge\n", i); return FALSE; } if (v.Default && v.Default < v.Purge) { (void)fprintf(stderr, "Line %d default>purge\n", i); return FALSE; } } /* Is this the default line? */ if (fields[0][0] == '*' && fields[0][1] == '\0' && mod == 'a') { if (SawDefault) { (void)fprintf(stderr, "Line %d duplicate default\n", i); return FALSE; } EXPdefault.Keep = v.Keep; EXPdefault.Default = v.Default; EXPdefault.Purge = v.Purge; EXPdefault.Poison = v.Poison; SawDefault = TRUE; } /* Assign to all groups that match the pattern and flags. */ if ((j = EXPsplit(fields[0], ',', patterns, nGroups)) == -1) { (void)fprintf(stderr, "Line %d too many patterns\n", i); return FALSE; } for (k = 0; k < j; k++) EXPmatch(patterns[k], &v, mod); } DISPOSE(patterns); return TRUE; }