Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
/* 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;
}
Exemplo n.º 7
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;
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
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;
}
Exemplo n.º 14
0
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;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
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);
}
Exemplo n.º 17
0
/* 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;
}
Exemplo n.º 18
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;
}
Exemplo n.º 19
0
/* 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));
    }
Exemplo n.º 20
0
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;
}
Exemplo n.º 21
0
/*
 * 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;
}
Exemplo n.º 22
0
/*
 * 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;
}
Exemplo n.º 23
0
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;
}
Exemplo n.º 24
0
/* 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;
}
Exemplo n.º 25
0
/* 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;
}
Exemplo n.º 26
0
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;
    }
}
Exemplo n.º 27
0
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;
}
Exemplo n.º 28
0
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;
}
Exemplo n.º 29
0
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;
}
Exemplo n.º 30
0
/*
 * 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