jabberd2  2.2.17
pkt.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
30 pkt_t pkt_error(pkt_t pkt, int err) {
31  if(pkt == NULL) return NULL;
32 
33  /* if it's an error already, log, free, return */
34  if(pkt->type & pkt_ERROR) {
35  log_debug(ZONE, "dropping error pkt");
36  pkt_free(pkt);
37  return NULL;
38  }
39 
40  stanza_error(pkt->nad, 1, err);
41 
42  /* update vars and attrs */
43  pkt_tofrom(pkt);
44  pkt->type |= pkt_ERROR;
45 
46  /* supplant route destination in case there was none in original packet */
47  if(pkt->to == NULL && pkt->rto != NULL)
48  pkt->to = jid_dup(pkt->rto);
49 
50  /* all done, error'd and addressed */
51  log_debug(ZONE, "processed %d error pkt", err);
52 
53  return pkt;
54 }
55 
58  jid_t tmp;
59 
60  if(pkt == NULL) return NULL;
61 
62  /* swap vars */
63  tmp = pkt->from;
64  pkt->from = pkt->to;
65  pkt->to = tmp;
66  tmp = pkt->rfrom;
67  pkt->rfrom = pkt->rto;
68  pkt->rto = tmp;
69 
70  /* update attrs */
71  if(pkt->to != NULL)
72  nad_set_attr(pkt->nad, 1, -1, "to", jid_full(pkt->to), 0);
73  if(pkt->from != NULL)
74  nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0);
75  if(pkt->rto != NULL)
76  nad_set_attr(pkt->nad, 0, -1, "to", jid_full(pkt->rto), 0);
77  if(pkt->rfrom != NULL)
78  nad_set_attr(pkt->nad, 0, -1, "from", jid_full(pkt->rfrom), 0);
79 
80  return pkt;
81 }
82 
84 pkt_t pkt_dup(pkt_t pkt, const char *to, const char *from) {
85  pkt_t pnew;
86 
87  if(pkt == NULL) return NULL;
88 
89  pnew = (pkt_t) calloc(1, sizeof(struct pkt_st));
90 
91  pnew->sm = pkt->sm;
92  pnew->type = pkt->type;
93  pnew->nad = nad_copy(pkt->nad);
94 
95  /* set replacement attrs */
96  if(to != NULL) {
97  pnew->to = jid_new(to, -1);
98  nad_set_attr(pnew->nad, 1, -1, "to", jid_full(pnew->to), 0);
99  } else if(pkt->to != NULL)
100  pnew->to = jid_dup(pkt->to);
101 
102  if(from != NULL) {
103  pnew->from = jid_new(from, -1);
104  nad_set_attr(pnew->nad, 1, -1, "from", jid_full(pnew->from), 0);
105  } else if(pkt->from != NULL)
106  pnew->from = jid_dup(pkt->from);
107 
108  log_debug(ZONE, "duplicated packet");
109 
110  return pnew;
111 }
112 
114  pkt_t pkt;
115  int ns, attr, elem;
116  char pri[20];
117 
118  log_debug(ZONE, "creating new packet");
119 
120  /* find the route */
121  ns = nad_find_namespace(nad, 0, uri_COMPONENT, NULL);
122  if(ns < 0) {
123  log_debug(ZONE, "packet not in component namespace");
124  nad_free(nad);
125  return NULL;
126  }
127 
128  /* create the pkt holder */
129  pkt = (pkt_t) calloc(1, sizeof(struct pkt_st));
130 
131  pkt->sm = sm;
132  pkt->nad = nad;
133 
134  /* routes */
135  if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) {
136  /* route element */
137  if((attr = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0)
138  pkt->rto = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
139  if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0)
140  pkt->rfrom = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
141 
142  /* route type */
143  attr = nad_find_attr(nad, 0, -1, "type", NULL);
144  if(attr < 0)
145  pkt->rtype = route_UNICAST;
146  else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("broadcast", NAD_AVAL(nad, attr), 9) == 0)
147  pkt->rtype = route_BROADCAST;
148 
149  /* route errors */
150  if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0)
151  pkt->rtype |= route_ERROR;
152 
153  /* client packets */
154  ns = nad_find_namespace(nad, 1, uri_CLIENT, NULL);
155  if(ns >= 0) {
156 
157  /* get initial addresses */
158  if((attr = nad_find_attr(pkt->nad, 1, -1, "to", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0)
159  pkt->to = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
160  if((attr = nad_find_attr(pkt->nad, 1, -1, "from", NULL)) >= 0 && NAD_AVAL_L(pkt->nad, attr) > 0)
161  pkt->from = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
162 
163  /* find type, if any */
164  attr = nad_find_attr(pkt->nad, 1, -1, "type", NULL);
165 
166  /* messages are simple, only subtypes */
167  if(NAD_ENAME_L(pkt->nad, 1) == 7 && strncmp("message", NAD_ENAME(pkt->nad, 1), 7) == 0) {
168  pkt->type = pkt_MESSAGE;
169  if(attr >= 0) {
170  if(NAD_AVAL_L(pkt->nad, attr) == 4 && strncmp("chat", NAD_AVAL(pkt->nad, attr), 4) == 0)
171  pkt->type = pkt_MESSAGE_CHAT;
172  else if(NAD_AVAL_L(pkt->nad, attr) == 8 && strncmp("headline", NAD_AVAL(pkt->nad, attr), 8) == 0)
173  pkt->type = pkt_MESSAGE_HEADLINE;
174  else if(NAD_AVAL_L(pkt->nad, attr) == 9 && strncmp("groupchat", NAD_AVAL(pkt->nad, attr), 9) == 0)
176  else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0)
177  pkt->type = pkt_MESSAGE | pkt_ERROR;
178  }
179 
180  return pkt;
181  }
182 
183  /* presence is a mixed bag, s10ns in here too */
184  if(NAD_ENAME_L(pkt->nad, 1) == 8 && strncmp("presence", NAD_ENAME(pkt->nad, 1), 8) == 0) {
185  pkt->type = pkt_PRESENCE;
186  if(attr >= 0) {
187  if(NAD_AVAL_L(pkt->nad, attr) == 11 && strncmp("unavailable", NAD_AVAL(pkt->nad, attr), 11) == 0)
188  pkt->type = pkt_PRESENCE_UN;
189  else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("probe", NAD_AVAL(pkt->nad, attr), 5) == 0)
190  pkt->type = pkt_PRESENCE_PROBE;
191  else if(NAD_AVAL_L(pkt->nad, attr) == 9 && strncmp("subscribe", NAD_AVAL(pkt->nad, attr), 9) == 0)
192  pkt->type = pkt_S10N;
193  else if(NAD_AVAL_L(pkt->nad, attr) == 10 && strncmp("subscribed", NAD_AVAL(pkt->nad, attr), 10) == 0)
194  pkt->type = pkt_S10N_ED;
195  else if(NAD_AVAL_L(pkt->nad, attr) == 11 && strncmp("unsubscribe", NAD_AVAL(pkt->nad, attr), 11) == 0)
196  pkt->type = pkt_S10N_UN;
197  else if(NAD_AVAL_L(pkt->nad, attr) == 12 && strncmp("unsubscribed", NAD_AVAL(pkt->nad, attr), 12) == 0)
198  pkt->type = pkt_S10N_UNED;
199  else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0)
200  pkt->type = pkt_PRESENCE | pkt_ERROR;
201  }
202 
203  /* priority */
204  if((elem = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "priority", 1)) < 0)
205  return pkt;
206 
207  if(NAD_CDATA_L(pkt->nad, elem) <= 0 || NAD_CDATA_L(pkt->nad, elem) > 19)
208  return pkt;
209 
210  memcpy(pri, NAD_CDATA(pkt->nad, elem), NAD_CDATA_L(pkt->nad, elem));
211  pri[NAD_CDATA_L(pkt->nad, elem)] = '\0';
212  pkt->pri = atoi(pri);
213 
214  if(pkt->pri > 127) pkt->pri = 127;
215  if(pkt->pri < -128) pkt->pri = -128;
216 
217  return pkt;
218  }
219 
220  /* iq's are pretty easy, but also set xmlns */
221  if(NAD_ENAME_L(pkt->nad, 1) == 2 && strncmp("iq", NAD_ENAME(pkt->nad, 1), 2) == 0) {
222  pkt->type = pkt_IQ;
223  if (attr < 0) {
224  log_write(sm->log, LOG_ERR, "dropping iq without type");
225  log_debug(ZONE, "dropping iq without type");
226  pkt_free(pkt);
227  return NULL;
228  }
229  if (NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("result", NAD_AVAL(pkt->nad, attr), 6) == 0) pkt->type = pkt_IQ_RESULT;
230  else if (NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("error", NAD_AVAL(pkt->nad, attr), 5) == 0) pkt->type = pkt_IQ | pkt_ERROR;
231  else if (NAD_AVAL_L(pkt->nad, attr) == 3 && strncmp("set", NAD_AVAL(pkt->nad, attr), 3) == 0) pkt->type = pkt_IQ_SET;
232  else if (NAD_AVAL_L(pkt->nad, attr) != 3 || strncmp("get", NAD_AVAL(pkt->nad, attr), 3)) {
233  log_write(sm->log, LOG_ERR, "dropping iq with bad type \"%.*s\"", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
234  log_debug(ZONE, "dropping iq with bad type \"%.*s\"", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
235  pkt_free(pkt);
236  return NULL;
237  }
238 
239  if(pkt->nad->ecur > 2 && (ns = NAD_ENS(pkt->nad, 2)) >= 0)
240  pkt->ns = (int) (long) xhash_getx(pkt->sm->xmlns, NAD_NURI(pkt->nad, ns), NAD_NURI_L(pkt->nad, ns));
241 
242  return pkt;
243  }
244 
245  log_debug(ZONE, "unknown client namespace packet");
246 
247  return pkt;
248  }
249 
250  /* sessions packets */
251  ns = nad_find_namespace(nad, 1, uri_SESSION, NULL);
252  if(ns >= 0) {
253 
254  /* sessions */
255  if(NAD_ENAME_L(pkt->nad, 1) == 7 && strncmp("session", NAD_ENAME(pkt->nad, 1), 7) == 0) {
256 
257  /* find action */
258  attr = nad_find_attr(pkt->nad, 1, -1, "action", NULL);
259 
260  if(attr >= 0) {
261  if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("start", NAD_AVAL(pkt->nad, attr), 5) >= 0)
262  pkt->type = pkt_SESS;
263  else if(NAD_AVAL_L(pkt->nad, attr) == 3 && strncmp("end", NAD_AVAL(pkt->nad, attr), 3) >= 0)
264  pkt->type = pkt_SESS_END;
265  else if(NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("create", NAD_AVAL(pkt->nad, attr), 6) >= 0)
266  pkt->type = pkt_SESS_CREATE;
267  else if(NAD_AVAL_L(pkt->nad, attr) == 6 && strncmp("delete", NAD_AVAL(pkt->nad, attr), 6) >= 0)
268  pkt->type = pkt_SESS_DELETE;
269  else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("started", NAD_AVAL(pkt->nad, attr), 7) >= 0)
270  pkt->type = pkt_SESS | pkt_SESS_FAILED;
271  else if(NAD_AVAL_L(pkt->nad, attr) == 5 && strncmp("ended", NAD_AVAL(pkt->nad, attr), 5) >= 0)
273  else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("created", NAD_AVAL(pkt->nad, attr), 7) >= 0)
275  else if(NAD_AVAL_L(pkt->nad, attr) == 7 && strncmp("deleted", NAD_AVAL(pkt->nad, attr), 7) >= 0)
277 
278  return pkt;
279  } else {
280  log_debug(ZONE, "missing action on session packet");
281  return pkt;
282  }
283  }
284 
285  log_debug(ZONE, "unknown session namespace packet");
286 
287  return pkt;
288  }
289 
290  log_debug(ZONE, "unknown packet");
291 
292  return pkt;
293  }
294 
295  /* advertisements */
296  if(NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) {
297  if(nad_find_attr(nad, 0, -1, "type", "unavailable") >= 0)
298  pkt->rtype = route_ADV_UN;
299  else
300  pkt->rtype = route_ADV;
301 
302  attr = nad_find_attr(nad, 0, -1, "from", NULL);
303  if(attr >= 0)
304  pkt->from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
305 
306  return pkt;
307  }
308 
309  log_debug(ZONE, "invalid component packet");
310 
311  pkt_free(pkt);
312  return NULL;
313 }
314 
315 void pkt_free(pkt_t pkt) {
316  log_debug(ZONE, "freeing pkt");
317 
318  if (pkt != NULL) {
319  if(pkt->rto != NULL) jid_free(pkt->rto);
320  if(pkt->rfrom != NULL) jid_free(pkt->rfrom);
321  if(pkt->to != NULL) jid_free(pkt->to);
322  if(pkt->from != NULL) jid_free(pkt->from);
323  if(pkt->nad != NULL) nad_free(pkt->nad);
324  free(pkt);
325  }
326 }
327 
328 pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from) {
329  nad_t nad;
330  int ns;
331 
332  nad = nad_new();
333 
334  ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
335  nad_append_elem(nad, ns, "route", 0);
336 
337  nad_add_namespace(nad, uri_SESSION, "sm");
338 
339  ns = nad_add_namespace(nad, uri_CLIENT, NULL);
340  nad_append_elem(nad, ns, elem, 1);
341 
342  if(type != NULL)
343  nad_append_attr(nad, -1, "type", type);
344  if(to != NULL)
345  nad_append_attr(nad, -1, "to", to);
346  if(from != NULL)
347  nad_append_attr(nad, -1, "from", from);
348 
349  return pkt_new(sm, nad);
350 }
351 
353 void pkt_id(pkt_t src, pkt_t dest) {
354  int attr;
355 
356  attr = nad_find_attr(src->nad, 1, -1, "id", NULL);
357  if(attr >= 0)
358  nad_set_attr(dest->nad, 1, -1, "id", NAD_AVAL(src->nad, attr), NAD_AVAL_L(src->nad, attr));
359  else
360  nad_set_attr(dest->nad, 1, -1, "id", NULL, 0);
361 }
362 
364 void pkt_id_new(pkt_t pkt) {
365  char id[40];
366  int i, r;
367 
368  /* as we are not using ids for tracking purposes, these can be generated randomly */
369  for(i = 0; i < 40; i++) {
370  r = (int) (36.0 * rand() / RAND_MAX);
371  id[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87);
372  }
373 
374  nad_set_attr(pkt->nad, 1, -1, "id", id, 40);
375 
376  return;
377 }
378 
379 void pkt_router(pkt_t pkt) {
380  mod_ret_t ret;
381  int ns, scan;
382 
383  if(pkt == NULL) return;
384 
385  log_debug(ZONE, "delivering pkt to router");
386 
387  if(pkt->to == NULL) {
388  log_debug(ZONE, "no to address on packet, unable to route");
389  pkt_free(pkt);
390  return;
391  }
392 
393  if(pkt->rto != NULL)
394  jid_free(pkt->rto);
395  pkt->rto = jid_new(pkt->to->domain, -1);
396 
397  if(pkt->rto == NULL) {
398  log_debug(ZONE, "invalid to address on packet, unable to route");
399  pkt_free(pkt);
400  return;
401  }
402 
403  nad_set_attr(pkt->nad, 0, -1, "to", pkt->rto->domain, 0);
404 
405  if(pkt->rfrom != NULL)
406  jid_free(pkt->rfrom);
407  pkt->rfrom = jid_new(pkt->sm->id, -1);
408 
409  if(pkt->rfrom == NULL) {
410  log_debug(ZONE, "invalid from address on packet, unable to route");
411  pkt_free(pkt);
412  return;
413  }
414 
415  nad_set_attr(pkt->nad, 0, -1, "from", pkt->rfrom->domain, 0);
416 
417  ret = mm_out_router(pkt->sm->mm, pkt);
418  switch(ret) {
419  case mod_HANDLED:
420  return;
421 
422  case mod_PASS:
423 
424  /* remove sm specifics */
425  ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL);
426  /* remove them if there is no session elements in packet */
427  if(ns >= 0 && nad_find_elem(pkt->nad, 0, ns, NULL, 1) < 0) {
428  nad_set_attr(pkt->nad, 1, ns, "c2s", NULL, 0);
429  nad_set_attr(pkt->nad, 1, ns, "sm", NULL, 0);
430 
431  /* forget about the internal namespace too */
432  if(pkt->nad->elems[1].ns == ns)
433  pkt->nad->elems[1].ns = pkt->nad->nss[ns].next;
434 
435  else {
436  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);
437 
438  /* got it */
439  if(pkt->nad->nss[scan].next != -1)
440  pkt->nad->nss[scan].next = pkt->nad->nss[ns].next;
441  }
442  }
443 
444  sx_nad_write(pkt->sm->router, pkt->nad);
445 
446  /* nad already free'd, free the rest */
447  pkt->nad = NULL;
448  pkt_free(pkt);
449 
450  break;
451 
452  default:
453  pkt_router(pkt_error(pkt, -ret));
454 
455  break;
456  }
457 }
458 
459 void pkt_sess(pkt_t pkt, sess_t sess) {
460  mod_ret_t ret;
461 
462  if(pkt == NULL) return;
463 
464  log_debug(ZONE, "delivering pkt to session %s", jid_full(sess->jid));
465 
466  if(pkt->rto != NULL)
467  jid_free(pkt->rto);
468  pkt->rto = jid_new(sess->c2s, -1);
469 
470  if(pkt->rto == NULL) {
471  log_debug(ZONE, "invalid to address on packet, unable to route");
472  pkt_free(pkt);
473  return;
474  }
475 
476  nad_set_attr(pkt->nad, 0, -1, "to", pkt->rto->domain, 0);
477 
478  if(pkt->rfrom != NULL)
479  jid_free(pkt->rfrom);
480  pkt->rfrom = jid_new(pkt->sm->id, -1);
481 
482  if(pkt->rfrom == NULL) {
483  log_debug(ZONE, "invalid from address on packet, unable to route");
484  pkt_free(pkt);
485  return;
486  }
487 
488  nad_set_attr(pkt->nad, 0, -1, "from", pkt->rfrom->domain, 0);
489 
490  ret = mm_out_sess(pkt->sm->mm, sess, pkt);
491  switch(ret) {
492  case mod_HANDLED:
493  return;
494 
495  case mod_PASS:
496  sess_route(sess, pkt);
497 
498  break;
499 
500  default:
501  pkt_router(pkt_error(pkt, -ret));
502 
503  break;
504  }
505 }
506 
508 void pkt_delay(pkt_t pkt, time_t t, const char *from) {
509  char timestamp[21];
510  int ns, elem;
511 
512 #ifdef ENABLE_SUPERSEDED
513  datetime_out(t, dt_LEGACY, timestamp, 18);
514  ns = nad_add_namespace(pkt->nad, uri_DELAY, NULL);
515  elem = nad_insert_elem(pkt->nad, 1, ns, "x", NULL);
516  nad_set_attr(pkt->nad, elem, -1, "stamp", timestamp, 0);
517  if(from != NULL)
518  nad_set_attr(pkt->nad, elem, -1, "from", from, 0);
519  log_debug(ZONE, "added pkt XEP-0091 delay stamp %s", timestamp);
520 #endif
521  datetime_out(t, dt_DATETIME, timestamp, 21);
522  ns = nad_add_namespace(pkt->nad, uri_URN_DELAY, NULL);
523  elem = nad_insert_elem(pkt->nad, 1, ns, "delay", NULL);
524  nad_set_attr(pkt->nad, elem, -1, "stamp", timestamp, 0);
525  if(from != NULL)
526  nad_set_attr(pkt->nad, elem, -1, "from", from, 0);
527  log_debug(ZONE, "added pkt XEP-0203 delay stamp %s", timestamp);
528 }