static int read_msg(Msg **msg, Octstr *os, long *off) { unsigned char buf[4]; long i; Octstr *pack; gw_assert(*off >= 0); if (*off + 4 > octstr_len(os)) { error(0, "Packet too short while unpacking Msg."); return -1; } octstr_get_many_chars((char*)buf, os, *off, 4); i = decode_network_long(buf); *off += 4; pack = octstr_copy(os, *off, i); *off += octstr_len(pack); *msg = store_msg_unpack(pack); octstr_destroy(pack); if (!*msg) return -1; return 0; }
static void write_data(Octstr *out, int fd) { unsigned char buf[EVIL_BUFSIZE]; int len; ssize_t ret; len = sizeof(buf); if (len > octstr_len(out)) len = octstr_len(out); if (len == 0) return; octstr_get_many_chars(buf, out, 0, len); ret = write(fd, buf, len); if (ret > 0) { if (logging == LOG_data) pretty_print(buf, ret); octstr_delete(out, 0, ret); } else if (ret == 0) { warning(0, "empty write"); } else { if (errno == EINTR || errno == EAGAIN) return; error(errno, "write_data"); exit(1); } }
/* Is there a comment beginning at offset `pos'? */ static int html_comment_begins(Octstr *html, long pos) { char buf[10]; octstr_get_many_chars(buf, html, pos, 4); buf[5] = '\0'; return strcmp(buf, "<!--") == 0; }
/* * Find the first packet in "in", delete it from "in", and return it as * a struct. Return NULL if "in" contains no packet. Always delete * leading non-packet data from "in". */ static struct packet *packet_extract(Octstr *in, SMSCConn *conn) { Octstr *packet; int size, i; static char s[4][4] = { { 0x01, 0x0b, 0x00, 0x00 }, { 0x01, 0x00, 0x00, 0x00 }, { 0x00, 0x04, 0x00, 0x00 }, { 0x00, 0x09, 0x00, 0x00 } }; /* msgtype, oper, 0, 0 */ char known_bytes[4]; if (octstr_len(in) < 10) return NULL; octstr_get_many_chars(known_bytes, in, 4, 4); /* Find s, and delete everything up to it. */ /* If packet starts with one of s, it should be good packet */ for (i = 0; i < 4; i++) { if (memcmp(s[i], known_bytes, 4) == 0) break; } if (i >= 4) { error(0, "OISD[%s]: wrong packet", octstr_get_cstr(conn->id)); octstr_dump(in, 0); return NULL; } /* Find end of packet */ size = (octstr_get_char(in, 9) << 8) | octstr_get_char(in, 8); if (size + 10 > octstr_len(in)) return NULL; packet = octstr_copy(in, 0, size + 10); octstr_delete(in, 0, size + 10); return packet_parse(packet); }
long smpp_pdu_read_len(Connection *conn) { Octstr *os; char buf[4]; /* The length is 4 octets. */ long len; os = conn_read_fixed(conn, sizeof(buf)); if (os == NULL) return 0; octstr_get_many_chars(buf, os, 0, sizeof(buf)); octstr_destroy(os); len = decode_network_long(buf); if (len < MIN_SMPP_PDU_LEN) { error(0, "SMPP: PDU length was too small (%ld, minimum is %ld).", len, (long) MIN_SMPP_PDU_LEN); return -1; } if (len > MAX_SMPP_PDU_LEN) { error(0, "SMPP: PDU length was too large (%ld, maximum is %ld).", len, (long) MAX_SMPP_PDU_LEN); return -1; } return len; }
/* Convert an HTML entity into a single character and advance `*html' past the entity. */ static void convert_html_entity(Octstr *sms, Octstr *html, long *pos) { static struct { char *entity; int latin1; } tab[] = { { "&", '&' }, { "<", '<' }, { ">", '>' }, /* The following is copied from http://www.hut.fi/~jkorpela/HTML3.2/latin1.html by Jukka Korpela. Hand and script edited to form this table. */ { " ", ' ' }, { "¡", 161 }, { "¢", 162 }, { "£", 163 }, { "¤", 164 }, { "¥", 165 }, { "¦", 166 }, { "§", 167 }, { "¨", 168 }, { "©", 169 }, { "ª", 170 }, { "«", 171 }, { "¬", 172 }, { "­", 173 }, { "®", 174 }, { "¯", 175 }, { "°", 176 }, { "±", 177 }, { "²", 178 }, { "³", 179 }, { "´", 180 }, { "µ", 181 }, { "¶", 182 }, { "·", 183 }, { "¸", 184 }, { "¹", 185 }, { "º", 186 }, { "»", 187 }, { "¼", 188 }, { "½", 189 }, { "¾", 190 }, { "¿", 191 }, { "À", 192 }, { "Á", 193 }, { "Â", 194 }, { "Ã", 195 }, { "Ä", 196 }, { "Å", 197 }, { "Æ", 198 }, { "Ç", 199 }, { "È", 200 }, { "É", 201 }, { "Ê", 202 }, { "Ë", 203 }, { "Ì", 204 }, { "Í", 205 }, { "Î", 206 }, { "Ï", 207 }, { "Ð", 208 }, { "Ñ", 209 }, { "Ò", 210 }, { "Ó", 211 }, { "Ô", 212 }, { "Õ", 213 }, { "Ö", 214 }, { "×", 215 }, { "Ø", 216 }, { "Ù", 217 }, { "Ú", 218 }, { "Û", 219 }, { "Ü", 220 }, { "Ý", 221 }, { "Þ", 222 }, { "ß", 223 }, { "à", 224 }, { "á", 225 }, { "â", 226 }, { "ã", 227 }, { "ä", 228 }, { "å", 229 }, { "æ", 230 }, { "ç", 231 }, { "è", 232 }, { "é", 233 }, { "ê", 234 }, { "ë", 235 }, { "ì", 236 }, { "í", 237 }, { "î", 238 }, { "ï", 239 }, { "ð", 240 }, { "ñ", 241 }, { "ò", 242 }, { "ó", 243 }, { "ô", 244 }, { "õ", 245 }, { "ö", 246 }, { "÷", 247 }, { "ø", 248 }, { "ù", 249 }, { "ú", 250 }, { "û", 251 }, { "ü", 252 }, { "ý", 253 }, { "þ", 254 }, { "ÿ", 255 }, }; int num_tab = sizeof(tab) / sizeof(tab[0]); long i, code; size_t len; char buf[1024]; if (octstr_get_char(html, *pos + 1) == '#') { if (octstr_get_char(html, *pos + 2) == 'x' || octstr_get_char(html, *pos + 2) == 'X') i = octstr_parse_long(&code, html, *pos + 3, 16); /* hex */ else i = octstr_parse_long(&code, html, *pos + 2, 10); /* decimal */ if (i > 0) { if (code < 256) octstr_append_char(sms, code); *pos = i + 1; if (octstr_get_char(html, *pos) == ';') ++(*pos); } else { ++(*pos); octstr_append_char(sms, '&'); } } else { for (i = 0; i < num_tab; ++i) { len = strlen(tab[i].entity); octstr_get_many_chars(buf, html, *pos, len); buf[len] = '\0'; if (strcmp(buf, tab[i].entity) == 0) { *pos += len; octstr_append_char(sms, tab[i].latin1); break; } } if (i == num_tab) { ++(*pos); octstr_append_char(sms, '&'); } } }
Octstr *conn_read_withlen(Connection *conn) { Octstr *result = NULL; unsigned char lengthbuf[4]; long length = 0; /* for compiler please */ int try, retry; lock_in(conn); for (try = 1; try <= 2; try++) { if (try > 1) unlocked_read(conn); do { retry = 0; /* First get the length. */ if (unlocked_inbuf_len(conn) < 4) continue; octstr_get_many_chars(lengthbuf, conn->inbuf, conn->inbufpos, 4); length = decode_network_long(lengthbuf); if (length < 0) { warning(0, "conn_read_withlen: got negative length, skipping"); conn->inbufpos += 4; retry = 1; } } while(retry == 1); /* Then get the data. */ if (unlocked_inbuf_len(conn) - 4 < length) continue; conn->inbufpos += 4; result = unlocked_get(conn, length); gw_claim_area(result); break; } unlock_in(conn); return result; } Octstr *conn_read_packet(Connection *conn, int startmark, int endmark) { int startpos, endpos; Octstr *result = NULL; int try; lock_in(conn); for (try = 1; try <= 2; try++) { if (try > 1) unlocked_read(conn); /* Find startmark, and discard everything up to it */ if (startmark >= 0) { startpos = octstr_search_char(conn->inbuf, startmark, conn->inbufpos); if (startpos < 0) { conn->inbufpos = octstr_len(conn->inbuf); continue; } else { conn->inbufpos = startpos; } } else { startpos = conn->inbufpos; } /* Find first endmark after startmark */ endpos = octstr_search_char(conn->inbuf, endmark, conn->inbufpos); if (endpos < 0) continue; result = unlocked_get(conn, endpos - startpos + 1); gw_claim_area(result); break; } unlock_in(conn); return result; } #ifdef HAVE_LIBSSL X509 *conn_get_peer_certificate(Connection *conn) { /* Don't know if it needed to be locked , but better safe as crash */ lock_out(conn); lock_in(conn); if (conn->peer_certificate == NULL && conn->ssl != NULL) conn->peer_certificate = SSL_get_peer_certificate(conn->ssl); unlock_in(conn); unlock_out(conn); return conn->peer_certificate; } /* * XXX Alex decalred the RSA callback routine static and now we're getting * warning messages for our automatic compilation tests. So we are commenting * the function out to avoid the warnings. * static RSA *tmp_rsa_callback(SSL *ssl, int export, int key_len) { static RSA *rsa = NULL; debug("gwlib.http", 0, "SSL: Generating new RSA key (export=%d, keylen=%d)", export, key_len); if (export) { rsa = RSA_generate_key(key_len, RSA_F4, NULL, NULL); } else { debug("gwlib.http", 0, "SSL: Export not set"); } return rsa; } */ static Mutex **ssl_static_locks = NULL; /* the call-back function for the openssl crypto thread locking */ static void openssl_locking_function(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) mutex_lock(ssl_static_locks[n-1]); else mutex_unlock(ssl_static_locks[n-1]); } void openssl_init_locks(void) { int c, maxlocks = CRYPTO_num_locks(); gw_assert(ssl_static_locks == NULL); ssl_static_locks = gw_malloc(sizeof(Mutex *) * maxlocks); for (c = 0; c < maxlocks; c++) ssl_static_locks[c] = mutex_create(); /* after the mutexes have been created, apply the call-back to it */ CRYPTO_set_locking_callback(openssl_locking_function); CRYPTO_set_id_callback((CRYPTO_CALLBACK_PTR)gwthread_self); }
/****************************************************************************** * Send a MT message, returns as in smsc_submit_smsmessage in smsc.h */ int cimd_submit_msg(SMSCenter *smsc, Msg *msg) { char *tmpbuff = NULL, *tmptext = NULL; char msgtext[1024]; int ret; int cmd = 0, err = 0; /* Fix these by implementing a could-not-send-because- protocol-does-not-allow in smsc.c or smsgateway.c */ if (octstr_len(msg->sms.msgdata) + octstr_len(msg->sms.udhdata) < 1) { if (msg->sms.msgdata == NULL) msg->sms.msgdata = octstr_create(""); octstr_append_from_hex(msg->sms.msgdata, "20"); } if (octstr_len(msg->sms.sender) < 1) { warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field"); goto okay; /* THIS IS NOT OKAY!!!! XXX */ } if (octstr_len(msg->sms.receiver) < 1) { warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field"); goto okay; /* THIS IS NOT OKAY!!!! XXX */ } tmpbuff = gw_malloc(10 * 1024); tmptext = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); memset(tmptext, 0, 10*1024); memset(msgtext, 0, sizeof(msgtext)); if (octstr_len(msg->sms.udhdata)) { octstr_get_many_chars(msgtext, msg->sms.udhdata, 0, octstr_len(msg->sms.udhdata)); octstr_get_many_chars(msgtext + octstr_len(msg->sms.udhdata), msg->sms.msgdata, 0, 140 - octstr_len(msg->sms.udhdata)); } else { octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata)); } /* XXX parse_iso88591_to_cimd should use Octstr * directly, or get a char* and a length, instead of using NUL * terminated strings. */ parse_iso88591_to_cimd(msgtext, tmptext, 10*1024, smsc->alt_charset); /* If messages has UDHs, add the magic number 31 to the right spot */ sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c%c", 0x02, "03", 0x09, octstr_get_cstr(msg->sms.receiver), 0x09, tmptext, 0x09, "", 0x09, "", 0x09, (octstr_len(msg->sms.udhdata)) ? "31" : "", 0x09, "11", 0x03, 0x0A); ret = write_to_socket(smsc->socket, tmpbuff); if (ret < 0) { debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: socket write error"); goto error; } /* The Nokia SMSC MAY be configured to send delivery information, which we then will HAVE to acknowledge. Naturally the CIMD 1.3 protocol does not include any kind of negotiation mechanism. */ ret = expect_acknowledge(smsc, &cmd, &err); if (ret >= 1) { if (cmd == 4) { send_acknowledge(smsc); goto okay; } else if (cmd == 3) { goto okay; } } else if (ret == 0) { if (cmd == 4) { send_acknowledge(smsc); goto okay; /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */ goto error; } else if (cmd == 3) { goto okay; /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */ goto error; } else { error(0, "Unexpected behaviour from the CIMD server"); debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: acknowledge was <%i>", ret); debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: buffer==<%s>", smsc->buffer); goto error; } } okay: gw_free(tmpbuff); gw_free(tmptext); return 0; error: debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: returning error"); gw_free(tmpbuff); gw_free(tmptext); return -1; }