jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 #include "sm.h" 00022 00030 pkt_t pkt_error(pkt_t pkt, int err) { 00031 if(pkt == NULL) return NULL; 00032 00033 /* if it's an error already, log, free, return */ 00034 if(pkt->type & pkt_ERROR) { 00035 log_debug(ZONE, "dropping error pkt"); 00036 pkt_free(pkt); 00037 return NULL; 00038 } 00039 00040 stanza_error(pkt->nad, 1, err); 00041 00042 /* update vars and attrs */ 00043 pkt_tofrom(pkt); 00044 pkt->type |= pkt_ERROR; 00045 00046 /* supplant route destination in case there was none in original packet */ 00047 if(pkt->to == NULL && pkt->rto != NULL) 00048 pkt->to = jid_dup(pkt->rto); 00049 00050 /* all done, error'd and addressed */ 00051 log_debug(ZONE, "processed %d error pkt", err); 00052 00053 return pkt; 00054 } 00055 00057 pkt_t pkt_tofrom(pkt_t pkt) { 00058 jid_t tmp; 00059 00060 if(pkt == NULL) return NULL; 00061 00062 /* swap vars */ 00063 tmp = pkt->from; 00064 pkt->from = pkt->to; 00065 pkt->to = tmp; 00066 tmp = pkt->rfrom; 00067 pkt->rfrom = pkt->rto; 00068 pkt->rto = tmp; 00069 00070 /* update attrs */ 00071 if(pkt->to != NULL) 00072 nad_set_attr(pkt->nad, 1, -1, "to", jid_full(pkt->to), 0); 00073 if(pkt->from != NULL) 00074 nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0); 00075 if(pkt->rto != NULL) 00076 nad_set_attr(pkt->nad, 0, -1, "to", jid_full(pkt->rto), 0); 00077 if(pkt->rfrom != NULL) 00078 nad_set_attr(pkt->nad, 0, -1, "from", jid_full(pkt->rfrom), 0); 00079 00080 return pkt; 00081 } 00082 00084 pkt_t pkt_dup(pkt_t pkt, const char *to, const char *from) { 00085 pkt_t pnew; 00086 00087 if(pkt == NULL) return NULL; 00088 00089 pnew = (pkt_t) calloc(1, sizeof(struct pkt_st)); 00090 00091 pnew->sm = pkt->sm; 00092 pnew->type = pkt->type; 00093 pnew->nad = nad_copy(pkt->nad); 00094 00095 /* set replacement attrs */ 00096 if(to != NULL) { 00097 pnew->to = jid_new(to, -1); 00098 nad_set_attr(pnew->nad, 1, -1, "to", jid_full(pnew->to), 0); 00099 } else if(pkt->to != NULL) 00100 pnew->to = jid_dup(pkt->to); 00101 00102 if(from != NULL) { 00103 pnew->from = jid_new(from, -1); 00104 nad_set_attr(pnew->nad, 1, -1, "from", jid_full(pnew->from), 0); 00105 } else if(pkt->from != NULL) 00106 pnew->from = jid_dup(pkt->from); 00107 00108 log_debug(ZONE, "duplicated packet"); 00109 00110 return pnew; 00111 } 00112 00113 pkt_t pkt_new(sm_t sm, nad_t nad) { 00114 pkt_t pkt; 00115 int ns, attr, elem; 00116 char pri[20]; 00117 00118 log_debug(ZONE, "creating new packet"); 00119 00120 /* find the route */ 00121 ns = nad_find_namespace(nad, 0, uri_COMPONENT, NULL); 00122 if(ns < 0) { 00123 log_debug(ZONE, "packet not in component namespace"); 00124 nad_free(nad); 00125 return NULL; 00126 } 00127 00128 /* create the pkt holder */ 00129 pkt = (pkt_t) calloc(1, sizeof(struct pkt_st)); 00130 00131 pkt->sm = sm; 00132 pkt->nad = nad; 00133 00134 /* routes */ 00135 if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) { 00136 /* route element */ 00137 if((attr = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0) 00138 pkt->rto = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); 00139 if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) 00140 pkt->rfrom = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); 00141 00142 /* route type */ 00143 attr = nad_find_attr(nad, 0, -1, "type", NULL); 00144 if(attr < 0) 00145 pkt->rtype = route_UNICAST; 00146 else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("broadcast", NAD_AVAL(nad, attr), 9) == 0) 00147 pkt->rtype = route_BROADCAST; 00148 00149 /* route errors */ 00150 if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) 00151 pkt->rtype |= route_ERROR; 00152 00153 /* client packets */ 00154 ns = nad_find_namespace(nad, 1, uri_CLIENT, NULL); 00155 if(ns >= 0) { 00156 00157 /* get initial addresses */ 00158 if((attr = nad_find_attr(pkt->nad, 1, -1, "to", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0) 00159 pkt->to = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00160 if((attr = nad_find_attr(pkt->nad, 1, -1, "from", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0) 00161 pkt->from = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); 00162 00163 /* find type, if any */ 00164 attr = nad_find_attr(pkt->nad, 1, -1, "type", NULL); 00165 00166 /* messages are simple, only subtypes */ 00167 if(NAD_ENAME_L(pkt->nad, 1) == 7 && strncmp("message", NAD_ENAME(pkt->nad, 1), 7) == 0) { 00168 pkt->type = pkt_MESSAGE; 00169 if(attr >= 0) { 00170 if(NAD_AVAL_L(pkt->nad, attr) == 4 && strncmp("chat", NAD_AVAL(pkt->nad, attr), 4) == 0) 00171 pkt->type = pkt_MESSAGE_CHAT; 00172 else if(NAD_AVAL_L(pkt->nad, attr) == 8 && strncmp("headline", NAD_AVAL(pkt->nad, attr), 8) == 0) 00173 pkt->type = pkt_MESSAGE_HEADLINE; 00174 else if(NAD_AVAL_L(pkt->nad, attr) == 9 && strncmp("groupchat", NAD_AVAL(pkt->nad, attr), 9) == 0) 00175 pkt->type = pkt_MESSAGE_GROUPCHAT; 00176 else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) 00177 pkt->type = pkt_MESSAGE | pkt_ERROR; 00178 } 00179 00180 return pkt; 00181 } 00182 00183 /* presence is a mixed bag, s10ns in here too */ 00184 if(NAD_ENAME_L(pkt->nad, 1) == 8 && strncmp("presence", NAD_ENAME(pkt->nad, 1), 8) == 0) { 00185 pkt->type = pkt_PRESENCE; 00186 if(attr >= 0) { 00187 if(NAD_AVAL_L(pkt->nad, attr) == 11 && strncmp("unavailable", NAD_AVAL(pkt->nad, attr), 11) == 0) 00188 pkt->type = pkt_PRESENCE_UN; 00189 else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("probe", NAD_AVAL(pkt->nad, attr), 5) == 0) 00190 pkt->type = pkt_PRESENCE_PROBE; 00191 else if(NAD_AVAL_L(pkt->nad, attr) == 9 && strncmp("subscribe", NAD_AVAL(pkt->nad, attr), 9) == 0) 00192 pkt->type = pkt_S10N; 00193 else if(NAD_AVAL_L(pkt->nad, attr) == 10 && strncmp("subscribed", NAD_AVAL(pkt->nad, attr), 10) == 0) 00194 pkt->type = pkt_S10N_ED; 00195 else if(NAD_AVAL_L(pkt->nad, attr) == 11 && strncmp("unsubscribe", NAD_AVAL(pkt->nad, attr), 11) == 0) 00196 pkt->type = pkt_S10N_UN; 00197 else if(NAD_AVAL_L(pkt->nad, attr) == 12 && strncmp("unsubscribed", NAD_AVAL(pkt->nad, attr), 12) == 0) 00198 pkt->type = pkt_S10N_UNED; 00199 else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) 00200 pkt->type = pkt_PRESENCE | pkt_ERROR; 00201 } 00202 00203 /* priority */ 00204 if((elem = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "priority", 1)) < 0) 00205 return pkt; 00206 00207 if(NAD_CDATA_L(pkt->nad, elem) <= 0 || NAD_CDATA_L(pkt->nad, elem) > 19) 00208 return pkt; 00209 00210 memcpy(pri, NAD_CDATA(pkt->nad, elem), NAD_CDATA_L(pkt->nad, elem)); 00211 pri[NAD_CDATA_L(pkt->nad, elem)] = '\0'; 00212 pkt->pri = atoi(pri); 00213 00214 if(pkt->pri > 127) pkt->pri = 127; 00215 if(pkt->pri < -128) pkt->pri = -128; 00216 00217 return pkt; 00218 } 00219 00220 /* iq's are pretty easy, but also set xmlns */ 00221 if(NAD_ENAME_L(pkt->nad, 1) == 2 && strncmp("iq", NAD_ENAME(pkt->nad, 1), 2) == 0) { 00222 pkt->type = pkt_IQ; 00223 if (attr < 0) { 00224 log_write(sm->log, LOG_ERR, "dropping iq without type"); 00225 log_debug(ZONE, "dropping iq without type"); 00226 pkt_free(pkt); 00227 return NULL; 00228 } 00229 if (NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("result", NAD_AVAL(pkt->nad, attr), 6) == 0) pkt->type = pkt_IQ_RESULT; 00230 else if (NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) pkt->type = pkt_IQ | pkt_ERROR; 00231 else if (NAD_AVAL_L(pkt->nad, attr) == 3 && strncmp("set", NAD_AVAL(pkt->nad, attr), 3) == 0) pkt->type = pkt_IQ_SET; 00232 else if (NAD_AVAL_L(pkt->nad, attr) != 3 || strncmp("get", NAD_AVAL(pkt->nad, attr), 3)) { 00233 log_write(sm->log, LOG_ERR, "dropping iq with bad type \"%.*s\"", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00234 log_debug(ZONE, "dropping iq with bad type \"%.*s\"", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00235 pkt_free(pkt); 00236 return NULL; 00237 } 00238 00239 if(pkt->nad->ecur > 2 && (ns = NAD_ENS(pkt->nad, 2)) >= 0) 00240 pkt->ns = (int) (long) xhash_getx(pkt->sm->xmlns, NAD_NURI(pkt->nad, ns), NAD_NURI_L(pkt->nad, ns)); 00241 00242 return pkt; 00243 } 00244 00245 log_debug(ZONE, "unknown client namespace packet"); 00246 00247 return pkt; 00248 } 00249 00250 /* sessions packets */ 00251 ns = nad_find_namespace(nad, 1, uri_SESSION, NULL); 00252 if(ns >= 0) { 00253 00254 /* sessions */ 00255 if(NAD_ENAME_L(pkt->nad, 1) == 7 && strncmp("session", NAD_ENAME(pkt->nad, 1), 7) == 0) { 00256 00257 /* find action */ 00258 attr = nad_find_attr(pkt->nad, 1, -1, "action", NULL); 00259 00260 if(attr >= 0) { 00261 if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("start", NAD_AVAL(pkt->nad, attr), 5) >= 0) 00262 pkt->type = pkt_SESS; 00263 else if(NAD_AVAL_L(pkt->nad, attr) == 3 && strncmp("end", NAD_AVAL(pkt->nad, attr), 3) >= 0) 00264 pkt->type = pkt_SESS_END; 00265 else if(NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("create", NAD_AVAL(pkt->nad, attr), 6) >= 0) 00266 pkt->type = pkt_SESS_CREATE; 00267 else if(NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("delete", NAD_AVAL(pkt->nad, attr), 6) >= 0) 00268 pkt->type = pkt_SESS_DELETE; 00269 else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("started", NAD_AVAL(pkt->nad, attr), 7) >= 0) 00270 pkt->type = pkt_SESS | pkt_SESS_FAILED; 00271 else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("ended", NAD_AVAL(pkt->nad, attr), 5) >= 0) 00272 pkt->type = pkt_SESS_END | pkt_SESS_FAILED; 00273 else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("created", NAD_AVAL(pkt->nad, attr), 7) >= 0) 00274 pkt->type = pkt_SESS_CREATE | pkt_SESS_FAILED; 00275 else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("deleted", NAD_AVAL(pkt->nad, attr), 7) >= 0) 00276 pkt->type = pkt_SESS_DELETE | pkt_SESS_FAILED; 00277 00278 return pkt; 00279 } else { 00280 log_debug(ZONE, "missing action on session packet"); 00281 return pkt; 00282 } 00283 } 00284 00285 log_debug(ZONE, "unknown session namespace packet"); 00286 00287 return pkt; 00288 } 00289 00290 log_debug(ZONE, "unknown packet"); 00291 00292 return pkt; 00293 } 00294 00295 /* advertisements */ 00296 if(NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) { 00297 if(nad_find_attr(nad, 0, -1, "type", "unavailable") >= 0) 00298 pkt->rtype = route_ADV_UN; 00299 else 00300 pkt->rtype = route_ADV; 00301 00302 attr = nad_find_attr(nad, 0, -1, "from", NULL); 00303 if(attr >= 0) 00304 pkt->from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); 00305 00306 return pkt; 00307 } 00308 00309 log_debug(ZONE, "invalid component packet"); 00310 00311 pkt_free(pkt); 00312 return NULL; 00313 } 00314 00315 void pkt_free(pkt_t pkt) { 00316 log_debug(ZONE, "freeing pkt"); 00317 00318 if (pkt != NULL) { 00319 if(pkt->rto != NULL) jid_free(pkt->rto); 00320 if(pkt->rfrom != NULL) jid_free(pkt->rfrom); 00321 if(pkt->to != NULL) jid_free(pkt->to); 00322 if(pkt->from != NULL) jid_free(pkt->from); 00323 if(pkt->nad != NULL) nad_free(pkt->nad); 00324 free(pkt); 00325 } 00326 } 00327 00328 pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from) { 00329 nad_t nad; 00330 int ns; 00331 00332 nad = nad_new(); 00333 00334 ns = nad_add_namespace(nad, uri_COMPONENT, NULL); 00335 nad_append_elem(nad, ns, "route", 0); 00336 00337 nad_add_namespace(nad, uri_SESSION, "sm"); 00338 00339 ns = nad_add_namespace(nad, uri_CLIENT, NULL); 00340 nad_append_elem(nad, ns, elem, 1); 00341 00342 if(type != NULL) 00343 nad_append_attr(nad, -1, "type", type); 00344 if(to != NULL) 00345 nad_append_attr(nad, -1, "to", to); 00346 if(from != NULL) 00347 nad_append_attr(nad, -1, "from", from); 00348 00349 return pkt_new(sm, nad); 00350 } 00351 00353 void pkt_id(pkt_t src, pkt_t dest) { 00354 int attr; 00355 00356 attr = nad_find_attr(src->nad, 1, -1, "id", NULL); 00357 if(attr >= 0) 00358 nad_set_attr(dest->nad, 1, -1, "id", NAD_AVAL(src->nad, attr), NAD_AVAL_L(src->nad, attr)); 00359 else 00360 nad_set_attr(dest->nad, 1, -1, "id", NULL, 0); 00361 } 00362 00364 void pkt_id_new(pkt_t pkt) { 00365 char id[40]; 00366 int i, r; 00367 00368 /* as we are not using ids for tracking purposes, these can be generated randomly */ 00369 for(i = 0; i < 40; i++) { 00370 r = (int) (36.0 * rand() / RAND_MAX); 00371 id[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); 00372 } 00373 00374 nad_set_attr(pkt->nad, 1, -1, "id", id, 40); 00375 00376 return; 00377 } 00378 00379 void pkt_router(pkt_t pkt) { 00380 mod_ret_t ret; 00381 int ns, scan; 00382 00383 if(pkt == NULL) return; 00384 00385 log_debug(ZONE, "delivering pkt to router"); 00386 00387 if(pkt->to == NULL) { 00388 log_debug(ZONE, "no to address on packet, unable to route"); 00389 pkt_free(pkt); 00390 return; 00391 } 00392 00393 if(pkt->rto != NULL) 00394 jid_free(pkt->rto); 00395 pkt->rto = jid_new(pkt->to->domain, -1); 00396 00397 if(pkt->rto == NULL) { 00398 log_debug(ZONE, "invalid to address on packet, unable to route"); 00399 pkt_free(pkt); 00400 return; 00401 } 00402 00403 nad_set_attr(pkt->nad, 0, -1, "to", pkt->rto->domain, 0); 00404 00405 if(pkt->rfrom != NULL) 00406 jid_free(pkt->rfrom); 00407 pkt->rfrom = jid_new(pkt->sm->id, -1); 00408 00409 if(pkt->rfrom == NULL) { 00410 log_debug(ZONE, "invalid from address on packet, unable to route"); 00411 pkt_free(pkt); 00412 return; 00413 } 00414 00415 nad_set_attr(pkt->nad, 0, -1, "from", pkt->rfrom->domain, 0); 00416 00417 ret = mm_out_router(pkt->sm->mm, pkt); 00418 switch(ret) { 00419 case mod_HANDLED: 00420 return; 00421 00422 case mod_PASS: 00423 00424 /* remove sm specifics */ 00425 ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL); 00426 /* remove them if there is no session elements in packet */ 00427 if(ns >= 0 && nad_find_elem(pkt->nad, 0, ns, NULL, 1) < 0) { 00428 nad_set_attr(pkt->nad, 1, ns, "c2s", NULL, 0); 00429 nad_set_attr(pkt->nad, 1, ns, "sm", NULL, 0); 00430 00431 /* forget about the internal namespace too */ 00432 if(pkt->nad->elems[1].ns == ns) 00433 pkt->nad->elems[1].ns = pkt->nad->nss[ns].next; 00434 00435 else { 00436 for(scan = pkt->nad->elems[1].ns; pkt->nad->nss[scan].next != -1 && pkt->nad->nss[scan].next != ns; scan = pkt->nad->nss[scan].next); 00437 00438 /* got it */ 00439 if(pkt->nad->nss[scan].next != -1) 00440 pkt->nad->nss[scan].next = pkt->nad->nss[ns].next; 00441 } 00442 } 00443 00444 sx_nad_write(pkt->sm->router, pkt->nad); 00445 00446 /* nad already free'd, free the rest */ 00447 pkt->nad = NULL; 00448 pkt_free(pkt); 00449 00450 break; 00451 00452 default: 00453 pkt_router(pkt_error(pkt, -ret)); 00454 00455 break; 00456 } 00457 } 00458 00459 void pkt_sess(pkt_t pkt, sess_t sess) { 00460 mod_ret_t ret; 00461 00462 if(pkt == NULL) return; 00463 00464 log_debug(ZONE, "delivering pkt to session %s", jid_full(sess->jid)); 00465 00466 if(pkt->rto != NULL) 00467 jid_free(pkt->rto); 00468 pkt->rto = jid_new(sess->c2s, -1); 00469 00470 if(pkt->rto == NULL) { 00471 log_debug(ZONE, "invalid to address on packet, unable to route"); 00472 pkt_free(pkt); 00473 return; 00474 } 00475 00476 nad_set_attr(pkt->nad, 0, -1, "to", pkt->rto->domain, 0); 00477 00478 if(pkt->rfrom != NULL) 00479 jid_free(pkt->rfrom); 00480 pkt->rfrom = jid_new(pkt->sm->id, -1); 00481 00482 if(pkt->rfrom == NULL) { 00483 log_debug(ZONE, "invalid from address on packet, unable to route"); 00484 pkt_free(pkt); 00485 return; 00486 } 00487 00488 nad_set_attr(pkt->nad, 0, -1, "from", pkt->rfrom->domain, 0); 00489 00490 ret = mm_out_sess(pkt->sm->mm, sess, pkt); 00491 switch(ret) { 00492 case mod_HANDLED: 00493 return; 00494 00495 case mod_PASS: 00496 sess_route(sess, pkt); 00497 00498 break; 00499 00500 default: 00501 pkt_router(pkt_error(pkt, -ret)); 00502 00503 break; 00504 } 00505 } 00506 00508 void pkt_delay(pkt_t pkt, time_t t, const char *from) { 00509 char timestamp[21]; 00510 int ns, elem; 00511 00512 #ifdef ENABLE_SUPERSEDED 00513 datetime_out(t, dt_LEGACY, timestamp, 18); 00514 ns = nad_add_namespace(pkt->nad, uri_DELAY, NULL); 00515 elem = nad_insert_elem(pkt->nad, 1, ns, "x", NULL); 00516 nad_set_attr(pkt->nad, elem, -1, "stamp", timestamp, 0); 00517 if(from != NULL) 00518 nad_set_attr(pkt->nad, elem, -1, "from", from, 0); 00519 log_debug(ZONE, "added pkt XEP-0091 delay stamp %s", timestamp); 00520 #endif 00521 datetime_out(t, dt_DATETIME, timestamp, 21); 00522 ns = nad_add_namespace(pkt->nad, uri_URN_DELAY, NULL); 00523 elem = nad_insert_elem(pkt->nad, 1, ns, "delay", NULL); 00524 nad_set_attr(pkt->nad, elem, -1, "stamp", timestamp, 0); 00525 if(from != NULL) 00526 nad_set_attr(pkt->nad, elem, -1, "from", from, 0); 00527 log_debug(ZONE, "added pkt XEP-0203 delay stamp %s", timestamp); 00528 }