static Xapian::Stopper *get_stopper() { Xapian::Stopper *stopper = NULL; const char *swpath = config_getstring(IMAPOPT_SEARCH_STOPWORD_PATH); if (swpath) { // Set path to stopword file struct buf buf = BUF_INITIALIZER; buf_setcstr(&buf, swpath); // XXX doesn't play nice with WIN32 paths buf_appendcstr(&buf, "/english.list"); // Open the stopword file errno = 0; std::ifstream inFile (buf_cstring(&buf)); if (inFile.fail()) { syslog(LOG_ERR, "Xapian: could not open stopword file %s: %s", buf_cstring(&buf), errno ? strerror(errno) : "unknown error"); exit(1); } // Create the Xapian stopper stopper = new Xapian::SimpleStopper( std::istream_iterator<std::string>(inFile), std::istream_iterator<std::string>()); // Clean up buf_free(&buf); } return stopper; }
static int compact_open(const char *name, struct backup **originalp, struct backup **compactp, enum backup_open_nonblock nonblock) { struct backup *original = NULL; struct backup *compact = NULL; struct buf original_data_fname = BUF_INITIALIZER; struct buf original_index_fname = BUF_INITIALIZER; struct buf compact_data_fname = BUF_INITIALIZER; struct buf compact_index_fname = BUF_INITIALIZER; int r; buf_printf(&original_data_fname, "%s", name); buf_printf(&original_index_fname, "%s.index", name); buf_printf(&compact_data_fname, "%s.new", name); buf_printf(&compact_index_fname, "%s.index.new", name); r = backup_real_open(&original, buf_cstring(&original_data_fname), buf_cstring(&original_index_fname), BACKUP_OPEN_NOREINDEX, nonblock, BACKUP_OPEN_NOCREATE); if (r) goto done; r = backup_real_open(&compact, buf_cstring(&compact_data_fname), buf_cstring(&compact_index_fname), BACKUP_OPEN_NOREINDEX, BACKUP_OPEN_NONBLOCK, // FIXME think about this BACKUP_OPEN_CREATE_EXCL); if (r) { backup_close(&original); goto done; } *originalp = original; *compactp = compact; done: buf_free(&original_data_fname); buf_free(&original_index_fname); buf_free(&compact_data_fname); buf_free(&compact_index_fname); return r; }
static void encode(const char *ps, int len, struct buf *buf) { const unsigned char *p = (const unsigned char *)ps; buf_reset(buf); /* allocate enough space plus a little slop to cover * escaping a few characters */ buf_ensure(buf, len+10); for ( ; len > 0 ; len--, p++) { switch (*p) { case '\0': case '\t': case '\r': case '\n': buf_putc(buf, ESCAPE); buf_putc(buf, 0x80|(*p)); break; case ESCAPE: buf_putc(buf, ESCAPE); buf_putc(buf, ESCAPE); break; default: buf_putc(buf, *p); break; } } /* ensure the buf is NUL-terminated; we pass the buf's data to * bsearch_mem(), which expects a C string, several times */ buf_cstring(buf); }
static int denydb_foreach_cb(void *rock, const char *key, size_t keylen, const char *data, size_t datalen) { struct denydb_rock *dr = (struct denydb_rock *)rock; struct buf user = BUF_INITIALIZER; struct buf buf = BUF_INITIALIZER; char *wild = NULL; const char *msg = NULL; int r; /* ensure we have a nul-terminated user string */ buf_appendmap(&user, key, keylen); buf_cstring(&user); /* get fields from the record */ buf_init_ro(&buf, data, datalen); r = parse_record(&buf, &wild, &msg); if (r) { syslog(LOG_WARNING, "DENYDB_ERROR: invalid entry for '%s'", user.s); r = 0; /* whatever, keep going */ goto out; } r = dr->proc(user.s, wild, msg, dr->rock); out: buf_free(&user); buf_free(&buf); return r; }
static int ping(struct backend *s, const char *userid) { unsigned code = 0; const char *errstr; hdrcache_t resp_hdrs = NULL; struct body_t resp_body; /* Send Authorization request to server */ prot_puts(s->out, "OPTIONS * HTTP/1.1\r\n"); prot_printf(s->out, "Host: %s\r\n", s->hostname); prot_printf(s->out, "User-Agent: %s\r\n", buf_cstring(&serverinfo)); prot_printf(s->out, "Authorize-As: %s\r\n", userid ? userid : "anonymous"); prot_puts(s->out, "\r\n"); prot_flush(s->out); /* Read response(s) from backend until final response or error */ do { resp_body.flags = BODY_DISCARD; if (http_read_response(s, METH_OPTIONS, &code, NULL, &resp_hdrs, &resp_body, &errstr)) { break; } } while (code < 200); if (resp_hdrs) spool_free_hdrcache(resp_hdrs); return (code != 200); }
/* parse the data */ static int parse_record(struct buf *buf, char **wildp, const char **msgp) { const char *msg = default_message; char *wild; unsigned long version; buf_cstring(buf); /* use a working copy */ /* check version */ if (((version = strtoul(buf->s, &wild, 10)) < 1) || (version > USERDENY_VERSION)) return IMAP_MAILBOX_BADFORMAT; if (*wild++ != '\t') return IMAP_MAILBOX_BADFORMAT; /* check if we have a deny message */ if (version == USERDENY_VERSION) { char *p = strchr(wild, '\t'); if (p) { *p++ = '\0'; msg = p; } } *wildp = wild; *msgp = msg; return 0; }
static const char *column_text_to_buf(const char *text, struct buf *buf) { if (text) { buf_setcstr(buf, text); text = buf_cstring(buf); } return text; }
static void append_byrule(char *byrule, struct buf *vals, struct buf *rrule) { /* append BY* rule to RRULE buffer */ buf_printf(rrule, ";%s=%s", ucase(byrule), buf_cstring(vals)); /* free the vals buffer */ buf_free(vals); free(vals); }
EXPORTED sqldb_t *dav_open_mailbox(struct mailbox *mailbox) { sqldb_t *db = NULL; struct buf fname = BUF_INITIALIZER; dav_getpath(&fname, mailbox); if (in_reconstruct) buf_printf(&fname, ".NEW"); db = sqldb_open(buf_cstring(&fname), CMD_CREATE, DB_VERSION, davdb_upgrade); buf_free(&fname); return db; }
EXPORTED sqldb_t *dav_open_userid(const char *userid) { sqldb_t *db = NULL; struct buf fname = BUF_INITIALIZER; dav_getpath_byuserid(&fname, userid); if (in_reconstruct) buf_printf(&fname, ".NEW"); db = sqldb_open(buf_cstring(&fname), CMD_CREATE, DB_VERSION, davdb_upgrade); buf_free(&fname); return db; }
static int my_mkparentdir(const char *fname) { struct buf buf = BUF_INITIALIZER; int r; buf_setcstr(&buf, fname); r = cyrus_mkdir(buf_cstring(&buf), 0755); buf_free(&buf); return r; }
static int compact_closerename(struct backup **originalp, struct backup **compactp, time_t now) { struct backup *original = *originalp; struct backup *compact = *compactp; struct buf ts_data_fname = BUF_INITIALIZER; struct buf ts_index_fname = BUF_INITIALIZER; int r; buf_printf(&ts_data_fname, "%s.%ld", original->data_fname, now); buf_printf(&ts_index_fname, "%s.%ld", original->index_fname, now); /* link original files into timestamped names */ r = link(original->data_fname, buf_cstring(&ts_data_fname)); if (!r) link(original->index_fname, buf_cstring(&ts_index_fname)); if (r) { /* on error, trash the new links and bail out */ unlink(buf_cstring(&ts_data_fname)); unlink(buf_cstring(&ts_index_fname)); goto done; } /* replace original files with compacted files */ r = rename(compact->data_fname, original->data_fname); if (!r) r = rename(compact->index_fname, original->index_fname); if (r) { /* on error, put original files back */ unlink(original->data_fname); unlink(original->index_fname); link(buf_cstring(&ts_data_fname), original->data_fname); link(buf_cstring(&ts_index_fname), original->index_fname); goto done; } /* finally, clean up the timestamped ones */ if (!config_getswitch(IMAPOPT_BACKUP_KEEP_PREVIOUS)) { unlink(buf_cstring(&ts_data_fname)); unlink(buf_cstring(&ts_index_fname)); } /* release our locks */ backup_close(originalp); backup_close(compactp); done: buf_free(&ts_data_fname); buf_free(&ts_index_fname); return r; }
icalcomponent *record_to_ical(struct mailbox *mailbox, const struct index_record *record) { struct buf buf = BUF_INITIALIZER; icalcomponent *ical = NULL; /* Load message containing the resource and parse iCal data */ if (!mailbox_map_record(mailbox, record, &buf)) { ical = icalparser_parse_string(buf_cstring(&buf) + record->header_size); buf_free(&buf); } return ical; }
static int show_message_headers(const struct buf *buf, void *rock) { FILE *out = (FILE *) rock; const char *start = buf_cstring(buf); const char *end = strstr(start, "\r\n\r\n"); if (!end) return -1; fwrite(start, 1, end - start, out); fputs("\r\n", out); return 0; }
static struct vparse_state *vcard_string_as_vparser(const struct buf *buf) { struct vparse_state *vparser; int vr; vparser = (struct vparse_state *) xzmalloc(sizeof(struct vparse_state)); vparser->base = buf_cstring(buf); vparse_set_multival(vparser, "adr"); vparse_set_multival(vparser, "org"); vparse_set_multival(vparser, "n"); vr = vparse_parse(vparser, 0); if (vr) return NULL; // XXX report error return vparser; }
static int do_restart() { static int restartcnt = 0; if (sync_out->userdata) { /* IMAP flavor (w/ tag) */ struct buf *tag = (struct buf *) sync_out->userdata; buf_reset(tag); buf_printf(tag, "R%d", restartcnt++); prot_printf(sync_out, "%s SYNC", buf_cstring(tag)); } prot_printf(sync_out, "RESTART\r\n"); prot_flush(sync_out); return sync_parse_response("RESTART", sync_in, NULL); }
/* Match the response code to an expected return code defined in rock. * * Rock must be a zero-terminated string up to length 3 (excluding the * NUL byte). Matching is performed by string matching the SMTP return * code to the expected code, stopping at the zero byte. * * E.g. return code "250", "251" both would match a "2" or "25" rock. * * Also see Daniel Bernstein's site https://cr.yp.to/smtp/request.html: * "I recommend that clients avoid looking past the first digit of the * code, either 2, 3, 4, or 5. The other two digits and the text are * primarily for human consumption. (Exception: See EHLO.)" * * Return IMAP_PROTOCOL_ERROR on mismatch, 0 on success. */ static int expect_code_cb(smtpclient_t *sm, void *rock) { size_t i; const char *code = rock; smtp_resp_t *resp = &sm->resp; for (i = 0; i < 3 && code[i]; i++) { if (code[i] != resp->code[i]) { const char *text = buf_cstring(&resp->text); syslog(LOG_ERR, "smtpclient: unexpected response: code=%c%c%c text=%s", resp->code[0], resp->code[1], resp->code[2], text); /* Try to glean specific error from response */ if (CAPA(sm->backend, SMTPCLIENT_CAPA_STATUS)) { if (text[2] == '1' && text[4] >= '1' && text[4] <= '3') return IMAP_MAILBOX_NONEXISTENT; else if (text[2] == '3' && text[4] == '4') return IMAP_MESSAGE_TOO_LARGE; else if (text[2] == '5' && text[4] == '3') return IMAP_MAILBOX_DISABLED; else if (text[2] == '3' && text[4] == '0') return IMAP_REMOTE_DENIED; } else { switch (atoi(resp->code)) { case 421: case 451: case 554: return IMAP_REMOTE_DENIED; case 450: case 550: return IMAP_MAILBOX_DISABLED; case 452: case 552: return IMAP_MESSAGE_TOO_LARGE; case 553: return IMAP_MAILBOX_NONEXISTENT; } } return IMAP_PROTOCOL_ERROR; } } return 0; }
static int send_notify_callback(sieve_interp_t *interp, void *message_context, void *script_context, notify_list_t *notify, char *actions_string, const char **errmsg) { sieve_notify_context_t nc; struct buf out = BUF_INITIALIZER; int ret; assert(notify->isactive); if (!notify->method || !notify->options || !notify->priority || !notify->message) { return SIEVE_RUN_ERROR; } nc.method = notify->method; nc.options = notify->options ? notify->options : NULL; nc.priority = notify->priority; if(nc.options && !strcmp(nc.method,"mailto")) if(!strcmp("$env-from$",*nc.options)) interp->getenvelope(message_context, "From", &nc.options); build_notify_message(interp, notify->message, message_context, &out); buf_appendcstr(&out, "\n\n"); buf_appendcstr(&out, actions_string); nc.message = buf_cstring(&out); nc.fname = NULL; if (interp->getfname) interp->getfname(message_context, &nc.fname); ret = interp->notify(&nc, interp->interp_context, script_context, message_context, errmsg); buf_free(&out); return ret; }
/* Print the build information as flattened properties, prefixed by * the contents of buf. */ static void format_flat(json_t *buildinfo, struct buf *buf) { const char *key; json_t *val; json_object_foreach(buildinfo, key, val) { buf_appendcstr(buf, key); if (json_typeof(val) == JSON_OBJECT) { buf_appendcstr(buf, "."); format_flat(val, buf); buf_truncate(buf, -1); } else { char *jval = json_dumps(val, JSON_ENCODE_ANY); buf_appendcstr(buf, "="); buf_appendcstr(buf, jval); printf("%s\n", buf_cstring(buf)); buf_truncate(buf, -strlen(jval)-1); free(jval); } buf_truncate(buf, -strlen(key)); }
HIDDEN int backup_index(struct backup *backup, struct dlist *dlist, time_t ts, off_t start, size_t len) { int r = IMAP_PROTOCOL_ERROR; if (strcmp(dlist->name, "EXPUNGE") == 0) r = _index_expunge(backup, dlist, ts, start); else if (strcmp(dlist->name, "MAILBOX") == 0) r = _index_mailbox(backup, dlist, ts, start); else if (strcmp(dlist->name, "UNMAILBOX") == 0) r = _index_unmailbox(backup, dlist, ts, start); else if (strcmp(dlist->name, "MESSAGE") == 0) r = _index_message(backup, dlist, ts, start, len); else if (strcmp(dlist->name, "RENAME") == 0) r = _index_rename(backup, dlist, ts, start); else if (strcmp(dlist->name, "RESERVE") == 0) r = 0; /* nothing to index for a reserve, just return success */ else if (strcmp(dlist->name, "SEEN") == 0) r = _index_seen(backup, dlist, ts, start); else if (strcmp(dlist->name, "SUB") == 0) r = _index_sub(backup, dlist, ts, start); else if (strcmp(dlist->name, "UNSUB") == 0) r = _index_sub(backup, dlist, ts, start); else if (strcmp(dlist->name, "SIEVE") == 0) r = _index_sieve(backup, dlist, ts, start); else if (strcmp(dlist->name, "UNSIEVE") == 0) r = _index_sieve(backup, dlist, ts, start); else if (config_debug) { struct buf tmp = BUF_INITIALIZER; dlist_printbuf(dlist, 1, &tmp); syslog(LOG_DEBUG, "ignoring unrecognised dlist: %s\n", buf_cstring(&tmp)); buf_free(&tmp); } return r; }
/* * Construct an iCalendar property from a XML element. */ static icalproperty *xml_element_to_icalproperty(xmlNodePtr xprop) { const char *propname, *typestr; icalproperty_kind kind; icalproperty *prop = NULL; icalvalue_kind valkind; icalvalue *value; xmlNodePtr node; /* Get the property type */ propname = ucase(icalmemory_tmp_copy((const char *) xprop->name)); kind = icalenum_string_to_property_kind(propname); if (kind == ICAL_NO_PROPERTY) { syslog(LOG_WARNING, "Unknown xCal property type: %s", propname); return NULL; } /* Create new property */ prop = icalproperty_new(kind); if (!prop) { syslog(LOG_ERR, "Creation of new %s property failed", propname); return NULL; } if (kind == ICAL_X_PROPERTY) icalproperty_set_x_name(prop, propname); /* Add parameters */ node = xmlFirstElementChild(xprop); if (node && !xmlStrcmp(node->name, BAD_CAST "parameters")) { xmlNodePtr xparam; for (xparam = xmlFirstElementChild(node); xparam; xparam = xmlNextElementSibling(xparam)) { char *paramname = ucase(icalmemory_tmp_copy((const char *) xparam->name)); xmlChar *paramval = xmlNodeGetContent(xmlFirstElementChild(xparam)); /* XXX Need to handle multi-valued parameters */ icalproperty_set_parameter_from_string(prop, paramname, (const char *) paramval); xmlFree(paramval); } node = xmlNextElementSibling(node); } /* Get the value type */ if (!node) { syslog(LOG_WARNING, "Missing xCal value for %s property", propname); return NULL; } typestr = ucase(icalmemory_tmp_copy((const char *) node->name)); valkind = !strcmp(typestr, "UNKNOWN") ? ICAL_X_VALUE : icalenum_string_to_value_kind(typestr); if (valkind == ICAL_NO_VALUE) { syslog(LOG_WARNING, "Unknown xCal value type for %s property: %s", propname, typestr); return NULL; } else if (valkind == ICAL_TEXT_VALUE) { /* "text" also includes enumerated types - grab type from property */ valkind = icalproperty_kind_to_value_kind(kind); } /* Add value */ switch (kind) { case ICAL_CATEGORIES_PROPERTY: case ICAL_RESOURCES_PROPERTY: case ICAL_POLLPROPERTIES_PROPERTY: if (valkind == ICAL_TEXT_VALUE) { /* Handle multi-valued properties */ struct buf buf = BUF_INITIALIZER; xmlChar *content = NULL; content = xmlNodeGetContent(node); buf_setcstr(&buf, (const char *) content); free(content); while ((node = xmlNextElementSibling(node))) { buf_putc(&buf, ','); content = xmlNodeGetContent(node); buf_appendcstr(&buf, (const char *) content); free(content); } value = icalvalue_new_from_string(valkind, buf_cstring(&buf)); buf_free(&buf); break; } default: value = xml_element_to_icalvalue(node, valkind); if (!value) { syslog(LOG_ERR, "Parsing %s property value failed", propname); goto error; } } icalproperty_set_value(prop, value); /* Sanity check */ if ((node = xmlNextElementSibling(node))) { syslog(LOG_WARNING, "Unexpected XML element in property: %s", node->name); goto error; } return prop; error: icalproperty_free(prop); return NULL; }
/* * Construct an iCalendar property value from XML content. */ static icalvalue *xml_element_to_icalvalue(xmlNodePtr xtype, icalvalue_kind kind) { icalvalue *value = NULL; xmlNodePtr node; xmlChar *content = NULL; switch (kind) { case ICAL_GEO_VALUE: { struct icalgeotype geo; node = xmlFirstElementChild(xtype); if (!node) { syslog(LOG_WARNING, "Missing <latitude> XML element"); break; } else if (xmlStrcmp(node->name, BAD_CAST "latitude")) { syslog(LOG_WARNING, "Expected <latitude> XML element, received %s", node->name); break; } content = xmlNodeGetContent(node); geo.lat = atof((const char *) content); node = xmlNextElementSibling(node); if (!node) { syslog(LOG_WARNING, "Missing <longitude> XML element"); break; } else if (xmlStrcmp(node->name, BAD_CAST "longitude")) { syslog(LOG_WARNING, "Expected <longitude> XML element, received %s", node->name); break; } xmlFree(content); content = xmlNodeGetContent(node); geo.lon = atof((const char *) content); value = icalvalue_new_geo(geo); break; } case ICAL_PERIOD_VALUE: { struct icalperiodtype p; p.start = p.end = icaltime_null_time(); p.duration = icaldurationtype_from_int(0); node = xmlFirstElementChild(xtype); if (!node) { syslog(LOG_WARNING, "Missing <start> XML element"); break; } else if (xmlStrcmp(node->name, BAD_CAST "start")) { syslog(LOG_WARNING, "Expected <start> XML element, received %s", node->name); break; } content = xmlNodeGetContent(node); p.start = icaltime_from_string((const char *) content); if (icaltime_is_null_time(p.start)) break; node = xmlNextElementSibling(node); if (!node) { syslog(LOG_WARNING, "Missing <end> / <duration> XML element"); break; } else if (!xmlStrcmp(node->name, BAD_CAST "end")) { xmlFree(content); content = xmlNodeGetContent(node); p.end = icaltime_from_string((const char *) content); if (icaltime_is_null_time(p.end)) break; } else if (!xmlStrcmp(node->name, BAD_CAST "duration")) { xmlFree(content); content = xmlNodeGetContent(node); p.duration = icaldurationtype_from_string((const char *) content); if (icaldurationtype_as_int(p.duration) == 0) break; } else { syslog(LOG_WARNING, "Expected <end> / <duration> XML element, received %s", node->name); break; } value = icalvalue_new_period(p); break; } case ICAL_RECUR_VALUE: { struct buf rrule = BUF_INITIALIZER; struct hash_table byrules; struct icalrecurrencetype rt; char *sep = ""; construct_hash_table(&byrules, 10, 1); /* create an iCal RRULE string from xCal <recur> sub-elements */ for (node = xmlFirstElementChild(xtype); node; node = xmlNextElementSibling(node)) { content = xmlNodeGetContent(node); if (!xmlStrncmp(node->name, BAD_CAST "by", 2)) { /* BY* rules can have a list of values - assemble them using a hash table */ struct buf *vals = hash_lookup((const char *) node->name, &byrules); if (vals) { /* append this value to existing list */ buf_printf(vals, ",%s", (char *) content); } else { /* create new list with this valiue */ vals = xzmalloc(sizeof(struct buf)); buf_setcstr(vals, (char *) content); hash_insert((char *) node->name, vals, &byrules); } } else { /* single value rpart */ buf_printf(&rrule, "%s%s=%s", sep, ucase((char *) node->name), (char *) content); sep = ";"; } xmlFree(content); content = NULL; } /* append the BY* rules to RRULE buffer */ hash_enumerate(&byrules, (void (*)(const char*, void*, void*)) &append_byrule, &rrule); free_hash_table(&byrules, NULL); /* parse our iCal RRULE string */ rt = icalrecurrencetype_from_string(buf_cstring(&rrule)); buf_free(&rrule); if (rt.freq != ICAL_NO_RECURRENCE) value = icalvalue_new_recur(rt); break; } case ICAL_REQUESTSTATUS_VALUE: { struct icalreqstattype rst = { ICAL_UNKNOWN_STATUS, NULL, NULL }; short maj, min; node = xmlFirstElementChild(xtype); if (!node) { syslog(LOG_WARNING, "Missing <code> XML element"); break; } else if (xmlStrcmp(node->name, BAD_CAST "code")) { syslog(LOG_WARNING, "Expected <code> XML element, received %s", node->name); break; } content = xmlNodeGetContent(node); if (sscanf((const char *) content, "%hd.%hd", &maj, &min) == 2) { rst.code = icalenum_num_to_reqstat(maj, min); } if (rst.code == ICAL_UNKNOWN_STATUS) { syslog(LOG_WARNING, "Unknown request-status code"); break; } node = xmlNextElementSibling(node); if (!node) { syslog(LOG_WARNING, "Missing <description> XML element"); break; } else if (xmlStrcmp(node->name, BAD_CAST "description")) { syslog(LOG_WARNING, "Expected <description> XML element, received %s", node->name); break; } xmlFree(content); content = xmlNodeGetContent(node); rst.desc = (const char *) content; node = xmlNextElementSibling(node); if (node) { if (xmlStrcmp(node->name, BAD_CAST "data")) { syslog(LOG_WARNING, "Expected <data> XML element, received %s", node->name); break; } xmlFree(content); content = xmlNodeGetContent(node); rst.debug = (const char *) content; } value = icalvalue_new_requeststatus(rst); break; } case ICAL_UTCOFFSET_VALUE: { int n, utcoffset, hours, minutes, seconds = 0; char sign; content = xmlNodeGetContent(xtype); n = sscanf((const char *) content, "%c%02d:%02d:%02d", &sign, &hours, &minutes, &seconds); if (n < 3) { syslog(LOG_WARNING, "Unexpected utc-offset format"); break; } utcoffset = hours*3600 + minutes*60 + seconds; if (sign == '-') utcoffset = -utcoffset; value = icalvalue_new_utcoffset(utcoffset); break; } default: content = xmlNodeGetContent(xtype); value = icalvalue_new_from_string(kind, (const char *) content); break; } if (content) xmlFree(content); return value; }
int main(int argc, char **argv) { int opt, r = 0; char *alt_config = NULL, *pub = NULL, *ver = NULL, *winfile = NULL; char prefix[2048]; enum { REBUILD, WINZONES, NONE } op = NONE; if ((geteuid()) == 0 && (become_cyrus(/*ismaster*/0) != 0)) { fatal("must run as the Cyrus user", EC_USAGE); } while ((opt = getopt(argc, argv, "C:r:vw:")) != EOF) { switch (opt) { case 'C': /* alt config file */ alt_config = optarg; break; case 'r': if (op == NONE) { op = REBUILD; pub = optarg; ver = strchr(optarg, ':'); if (ver) *ver++ = '\0'; else usage(); } else usage(); break; case 'v': verbose = 1; break; case 'w': if (op == NONE) { op = WINZONES; winfile = optarg; } else usage(); break; default: usage(); } } cyrus_init(alt_config, "ctl_zoneinfo", 0, 0); signals_set_shutdown(&shut_down); signals_add_handlers(0); snprintf(prefix, sizeof(prefix), "%s%s", config_dir, FNAME_ZONEINFODIR); switch (op) { case REBUILD: { struct hash_table tzentries; struct zoneinfo *info; struct txn *tid = NULL; char buf[1024]; FILE *fp; construct_hash_table(&tzentries, 500, 1); /* Add INFO record (overall lastmod and TZ DB source version) */ info = xzmalloc(sizeof(struct zoneinfo)); info->type = ZI_INFO; appendstrlist(&info->data, pub); appendstrlist(&info->data, ver); hash_insert(INFO_TZID, info, &tzentries); /* Add LEAP record (last updated and hash) */ snprintf(buf, sizeof(buf), "%s%s", prefix, FNAME_LEAPSECFILE); if (verbose) printf("Processing leap seconds file %s\n", buf); if (!(fp = fopen(buf, "r"))) { fprintf(stderr, "Could not open leap seconds file %s\n", buf); } else { struct zoneinfo *leap = xzmalloc(sizeof(struct zoneinfo)); leap->type = ZI_INFO; while(fgets(buf, sizeof(buf), fp)) { if (buf[0] == '#') { /* comment line */ if (buf[1] == '$') { /* last updated */ unsigned long last; sscanf(buf+2, "\t%lu", &last); leap->dtstamp = last - NIST_EPOCH_OFFSET; } else if (buf[1] == 'h') { /* hash */ char *p, *hash = buf+3 /* skip "#h\t" */; /* trim trailing whitespace */ for (p = hash + strlen(hash); isspace(*--p); *p = '\0'); appendstrlist(&leap->data, hash); } } } fclose(fp); hash_insert(LEAP_TZID, leap, &tzentries); info->dtstamp = leap->dtstamp; } /* Add ZONE/LINK records */ do_zonedir(prefix, &tzentries, info); zoneinfo_open(NULL); /* Store records */ hash_enumerate(&tzentries, &store_zoneinfo, &tid); zoneinfo_close(tid); free_hash_table(&tzentries, &free_zoneinfo); break; } case WINZONES: { xmlParserCtxtPtr ctxt; xmlDocPtr doc; xmlNodePtr node; struct buf tzidbuf = BUF_INITIALIZER; struct buf aliasbuf = BUF_INITIALIZER; if (verbose) printf("Processing Windows Zone file %s\n", winfile); /* Parse the XML file */ ctxt = xmlNewParserCtxt(); if (!ctxt) { fprintf(stderr, "Failed to create XML parser context\n"); break; } doc = xmlCtxtReadFile(ctxt, winfile, NULL, 0); xmlFreeParserCtxt(ctxt); if (!doc) { fprintf(stderr, "Failed to parse XML document\n"); break; } node = xmlDocGetRootElement(doc); if (!node || xmlStrcmp(node->name, BAD_CAST "supplementalData")) { fprintf(stderr, "Incorrect root node\n"); goto done; } for (node = xmlFirstElementChild(node); node && xmlStrcmp(node->name, BAD_CAST "windowsZones"); node = xmlNextElementSibling(node)); if (!node) { fprintf(stderr, "Missing windowsZones node\n"); goto done; } node = xmlFirstElementChild(node); if (!node || xmlStrcmp(node->name, BAD_CAST "mapTimezones")) { fprintf(stderr, "Missing mapTimezones node\n"); goto done; } if (chdir(prefix)) { fprintf(stderr, "chdir(%s) failed\n", prefix); goto done; } for (node = xmlFirstElementChild(node); node; node = xmlNextElementSibling(node)) { if (!xmlStrcmp(node->name, BAD_CAST "mapZone") && !xmlStrcmp(xmlGetProp(node, BAD_CAST "territory"), BAD_CAST "001")) { const char *tzid, *alias; buf_setcstr(&tzidbuf, (const char *) xmlGetProp(node, BAD_CAST "type")); buf_appendcstr(&tzidbuf, ".ics"); tzid = buf_cstring(&tzidbuf); buf_setcstr(&aliasbuf, (const char *) xmlGetProp(node, BAD_CAST "other")); buf_appendcstr(&aliasbuf, ".ics"); alias = buf_cstring(&aliasbuf); if (verbose) printf("\tLINK: %s -> %s\n", alias, tzid); if (symlink(tzid, alias)) { if (errno == EEXIST) { struct stat sbuf; if (stat(alias, &sbuf)) { fprintf(stderr, "stat(%s) failed: %s\n", alias, strerror(errno)); errno = EEXIST; } else if (sbuf.st_mode & S_IFLNK) { char link[MAX_MAILBOX_PATH+1]; int n = readlink(alias, link, MAX_MAILBOX_PATH); if (n == -1) { fprintf(stderr, "readlink(%s) failed: %s\n", alias, strerror(errno)); errno = EEXIST; } else if (n == (int) strlen(tzid) && !strncmp(tzid, link, n)) { errno = 0; } } } if (errno) { fprintf(stderr, "symlink(%s, %s) failed: %s\n", tzid, alias, strerror(errno)); } } } } done: buf_free(&aliasbuf); buf_free(&tzidbuf); xmlFreeDoc(doc); break; } case NONE: r = 2; usage(); break; } cyrus_done(); return r; }
/* This handles piping of the LSUB command, because we have to figure out * what mailboxes actually exist before passing them to the end user. * * It is also needed if we are doing a FIND MAILBOXES, for that we do an * LSUB on the backend anyway, because the semantics of FIND do not allow * it to return nonexistant mailboxes (RFC1176), but we need to really dumb * down the response when this is the case. */ int pipe_lsub(struct backend *s, const char *userid, const char *tag, int force_notfatal, const char *resp) { int taglen = strlen(tag); int c; int r = PROXY_OK; int exist_r; static struct buf tagb, cmd, sep, name; struct buf flags = BUF_INITIALIZER; const char *end_strip_flags[] = { " \\NonExistent)", "\\NonExistent)", " \\Noselect)", "\\Noselect)", NULL }; const char *mid_strip_flags[] = { "\\NonExistent ", "\\Noselect ", NULL }; assert(s); assert(s->timeout); s->timeout->mark = time(NULL) + IDLE_TIMEOUT; while(1) { c = getword(s->in, &tagb); if(c == EOF) { if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } if(!strncmp(tag, tagb.s, taglen)) { char buf[2048]; if(!prot_fgets(buf, sizeof(buf), s->in)) { if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* Got the end of the response */ buf_appendcstr(&s->last_result, buf); buf_cstring(&s->last_result); switch (buf[0]) { case 'O': case 'o': r = PROXY_OK; break; case 'N': case 'n': r = PROXY_NO; break; case 'B': case 'b': r = PROXY_BAD; break; default: /* huh? no result? */ if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; break; } break; /* we're done */ } c = getword(s->in, &cmd); if(c == EOF) { if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } if(strncasecmp("LSUB", cmd.s, 4) && strncasecmp("LIST", cmd.s, 4)) { prot_printf(imapd_out, "%s %s ", tagb.s, cmd.s); r = pipe_to_end_of_response(s, force_notfatal); if (r != PROXY_OK) goto out; } else { /* build up the response bit by bit */ int i; buf_reset(&flags); c = prot_getc(s->in); while(c != ')' && c != EOF) { buf_putc(&flags, c); c = prot_getc(s->in); } if(c != EOF) { /* terminate string */ buf_putc(&flags, ')'); buf_cstring(&flags); /* get the next character */ c = prot_getc(s->in); } if(c != ' ') { if(s == backend_current && !force_notfatal) fatal("Bad LSUB response from selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* Check for flags that we should remove * (e.g. Noselect, NonExistent) */ for(i=0; end_strip_flags[i]; i++) buf_replace_all(&flags, end_strip_flags[i], ")"); for (i=0; mid_strip_flags[i]; i++) buf_replace_all(&flags, mid_strip_flags[i], NULL); /* Get separator */ c = getastring(s->in, s->out, &sep); if(c != ' ') { if(s == backend_current && !force_notfatal) fatal("Bad LSUB response from selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* Get name */ c = getastring(s->in, s->out, &name); if(c == '\r') c = prot_getc(s->in); if(c != '\n') { if(s == backend_current && !force_notfatal) fatal("Bad LSUB response from selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; goto out; } /* lookup name */ exist_r = 1; char *intname = mboxname_from_external(name.s, &imapd_namespace, userid); mbentry_t *mbentry = NULL; exist_r = mboxlist_lookup(intname, &mbentry, NULL); free(intname); if(!exist_r && (mbentry->mbtype & MBTYPE_RESERVE)) exist_r = IMAP_MAILBOX_RESERVED; mboxlist_entry_free(&mbentry); /* send our response */ /* we need to set \Noselect if it's not in our mailboxes.db */ if (resp[0] == 'L') { if(!exist_r) { prot_printf(imapd_out, "* %s %s \"%s\" ", resp, flags.s, sep.s); } else { prot_printf(imapd_out, "* %s (\\Noselect) \"%s\" ", resp, sep.s); } prot_printstring(imapd_out, name.s); prot_printf(imapd_out, "\r\n"); } else if(resp[0] == 'M' && !exist_r) { /* Note that it has to exist for a find response */ prot_printf(imapd_out, "* %s ", resp); prot_printastring(imapd_out, name.s); prot_printf(imapd_out, "\r\n"); } } } /* while(1) */ out: buf_free(&flags); return r; }
/* pipe_response() reads from 's->in' until either the tagged response starting with 'tag' appears, or if 'tag' is NULL, to the end of the current line. If 'include_last' is set, the last/tagged line is included in the output, otherwise the last/tagged line is stored in 's->last_result'. In either case, the result of the tagged command is returned. 's->last_result' assumes that tagged responses don't contain literals. Unfortunately, the IMAP grammar allows them force_notfatal says to not fatal() if we lose connection to backend_current even though it is in 95% of the cases, a good idea... */ static int pipe_response(struct backend *s, const char *tag, int include_last, int force_notfatal) { char buf[2048]; char eol[128]; unsigned sl; int cont = 0, last = !tag, r = PROXY_OK; size_t taglen = 0; s->timeout->mark = time(NULL) + IDLE_TIMEOUT; if (tag) { taglen = strlen(tag); if(taglen >= sizeof(buf) + 1) { fatal("tag too large",EC_TEMPFAIL); } } buf_reset(&s->last_result); /* the only complication here are literals */ do { /* if 'cont' is set, we're looking at the continuation to a very long line. if 'last' is set, we've seen the tag we're looking for, we're just reading the end of the line. */ if (!cont) eol[0] = '\0'; if (!prot_fgets(buf, sizeof(buf), s->in)) { /* uh oh */ if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); return PROXY_NOCONNECTION; } sl = strlen(buf); if (tag) { /* Check for the tagged line */ if (!cont && buf[taglen] == ' ' && !strncmp(tag, buf, taglen)) { switch (buf[taglen + 1]) { case 'O': case 'o': r = PROXY_OK; break; case 'N': case 'n': r = PROXY_NO; break; case 'B': case 'b': r = PROXY_BAD; break; default: /* huh? no result? */ if(s == backend_current && !force_notfatal) fatal("Lost connection to selected backend", EC_UNAVAILABLE); proxy_downserver(s); r = PROXY_NOCONNECTION; break; } last = 1; } if (last && !include_last) { /* Store the tagged line */ buf_appendcstr(&s->last_result, buf+taglen+1); buf_cstring(&s->last_result); } } if (sl == (sizeof(buf) - 1) && buf[sl-1] != '\n') { /* only got part of a line */ /* we save the last 64 characters in case it has important literal information */ strcpy(eol, buf + sl - 64); /* write out this part, but we have to keep reading until we hit the end of the line */ if (!last || include_last) prot_write(imapd_out, buf, sl); cont = 1; continue; } else { /* we got the end of the line */ int i; int litlen = 0, islit = 0; if (!last || include_last) prot_write(imapd_out, buf, sl); /* now we have to see if this line ends with a literal */ if (sl < 64) { strcat(eol, buf); } else { strcat(eol, buf + sl - 63); } /* eol now contains the last characters from the line; we want to see if we've hit a literal */ i = strlen(eol); if (i >= 4 && eol[i-1] == '\n' && eol[i-2] == '\r' && eol[i-3] == '}') { /* possible literal */ i -= 4; while (i > 0 && eol[i] != '{' && Uisdigit(eol[i])) { i--; } if (eol[i] == '{') { islit = 1; litlen = atoi(eol + i + 1); } } /* copy the literal over */ if (islit) { while (litlen > 0) { int j = (litlen > (int) sizeof(buf) ? (int) sizeof(buf) : litlen); j = prot_read(s->in, buf, j); if(!j) { /* EOF or other error */ return -1; } if (!last || include_last) prot_write(imapd_out, buf, j); litlen -= j; } /* none of our saved information has any relevance now */ eol[0] = '\0'; /* have to keep going for the end of the line */ cont = 1; continue; } } /* ok, let's read another line */ cont = 0; } while (!last || cont); return r; }
static void proxy_part_filldata(partlist_t *part_list, int idx) { char mytag[128]; struct backend *be; partitem_t *item = &part_list->items[idx]; item->id = 0; item->available = 0; item->total = 0; item->quota = 0.; syslog(LOG_DEBUG, "checking free space on server '%s'", item->value); /* connect to server */ be = proxy_findserver(item->value, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); if (be) { uint64_t server_available = 0; uint64_t server_total = 0; const char *annot = (part_list->mode == PART_SELECT_MODE_FREESPACE_MOST) ? "freespace/total" : "freespace/percent/most"; struct buf cmd = BUF_INITIALIZER; int c; /* fetch annotation from remote */ proxy_gentag(mytag, sizeof(mytag)); if (CAPA(be, CAPA_METADATA)) { buf_printf(&cmd, "METADATA \"\" (\"/shared" IMAP_ANNOT_NS "%s\"", annot); } else { buf_printf(&cmd, "ANNOTATION \"\" \"" IMAP_ANNOT_NS "%s\" " "(\"value.shared\"", annot); } prot_printf(be->out, "%s GET%s)\r\n", mytag, buf_cstring(&cmd)); 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, buf_cstring(&cmd)); if (c == ' ') c = prot_getc(be->in); if ((c == EOF) || (c != '\"')) { /* we don't care about this response */ eatline(be->in, c); continue; } /* read available */ c = getuint64(be->in, &server_available); if (c != ';') { c = EOF; break; } /* read total */ c = getuint64(be->in, &server_total); if (c != '\"') { c = EOF; break; } eatline(be->in, c); /* we don't care about the rest of the line */ } buf_free(&cmd); 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); } /* unique id */ item->id = idx; item->available = server_available; item->total = server_total; } }
static int build_notify_message(sieve_interp_t *i, const char *msg, void *message_context, struct buf *out) { const char *c; size_t n; if (msg == NULL) return SIEVE_OK; /* construct the message */ c = msg; while (*c) { /* expand variables */ if (!strncasecmp(c, "$from$", 6)) { add_header(i, 0 ,"From", message_context, out); c += 6; } else if (!strncasecmp(c, "$env-from$", 10)) { add_header(i, 1, "From", message_context, out); c += 10; } else if (!strncasecmp(c, "$subject$", 9)) { add_header(i, 0, "Subject", message_context, out); c += 9; } else if (i->getbody && !strncasecmp(c, "$text", 5) && (c[5] == '[' || c[5] == '$')) { const char *content_types[] = { "text", NULL }; sieve_bodypart_t **parts = NULL; c += 5; n = 0; if (*c++ == '[') { while (*c != ']') n = n * 10 + (*c++ - '0'); c += 2; /* skip ]$ */ } i->getbody(message_context, content_types, &parts); /* we only use the first text part */ if (parts && parts[0] && parts[0]->decoded_body) { size_t size = strlen(parts[0]->decoded_body); if (n && size > n) size = n; buf_appendmap(out, parts[0]->decoded_body, size); } /* free the results */ if (parts) { sieve_bodypart_t **p; for (p = parts; *p; p++) free(*p); free(parts); } } else { /* find length of plaintext up to next potential variable */ n = strcspn(c+1, "$") + 1; /* skip opening '$' */ buf_appendmap(out, c, n); c += n; } } buf_cstring(out); return SIEVE_OK; }
static int login(struct backend *s, const char *userid, sasl_callback_t *cb, const char **status, int noauth __attribute__((unused))) { int r = 0; socklen_t addrsize; struct sockaddr_storage saddr_l, saddr_r; char remoteip[60], localip[60]; static struct buf buf = BUF_INITIALIZER; sasl_security_properties_t secprops = { 0, 0xFF, PROT_BUFSIZE, 0, NULL, NULL }; /* default secprops */ const char *mech_conf, *pass, *clientout = NULL; struct auth_scheme_t *scheme = NULL; unsigned need_tls = 0, tls_done = 0, auth_done = 0, clientoutlen; hdrcache_t hdrs = NULL; if (status) *status = NULL; /* set the IP addresses */ addrsize = sizeof(struct sockaddr_storage); if (getpeername(s->sock, (struct sockaddr *) &saddr_r, &addrsize) || iptostring((struct sockaddr *) &saddr_r, addrsize, remoteip, 60)) { if (status) *status = "Failed to get remote IP address"; return SASL_FAIL; } addrsize = sizeof(struct sockaddr_storage); if (getsockname(s->sock, (struct sockaddr *) &saddr_l, &addrsize) || iptostring((struct sockaddr *) &saddr_l, addrsize, localip, 60)) { if (status) *status = "Failed to get local IP address"; return SASL_FAIL; } /* Create callbacks, if necessary */ if (!cb) { buf_setmap(&buf, s->hostname, strcspn(s->hostname, ".")); buf_appendcstr(&buf, "_password"); pass = config_getoverflowstring(buf_cstring(&buf), NULL); if (!pass) pass = config_getstring(IMAPOPT_PROXY_PASSWORD); cb = mysasl_callbacks(NULL, /* userid */ config_getstring(IMAPOPT_PROXY_AUTHNAME), config_getstring(IMAPOPT_PROXY_REALM), pass); s->sasl_cb = cb; } /* Create SASL context */ r = sasl_client_new(s->prot->sasl_service, s->hostname, localip, remoteip, cb, SASL_USAGE_FLAGS, &s->saslconn); if (r != SASL_OK) goto done; r = sasl_setprop(s->saslconn, SASL_SEC_PROPS, &secprops); if (r != SASL_OK) goto done; /* Get SASL mechanism list. We can force a particular mechanism using a <shorthost>_mechs option */ buf_setmap(&buf, s->hostname, strcspn(s->hostname, ".")); buf_appendcstr(&buf, "_mechs"); if (!(mech_conf = config_getoverflowstring(buf_cstring(&buf), NULL))) { mech_conf = config_getstring(IMAPOPT_FORCE_SASL_CLIENT_MECH); } do { unsigned code; const char **hdr, *errstr, *serverin; char base64[BASE64_BUF_SIZE+1]; unsigned int serverinlen; struct body_t resp_body; #ifdef SASL_HTTP_REQUEST sasl_http_request_t httpreq = { "OPTIONS", /* Method */ "*", /* URI */ (u_char *) "", /* Empty body */ 0, /* Zero-length body */ 0 }; /* Persistent cxn? */ #endif /* Base64 encode any client response, if necessary */ if (clientout && scheme && (scheme->flags & AUTH_BASE64)) { r = sasl_encode64(clientout, clientoutlen, base64, BASE64_BUF_SIZE, &clientoutlen); if (r != SASL_OK) break; clientout = base64; } /* Send Authorization and/or Upgrade request to server */ prot_puts(s->out, "OPTIONS * HTTP/1.1\r\n"); prot_printf(s->out, "Host: %s\r\n", s->hostname); prot_printf(s->out, "User-Agent: %s\r\n", buf_cstring(&serverinfo)); if (scheme) { prot_printf(s->out, "Authorization: %s %s\r\n", scheme->name, clientout ? clientout : ""); prot_printf(s->out, "Authorize-As: %s\r\n", userid ? userid : "anonymous"); } else { prot_printf(s->out, "Upgrade: %s\r\n", TLS_VERSION); if (need_tls) { prot_puts(s->out, "Connection: Upgrade\r\n"); need_tls = 0; } prot_puts(s->out, "Authorization: \r\n"); } prot_puts(s->out, "\r\n"); prot_flush(s->out); serverin = clientout = NULL; serverinlen = clientoutlen = 0; /* Read response(s) from backend until final response or error */ do { resp_body.flags = BODY_DISCARD; r = http_read_response(s, METH_OPTIONS, &code, NULL, &hdrs, &resp_body, &errstr); if (r) { if (status) *status = errstr; break; } if (code == 101) { /* Switching Protocols */ if (tls_done) { r = HTTP_BAD_GATEWAY; if (status) *status = "TLS already active"; break; } else if (backend_starttls(s, NULL, NULL, NULL)) { r = HTTP_SERVER_ERROR; if (status) *status = "Unable to start TLS"; break; } else tls_done = 1; } } while (code < 200); switch (code) { default: /* Failure */ if (!r) { r = HTTP_BAD_GATEWAY; if (status) { buf_reset(&buf); buf_printf(&buf, "Unexpected status code from backend: %u", code); *status = buf_cstring(&buf); } } break; case 426: /* Upgrade Required */ if (tls_done) { r = HTTP_BAD_GATEWAY; if (status) *status = "TLS already active"; } else need_tls = 1; break; case 200: /* OK */ if (scheme->recv_success && (serverin = scheme->recv_success(hdrs))) { /* Process success data */ serverinlen = strlen(serverin); goto challenge; } break; case 401: /* Unauthorized */ if (auth_done) { r = SASL_BADAUTH; break; } if (!serverin) { int i = 0; hdr = spool_getheader(hdrs, "WWW-Authenticate"); if (!scheme) { unsigned avail_auth_schemes = 0; const char *mech = NULL; size_t len; /* Compare authentication schemes offered in * WWW-Authenticate header(s) to what we support */ buf_reset(&buf); for (i = 0; hdr && hdr[i]; i++) { len = strcspn(hdr[i], " "); for (scheme = auth_schemes; scheme->name; scheme++) { if (!strncmp(scheme->name, hdr[i], len) && !((scheme->flags & AUTH_NEED_PERSIST) && (resp_body.flags & BODY_CLOSE))) { /* Tag the scheme as available */ avail_auth_schemes |= (1 << scheme->idx); /* Add SASL-based schemes to SASL mech list */ if (scheme->saslmech) { if (buf_len(&buf)) buf_putc(&buf, ' '); buf_appendcstr(&buf, scheme->saslmech); } break; } } } /* If we have a mech_conf, use it */ if (mech_conf && buf_len(&buf)) { char *conf = xstrdup(mech_conf); char *newmechlist = intersect_mechlists(conf, (char *) buf_cstring(&buf)); if (newmechlist) { buf_setcstr(&buf, newmechlist); free(newmechlist); } else { syslog(LOG_DEBUG, "%s did not offer %s", s->hostname, mech_conf); buf_reset(&buf); } free(conf); } #ifdef SASL_HTTP_REQUEST /* Set HTTP request as specified above (REQUIRED) */ httpreq.non_persist = (resp_body.flags & BODY_CLOSE); sasl_setprop(s->saslconn, SASL_HTTP_REQUEST, &httpreq); #endif /* Try to start SASL exchange using available mechs */ r = sasl_client_start(s->saslconn, buf_cstring(&buf), NULL, /* no prompts */ NULL, NULL, /* no initial resp */ &mech); if (mech) { /* Find auth scheme associated with chosen SASL mech */ for (scheme = auth_schemes; scheme->name; scheme++) { if (scheme->saslmech && !strcmp(scheme->saslmech, mech)) break; } } else { /* No matching SASL mechs - try Basic */ scheme = &auth_schemes[AUTH_BASIC]; if (!(avail_auth_schemes & (1 << scheme->idx))) { need_tls = !tls_done; break; /* case 401 */ } } /* Find the associated WWW-Authenticate header */ for (i = 0; hdr && hdr[i]; i++) { len = strcspn(hdr[i], " "); if (!strncmp(scheme->name, hdr[i], len)) break; } } /* Get server challenge, if any */ if (hdr) { const char *p = strchr(hdr[i], ' '); serverin = p ? ++p : ""; serverinlen = strlen(serverin); } } challenge: if (serverin) { /* Perform the next step in the auth exchange */ if (scheme->idx == AUTH_BASIC) { /* Don't care about "realm" in server challenge */ const char *authid = callback_getdata(s->saslconn, cb, SASL_CB_AUTHNAME); pass = callback_getdata(s->saslconn, cb, SASL_CB_PASS); buf_reset(&buf); buf_printf(&buf, "%s:%s", authid, pass); clientout = buf_cstring(&buf); clientoutlen = buf_len(&buf); auth_done = 1; } else { /* Base64 decode any server challenge, if necessary */ if (serverin && (scheme->flags & AUTH_BASE64)) { r = sasl_decode64(serverin, serverinlen, base64, BASE64_BUF_SIZE, &serverinlen); if (r != SASL_OK) break; /* case 401 */ serverin = base64; } /* SASL mech (Digest, Negotiate, NTLM) */ r = sasl_client_step(s->saslconn, serverin, serverinlen, NULL, /* no prompts */ &clientout, &clientoutlen); if (r == SASL_OK) auth_done = 1; } } break; /* case 401 */ } } while (need_tls || clientout); done: if (hdrs) spool_free_hdrcache(hdrs); if (r && status && !*status) *status = sasl_errstring(r, NULL, NULL); return r; }
static void test_printstring(void) { PROLOG; struct protstream *p; int len; struct buf b = BUF_INITIALIZER; int i; char str[2600]; p = prot_new(_fd, 1); CU_ASSERT_PTR_NOT_NULL_FATAL(p); /* NULL string */ BEGIN; prot_printstring(p, NULL); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 3); CU_ASSERT_STRING_EQUAL(str, "NIL"); /* Zero length string */ BEGIN; prot_printstring(p, ""); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 2); CU_ASSERT_STRING_EQUAL(str, "\"\""); /* Boring string */ BEGIN; prot_printstring(p, "Hello"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 7); CU_ASSERT_STRING_EQUAL(str, "\"Hello\""); /* String with non-dangerous whitespace */ BEGIN; prot_printstring(p, "Hello World\tagain"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 19); CU_ASSERT_STRING_EQUAL(str, "\"Hello World\tagain\""); /* String with dangerous whitespace */ BEGIN; prot_printstring(p, "Good\rBye\nEarth"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 20); CU_ASSERT_STRING_EQUAL(str, "{14}\r\nGood\rBye\nEarth"); /* String with embedded dquote */ BEGIN; prot_printstring(p, "Quot\"able"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 14); CU_ASSERT_STRING_EQUAL(str, "{9}\r\nQuot\"able"); /* String with embedded percent */ BEGIN; prot_printstring(p, "per%ent"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 12); CU_ASSERT(!strcmp(str, "{7}\r\nper%ent")); /* String with embedded backslash */ BEGIN; prot_printstring(p, "slash\\dot"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 14); CU_ASSERT_STRING_EQUAL(str, "{9}\r\nslash\\dot"); /* String with embedded 8-bit chars */ BEGIN; prot_printstring(p, "Hi I'm \330l\345f"); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, 17); CU_ASSERT_STRING_EQUAL(str, "{11}\r\nHi I'm \330l\345f"); /* Boring but overly long string */ for (i = 0 ; i<500 ; i++) buf_appendcstr(&b, "blah "); buf_cstring(&b); BEGIN; prot_printstring(p, b.s); prot_flush(p); END(str, len); CU_ASSERT_EQUAL(len, b.len+8); CU_ASSERT_STRING_EQUAL(str+8, b.s); str[8] = '\0'; CU_ASSERT_STRING_EQUAL(str, "{2500}\r\n"); buf_free(&b); prot_free(p); EPILOG; }
/* * Construct an iCalendar property value from a JSON object. */ static icalvalue *json_object_to_icalvalue(json_t *jvalue, icalvalue_kind kind) { icalvalue *value = NULL; int len, i; switch (kind) { case ICAL_BOOLEAN_VALUE: if (json_is_boolean(jvalue)) value = icalvalue_new_integer(json_is_true(jvalue)); else syslog(LOG_WARNING, "jCal boolean object expected"); break; case ICAL_FLOAT_VALUE: if (json_is_real(jvalue)) value = icalvalue_new_float((float) json_real_value(jvalue)); else syslog(LOG_WARNING, "jCal double object expected"); break; case ICAL_GEO_VALUE: /* MUST be an array of 2 doubles */ if (json_is_array(jvalue) && (len = json_array_size(jvalue)) != 2) { for (i = 0; i < len && json_is_real(json_array_get(jvalue, i)); i++); if (i == len) { struct icalgeotype geo; geo.lat = json_real_value(json_array_get(jvalue, 0)); geo.lon = json_real_value(json_array_get(jvalue, 1)); value = icalvalue_new_geo(geo); } } if (!value) syslog(LOG_WARNING, "jCal array object of 2 doubles expected"); break; case ICAL_INTEGER_VALUE: if (json_is_integer(jvalue)) value = icalvalue_new_integer((int) json_integer_value(jvalue)); else if (json_is_string(jvalue)) value = icalvalue_new_integer(atoi(json_string_value(jvalue))); else syslog(LOG_WARNING, "jCal integer object expected"); break; case ICAL_RECUR_VALUE: if (json_is_object(jvalue)) { struct buf rrule = BUF_INITIALIZER; struct icalrecurrencetype rt; const char *key, *sep = ""; json_t *val; /* create an iCal RRULE string from jCal 'recur' object */ json_object_foreach(jvalue, key, val) { char *mykey = xstrdup(key); buf_printf(&rrule, "%s%s=", sep, ucase(mykey)); buf_appendjson(&rrule, val); sep = ";"; free(mykey); } /* parse our iCal RRULE string */ rt = icalrecurrencetype_from_string(buf_cstring(&rrule)); buf_free(&rrule); if (rt.freq != ICAL_NO_RECURRENCE) value = icalvalue_new_recur(rt); } else