int iks_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass) { iks *x; x = iks_new("auth"); iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL); switch(type) { case IKS_SASL_PLAIN: { int len = iks_strlen(username) + iks_strlen(pass) + 2; char *s = iks_malloc(80 + len); char *base64; iks_insert_attrib(x, "mechanism", "PLAIN"); sprintf(s, "%c%s%c%s", 0, username, 0, pass); base64 = iks_base64_encode(s, len); iks_insert_cdata(x, base64, 0); iks_free(base64); iks_free(s); break; } case IKS_SASL_DIGEST_MD5: { struct stream_data *data = iks_user_data(prs); iks_insert_attrib(x, "mechanism", "DIGEST-MD5"); data->auth_username = username; data->auth_pass = pass; break; } case IKS_SASL_OAUTH_2: { int len = iks_strlen(username) + iks_strlen(pass) + 2; char *s = iks_malloc(80 + len); char *base64; iks_insert_attrib(x, "mechanism", "X-OAUTH2"); iks_insert_attrib(x, "auth:service", "oauth2"); iks_insert_attrib(x, "xmlns:auth", "http://www.google.com/talk/protocol/auth"); sprintf(s, "%c%s%c%s", 0, username, 0, pass); base64 = iks_base64_encode(s, len); iks_insert_cdata(x, base64, 0); iks_free(base64); iks_free(s); break; } default: iks_delete(x); return IKS_NET_NOTSUPP; } iks_send(prs, x); iks_delete(x); return IKS_OK; }
ikstack * iks_stack_new (size_t meta_chunk, size_t data_chunk) { ikstack *s; size_t len; if (meta_chunk < MIN_CHUNK_SIZE) meta_chunk = MIN_CHUNK_SIZE; if (meta_chunk & ALIGN_MASK) meta_chunk = ALIGN (meta_chunk); if (data_chunk < MIN_CHUNK_SIZE) data_chunk = MIN_CHUNK_SIZE; if (data_chunk & ALIGN_MASK) data_chunk = ALIGN (data_chunk); len = sizeof (ikstack) + meta_chunk + data_chunk + (sizeof (ikschunk) * 2); s = iks_malloc (len); if (!s) return NULL; s->allocated = len; s->meta = (ikschunk *) ((char *) s + sizeof (ikstack)); s->meta->next = NULL; s->meta->size = meta_chunk; s->meta->used = 0; s->meta->last = (size_t) -1; s->data = (ikschunk *) ((char *) s + sizeof (ikstack) + sizeof (ikschunk) + meta_chunk); s->data->next = NULL; s->data->size = data_chunk; s->data->used = 0; s->data->last = (size_t) -1; return s; }
static int stack_expand (iksparser *prs, int len) { size_t need; off_t diff; char *tmp; need = len - (prs->stack_max - prs->stack_pos); if (need < prs->stack_max) { need = prs->stack_max * 2; } else { /* need x 1.2 for integer only archs like ARM */ need = prs->stack_max + ( (need * 6) / 5); } tmp = iks_malloc (need); if (!tmp) return 0; diff = tmp - prs->stack; memcpy (tmp, prs->stack, prs->stack_max); iks_free (prs->stack); prs->stack = tmp; prs->stack_max = need; prs->tag_name += diff; if (prs->attflag != 0) { int i = 0; while ((unsigned)i < (prs->attmax * 2)) { if (prs->atts[i]) prs->atts[i] += diff; i++; } } return 1; }
static int tls_handshake (struct ikstls_data **datap, ikstransport *trans, void *sock) { const int protocol_priority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; const int kx_priority[] = { GNUTLS_KX_RSA, 0 }; const int cipher_priority[] = { GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0}; const int comp_priority[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; const int mac_priority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 }; struct ikstls_data *data; int ret; *datap = NULL; data = iks_malloc (sizeof(*data)); if (!data) return IKS_NOMEM; memset (data, 0, sizeof(*data)); data->trans = trans; data->sock = sock; data->timeout = -1; if (gnutls_global_init () != 0) { iks_free (data); return IKS_NOMEM; } if (gnutls_certificate_allocate_credentials (&data->cred) < 0) { iks_free (data); return IKS_NOMEM; } if (gnutls_init (&data->sess, GNUTLS_CLIENT) != 0) { gnutls_certificate_free_credentials (data->cred); iks_free (data); return IKS_NOMEM; } gnutls_protocol_set_priority (data->sess, protocol_priority); gnutls_cipher_set_priority(data->sess, cipher_priority); gnutls_compression_set_priority(data->sess, comp_priority); gnutls_kx_set_priority(data->sess, kx_priority); gnutls_mac_set_priority(data->sess, mac_priority); gnutls_credentials_set (data->sess, GNUTLS_CRD_CERTIFICATE, data->cred); gnutls_transport_set_push_function (data->sess, (gnutls_push_func) tls_push); gnutls_transport_set_pull_function (data->sess, (gnutls_pull_func) tls_pull); gnutls_transport_set_ptr (data->sess, data); ret = gnutls_handshake (data->sess); if (ret != 0) { gnutls_deinit (data->sess); gnutls_certificate_free_credentials (data->cred); iks_free (data); return IKS_NET_TLSFAIL; } *datap = data; return IKS_OK; }
static int stack_init (iksparser *prs) { prs->stack = iks_malloc (128); if (!prs->stack) return 0; prs->stack_max = 128; prs->stack_pos = 0; return 1; }
iksmd5 *iks_md5_new(void) { iksmd5 *md5 = iks_malloc(sizeof(iksmd5)); if (!md5) return NULL; iks_md5_reset(md5); return md5; }
char *iks_urlencode_new(const char *s) { int len = iks_urlencode_len(s) + 1; char *res; if((res = iks_malloc(len))) { iks_urlencode_copy(s, res); res[len] = 0x00; } return res; }
iksparser * iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook) { iksparser *prs; prs = iks_malloc (sizeof (iksparser)); if (NULL == prs) return NULL; memset (prs, 0, sizeof (iksparser)); prs->user_data = user_data; prs->tagHook = tagHook; prs->cdataHook = cdataHook; return prs; }
char *iks_base64_decode(const char *buf) { char *res, *save; char val; const char *foo; const char *end; int index; size_t len; if (!buf) return NULL; len = iks_strlen(buf) * 6 / 8 + 1; save = res = iks_malloc(len); if (!save) return NULL; memset(res, 0, len); index = 0; end = buf + iks_strlen(buf); while (*buf && buf < end) { if (!(foo = strchr(base64_charset, *buf))) foo = base64_charset; val = (int)(foo - base64_charset); buf++; switch (index) { case 0: *res |= val << 2; break; case 1: *res++ |= val >> 4; *res |= val << 4; break; case 2: *res++ |= val >> 2; *res |= val << 6; break; case 3: *res++ |= val; break; } index++; index %= 4; } *res = 0; return save; }
int iks_send_header(iksparser *prs, const char *to) { struct stream_data *data = iks_user_data(prs); char *msg; int len, err; len = 91 + strlen(data->name_space) + 6 + strlen(to) + 16 + 1; msg = iks_malloc(len); if(!msg) return IKS_NOMEM; sprintf(msg, "<?xml version='1.0'?>" "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='" "%s' to='%s' version='1.0'>", data->name_space, to); err = iks_send_raw(prs, msg); iks_free(msg); if(err) return err; data->server = to; return IKS_OK; }
// In the mainline version this function took "to" as an argument, but // are we not always talking to self->server? int ikss_Stream_send_header (ikss_Stream *self) { char *msg; int len, err; const char *to = self->server; len = 91 + strlen (self->name_space) + 6 + strlen (to) + 16 + 1; msg = iks_malloc (len); if (!msg) return IKS_NOMEM; // We are XMPP compliant, and hence sending a version number, too. // Note that "jabberd" is not compliant in this sense. sprintf (msg, "<?xml version='1.0'?>" "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='" "%s' to='%s' version='1.0'>", self->name_space, to); err = ikss_Stream_send_raw (self, msg); if (err) return err; return IKS_OK; }
char *iks_base64_encode(const char *buf, int len) { char *res, *save; int k, t; if (len == 0) len = (iks_strlen(buf)); save = res = iks_malloc((len*8) / 6 + 4); if (!save) return NULL; for (k = 0; k < len/3; ++k) { *res++ = base64_charset[*buf >> 2]; t = ((*buf & 0x03) << 4); buf++; *res++ = base64_charset[t | (*buf >> 4)]; t = ((*buf & 0x0F) << 2); buf++; *res++ = base64_charset[t | (*buf >> 6)]; *res++ = base64_charset[*buf++ & 0x3F]; } switch (len % 3) { case 2: *res++ = base64_charset[*buf >> 2]; t = ((*buf & 0x03) << 4); buf++; *res++ = base64_charset[t | (*buf >> 4)]; *res++ = base64_charset[((*buf++ & 0x0F) << 2)]; *res++ = '='; break; case 1: *res++ = base64_charset[*buf >> 2]; *res++ = base64_charset[(*buf++ & 0x03) << 4]; *res++ = '='; *res++ = '='; break; } *res = 0; return save; }
static ikschunk * find_space (ikstack *s, ikschunk *c, size_t size) { /* FIXME: dont use *2 after over allocated chunks */ while (1) { if (c->size - c->used >= size) return c; if (!c->next) { if ((c->size * 2) > size) size = c->size * 2; c->next = iks_malloc (sizeof (ikschunk) + size); if (!c->next) return NULL; s->allocated += sizeof (ikschunk) + size; c = c->next; c->next = NULL; c->size = size; c->used = 0; c->last = (size_t) -1; return c; } c = c->next; } return NULL; }
// Takes ownership of "xmlstr", unconditionally. Do NOT pass in any // string allocated from an iks_stack, as mallocing is assumed. int ikss_Stream_send_raw (ikss_Stream *self, char *xmlstr) { #if !defined(__SYMBIAN32__) printf("SEND '%s'\n", xmlstr); #endif /* __SYMBIAN32__ */ if (ikst_IsSendActive(self->sock)) { // Not allowed to do another send, just buffer the data. if (self->send_more_buf) { char* newbuf = iks_malloc(strlen(self->send_more_buf) + strlen(xmlstr) + 1); if (!newbuf) return IKS_NOMEM; strcpy(newbuf, self->send_more_buf); strcat(newbuf, xmlstr); free(xmlstr); free(self->send_more_buf); self->send_more_buf = newbuf; } else { self->send_more_buf = xmlstr; } return 0; } resetSendBuf(self); int len = strlen(xmlstr); int ret = ikst_Send (self->sock, xmlstr, len); if (ret) { free(xmlstr); return ret; } else { self->send_buf = xmlstr; self->send_len = len; self->send_count = 0; return IKS_OK; } }
// if returns IKS_OK, do not send more before ikss_SENT callback int ikss_Stream_start_sasl (ikss_Stream *self, enum ikssasltype type, const char *username, const char *pass) { iks *x; x = iks_new ("auth"); // xxx check return? iks_insert_attrib (x, "xmlns", IKS_NS_XMPP_SASL); // xxx check return? switch (type) { case IKS_SASL_PLAIN: { int len = iks_strlen (username) + iks_strlen (pass) + 2; char *s = iks_malloc (80+len); // xxx check for oom, on error free x and return error code char *base64; iks_insert_attrib (x, "mechanism", "PLAIN"); // xxx check return? sprintf (s, "%c%s%c%s", 0, username, 0, pass); base64 = iks_base64_encode (s, len); // xxx check return? iks_insert_cdata (x, base64, 0); iks_free (base64); iks_free (s); break; } case IKS_SASL_DIGEST_MD5: { iks_insert_attrib (x, "mechanism", "DIGEST-MD5"); // xxx check return? self->auth_username = username; self->auth_pass = pass; break; } default: iks_delete (x); return IKS_NET_NOTSUPP; } int ret = ikss_Stream_send_node (self, x); iks_delete (x); // delete ok since above makes a copy if (ret) return ret; return IKS_OK; }
static enum ikserror sax_core (iksparser *prs, char *buf, int len) { enum ikserror err; int pos = 0, old = 0, re, stack_old = -1; unsigned char c; while (pos < len) { re = 0; c = buf[pos]; if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML; if (prs->uni_max) { if ((c & 0xC0) != 0x80) return IKS_BADXML; prs->uni_char <<= 6; prs->uni_char += (c & 0x3f); prs->uni_len++; if (prs->uni_len == prs->uni_max) { /* Security check: avoid overlong sequences */ if (prs->uni_max == 2 && prs->uni_char < 0x80) return IKS_BADXML; if (prs->uni_max == 3 && prs->uni_char < 0x7FF) return IKS_BADXML; if (prs->uni_max == 4 && prs->uni_char < 0xffff) return IKS_BADXML; if (prs->uni_max == 5 && prs->uni_char < 0x1fffff) return IKS_BADXML; if (prs->uni_max == 6 && prs->uni_char < 0x3ffffff) return IKS_BADXML; prs->uni_max = 0; prs->uni_char = 0; } goto cont; } else { if (c & 0x80) { unsigned char mask; if ((c & 0x60) == 0x40) { prs->uni_max = 2; mask = 0x1F; } else if ((c & 0x70) == 0x60) { prs->uni_max = 3; mask = 0x0F; } else if ((c & 0x78) == 0x70) { prs->uni_max = 4; mask = 0x07; } else if ((c & 0x7C) == 0x78) { prs->uni_max = 5; mask = 0x03; } else if ((c & 0x7E) == 0x7C) { prs->uni_max = 6; mask = 0x01; } else { return IKS_BADXML; } prs->uni_char = c & mask; prs->uni_len = 1; if (stack_old == -1 && (prs->context == C_TAG || prs->context == C_ATTRIBUTE_1 || prs->context == C_VALUE_APOS || prs->context == C_VALUE_QUOT)) stack_old = pos; goto cont; } } switch (prs->context) { case C_CDATA: if ('&' == c) { if (old < pos && prs->cdataHook) { err = prs->cdataHook (prs->user_data, &buf[old], pos - old); if (IKS_OK != err) return err; } prs->context = C_ENTITY; prs->entpos = 0; break; } if ('<' == c) { if (old < pos && prs->cdataHook) { err = prs->cdataHook (prs->user_data, &buf[old], pos - old); if (IKS_OK != err) return err; } STACK_INIT; prs->tag_name = STACK_PUSH_START; if (!prs->tag_name) return IKS_NOMEM; prs->context = C_TAG_START; } break; case C_TAG_START: prs->context = C_TAG; if ('/' == c) { prs->tagtype = IKS_CLOSE; break; } if ('?' == c) { prs->context = C_PI; break; } if ('!' == c) { prs->context = C_MARKUP; break; } prs->tagtype = IKS_OPEN; stack_old = pos; break; case C_TAG: if (IS_WHITESPACE(c)) { if (IKS_CLOSE == prs->tagtype) prs->oldcontext = C_TAG_END; else prs->oldcontext = C_ATTRIBUTE; prs->context = C_WHITESPACE; if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; break; } if ('/' == c) { if (IKS_CLOSE == prs->tagtype) return IKS_BADXML; prs->tagtype = IKS_SINGLE; prs->context = C_TAG_END; if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; break; } if ('>' == c) { prs->context = C_TAG_END; if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; re = 1; break; } if (stack_old == -1) stack_old = pos; break; case C_TAG_END: if (c != '>') return IKS_BADXML; if (prs->tagHook) { char **tmp; if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts; err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype); if (IKS_OK != err) return err; } prs->stack_pos = 0; stack_old = -1; prs->attcur = 0; prs->attflag = 0; prs->context = C_CDATA; old = pos + 1; break; case C_ATTRIBUTE: if ('/' == c) { prs->tagtype = IKS_SINGLE; prs->context = C_TAG_END; break; } if ('>' == c) { prs->context = C_TAG_END; re = 1; break; } if (!prs->atts) { prs->attmax = 12; prs->atts = iks_malloc (sizeof(char *) * 2 * 12); if (!prs->atts) return IKS_NOMEM; memset (prs->atts, 0, sizeof(char *) * 2 * 12); prs->attcur = 0; } else { if (prs->attcur >= ((prs->attmax - 1) * 2)) { void *tmp; prs->attmax += 12; tmp = iks_malloc (sizeof(char *) * 2 * prs->attmax); if (!tmp) return IKS_NOMEM; memset (tmp, 0, sizeof(char *) * 2 * prs->attmax); memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur); free (prs->atts); prs->atts = tmp; } } prs->attflag = 1; prs->atts[prs->attcur] = STACK_PUSH_START; stack_old = pos; prs->context = C_ATTRIBUTE_1; break; case C_ATTRIBUTE_1: if ('=' == c) { if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; prs->context = C_VALUE; break; } if (IS_WHITESPACE(c)) { if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; prs->oldcontext = C_ATTRIBUTE_1; prs->context = C_WHITESPACE; break; } if (stack_old == -1) stack_old = pos; break; case C_ATTRIBUTE_2: if ('/' == c) { prs->tagtype = IKS_SINGLE; prs->atts[prs->attcur] = NULL; prs->context = C_TAG_END; break; } if ('>' == c) { prs->atts[prs->attcur] = NULL; prs->context = C_TAG_END; re = 1; break; } prs->context = C_ATTRIBUTE; re = 1; break; case C_VALUE: if (IS_WHITESPACE(c)) break; prs->atts[prs->attcur + 1] = STACK_PUSH_START; if ('\'' == c) { prs->context = C_VALUE_APOS; break; } if ('"' == c) { prs->context = C_VALUE_QUOT; break; } return IKS_BADXML; case C_VALUE_APOS: if ('\'' == c) { if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; prs->oldcontext = C_ATTRIBUTE_2; prs->context = C_WHITESPACE; prs->attcur += 2; } if (stack_old == -1) stack_old = pos; break; case C_VALUE_QUOT: if ('"' == c) { if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); stack_old = -1; STACK_PUSH_END; prs->oldcontext = C_ATTRIBUTE_2; prs->context = C_WHITESPACE; prs->attcur += 2; } if (stack_old == -1) stack_old = pos; break; case C_WHITESPACE: if (NOT_WHITESPACE(c)) { prs->context = prs->oldcontext; re = 1; } break; case C_ENTITY: if (';' == c) { char hede[2]; char t = '?'; prs->entity[prs->entpos] = '\0'; if (strcmp(prs->entity, "amp") == 0) t = '&'; else if (strcmp(prs->entity, "quot") == 0) t = '"'; else if (strcmp(prs->entity, "apos") == 0) t = '\''; else if (strcmp(prs->entity, "lt") == 0) t = '<'; else if (strcmp(prs->entity, "gt") == 0) t = '>'; old = pos + 1; hede[0] = t; if (prs->cdataHook) { err = prs->cdataHook (prs->user_data, &hede[0], 1); if (IKS_OK != err) return err; } prs->context = C_CDATA; } else { prs->entity[prs->entpos++] = buf[pos]; if (prs->entpos > 7) return IKS_BADXML; } break; case C_COMMENT: if ('-' != c) return IKS_BADXML; prs->context = C_COMMENT_1; break; case C_COMMENT_1: if ('-' == c) prs->context = C_COMMENT_2; break; case C_COMMENT_2: if ('-' == c) prs->context = C_COMMENT_3; else prs->context = C_COMMENT_1; break; case C_COMMENT_3: if ('>' != c) return IKS_BADXML; prs->context = C_CDATA; old = pos + 1; break; case C_MARKUP: if ('[' == c) { prs->context = C_SECT; break; } if ('-' == c) { prs->context = C_COMMENT; break; } prs->context = C_MARKUP_1; case C_MARKUP_1: if ('>' == c) { old = pos + 1; prs->context = C_CDATA; } break; case C_SECT: if ('C' == c) { prs->context = C_SECT_CDATA; break; } return IKS_BADXML; case C_SECT_CDATA: if ('D' != c) return IKS_BADXML; prs->context = C_SECT_CDATA_1; break; case C_SECT_CDATA_1: if ('A' != c) return IKS_BADXML; prs->context = C_SECT_CDATA_2; break; case C_SECT_CDATA_2: if ('T' != c) return IKS_BADXML; prs->context = C_SECT_CDATA_3; break; case C_SECT_CDATA_3: if ('A' != c) return IKS_BADXML; prs->context = C_SECT_CDATA_4; break; case C_SECT_CDATA_4: if ('[' != c) return IKS_BADXML; old = pos + 1; prs->context = C_SECT_CDATA_C; break; case C_SECT_CDATA_C: if (']' == c) { prs->context = C_SECT_CDATA_E; if (prs->cdataHook && old < pos) { err = prs->cdataHook (prs->user_data, &buf[old], pos - old); if (IKS_OK != err) return err; } } break; case C_SECT_CDATA_E: if (']' == c) { prs->context = C_SECT_CDATA_E2; } else { if (prs->cdataHook) { err = prs->cdataHook (prs->user_data, "]", 1); if (IKS_OK != err) return err; } old = pos; prs->context = C_SECT_CDATA_C; } break; case C_SECT_CDATA_E2: if ('>' == c) { old = pos + 1; prs->context = C_CDATA; } else { if (prs->cdataHook) { err = prs->cdataHook (prs->user_data, "]]", 2); if (IKS_OK != err) return err; } old = pos; prs->context = C_SECT_CDATA_C; } break; case C_PI: old = pos + 1; if ('>' == c) prs->context = C_CDATA; break; } cont: if (0 == re) { pos++; prs->nr_bytes++; if ('\n' == c) prs->nr_lines++; } } if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); err = IKS_OK; if (prs->cdataHook && (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) && old < pos) err = prs->cdataHook (prs->user_data, &buf[old], pos - old); return err; }
static iks *make_sasl_response(struct stream_data *data, char *message) { iks *x = NULL; char *realm, *realm_end; char *nonce, *nonce_end; char cnonce[CNONCE_LEN * 8 + 1]; iksmd5 *md5; unsigned char a1_h[16], a1[33], a2[33], response_value[33]; char *response, *response_coded; int i; parse_digest(message, "realm=\"", &realm, &realm_end); parse_digest(message, "nonce=\"", &nonce, &nonce_end); /* nonce is necessary for auth */ if(!nonce || !nonce_end) return NULL; *nonce_end = '\0'; /* if no realm is given use the server hostname */ if(realm) { if(!realm_end) return NULL; *realm_end = '\0'; } else { realm = (char *) data->server; } /* generate random client challenge */ for(i = 0; i < CNONCE_LEN; ++i) sprintf(cnonce + i * 8, "%08x", rand()); md5 = iks_md5_new(); if(!md5) return NULL; iks_md5_hash(md5, (const unsigned char*)data->auth_username, iks_strlen(data->auth_username), 0); iks_md5_hash(md5, (const unsigned char*)":", 1, 0); iks_md5_hash(md5, (const unsigned char*)realm, iks_strlen(realm), 0); iks_md5_hash(md5, (const unsigned char*)":", 1, 0); iks_md5_hash(md5, (const unsigned char*)data->auth_pass, iks_strlen(data->auth_pass), 1); iks_md5_digest(md5, a1_h); iks_md5_reset(md5); iks_md5_hash(md5, (const unsigned char*)a1_h, 16, 0); iks_md5_hash(md5, (const unsigned char*)":", 1, 0); iks_md5_hash(md5, (const unsigned char*)nonce, iks_strlen(nonce), 0); iks_md5_hash(md5, (const unsigned char*)":", 1, 0); iks_md5_hash(md5, (const unsigned char*)cnonce, iks_strlen(cnonce), 1); iks_md5_print(md5, (char*)a1); iks_md5_reset(md5); iks_md5_hash(md5, (const unsigned char*)"AUTHENTICATE:xmpp/", 18, 0); iks_md5_hash(md5, (const unsigned char*)data->server, iks_strlen(data->server), 1); iks_md5_print(md5, (char*)a2); iks_md5_reset(md5); iks_md5_hash(md5, (const unsigned char*)a1, 32, 0); iks_md5_hash(md5, (const unsigned char*)":", 1, 0); iks_md5_hash(md5, (const unsigned char*)nonce, iks_strlen(nonce), 0); iks_md5_hash(md5, (const unsigned char*)":00000001:", 10, 0); iks_md5_hash(md5, (const unsigned char*)cnonce, iks_strlen(cnonce), 0); iks_md5_hash(md5, (const unsigned char*)":auth:", 6, 0); iks_md5_hash(md5, (const unsigned char*)a2, 32, 1); iks_md5_print(md5, (char*)response_value); iks_md5_delete(md5); i = iks_strlen(data->auth_username) + iks_strlen(realm) + iks_strlen(nonce) + iks_strlen(data->server) + CNONCE_LEN * 8 + 136; response = iks_malloc(i); if(!response) return NULL; sprintf(response, "username=\"%s\",realm=\"%s\",nonce=\"%s\"" ",cnonce=\"%s\",nc=00000001,qop=auth,digest-uri=\"" "xmpp/%s\",response=%s,charset=utf-8", data->auth_username, realm, nonce, cnonce, data->server, response_value); response_coded = iks_base64_encode(response, 0); if(response_coded) { x = iks_new("response"); iks_insert_cdata(x, response_coded, 0); iks_free(response_coded); } iks_free(response); return x; }
// Note that "s" may be NULL, in which case strings are not allocated // from the stack, and in which case the caller is responsible for // freeing any returned string. char * iks_string (ikstack *s, iks *x) { size_t size; int level, dir; iks *y, *z; char *ret, *t; if (!x) return NULL; if (x->type == IKS_CDATA) { if (s) { return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); } else { ret = iks_malloc (IKS_CDATA_LEN (x)); memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); return ret; } } size = 0; level = 0; dir = 0; y = x; while (1) { if (dir==0) { if (y->type == IKS_TAG) { size++; size += strlen (IKS_TAG_NAME (y)); for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) { size += 4 + strlen (IKS_ATTRIB_NAME (z)) + escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z))); } if (IKS_TAG_CHILDREN (y)) { size++; y = IKS_TAG_CHILDREN (y); level++; continue; } else { size += 2; } } else { size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y)); } } z = y->next; if (z) { if (0 == level) { if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y)); break; } y = z; dir = 0; } else { y = y->parent; level--; if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y)); if (level < 1) break; dir = 1; } } if (s) ret = iks_stack_alloc (s, size + 1); else ret = iks_malloc (size + 1); if (!ret) return NULL; t = ret; level = 0; dir = 0; while (1) { if (dir==0) { if (x->type == IKS_TAG) { *t++ = '<'; t = my_strcat (t, IKS_TAG_NAME (x), 0); y = IKS_TAG_ATTRIBS (x); while (y) { *t++ = ' '; t = my_strcat (t, IKS_ATTRIB_NAME (y), 0); *t++ = '='; *t++ = '\''; t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y))); *t++ = '\''; y = y->next; } if (IKS_TAG_CHILDREN (x)) { *t++ = '>'; x = IKS_TAG_CHILDREN (x); level++; continue; } else { *t++ = '/'; *t++ = '>'; } } else { t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); } } y = x->next; if (y) { if (0 == level) { if (IKS_TAG_CHILDREN (x)) { *t++ = '<'; *t++ = '/'; t = my_strcat (t, IKS_TAG_NAME (x), 0); *t++ = '>'; } break; } x = y; dir = 0; } else { x = x->parent; level--; if (level >= 0) { *t++ = '<'; *t++ = '/'; t = my_strcat (t, IKS_TAG_NAME (x), 0); *t++ = '>'; } if (level < 1) break; dir = 1; } } *t = '\0'; return ret; }