void log_pdu(struct pdu *p, int all) { struct iscsi_pdu *pdu; void *b; size_t s; if (!debug) return; if (!(pdu = pdu_getbuf(p, NULL, PDU_HEADER))) { log_debug("empty pdu"); return; } fprintf(stderr, "PDU: op %x%s flags %02x%02x%02x ahs %d len %d\n", ISCSI_PDU_OPCODE(pdu->opcode), ISCSI_PDU_I(pdu) ? " I" : "", pdu->flags, pdu->_reserved1[0], pdu->_reserved1[1], pdu->ahslen, pdu->datalen[0] << 16 | pdu->datalen[1] << 8 | pdu->datalen[2]); fprintf(stderr, " lun %02x%02x%02x%02x%02x%02x%02x%02x itt %u " "cmdsn %u expstatsn %u\n", pdu->lun[0], pdu->lun[1], pdu->lun[2], pdu->lun[3], pdu->lun[4], pdu->lun[5], pdu->lun[6], pdu->lun[7], ntohl(pdu->itt), ntohl(pdu->cmdsn), ntohl(pdu->expstatsn)); log_hexdump(pdu, sizeof(*pdu)); if (all && (b = pdu_getbuf(p, &s, PDU_DATA))) log_hexdump(b, s); }
static void asc_process_aggregate(struct conn *c, struct token *token, int ntoken) { int32_t interval; if (ntoken != 4) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (!mc_strtol(token[TOKEN_AGGR_COMMAND].val, &interval)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid option '%.*s'", c->sd, c->req_type, token[TOKEN_AGGR_COMMAND].len, token[TOKEN_AGGR_COMMAND].val); asc_write_client_error(c); return; } if (interval > 0) { stats_set_interval(interval); asc_write_ok(c); } else if (interval == 0) { stats_set_interval(STATS_DEFAULT_INTVL); asc_write_ok(c); } else { stats_set_interval(-1000000); asc_write_ok(c); } }
static void asc_process_evict(struct conn *c, struct token *token, int ntoken) { int32_t option; if (ntoken != 4) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (!mc_strtol(token[TOKEN_EVICT_COMMAND].val, &option)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid option '%.*s'", c->sd, c->req_type, token[TOKEN_EVICT_COMMAND].len,token[TOKEN_EVICT_COMMAND].val); asc_write_client_error(c); return; } if (option >= EVICT_NONE && option < EVICT_INVALID) { settings.evict_opt = option; asc_write_ok(c); return; } log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid option %"PRId32"", c->sd, c->req_type, option); asc_write_client_error(c); }
rstatus_t asc_parse(struct conn *c) { char *el, *cont; /* eol marker, continue marker */ ASSERT(c->rcurr <= c->rbuf + c->rsize); if (c->rbytes == 0) { return MC_EAGAIN; } el = memchr(c->rcurr, '\n', c->rbytes); if (el == NULL) { if (c->rbytes > 1024) { char *ptr = c->rcurr; /* * We didn't have a '\n' in the first k. This _has_ to be a * large multiget, if not we should just nuke the connection. */ /* ignore leading whitespaces */ while (*ptr == ' ') { ++ptr; } if (ptr - c->rcurr > 100 || (strncmp(ptr, "get ", 4) && strncmp(ptr, "gets ", 5))) { conn_set_state(c, CONN_CLOSE); return MC_ERROR; } } return MC_EAGAIN; } cont = el + 1; if ((el - c->rcurr) > 1 && *(el - 1) == '\r') { el--; } *el = '\0'; log_hexdump(LOG_VERB, c->rcurr, el - c->rcurr, "recv on c %d req with " "%d bytes", c->sd, el - c->rcurr); ASSERT(cont <= c->rbuf + c->rsize); ASSERT(cont <= c->rcurr + c->rbytes); c->req = c->rcurr; c->req_len = (uint16_t)(el - c->rcurr); asc_dispatch(c); /* update the read marker to point to continue marker */ c->rbytes -= (cont - c->rcurr); c->rcurr = cont; return MC_OK; }
static void asc_process_verbosity(struct conn *c, struct token *token, int ntoken) { uint32_t level; asc_set_noreply_maybe(c, token, ntoken); if (ntoken != 3 && ntoken != 4) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_SUBCOMMAND].val, &level)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid level '%.*s'", c->sd, c->req_type, token[TOKEN_SUBCOMMAND].len, token[TOKEN_SUBCOMMAND].val); asc_write_client_error(c); return; } log_level_set(level); asc_write_ok(c); }
rstatus_t dmsg_write(struct mbuf *mbuf, uint64_t msg_id, uint8_t type, struct conn *conn, uint32_t payload_len) { mbuf_write_string(mbuf, &MAGIC_STR); mbuf_write_uint64(mbuf, msg_id); mbuf_write_char(mbuf, ' '); mbuf_write_uint8(mbuf, type); mbuf_write_char(mbuf, ' '); //encryption bit if (conn->dnode_secured) { mbuf_write_uint8(mbuf, 1); } else { mbuf_write_uint8(mbuf, 0); } mbuf_write_char(mbuf, ' '); mbuf_write_uint8(mbuf, version); //mbuf_write_string(mbuf, &CRLF_STR); mbuf_write_char(mbuf, ' '); mbuf_write_char(mbuf, '*'); //write aes key unsigned char *aes_key = conn->aes_key; if (conn->dnode_secured && conn->dnode_crypto_state == 0) { mbuf_write_uint32(mbuf, AES_ENCRYPTED_KEYLEN); } else { mbuf_write_uint32(mbuf, 1); } mbuf_write_char(mbuf, ' '); //mbuf_write_string(mbuf, data); if (conn->dnode_secured && conn->dnode_crypto_state == 0) { #ifdef DN_DEBUG_LOG loga("AES key to be encrypted : %s \n", base64_encode(aes_key, 32)); #endif dyn_rsa_encrypt(aes_key, aes_encrypted_buf); mbuf_write_bytes(mbuf, aes_encrypted_buf, AES_ENCRYPTED_KEYLEN); conn->dnode_crypto_state = 1; } else { mbuf_write_char(mbuf, 'd'); //TODOs: replace with another string } //mbuf_write_string(mbuf, &CRLF_STR); mbuf_write_char(mbuf, ' '); mbuf_write_char(mbuf, '*'); mbuf_write_uint32(mbuf, payload_len); mbuf_write_string(mbuf, &CRLF_STR); #ifdef DN_DEBUG_LOG log_hexdump(LOG_VERB, mbuf->pos, mbuf_length(mbuf), "dyn message producer: "); #endif return DN_OK; }
static void asc_process_flushall(struct conn *c, struct token *token, int ntoken) { struct bound *t = &ntoken_bound[REQ_FLUSHALL]; int32_t exptime_int; time_t exptime; time_update(); asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (ntoken == t->b[c->noreply].min) { settings.oldest_live = time_now() - 1; item_flush_expired(); asc_write_ok(c); return; } if (!mc_strtol(token[TOKEN_SUBCOMMAND].val, &exptime_int)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid numeric value '%.*s'", c->sd, c->req_type, token[TOKEN_SUBCOMMAND].len, token[TOKEN_SUBCOMMAND].val); asc_write_client_error(c); return; } exptime = (time_t)exptime_int; /* * If exptime is zero time_reltime() would return zero too, and * time_reltime(exptime) - 1 would overflow to the max unsigned value. * So we process exptime == 0 the same way we do when no delay is * given at all. */ if (exptime > 0) { settings.oldest_live = time_reltime(exptime) - 1; } else { /* exptime == 0 */ settings.oldest_live = time_now() - 1; } item_flush_expired(); asc_write_ok(c); }
static void show_replys_inconsistency_msg(data_unit *du, redisReply *reply1, redisReply *reply2) { int *keyindex, numkeys; sds key = NULL; keyindex = get_keys_from_data_producer(du->dp, du->argv, du->argc, &numkeys); if (numkeys > 0) { key = du->argv[keyindex[0]]; } free(keyindex); if (key) { log_hexdump(LOG_ERR,key,sdslen(key), "%s command replys are inconsistency, " "reply type: %d %d, " "reply status: %s %s, " "reply error: %s %s, " "reply integer: %lld %lld, " "reply array len: %zu %zu, " "key(len:%zu): ", du->dp->name, reply1->type, reply2->type, reply1->type==REDIS_REPLY_STATUS?reply1->str:"NULL", reply2->type==REDIS_REPLY_STATUS?reply2->str:"NULL", reply1->type==REDIS_REPLY_ERROR?reply1->str:"NULL", reply2->type==REDIS_REPLY_ERROR?reply2->str:"NULL", reply1->type==REDIS_REPLY_INTEGER?reply1->integer:0, reply2->type==REDIS_REPLY_INTEGER?reply2->integer:0, reply1->type==REDIS_REPLY_ARRAY?reply1->elements:0, reply2->type==REDIS_REPLY_ARRAY?reply2->elements:0, sdslen(key)); } else { log_error("%s command replys are inconsistency, " "reply type: %d %d, " "reply status: %s %s, " "reply error: %s %s, " "reply integer: %lld %lld, " "reply array len: %zu %zu", du->dp->name, reply1->type, reply2->type, reply1->type==REDIS_REPLY_STATUS?reply1->str:"NULL", reply2->type==REDIS_REPLY_STATUS?reply2->str:"NULL", reply1->type==REDIS_REPLY_ERROR?reply1->str:"NULL", reply2->type==REDIS_REPLY_ERROR?reply2->str:"NULL", reply1->type==REDIS_REPLY_INTEGER?reply1->integer:0, reply2->type==REDIS_REPLY_INTEGER?reply2->integer:0, reply1->type==REDIS_REPLY_ARRAY?reply1->elements:0, reply2->type==REDIS_REPLY_ARRAY?reply2->elements:0); } }
int __ssl_recv2(void *handle, char *buffer, int *length, int timeout) { ABSTRACT_SOCKET *so = handle; _SSLO *sslo = so->sslo; int ret; struct timeval to; fd_set sockSet; if (sslo == NULL) { return ERR_TR50_BADHANDLE; } if (timeout < -1) { //so->err = GETNETERR(); return ERR_TR50_SOCK_OTHER; } if (SSL_pending(sslo->ssl) == 0 && timeout > 0) { to.tv_usec = (timeout % 1000) * 1000; to.tv_sec = timeout / 1000; FD_ZERO(&sockSet); FD_SET(so->s, &sockSet); if ((ret = select(so->s + 1, &sockSet, NULL, NULL, &to)) == 0) { so->err = ERR_TR50_SOCK_TIMEOUT; return ERR_TR50_SOCK_TIMEOUT; } else if (ret == -1) { //so->err = GETNETERR(); return ERR_TR50_SOCK_OTHER; } } ret = SSL_read(sslo->ssl, buffer, *length); if (ret == -1) { *length = 0; if ((SSL_get_shutdown(sslo->ssl) & SSL_RECEIVED_SHUTDOWN)) { so->err = ERR_TR50_SOCK_SHUTDOWN; return ERR_TR50_SOCK_SHUTDOWN; } sslo->errcode = SSL_get_error(sslo->ssl, ret); //ERR_error_string_n(sslo->errcode, sslo->errmsg, SSL_ERR_STR_LEN); return ERR_TR50_SSL_GENERIC; } else if (ret == 0) { *length = 0; so->err = ERR_TR50_SOCK_SHUTDOWN; return ERR_TR50_SOCK_SHUTDOWN; } else { *length = ret; log_hexdump(LOG_TYPE_LOW_LEVEL, "_ssl_recv2()", buffer, ret); return 0; } }
int APP_CC dev_redir_send(struct stream* s){ int rv; int size = (int)(s->end - s->data); rv = send_channel_data(g_rdpdr_chan_id, s->data, size); if (rv != 0) { log_message(&log_conf, LOG_LEVEL_ERROR, "rdpdr channel: enable to send message"); } rv = log_message(&log_conf, LOG_LEVEL_DEBUG, "xrdp-devredir: send message: "); log_hexdump(&log_conf, LOG_LEVEL_DEBUG, (unsigned char*)s->data, size ); return rv; }
/* * We get here after reading the value in update commands. The command * is stored in c->req_type, and the item is ready in c->item. */ void asc_complete_nread(struct conn *c) { item_store_result_t ret; struct item *it; char *end; it = c->item; end = item_data(it) + it->nbyte; if (!strcrlf(end)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with missing crlf", c->sd, c->req_type); asc_write_client_error(c); } else { ret = item_store(it, c->req_type, c); switch (ret) { case STORED: asc_write_stored(c); break; case EXISTS: asc_write_exists(c); break; case NOT_FOUND: asc_write_not_found(c); break; case NOT_STORED: asc_write_not_stored(c); break; default: log_warn("server error on c %d for req of type %d with unknown " "store result %d", c->sd, c->req_type, ret); asc_write_server_error(c); break; } } item_remove(c->item); c->item = NULL; }
int cliprdr_process_data_request_response(struct stream* s, int msg_flags, int size) { int clipboard_size = 0; unsigned char* clipboard_data = NULL; if (msg_flags == CB_RESPONSE_FAIL) { log_message(l_config, LOG_LEVEL_WARNING, "vchannel_cliprdr[cliprdr_process_data_request_response]: " "Unable to get clipboard data"); return 1; } log_hexdump(l_config, LOG_LEVEL_DEBUG_PLUS, (unsigned char*)s->p, size); if (XGetSelectionOwner(display, clipboard_atom) != wclip) { log_message(l_config, LOG_LEVEL_WARNING, "vchannel_cliprdr[cliprdr_process_data_request_response]: " "Xrpd is not the owner of the selection"); return 1; } if (clipboard_data != 0) { g_free(clipboard_data); } /* An UTF-16 String form RDP is always on 16bits. An UTF-8 string can be coded either * on 8, 16, 24 or 32 bits. So it can be AT MOST input size*2 */ clipboard_data = g_malloc(size*2, 1); clipboard_size = uni_rdp_in_str(s, (char*)clipboard_data, size*2, size); // Remove NULL characters from clipboard data end, it is not a null terminated string if (clipboard_data) { while (clipboard_size > 0 && clipboard_data[clipboard_size-1] == '\0') { clipboard_size--; } } clipboard_add_current_clipboard_data(&clipboard, clipboard_data, clipboard_size, format_utf8_string_atom); return 0; }
static void asc_process_delete(struct conn *c, struct token *token, int ntoken) { char *key; /* key to be deleted */ size_t nkey; /* # key bytes */ struct item *it; /* item for this key */ asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } key = token[TOKEN_KEY].val; nkey = token[TOKEN_KEY].len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d " "length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } /* * FIXME: This is not thread-safe, two threads could try to delete the same * item twice after succeeding in item_get, leading to erroneous stats */ it = item_get(key, nkey); if (it != NULL) { stats_slab_incr(it->id, delete_hit); item_delete(it); asc_write_deleted(c); } else { stats_thread_incr(delete_miss); asc_write_not_found(c); } }
static int client_packet(const void *data, size_t length, void *ctx) { struct connection *c = ctx; packet_action_t action; struct linked_server *ls; assert(c->client.client != NULL); action = handle_packet_from_server(server_packet_bindings, c, data, length); switch (action) { case PA_ACCEPT: if (!c->client.reconnecting) list_for_each_entry(ls, &c->servers, siblings) if (!ls->attaching && !ls->is_zombie) uo_server_send(ls->server, data, length); break; case PA_DROP: break; case PA_DISCONNECT: log(2, "aborting connection to server after packet 0x%x\n", *(const unsigned char*)data); log_hexdump(6, data, length); if (c->autoreconnect && c->in_game) { log(2, "auto-reconnecting\n"); connection_disconnect(c); connection_reconnect_delayed(c); } else { connection_delete(c); } return -1; case PA_DELETED: return -1; } return 0; }
/* * return : true to bypass all processing from the stack * false to go through the whole stack to process a given msg */ bool dmsg_process(struct context *ctx, struct conn *conn, struct dmsg *dmsg) { ASSERT(dmsg != NULL); ASSERT(conn->dyn_mode); struct string s; log_debug(LOG_DEBUG, "dmsg process: type %d", dmsg->type); switch(dmsg->type) { case DMSG_DEBUG: s.len = dmsg->mlen; s.data = dmsg->data; log_hexdump(LOG_VERB, s.data, s.len, "dyn processing message "); return true; case GOSSIP_SYN: log_debug(LOG_DEBUG, "I have got a GOSSIP_SYN!!!!!!"); dmsg_dump(dmsg); //TODOs: fix this to reply the 1st time sender //dnode_rsp_gos_syn(ctx, conn, dmsg->owner); dmsg_parse(dmsg); return true; case CRYPTO_HANDSHAKE: log_debug(LOG_DEBUG, "I have a crypto handshake msg and processing it now"); //TODOs: will work on this to optimize the performance return true; case GOSSIP_SYN_REPLY: log_debug(LOG_DEBUG, "I have got a GOSSIP_SYN_REPLY!!!!!!"); return true; default: log_debug(LOG_DEBUG, "nothing to do"); } return false; }
static void asc_process_delete(struct conn *c, struct token *token, int ntoken) { char *key; /* key to be deleted */ size_t nkey; /* # key bytes */ struct item *it; /* item for this key */ asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_INFO, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } key = token[TOKEN_KEY].val; nkey = token[TOKEN_KEY].len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_INFO, "client error on c %d for req of type %d and %d " "length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } it = item_get(key, nkey); if (it != NULL) { stats_slab_incr(it->id, delete_hit); item_unlink(it); item_remove(it); asc_write_deleted(c); } else { stats_thread_incr(delete_miss); asc_write_not_found(c); } }
static bool dyn_parse_core(struct msg *r) { struct dmsg *dmsg; struct mbuf *b; uint8_t *p, *token; uint8_t ch = ' '; uint64_t num = 0; dyn_state = r->dyn_state; if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "dyn_state: %d", r->dyn_state); } if (r->dyn_state == DYN_DONE || r->dyn_state == DYN_POST_DONE) return true; b = STAILQ_LAST(&r->mhdr, mbuf, next); dmsg = r->dmsg; if (dmsg == NULL) { r->dmsg = dmsg_get(); dmsg = r->dmsg; dmsg->owner = r; if (dmsg == NULL) {//should track this as a dropped message loga("unable to create a new dmsg"); goto error; //should count as OOM error } } token = NULL; for (p = r->pos; p < b->last; p++) { ch = *p; switch (dyn_state) { case DYN_START: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_START"); } if (ch != ' ' && ch != '$') { break; } if (ch == ' ') { if (token == NULL) token = p; break; } if (ch == '$') { if (p + 5 < b->last) { if ((*(p+1) == '2') && (*(p+2) == '0') && (*(p+3) == '1') && (*(p+4) == '4') && (*(p+5) == '$')) { dyn_state = DYN_MAGIC_STRING; p += 5; } else { //goto skip; token = NULL; //reset } } else { goto split; } } else { loga("Facing a weird char %c", p); //goto skip; token = NULL; //reset } break; case DYN_MAGIC_STRING: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_MAGIC_STRING"); } if (ch == ' ') { dyn_state = DYN_MSG_ID; num = 0; break; } else { //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); token = NULL; loga("Facing a weird char %c", p); //goto skip; dyn_state = DYN_START; } break; case DYN_MSG_ID: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_MSG_ID"); log_debug(LOG_DEBUG, "num = %d", num); } if (isdigit(ch)) { num = num*10 + (ch - '0'); } else if (ch == ' ' && isdigit(*(p-1))) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "MSG ID : %d", num); } dmsg->id = num; dyn_state = DYN_TYPE_ID; num = 0; } else { //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); //goto skip; token = NULL; //reset dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_TYPE_ID: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_TYPE_ID: num = %d", num); } if (isdigit(ch)) { num = num*10 + (ch - '0'); } else if (ch == ' ' && isdigit(*(p-1))) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "Type Id: %d", num); } dmsg->type = num; dyn_state = DYN_BIT_FIELD; num = 0; } else { //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); token = NULL; dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_BIT_FIELD: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_BIT_FIELD, num = %d", num); } if (isdigit(ch)) { num = num*10 + (ch - '0'); } else if (ch == ' ' && isdigit(*(p-1))) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_BIT_FIELD : %d", num); } dmsg->bit_field = num & 0xF; dyn_state = DYN_VERSION; num = 0; } else { token = NULL; //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_VERSION: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_VERSION: num = %d", num); } if (isdigit(ch)) { num = num*10 + (ch - '0'); } else if (ch == ' ' && isdigit(*(p-1))) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "VERSION : %d", num); } dmsg->version = num; dyn_state = DYN_SAME_DC; num = 0; } else { token = NULL; //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_SAME_DC: if (isdigit(ch)) { dmsg->same_dc = ch - '0'; if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_SAME_DC %d", dmsg->same_dc); } } else if (ch == ' ' && isdigit(*(p-1))) { dyn_state = DYN_DATA_LEN; num = 0; } else { token = NULL; //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_DATA_LEN: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_DATA_LEN: num = %d", num); } if (ch == '*') { break; } else if (isdigit(ch)) { num = num*10 + (ch - '0'); } else if (ch == ' ' && isdigit(*(p-1))) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "Data len: %d", num); } dmsg->mlen = num; dyn_state = DYN_DATA; num = 0; } else { token = NULL; //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_DATA: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_DATA"); } if (p + dmsg->mlen < b->last) { dmsg->data = p; p += dmsg->mlen - 1; dyn_state = DYN_SPACES_BEFORE_PAYLOAD_LEN; } else { //loga("char is '%c %c %c %c'", *(p-2), *(p-1), ch, *(p+1)); goto split; } break; case DYN_SPACES_BEFORE_PAYLOAD_LEN: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_SPACES_BEFORE_PAYLOAD_LEN"); } if (ch == ' ') { break; } else if (ch == '*') { dyn_state = DYN_PAYLOAD_LEN; num = 0; } break; case DYN_PAYLOAD_LEN: if (isdigit(ch)) { num = num*10 + (ch - '0'); } else if (ch == CR) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "Payload len: %d", num); } dmsg->plen = num; num = 0; dyn_state = DYN_CRLF_BEFORE_DONE; } else { token = NULL; dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_CRLF_BEFORE_DONE: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_CRLF_BEFORE_DONE"); } if (*p == LF) { dyn_state = DYN_DONE; } else { token = NULL; dyn_state = DYN_START; if (ch == '$') p -= 1; } break; case DYN_DONE: if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "DYN_DONE"); } r->pos = p; dmsg->payload = p; r->dyn_state = DYN_DONE; b->pos = p; goto done; break; default: NOT_REACHED(); break; } } if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "Not fully parsed yet!!!!!!"); } split: //this is an attempt recovery when we got a bad message //we try to look for the start the next good one and throw away the bad part if (r->dyn_state == DYN_START) { r->result = MSG_PARSE_AGAIN; if (b->last == b->end) { struct mbuf *nbuf = mbuf_get(); if (nbuf == NULL) { loga("Unable to obtain a new mbuf for replacement!"); mbuf_put(b); nbuf = mbuf_get(); mbuf_insert_head(&r->mhdr, nbuf); r->pos = nbuf->pos; return false; } //replacing the bad mbuf with a new and empty mbuf mbuf_insert(&r->mhdr, nbuf); mbuf_remove(&r->mhdr, b); mbuf_put(b); r->pos = nbuf->pos; return false; } else { //split it and throw away the bad portion struct mbuf *nbuf; nbuf = mbuf_split(&r->mhdr, r->pos, NULL, NULL); if (nbuf == NULL) { return DN_ENOMEM; } mbuf_insert(&r->mhdr, nbuf); mbuf_remove(&r->mhdr, b); r->pos = nbuf->pos; return false; } } if (mbuf_length(b) == 0 || b->last == b->end) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "Would this case ever happen?"); } r->result = MSG_PARSE_AGAIN; return false; } if (r->pos == b->last) { if (log_loggable(LOG_DEBUG)) { log_debug(LOG_DEBUG, "Forward to reading the new block of data"); } r->dyn_state = DYN_START; r->result = MSG_PARSE_AGAIN; token = NULL; return false; } if (log_loggable(LOG_VVERB)) { log_debug(LOG_VVERB, "in split"); } r->dyn_state = DYN_START; r->pos = token; r->result = MSG_PARSE_REPAIR; if (log_loggable(LOG_VVERB)) { log_hexdump(LOG_VVERB, b->pos, mbuf_length(b), "split and inspecting req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, r->dyn_state); log_hexdump(LOG_VVERB, b->start, b->last - b->start, "split and inspecting full req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, r->dyn_state); } return false; done: r->pos = p; dmsg->source_address = r->owner->addr; if (log_loggable(LOG_VVERB)) { log_debug(LOG_VVERB, "at done with p at %d", p); log_hexdump(LOG_VVERB, r->pos, b->last - r->pos, "done and inspecting req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, r->dyn_state); log_hexdump(LOG_VVERB, b->start, b->last - b->start, "inspecting req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, r->dyn_state); } return true; error: log_debug(LOG_ERR, "at error for state %d and c %c", dyn_state, *p); r->result = MSG_PARSE_ERROR; r->pos = p; errno = EINVAL; if (log_loggable(LOG_ERR)) { log_hexdump(LOG_ERR, b->pos, mbuf_length(b), "parsed bad req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, dyn_state); log_hexdump(LOG_ERR, p, b->last - p, "inspecting req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, dyn_state); } r->dyn_state = dyn_state; return false; }
static void asc_dispatch(struct conn *c) { rstatus_t status; struct token token[TOKEN_MAX]; int ntoken; /* * For commands set, add, or replace, we build an item and read the data * directly into it, then continue in asc_complete_nread(). */ c->msg_curr = 0; c->msg_used = 0; c->iov_used = 0; status = conn_add_msghdr(c); if (status != MC_OK) { log_warn("server error on c %d for req of type %d because of oom in " "preparing response", c->sd, c->req_type); asc_write_server_error(c); return; } ntoken = asc_tokenize(c->req, token, TOKEN_MAX); c->req_type = asc_parse_type(c, token, ntoken); switch (c->req_type) { case REQ_GET: case REQ_GETS: /* we do not update stats metrics here because of multi-get */ asc_process_read(c, token, ntoken); break; case REQ_SET: stats_thread_incr(set); asc_process_update(c, token, ntoken); break; case REQ_ADD: stats_thread_incr(add); asc_process_update(c, token, ntoken); break; case REQ_REPLACE: stats_thread_incr(replace); asc_process_update(c, token, ntoken); break; case REQ_APPEND: stats_thread_incr(append); asc_process_update(c, token, ntoken); break; case REQ_PREPEND: stats_thread_incr(prepend); asc_process_update(c, token, ntoken); break; case REQ_CAS: stats_thread_incr(cas); asc_process_update(c, token, ntoken); break; case REQ_INCR: stats_thread_incr(incr); asc_process_arithmetic(c, token, ntoken); break; case REQ_DECR: stats_thread_incr(decr); asc_process_arithmetic(c, token, ntoken); break; case REQ_DELETE: stats_thread_incr(delete); asc_process_delete(c, token, ntoken); break; case REQ_STATS: stats_thread_incr(stats); asc_process_stats(c, token, ntoken); break; case REQ_FLUSHALL: stats_thread_incr(flush); asc_process_flushall(c, token, ntoken); break; case REQ_VERSION: asc_write_version(c); break; case REQ_QUIT: conn_set_state(c, CONN_CLOSE); break; case REQ_VERBOSITY: asc_process_verbosity(c, token, ntoken); break; case REQ_CONFIG: asc_process_config(c, token, ntoken); break; case REQ_UNKNOWN: default: log_hexdump(LOG_INFO, c->req, c->req_len, "req on c %d with %d " "invalid tokens", c->sd, ntoken); asc_write_client_error(c); break; } }
/* * Pre-coalesce handler is invoked when the message is a response to * the fragmented multi vector request - 'get' or 'gets' and all the * responses to the fragmented request vector hasn't been received */ void memcache_pre_coalesce(struct msg *r) { struct msg *pr = r->peer; /* peer request */ struct mbuf *mbuf; ASSERT(!r->request); ASSERT(pr->request); if (pr->frag_id == 0) { /* do nothing, if not a response to a fragmented request */ return; } pr->frag_owner->nfrag_done++; switch (r->type) { case MSG_RSP_MC_VALUE: case MSG_RSP_MC_END: /* * Readjust responses of the fragmented message vector by not * including the end marker for all */ ASSERT(r->end != NULL); for (;;) { mbuf = STAILQ_LAST(&r->mhdr, mbuf, next); ASSERT(mbuf != NULL); /* * We cannot assert that end marker points to the last mbuf * Consider a scenario where end marker points to the * penultimate mbuf and the last mbuf only contains spaces * and CRLF: mhdr -> [...END] -> [\r\n] */ if (r->end >= mbuf->pos && r->end < mbuf->last) { /* end marker is within this mbuf */ r->mlen -= (uint32_t)(mbuf->last - r->end); mbuf->last = r->end; break; } /* end marker is not in this mbuf */ r->mlen -= mbuf_length(mbuf); mbuf_remove(&r->mhdr, mbuf); mbuf_put(mbuf); } break; default: /* * Valid responses for a fragmented requests are MSG_RSP_MC_VALUE or, * MSG_RSP_MC_END. For an invalid response, we send out SERVER_ERRROR * with EINVAL errno */ mbuf = STAILQ_FIRST(&r->mhdr); log_hexdump(LOG_ERR, mbuf->pos, mbuf_length(mbuf), "rsp fragment " "with unknown type %d", r->type); pr->error = 1; pr->err = EINVAL; break; } }
void memcache_parse_rsp(struct msg *r) { struct mbuf *b; uint8_t *p, *m; uint8_t ch; enum { SW_START, SW_RSP_NUM, SW_RSP_STR, SW_SPACES_BEFORE_KEY, SW_KEY, SW_SPACES_BEFORE_FLAGS, /* 5 */ SW_FLAGS, SW_SPACES_BEFORE_VLEN, SW_VLEN, SW_RUNTO_VAL, SW_VAL, /* 10 */ SW_VAL_LF, SW_END, SW_RUNTO_CRLF, SW_CRLF, SW_ALMOST_DONE, /* 15 */ SW_SENTINEL } state; state = r->state; b = STAILQ_LAST(&r->mhdr, mbuf, next); ASSERT(!r->request); ASSERT(!r->redis); ASSERT(state >= SW_START && state < SW_SENTINEL); ASSERT(b != NULL); ASSERT(b->pos <= b->last); /* validate the parsing marker */ ASSERT(r->pos != NULL); ASSERT(r->pos >= b->pos && r->pos <= b->last); for (p = r->pos; p < b->last; p++) { ch = *p; switch (state) { case SW_START: if (isdigit(ch)) { state = SW_RSP_NUM; } else { state = SW_RSP_STR; } p = p - 1; /* go back by 1 byte */ break; case SW_RSP_NUM: if (r->token == NULL) { /* rsp_start <- p; type_start <- p */ r->token = p; } if (isdigit(ch)) { /* num <- num * 10 + (ch - '0') */ ; } else if (ch == ' ' || ch == CR) { /* type_end <- p - 1 */ r->token = NULL; r->type = MSG_RSP_MC_NUM; p = p - 1; /* go back by 1 byte */ state = SW_CRLF; } else { goto error; } break; case SW_RSP_STR: if (r->token == NULL) { /* rsp_start <- p; type_start <- p */ r->token = p; } if (ch == ' ' || ch == CR) { /* type_end <- p - 1 */ m = r->token; /* r->token = NULL; */ r->type = MSG_UNKNOWN; switch (p - m) { case 3: if (str4cmp(m, 'E', 'N', 'D', '\r')) { r->type = MSG_RSP_MC_END; /* end_start <- m; end_end <- p - 1 */ r->end = m; break; } break; case 5: if (str5cmp(m, 'V', 'A', 'L', 'U', 'E')) { /* * Encompasses responses for 'get', 'gets' and * 'cas' command. */ r->type = MSG_RSP_MC_VALUE; break; } if (str5cmp(m, 'E', 'R', 'R', 'O', 'R')) { r->type = MSG_RSP_MC_ERROR; break; } break; case 6: if (str6cmp(m, 'S', 'T', 'O', 'R', 'E', 'D')) { r->type = MSG_RSP_MC_STORED; break; } if (str6cmp(m, 'E', 'X', 'I', 'S', 'T', 'S')) { r->type = MSG_RSP_MC_EXISTS; break; } break; case 7: if (str7cmp(m, 'D', 'E', 'L', 'E', 'T', 'E', 'D')) { r->type = MSG_RSP_MC_DELETED; break; } break; case 9: if (str9cmp(m, 'N', 'O', 'T', '_', 'F', 'O', 'U', 'N', 'D')) { r->type = MSG_RSP_MC_NOT_FOUND; break; } break; case 10: if (str10cmp(m, 'N', 'O', 'T', '_', 'S', 'T', 'O', 'R', 'E', 'D')) { r->type = MSG_RSP_MC_NOT_STORED; break; } break; case 12: if (str12cmp(m, 'C', 'L', 'I', 'E', 'N', 'T', '_', 'E', 'R', 'R', 'O', 'R')) { r->type = MSG_RSP_MC_CLIENT_ERROR; break; } if (str12cmp(m, 'S', 'E', 'R', 'V', 'E', 'R', '_', 'E', 'R', 'R', 'O', 'R')) { r->type = MSG_RSP_MC_SERVER_ERROR; break; } break; } switch (r->type) { case MSG_UNKNOWN: goto error; case MSG_RSP_MC_STORED: case MSG_RSP_MC_NOT_STORED: case MSG_RSP_MC_EXISTS: case MSG_RSP_MC_NOT_FOUND: case MSG_RSP_MC_DELETED: state = SW_CRLF; break; case MSG_RSP_MC_END: state = SW_CRLF; break; case MSG_RSP_MC_VALUE: state = SW_SPACES_BEFORE_KEY; break; case MSG_RSP_MC_ERROR: state = SW_CRLF; break; case MSG_RSP_MC_CLIENT_ERROR: case MSG_RSP_MC_SERVER_ERROR: state = SW_RUNTO_CRLF; break; default: NOT_REACHED(); } p = p - 1; /* go back by 1 byte */ } break; case SW_SPACES_BEFORE_KEY: if (ch != ' ') { state = SW_KEY; p = p - 1; /* go back by 1 byte */ } break; case SW_KEY: if (ch == ' ') { /* r->token = NULL; */ state = SW_SPACES_BEFORE_FLAGS; } break; case SW_SPACES_BEFORE_FLAGS: if (ch != ' ') { if (!isdigit(ch)) { goto error; } state = SW_FLAGS; p = p - 1; /* go back by 1 byte */ } break; case SW_FLAGS: if (r->token == NULL) { /* flags_start <- p */ /* r->token = p; */ } if (isdigit(ch)) { /* flags <- flags * 10 + (ch - '0') */ ; } else if (ch == ' ') { /* flags_end <- p - 1 */ /* r->token = NULL; */ state = SW_SPACES_BEFORE_VLEN; } else { goto error; } break; case SW_SPACES_BEFORE_VLEN: if (ch != ' ') { if (!isdigit(ch)) { goto error; } p = p - 1; /* go back by 1 byte */ state = SW_VLEN; r->vlen = 0; } break; case SW_VLEN: if (isdigit(ch)) { r->vlen = r->vlen * 10 + (uint32_t)(ch - '0'); } else if (ch == ' ' || ch == CR) { /* vlen_end <- p - 1 */ p = p - 1; /* go back by 1 byte */ /* r->token = NULL; */ state = SW_RUNTO_CRLF; } else { goto error; } break; case SW_RUNTO_VAL: switch (ch) { case LF: /* val_start <- p + 1 */ state = SW_VAL; r->token = NULL; break; default: goto error; } break; case SW_VAL: m = p + r->vlen; if (m >= b->last) { ASSERT(r->vlen >= (uint32_t)(b->last - p)); r->vlen -= (uint32_t)(b->last - p); m = b->last - 1; p = m; /* move forward by vlen bytes */ break; } switch (*m) { case CR: /* val_end <- p - 1 */ p = m; /* move forward by vlen bytes */ state = SW_VAL_LF; break; default: goto error; } break; case SW_VAL_LF: switch (ch) { case LF: /* state = SW_END; */ state = SW_RSP_STR; break; default: goto error; } break; case SW_END: if (r->token == NULL) { if (ch != 'E') { goto error; } /* end_start <- p */ r->token = p; } else if (ch == CR) { /* end_end <- p */ m = r->token; r->token = NULL; switch (p - m) { case 3: if (str4cmp(m, 'E', 'N', 'D', '\r')) { r->end = m; state = SW_ALMOST_DONE; } break; default: goto error; } } break; case SW_RUNTO_CRLF: switch (ch) { case CR: if (r->type == MSG_RSP_MC_VALUE) { state = SW_RUNTO_VAL; } else { state = SW_ALMOST_DONE; } break; default: break; } break; case SW_CRLF: switch (ch) { case ' ': break; case CR: state = SW_ALMOST_DONE; break; default: goto error; } break; case SW_ALMOST_DONE: switch (ch) { case LF: /* rsp_end <- p */ goto done; default: goto error; } break; case SW_SENTINEL: default: NOT_REACHED(); break; } } ASSERT(p == b->last); r->pos = p; r->state = state; if (b->last == b->end && r->token != NULL) { if (state <= SW_RUNTO_VAL || state == SW_CRLF || state == SW_ALMOST_DONE) { r->state = SW_START; } r->pos = r->token; r->token = NULL; r->result = MSG_PARSE_REPAIR; } else { r->result = MSG_PARSE_AGAIN; } log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d " "type %d state %d rpos %d of %d", r->id, r->result, r->type, r->state, r->pos - b->pos, b->last - b->pos); return; done: ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL); r->pos = p + 1; ASSERT(r->pos <= b->last); r->state = SW_START; r->token = NULL; r->result = MSG_PARSE_OK; log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed rsp %"PRIu64" res %d " "type %d state %d rpos %d of %d", r->id, r->result, r->type, r->state, r->pos - b->pos, b->last - b->pos); return; error: r->result = MSG_PARSE_ERROR; r->state = state; errno = EINVAL; log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad rsp %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, r->state); }
static void asc_process_klog(struct conn *c, struct token *token, int ntoken) { struct token *t; if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } t = &token[TOKEN_KLOG_COMMAND]; if (strncmp(t->val, "run", t->len) == 0) { if (settings.klog_name == NULL) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "with klog filename not set", c->sd, c->req_type); asc_write_client_error(c); return; } t = &token[TOKEN_KLOG_SUBCOMMAND]; if (strncmp(t->val, "start", t->len) == 0) { log_debug(LOG_NOTICE, "klog start at epoch %u", time_now()); settings.klog_running = true; asc_write_ok(c); } else if (strncmp(t->val, "stop", t->len) == 0) { log_debug(LOG_NOTICE, "klog stops at epoch %u", time_now()); settings.klog_running = false; asc_write_ok(c); } else { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "with invalid klog run subcommand '%.*s'", c->sd, c->req_type, t->len, t->val); asc_write_client_error(c); } } else if (strncmp(t->val, "interval", t->len) == 0) { t = &token[TOKEN_KLOG_SUBCOMMAND]; if (strncmp(t->val, "reset", t->len) == 0) { stats_set_interval(STATS_DEFAULT_INTVL); asc_write_ok(c); } else { int32_t interval; if (!mc_strtol(t->val, &interval)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "with invalid klog interval '%.*s'", c->sd, c->req_type, t->len, t->val); asc_write_client_error(c); } else if (interval < KLOG_MIN_INTVL) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "with invalid klog interval %"PRId32"", c->sd, c->req_type, interval); asc_write_client_error(c); } else { stats_set_interval(interval); asc_write_ok(c); } } } else if (strncmp(t->val, "sampling", t->len) == 0) { t = &token[TOKEN_KLOG_SUBCOMMAND]; if (strncmp(t->val, "reset", t->len) == 0) { settings.klog_sampling_rate = KLOG_DEFAULT_SMP_RATE; asc_write_ok(c); } else { int32_t sampling; if (!mc_strtol(t->val, &sampling)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "with invalid klog sampling '%.*s'", c->sd, c->req_type, t->len, t->val); asc_write_client_error(c); } else if (sampling <= 0) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "with invalid klog sampling %"PRId32"", c->sd, c->req_type, sampling); asc_write_client_error(c); } else { settings.klog_sampling_rate = sampling; asc_write_ok(c); } } } else { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid klog subcommand '%.*s'", c->sd, c->req_type, t->len, t->val); asc_write_client_error(c); } }
/* dnode sends a response back to a peer */ struct msg * dnode_rsp_send_next(struct context *ctx, struct conn *conn) { if (TRACING_LEVEL == LOG_VVERB) { log_debug(LOG_VVERB, "dnode_rsp_send_next entering"); } ASSERT(conn->dnode_client && !conn->dnode_server); struct msg *msg = rsp_send_next(ctx, conn); if (msg != NULL && conn->dyn_mode) { struct msg *pmsg = TAILQ_FIRST(&conn->omsg_q); //peer request's msg //need to deal with multi-block later uint64_t msg_id = pmsg->dmsg->id; struct mbuf *header_buf = mbuf_get(); if (header_buf == NULL) { loga("Unable to obtain an mbuf for header!"); return NULL; //need to address error here properly } //TODOs: need to set the outcoming conn to be secured too if the incoming conn is secured if (pmsg->owner->dnode_secured || conn->dnode_secured) { if (TRACING_LEVEL == LOG_VVERB) { log_debug(LOG_VVERB, "Encrypting response ..."); loga("AES encryption key: %s\n", base64_encode(conn->aes_key, AES_KEYLEN)); } struct mbuf *data_buf = STAILQ_LAST(&msg->mhdr, mbuf, next); //if (ENCRYPTION) { struct mbuf *encrypted_buf = mbuf_get(); if (encrypted_buf == NULL) { loga("Unable to obtain an mbuf for encryption!"); return NULL; //TODOs: need to clean up } rstatus_t status = dyn_aes_encrypt(data_buf->pos, mbuf_length(data_buf), encrypted_buf, conn->aes_key); if (TRACING_LEVEL == LOG_VVERB) { log_debug(LOG_VERB, "#encrypted bytes : %d", status); } dmsg_write(header_buf, msg_id, DMSG_RES, conn, mbuf_length(encrypted_buf)); if (TRACING_LEVEL == LOG_VVERB) { log_hexdump(LOG_VVERB, data_buf->pos, mbuf_length(data_buf), "resp dyn message - original payload: "); log_hexdump(LOG_VVERB, encrypted_buf->pos, mbuf_length(encrypted_buf), "dyn message encrypted payload: "); } mbuf_copy(header_buf, encrypted_buf->start, mbuf_length(encrypted_buf)); mbuf_insert(&msg->mhdr, header_buf); //remove the original dbuf out of the queue and insert encrypted mbuf to replace mbuf_remove(&msg->mhdr, data_buf); //mbuf_insert(&msg->mhdr, encrypted_buf); mbuf_put(data_buf); mbuf_put(encrypted_buf); //} else { // log_debug(LOG_VERB, "no encryption on the response's payload"); // dmsg_write(header_buf, msg_id, DMSG_RES, conn, mbuf_length(data_buf)); //} } else { dmsg_write(header_buf, msg_id, DMSG_RES, conn, 0);//Dont care about 0 or the real length as we don't use that value in unencryption mode mbuf_insert_head(&msg->mhdr, header_buf); } if (TRACING_LEVEL == LOG_VVERB) { log_hexdump(LOG_VVERB, header_buf->pos, mbuf_length(header_buf), "resp dyn message - header: "); msg_dump(msg); } } return msg; }
static void asc_process_arithmetic(struct conn *c, struct token *token, int ntoken) { item_delta_result_t res; char temp[INCR_MAX_STORAGE_LEN]; uint64_t delta; char *key; size_t nkey; bool incr; asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } incr = (c->req_type == REQ_INCR) ? true : false; key = token[TOKEN_KEY].val; nkey = token[TOKEN_KEY].len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d " "length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } if (!mc_strtoull(token[TOKEN_DELTA].val, &delta)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid delta '%.*s'", c->sd, c->req_type, token[TOKEN_DELTA].len, token[TOKEN_DELTA].val); asc_write_client_error(c); return; } res = item_add_delta(c, key, nkey, incr, delta, temp); switch (res) { case DELTA_OK: asc_write_string(c, temp, strlen(temp)); klog_write(c->peer, c->req_type, c->req, c->req_len, res, strlen(temp)); break; case DELTA_NON_NUMERIC: log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "non-numeric value", c->sd, c->req_type); asc_write_client_error(c); break; case DELTA_EOM: log_warn("server error on c %d for req of type %d because of oom", c->sd, c->req_type); asc_write_server_error(c); break; case DELTA_NOT_FOUND: if (incr) { stats_thread_incr(incr_miss); } else { stats_thread_incr(decr_miss); } asc_write_not_found(c); break; default: NOT_REACHED(); break; } }
static inline void asc_process_read(struct conn *c, struct token *token, int ntoken) { rstatus_t status; char *key; size_t nkey; unsigned valid_key_iter = 0; struct item *it; struct token *key_token; bool return_cas; if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } return_cas = (c->req_type == REQ_GETS) ? true : false; key_token = &token[TOKEN_KEY]; do { while (key_token->len != 0) { key = key_token->val; nkey = key_token->len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "and %d length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } if (return_cas) { stats_thread_incr(gets); } else { stats_thread_incr(get); } it = item_get(key, nkey); if (it != NULL) { /* item found */ if (return_cas) { stats_slab_incr(it->id, gets_hit); } else { stats_slab_incr(it->id, get_hit); } if (valid_key_iter >= c->isize) { struct item **new_list; new_list = mc_realloc(c->ilist, sizeof(struct item *) * c->isize * 2); if (new_list != NULL) { c->isize *= 2; c->ilist = new_list; } else { item_remove(it); break; } } status = asc_respond_get(c, valid_key_iter, it, return_cas); if (status != MC_OK) { log_debug(LOG_NOTICE, "client error on c %d for req of type " "%d with %d tokens", c->sd, c->req_type, ntoken); stats_thread_incr(cmd_error); item_remove(it); break; } log_debug(LOG_VVERB, ">%d sending key %.*s", c->sd, it->nkey, item_key(it)); item_touch(it); *(c->ilist + valid_key_iter) = it; valid_key_iter++; } else { /* item not found */ if (return_cas) { stats_thread_incr(gets_miss); } else { stats_thread_incr(get_miss); } klog_write(c->peer, c->req_type, key, nkey, 1, 0); } key_token++; } /* * If the command string hasn't been fully processed, get the next set * of token. */ if (key_token->val != NULL) { ntoken = asc_tokenize(key_token->val, token, TOKEN_MAX); /* ntoken is unused */ key_token = token; } } while (key_token->val != NULL); c->icurr = c->ilist; c->ileft = valid_key_iter; if (return_cas) { c->scurr = c->slist; c->sleft = valid_key_iter; } log_debug(LOG_VVERB, ">%d END", c->sd); /* * If the loop was terminated because of out-of-memory, it is not * reliable to add END\r\n to the buffer, because it might not end * in \r\n. So we send SERVER_ERROR instead. */ if (key_token->val != NULL || conn_add_iov(c, "END\r\n", 5) != MC_OK || (c->udp && conn_build_udp_headers(c) != MC_OK)) { log_warn("server error on c %d for req of type %d with enomem", c->sd, c->req_type); asc_write_server_error(c); } else { conn_set_state(c, CONN_MWRITE); c->msg_curr = 0; } }
void memcache_parse_req(struct msg *r) { struct mbuf *b; uint8_t *p, *m; uint8_t ch; enum { SW_START, SW_REQ_TYPE, SW_SPACES_BEFORE_KEY, SW_KEY, SW_SPACES_BEFORE_KEYS, SW_SPACES_BEFORE_FLAGS, SW_FLAGS, SW_SPACES_BEFORE_EXPIRY, SW_EXPIRY, SW_SPACES_BEFORE_VLEN, SW_VLEN, SW_SPACES_BEFORE_CAS, SW_CAS, SW_RUNTO_VAL, SW_VAL, SW_SPACES_BEFORE_NUM, SW_NUM, SW_RUNTO_CRLF, SW_CRLF, SW_NOREPLY, SW_AFTER_NOREPLY, SW_ALMOST_DONE, SW_SENTINEL } state; state = r->state; b = STAILQ_LAST(&r->mhdr, mbuf, next); ASSERT(r->request); ASSERT(state >= SW_START && state < SW_SENTINEL); ASSERT(b != NULL); ASSERT(b->pos <= b->last); /* validate the parsing maker */ ASSERT(r->pos != NULL); ASSERT(r->pos >= b->pos && r->pos <= b->last); for (p = r->pos; p < b->last; p++) { ch = *p; switch (state) { case SW_START: if (ch == ' ') { break; } if (!islower(ch)) { goto error; } /* req_start <- p; type_start <- p */ r->token = p; state = SW_REQ_TYPE; break; case SW_REQ_TYPE: if (ch == ' ' || ch == CR) { /* type_end = p - 1 */ m = r->token; r->token = NULL; r->type = MSG_UNKNOWN; switch (p - m) { case 3: if (str4cmp(m, 'g', 'e', 't', ' ')) { r->type = MSG_REQ_GET; break; } if (str4cmp(m, 's', 'e', 't', ' ')) { r->type = MSG_REQ_SET; break; } if (str4cmp(m, 'a', 'd', 'd', ' ')) { r->type = MSG_REQ_ADD; break; } if (str4cmp(m, 'c', 'a', 's', ' ')) { r->type = MSG_REQ_CAS; break; } break; case 4: if (str4cmp(m, 'g', 'e', 't', 's')) { r->type = MSG_REQ_GETS; break; } if (str4cmp(m, 'i', 'n', 'c', 'r')) { r->type = MSG_REQ_INCR; break; } if (str4cmp(m, 'd', 'e', 'c', 'r')) { r->type = MSG_REQ_DECR; break; } if (str4cmp(m, 'q', 'u', 'i', 't')) { r->type = MSG_REQ_QUIT; r->quit = 1; break; } break; case 6: if (str6cmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) { r->type = MSG_REQ_APPEND; break; } if (str6cmp(m, 'd', 'e', 'l', 'e', 't', 'e')) { r->type = MSG_REQ_DELETE; break; } break; case 7: if (str7cmp(m, 'p', 'r', 'e', 'p', 'e', 'n', 'd')) { r->type = MSG_REQ_PREPEND; break; } if (str7cmp(m, 'r', 'e', 'p', 'l', 'a', 'c', 'e')) { r->type = MSG_REQ_REPLACE; break; } if (str7cmp(m, 'v', 'e', 'r', 's', 'i', 'o', 'n')) { r->type = MSG_REQ_VERSION; break; } break; } if (memcache_key(r)) { if (ch == CR) { goto error; } state = SW_SPACES_BEFORE_KEY; } else if (memcache_quit(r) || memcache_version(r)) { p = p - 1; /* go back by 1 byte */ state = SW_CRLF; } else { goto error; } } else if (!islower(ch)) { goto error; } break; case SW_SPACES_BEFORE_KEY: if (ch != ' ') { p = p - 1; /* go back by 1 byte */ state = SW_KEY; } break; case SW_KEY: if (r->token == NULL) { r->token = p; r->key_start = p; } if (ch == ' ' || ch == CR) { if ((p - r->key_start) > MEMCACHE_MAX_KEY_LENGTH) { log_error("parsed bad req %"PRIu64" of type %d with key " "prefix '%.*s...' and length %d that exceeds " "maximum key length", r->id, r->type, 16, r->key_start, p - r->key_start); goto error; } r->key_end = p; r->token = NULL; /* get next state */ if (memcache_storage(r)) { state = SW_SPACES_BEFORE_FLAGS; } else if (memcache_arithmetic(r)) { state = SW_SPACES_BEFORE_NUM; } else if (memcache_delete(r)) { state = SW_RUNTO_CRLF; } else if (memcache_retrieval(r)) { state = SW_SPACES_BEFORE_KEYS; } else { state = SW_RUNTO_CRLF; } if (ch == CR) { if (memcache_storage(r) || memcache_arithmetic(r)) { goto error; } p = p - 1; /* go back by 1 byte */ } } break; case SW_SPACES_BEFORE_KEYS: ASSERT(memcache_retrieval(r)); switch (ch) { case ' ': break; case CR: state = SW_ALMOST_DONE; break; default: r->token = p; goto fragment; } break; case SW_SPACES_BEFORE_FLAGS: if (ch != ' ') { if (!isdigit(ch)) { goto error; } p = p - 1; /* go back by 1 byte */ state = SW_FLAGS; } break; case SW_FLAGS: if (r->token == NULL) { /* flags_start <- p */ r->token = p; r->flags = 0; } if (isdigit(ch)) { r->flags = r->flags * 10 + (uint32_t)(ch - '0'); } else if (ch == ' ') { /* flags_end <- p - 1 */ r->token = NULL; state = SW_SPACES_BEFORE_EXPIRY; } else { goto error; } break; case SW_SPACES_BEFORE_EXPIRY: if (ch != ' ') { if (!isdigit(ch)) { goto error; } p = p - 1; /* go back by 1 byte */ state = SW_EXPIRY; } break; case SW_EXPIRY: if (r->token == NULL) { /* expiry_start <- p */ r->token = p; r->expiry = 0; } if (isdigit(ch)) { r->expiry = r->expiry * 10 + (uint32_t)(ch - '0'); } else if (ch == ' ') { /* expiry_end <- p - 1 */ r->token = NULL; state = SW_SPACES_BEFORE_VLEN; } else { goto error; } break; case SW_SPACES_BEFORE_VLEN: if (ch != ' ') { if (!isdigit(ch)) { goto error; } p = p - 1; /* go back by 1 byte */ state = SW_VLEN; } break; case SW_VLEN: if (r->token == NULL) { /* vlen_start <- p */ r->token = p; r->vlen = 0; } if (isdigit(ch)) { r->vlen = r->vlen * 10 + (uint32_t)(ch - '0'); } else if (memcache_cas(r)) { if (ch != ' ') { goto error; } /* vlen_end <- p - 1 */ r->rvlen = r->vlen; p = p - 1; /* go back by 1 byte */ r->token = NULL; state = SW_SPACES_BEFORE_CAS; } else if (ch == ' ' || ch == CR) { /* vlen_end <- p - 1 */ r->rvlen = r->vlen; p = p - 1; /* go back by 1 byte */ r->token = NULL; state = SW_RUNTO_CRLF; } else { goto error; } break; case SW_SPACES_BEFORE_CAS: if (ch != ' ') { if (!isdigit(ch)) { goto error; } p = p - 1; /* go back by 1 byte */ state = SW_CAS; } break; case SW_CAS: if (r->token == NULL) { /* cas_start <- p */ r->token = p; r->cas = 0; } if (isdigit(ch)) { r->cas = r->cas * 10ULL + (uint64_t)(ch - '0'); } else if (ch == ' ' || ch == CR) { /* cas_end <- p - 1 */ p = p - 1; /* go back by 1 byte */ r->token = NULL; state = SW_RUNTO_CRLF; } else { goto error; } break; case SW_RUNTO_VAL: switch (ch) { case LF: /* val_start <- p + 1 */ state = SW_VAL; break; default: goto error; } break; case SW_VAL: if (r->value == NULL) { r->value = p; } m = p + r->rvlen; if (m >= b->last) { ASSERT(r->rvlen >= (uint32_t)(b->last - p)); r->rvlen -= (uint32_t)(b->last - p); m = b->last - 1; p = m; /* move forward by vlen bytes */ break; } switch (*m) { case CR: /* val_end <- p - 1 */ p = m; /* move forward by vlen bytes */ state = SW_ALMOST_DONE; break; default: goto error; } break; case SW_SPACES_BEFORE_NUM: if (ch != ' ') { if (!isdigit(ch)) { goto error; } p = p - 1; /* go back by 1 byte */ state = SW_NUM; } break; case SW_NUM: if (r->token == NULL) { /* num_start <- p */ r->token = p; r->num = 0; } if (isdigit(ch)) { r->num = r->num * 10ULL + (uint64_t)(ch - '0'); } else if (ch == ' ' || ch == CR) { r->token = NULL; /* num_end <- p - 1 */ p = p - 1; /* go back by 1 byte */ state = SW_RUNTO_CRLF; } else { goto error; } break; case SW_RUNTO_CRLF: switch (ch) { case ' ': break; case 'n': if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)) { p = p - 1; /* go back by 1 byte */ state = SW_NOREPLY; } else { goto error; } break; case CR: if (memcache_storage(r)) { state = SW_RUNTO_VAL; } else { state = SW_ALMOST_DONE; } break; default: goto error; } break; case SW_NOREPLY: if (r->token == NULL) { /* noreply_start <- p */ r->token = p; } switch (ch) { case ' ': case CR: m = r->token; if (((p - m) == 7) && str7cmp(m, 'n', 'o', 'r', 'e', 'p', 'l', 'y')) { ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)); r->token = NULL; /* noreply_end <- p - 1 */ r->noreply = 1; state = SW_AFTER_NOREPLY; p = p - 1; /* go back by 1 byte */ } else { goto error; } } break; case SW_AFTER_NOREPLY: switch (ch) { case ' ': break; case CR: if (memcache_storage(r)) { state = SW_RUNTO_VAL; } else { state = SW_ALMOST_DONE; } break; default: goto error; } break; case SW_CRLF: switch (ch) { case ' ': break; case CR: state = SW_ALMOST_DONE; break; default: goto error; } break; case SW_ALMOST_DONE: switch (ch) { case LF: /* req_end <- p */ goto done; default: goto error; } break; case SW_SENTINEL: default: NOT_REACHED(); break; } } /* * At this point, buffer from b->pos to b->last has been parsed completely * but we haven't been able to reach to any conclusion. Normally, this * means that we have to parse again starting from the state we are in * after more data has been read. The newly read data is either read into * a new mbuf, if existing mbuf is full (b->last == b->end) or into the * existing mbuf. * * The only exception to this is when the existing mbuf is full (b->last * is at b->end) and token marker is set, which means that we have to * copy the partial token into a new mbuf and parse again with more data * read into new mbuf. */ ASSERT(p == b->last); r->pos = p; r->state = state; if (b->last == b->end && r->token != NULL) { r->pos = r->token; r->token = NULL; r->result = MSG_PARSE_REPAIR; } else { r->result = MSG_PARSE_AGAIN; } log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d " "type %d state %d rpos %d of %d", r->id, r->result, r->type, r->state, r->pos - b->pos, b->last - b->pos); return; fragment: ASSERT(p != b->last); ASSERT(r->token != NULL); r->pos = r->token; r->token = NULL; r->state = state; r->result = MSG_PARSE_FRAGMENT; log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d " "type %d state %d rpos %d of %d", r->id, r->result, r->type, r->state, r->pos - b->pos, b->last - b->pos); return; done: ASSERT(r->type > MSG_UNKNOWN && r->type < MSG_SENTINEL); r->pos = p + 1; ASSERT(r->pos <= b->last); r->state = SW_START; r->result = MSG_PARSE_OK; log_hexdump(LOG_VERB, b->pos, mbuf_length(b), "parsed req %"PRIu64" res %d " "type %d state %d rpos %d of %d", r->id, r->result, r->type, r->state, r->pos - b->pos, b->last - b->pos); return; error: r->result = MSG_PARSE_ERROR; r->state = state; errno = EINVAL; log_hexdump(LOG_INFO, b->pos, mbuf_length(b), "parsed bad req %"PRIu64" " "res %d type %d state %d", r->id, r->result, r->type, r->state); }
static int get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) { int rc; MPI plain_dek = NULL; byte *frame = NULL; unsigned n, nframe; u16 csum, csum2; int card = 0; if (sk->is_protected && sk->protect.s2k.mode == 1002) { /* Note, that we only support RSA for now. */ #ifdef ENABLE_CARD_SUPPORT unsigned char *rbuf; size_t rbuflen; char *snbuf; unsigned char *indata = NULL; unsigned int indatalen; snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk); indata = mpi_get_buffer (enc->data[0], &indatalen, NULL); if (!indata) BUG (); rc = agent_scd_pkdecrypt (snbuf, indata, indatalen, &rbuf, &rbuflen); xfree (snbuf); xfree (indata); if (rc) goto leave; frame = rbuf; nframe = rbuflen; card = 1; #else rc = G10ERR_UNSUPPORTED; goto leave; #endif /*!ENABLE_CARD_SUPPORT*/ } else { rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey ); if( rc ) goto leave; frame = mpi_get_buffer( plain_dek, &nframe, NULL ); mpi_free( plain_dek ); plain_dek = NULL; } /* Now get the DEK (data encryption key) from the frame * * Old versions encode the DEK in in this format (msb is left): * * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 * * Later versions encode the DEK like this: * * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (mpi_get_buffer already removed the leading zero). * * RND are non-zero randow bytes. * A is the cipher algorithm * DEK is the encryption key (session key) with length k * CSUM */ if( DBG_CIPHER ) log_hexdump("DEK frame:", frame, nframe ); n=0; if (!card) { if( n + 7 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } if( frame[n] == 1 && frame[nframe-1] == 2 ) { log_info(_("old encoding of the DEK is not supported\n")); rc = G10ERR_CIPHER_ALGO; goto leave; } if( frame[n] != 2 ) /* somethink is wrong */ { rc = G10ERR_WRONG_SECKEY; goto leave; } for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */ ; n++; /* and the zero byte */ } if( n + 4 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } dek->keylen = nframe - (n+1) - 2; dek->algo = frame[n++]; if( dek->algo == CIPHER_ALGO_IDEA ) write_status(STATUS_RSA_OR_IDEA); rc = check_cipher_algo( dek->algo ); if( rc ) { if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) { log_info(_("cipher algorithm %d%s is unknown or disabled\n"), dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":""); if(dek->algo==CIPHER_ALGO_IDEA) idea_cipher_warn(0); } dek->algo = 0; goto leave; } if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) { rc = G10ERR_WRONG_SECKEY; goto leave; } /* copy the key to DEK and compare the checksum */ csum = frame[nframe-2] << 8; csum |= frame[nframe-1]; memcpy( dek->key, frame+n, dek->keylen ); for( csum2=0, n=0; n < dek->keylen; n++ ) csum2 += dek->key[n]; if( csum != csum2 ) { rc = G10ERR_WRONG_SECKEY; goto leave; } if( DBG_CIPHER ) log_hexdump("DEK is:", dek->key, dek->keylen ); /* check that the algo is in the preferences and whether it has expired */ { PKT_public_key *pk = NULL; KBNODE pkb = get_pubkeyblock (keyid); if( !pkb ) { rc = -1; log_error("oops: public key not found for preference check\n"); } else if(pkb->pkt->pkt.public_key->selfsigversion > 3 && dek->algo != CIPHER_ALGO_3DES && !opt.quiet && !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo )) log_info(_("WARNING: cipher algorithm %s not found in recipient" " preferences\n"),cipher_algo_to_string(dek->algo)); if (!rc) { KBNODE k; for (k=pkb; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){ u32 aki[2]; keyid_from_pk(k->pkt->pkt.public_key, aki); if (aki[0]==keyid[0] && aki[1]==keyid[1]) { pk = k->pkt->pkt.public_key; break; } } } if (!pk) BUG (); if ( pk->expiredate && pk->expiredate <= make_timestamp() ) { log_info(_("NOTE: secret key %s expired at %s\n"), keystr(keyid), asctimestamp( pk->expiredate) ); } } if ( pk && pk->is_revoked ) { log_info( _("NOTE: key has been revoked") ); putc( '\n', log_stream() ); show_revocation_reason( pk, 1 ); } release_kbnode (pkb); rc = 0; } leave: mpi_free(plain_dek); xfree(frame); return rc; }
static void asc_process_update(struct conn *c, struct token *token, int ntoken) { char *key; size_t nkey; uint32_t flags, vlen; int32_t exptime_int; time_t exptime; uint64_t req_cas_id = 0; struct item *it; bool handle_cas; req_type_t type; uint8_t id; asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } type = c->req_type; handle_cas = (type == REQ_CAS) ? true : false; key = token[TOKEN_KEY].val; nkey = token[TOKEN_KEY].len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d " "length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_FLAGS].val, &flags)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid flags '%.*s'", c->sd, c->req_type, token[TOKEN_FLAGS].len, token[TOKEN_FLAGS].val); asc_write_client_error(c); return; } if (!mc_strtol(token[TOKEN_EXPIRY].val, &exptime_int)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid expiry '%.*s'", c->sd, c->req_type, token[TOKEN_EXPIRY].len, token[TOKEN_EXPIRY].val); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_VLEN].val, &vlen)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid vlen '%.*s'", c->sd, c->req_type, token[TOKEN_VLEN].len, token[TOKEN_VLEN].val); asc_write_client_error(c); return; } id = item_slabid(nkey, vlen); if (id == SLABCLASS_INVALID_ID) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "slab id out of range for key size %"PRIu8" and value size " "%"PRIu32, c->sd, c->req_type, nkey, vlen); asc_write_client_error(c); return; } exptime = (time_t)exptime_int; /* does cas value exist? */ if (handle_cas) { if (!mc_strtoull(token[TOKEN_CAS].val, &req_cas_id)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid cas '%.*s'", c->sd, c->req_type, token[TOKEN_CAS].len, token[TOKEN_CAS].val); asc_write_client_error(c); return; } } it = item_alloc(id, key, nkey, flags, time_reltime(exptime), vlen); if (it == NULL) { log_warn("server error on c %d for req of type %d because of oom in " "storing item", c->sd, c->req_type); asc_write_server_error(c); /* swallow the data line */ c->write_and_go = CONN_SWALLOW; c->sbytes = vlen + CRLF_LEN; /* * Avoid stale data persisting in cache because we failed alloc. * Unacceptable for SET. Anywhere else too? * * FIXME: either don't delete anything or should be unacceptable for * all but add. */ if (type == REQ_SET) { it = item_get(key, nkey); if (it != NULL) { item_delete(it); } } return; } item_set_cas(it, req_cas_id); c->item = it; c->ritem = item_data(it); c->rlbytes = it->nbyte + CRLF_LEN; conn_set_state(c, CONN_NREAD); }
/**************** * Encrypt the file with the given userids (or ask if none * is supplied). */ int encode_crypt( const char *filename, STRLIST remusr, int use_symkey ) { IOBUF inp = NULL, out = NULL; PACKET pkt; PKT_plaintext *pt = NULL; DEK *symkey_dek = NULL; STRING2KEY *symkey_s2k = NULL; int rc = 0, rc2 = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t afx; compress_filter_context_t zfx; text_filter_context_t tfx; progress_filter_context_t pfx; PK_LIST pk_list,work_list; int do_compress = opt.compress_algo && !RFC1991; memset( &cfx, 0, sizeof cfx); memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); if(use_symkey && (rc=setup_symkey(&symkey_s2k,&symkey_dek))) return rc; if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) ) return rc; if(PGP2) { for(work_list=pk_list; work_list; work_list=work_list->next) if(!(is_RSA(work_list->pk->pubkey_algo) && nbits_from_pk(work_list->pk)<=2048)) { log_info(_("you can only encrypt to RSA keys of 2048 bits or " "less in --pgp2 mode\n")); compliance_failure(); break; } } /* prepare iobufs */ inp = iobuf_open(filename); if (inp) iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */ if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; errno = EPERM; } if( !inp ) { log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]", strerror(errno) ); rc = G10ERR_OPEN_FILE; goto leave; } else if( opt.verbose ) log_info(_("reading from `%s'\n"), filename? filename: "[stdin]"); handle_progress (&pfx, inp, filename); if( opt.textmode ) iobuf_push_filter( inp, text_filter, &tfx ); if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) goto leave; if( opt.armor ) iobuf_push_filter( out, armor_filter, &afx ); /* create a session key */ cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek); if( !opt.def_cipher_algo ) { /* try to get it from the prefs */ cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL); /* The only way select_algo_from_prefs can fail here is when mixing v3 and v4 keys, as v4 keys have an implicit preference entry for 3DES, and the pk_list cannot be empty. In this case, use 3DES anyway as it's the safest choice - perhaps the v3 key is being used in an OpenPGP implementation and we know that the implementation behind any v4 key can handle 3DES. */ if( cfx.dek->algo == -1 ) { cfx.dek->algo = CIPHER_ALGO_3DES; if( PGP2 ) { log_info(_("unable to use the IDEA cipher for all of the keys " "you are encrypting to.\n")); compliance_failure(); } } } else { if(!opt.expert && select_algo_from_prefs(pk_list,PREFTYPE_SYM, opt.def_cipher_algo,NULL)!=opt.def_cipher_algo) log_info(_("WARNING: forcing symmetric cipher %s (%d)" " violates recipient preferences\n"), cipher_algo_to_string(opt.def_cipher_algo), opt.def_cipher_algo); cfx.dek->algo = opt.def_cipher_algo; } cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo); /* Only do the is-file-already-compressed check if we are using a MDC. This forces compressed files to be re-compressed if we do not have a MDC to give some protection against chosen ciphertext attacks. */ if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2) ) { if (opt.verbose) log_info(_("`%s' already compressed\n"), filename); do_compress = 0; } if (rc2) { rc = rc2; goto leave; } make_session_key( cfx.dek ); if( DBG_CIPHER ) log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen ); rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out ); if( rc ) goto leave; /* We put the passphrase (if any) after any public keys as this seems to be the most useful on the recipient side - there is no point in prompting a user for a passphrase if they have the secret key needed to decrypt. */ if(use_symkey && (rc=write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out))) goto leave; if (!opt.no_literal) { /* setup the inner packet */ if( filename || opt.set_filename ) { char *s = make_basename( opt.set_filename ? opt.set_filename : filename, iobuf_get_real_fname( inp ) ); pt = xmalloc( sizeof *pt + strlen(s) - 1 ); pt->namelen = strlen(s); memcpy(pt->name, s, pt->namelen ); xfree(s); } else { /* no filename */ pt = xmalloc( sizeof *pt - 1 ); pt->namelen = 0; } } if (!iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { off_t tmpsize; int overflow; if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) && !overflow ) log_info(_("WARNING: `%s' is an empty file\n"), filename ); /* We can't encode the length of very large files because OpenPGP uses only 32 bit for file sizes. So if the the size of a file is larger than 2^32 minus some bytes for packet headers, we switch to partial length encoding. */ if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) ) filesize = tmpsize; else filesize = 0; } else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { pt->timestamp = make_timestamp(); pt->mode = opt.textmode ? 't' : 'b'; pt->len = filesize; pt->new_ctb = !pt->len && !RFC1991; pt->buf = inp; pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0; } else cfx.datalen = filesize && !do_compress ? filesize : 0; /* register the cipher filter */ iobuf_push_filter( out, cipher_filter, &cfx ); /* register the compress filter */ if( do_compress ) { int compr_algo = opt.compress_algo; if(compr_algo==-1) { if((compr_algo= select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1) compr_algo=DEFAULT_COMPRESS_ALGO; /* Theoretically impossible to get here since uncompressed is implicit. */ } else if(!opt.expert && select_algo_from_prefs(pk_list,PREFTYPE_ZIP, compr_algo,NULL)!=compr_algo) log_info(_("WARNING: forcing compression algorithm %s (%d)" " violates recipient preferences\n"), compress_algo_to_string(compr_algo),compr_algo); /* algo 0 means no compression */ if( compr_algo ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; push_compress_filter(out,&zfx,compr_algo); } } /* do the work */ if (!opt.no_literal) { if( (rc = build_packet( out, &pkt )) ) log_error("build_packet failed: %s\n", g10_errstr(rc) ); } else { /* user requested not to create a literal packet, so we copy the plain data */ byte copy_buffer[4096]; int bytes_copied; while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1) if (iobuf_write(out, copy_buffer, bytes_copied) == -1) { rc = G10ERR_WRITE_FILE; log_error("copying input to output failed: %s\n", g10_errstr(rc) ); break; } wipememory(copy_buffer, 4096); /* burn buffer */ } /* finish the stuff */ leave: iobuf_close(inp); if( rc ) iobuf_cancel(out); else { iobuf_close(out); /* fixme: check returncode */ write_status( STATUS_END_ENCRYPTION ); } if( pt ) pt->buf = NULL; free_packet(&pkt); xfree(cfx.dek); xfree(symkey_dek); xfree(symkey_s2k); release_pk_list( pk_list ); return rc; }
static void asc_process_stats(struct conn *c, struct token *token, int ntoken) { struct token *t = &token[TOKEN_SUBCOMMAND]; if (!stats_enabled()) { log_warn("server error on c %d for req of type %d because stats is " "disabled", c->sd, c->req_type); asc_write_server_error(c); return; } if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (ntoken == 2) { stats_default(c); } else if (strncmp(t->val, "reset", t->len) == 0) { log_warn("server error on c %d for req of type %d because stats reset " "is not supported", c->sd, c->req_type); asc_write_server_error(c); return; } else if (strncmp(t->val, "settings", t->len) == 0) { stats_settings(c); } else if (strncmp(t->val, "cachedump", t->len) == 0) { char *buf; unsigned int bytes, id, limit = 0; if (ntoken < 5) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d " "for req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_CACHEDUMP_ID].val, &id) || !mc_strtoul(token[TOKEN_CACHEDUMP_LIMIT].val, &limit)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "because either id '%.*s' or limit '%.*s' is invalid", c->sd, c->req_type, token[TOKEN_CACHEDUMP_ID].len, token[TOKEN_CACHEDUMP_ID].val, token[TOKEN_CACHEDUMP_LIMIT].len, token[TOKEN_CACHEDUMP_LIMIT].val); asc_write_client_error(c); return; } if (id < SLABCLASS_MIN_ID || id > SLABCLASS_MAX_ID) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "because %d is an illegal slab id", c->sd, c->req_type, id); asc_write_client_error(c); return; } buf = item_cache_dump(id, limit, &bytes); core_write_and_free(c, buf, bytes); return; } else { /* * Getting here means that the sub command is either engine specific * or is invalid. query the engine and see */ if (strncmp(t->val, "slabs", t->len) == 0) { stats_slabs(c); } else if (strncmp(t->val, "sizes", t->len) == 0) { stats_sizes(c); } else { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid stats subcommand '%.*s", c->sd, c->req_type, t->len, t->val); asc_write_client_error(c); return; } if (c->stats.buffer == NULL) { log_warn("server error on c %d for req of type %d because of oom " "writing stats", c->sd, c->req_type); asc_write_server_error(c); } else { core_write_and_free(c, c->stats.buffer, c->stats.offset); c->stats.buffer = NULL; } return; } /* append terminator and start the transfer */ stats_append(c, NULL, 0, NULL, 0); if (c->stats.buffer == NULL) { log_warn("server error on c %d for req of type %d because of oom " "writing stats", c->sd, c->req_type); asc_write_server_error(c); } else { core_write_and_free(c, c->stats.buffer, c->stats.offset); c->stats.buffer = NULL; } }
/**************** * Filter to do a complete public key encryption. */ int encrypt_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { size_t size = *ret_len; encrypt_filter_context_t *efx = opaque; int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */ BUG(); /* not used */ } else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ if( !efx->header_okay ) { efx->cfx.dek = xmalloc_secure_clear( sizeof *efx->cfx.dek ); if( !opt.def_cipher_algo ) { /* try to get it from the prefs */ efx->cfx.dek->algo = select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,-1,NULL); if( efx->cfx.dek->algo == -1 ) { /* because 3DES is implicitly in the prefs, this can only * happen if we do not have any public keys in the list */ efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO; } } else { if(!opt.expert && select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM, opt.def_cipher_algo, NULL)!=opt.def_cipher_algo) log_info(_("forcing symmetric cipher %s (%d) " "violates recipient preferences\n"), cipher_algo_to_string(opt.def_cipher_algo), opt.def_cipher_algo); efx->cfx.dek->algo = opt.def_cipher_algo; } efx->cfx.dek->use_mdc = use_mdc(efx->pk_list,efx->cfx.dek->algo); make_session_key( efx->cfx.dek ); if( DBG_CIPHER ) log_hexdump("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen ); rc = write_pubkey_enc_from_list( efx->pk_list, efx->cfx.dek, a ); if( rc ) return rc; if(efx->symkey_s2k && efx->symkey_dek) { rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek, efx->cfx.dek,a); if(rc) return rc; } iobuf_push_filter( a, cipher_filter, &efx->cfx ); efx->header_okay = 1; } rc = iobuf_write( a, buf, size ); } else if( control == IOBUFCTRL_FREE ) { xfree(efx->symkey_dek); xfree(efx->symkey_s2k); } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "encrypt_filter"; } return rc; }