struct pkt *pkt_word_list_new(char **words)
{
	int len = 0;
	int i;
	for (i = 0; words[i]; i++) {
		len += strlen(words[i]) + 1;
	}
	if (!len) {
		pkt_error("pkt_wordlist_new(): empty packet\n");
		return NULL;
	}

	char *data = malloc(len);
	if (!data) {
		pkt_error("pkt_wordlist_new(): unable to allocate %d bytes\n", len);
		return NULL;
	}
	
	int offset = 0;
	for (i = 0; words[i]; i++) {
		strcpy(data + offset, words[i]);
		offset += strlen(words[i]) + 1;
	}

	struct pkt *pkt = pkt_new(PKT_TYPE_WORD_LIST, data, len);
	return pkt;
}
struct pkt *pkt_word_list_new_fixed_len(char *words, int num_words, int max_len)
{
	int len = 0;
	int i;
	for (i = 0; i < num_words; i++) {
		len += strnlen(words + i*max_len, max_len) + 1;
	}
	if (!len) {
		pkt_error("pkt_word_list_new_fixed_len(): empty packet\n");
		return NULL;
	}

	char *data = malloc(len);
	if (!data) {
		pkt_error("pkt_word_list_new_fixed_len(): unable to allocate %d bytes\n", len);
		return NULL;
	}

	int offset = 0;
	for (i = 0; i < num_words; i++) {
		int word_len = strnlen(words + i*max_len, max_len);
		memcpy(data + offset, words + i*max_len, word_len);
		offset += word_len;
		*(data + offset++) = 0;
	}
	
	struct pkt *pkt = pkt_new(PKT_TYPE_WORD_LIST, data, len);
	return pkt;	
}
Exemple #3
0
/** main packet dispatcher */
void dispatch(sm_t sm, pkt_t pkt) {
    user_t user;
    mod_ret_t ret;

    /* handle broadcasts */
    if(pkt->rtype == route_BROADCAST) {
        log_debug(ZONE, "can't handle broadcast routes (yet), dropping");
        pkt_free(pkt);
        return;
    }

    /* routing errors, add a im error */
    if(pkt->rtype & route_ERROR) {
        int i, aerror, stanza_err;
        aerror = nad_find_attr(pkt->nad, 0, -1, "error", NULL);
        stanza_err = stanza_err_REMOTE_SERVER_NOT_FOUND;
        if(aerror >= 0) {
            for(i=0; _stanza_errors[i].code != NULL; i++)
                if(strncmp(_stanza_errors[i].code, NAD_AVAL(pkt->nad, aerror), NAD_AVAL_L(pkt->nad, aerror)) == 0) {
                    stanza_err = stanza_err_BAD_REQUEST + i;
                    break;
                }
        }
        if(pkt_error(pkt, stanza_err) == NULL)
            return;
    }

    /*
     * - if its from the router (non-route) it goes straight to pkt_router
     * - hand it to in_router chain
     * - if its for the sm itself (no user), hand it to the pkt_sm chain
     * - find the user
     * - hand to pkt_user
     */

    /* non route packets are special-purpose things from the router */
    if(!(pkt->rtype & route_UNICAST)) {
        ret = mm_pkt_router(pkt->sm->mm, pkt);
        switch(ret) {
            case mod_HANDLED:
                break;

            case mod_PASS:
            default:
                /* don't ever bounce these */
                pkt_free(pkt);

                break;
        }

        return;
    }

    /* preprocessing */
    if (pkt != NULL && pkt->sm != NULL) {
        ret = mm_in_router(pkt->sm->mm, pkt);
        switch(ret) {
            case mod_HANDLED:
                return;
 
            case mod_PASS:
                break;

            default:
                pkt_router(pkt_error(pkt, -ret));
                return;
        }
    }

    /* has to come from someone and be directed to someone */
    if(pkt->from == NULL || pkt->to == NULL) {
        pkt_router(pkt_error(pkt, stanza_err_BAD_REQUEST));
        return;
    }

    /* packet is for the sm itself */
    if(*pkt->to->node == '\0') {
        ret = mm_pkt_sm(pkt->sm->mm, pkt);
        switch(ret) {
            case mod_HANDLED:
                break;

            case mod_PASS:
                /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */
                if(pkt->type == pkt_IQ_RESULT) {
                    pkt_free(pkt);
                    break;
                } else
                    ret = -stanza_err_FEATURE_NOT_IMPLEMENTED;

            default:
                pkt_router(pkt_error(pkt, -ret));

                break;
        }

        return;
    }

    /* get the user */
    user = user_load(sm, pkt->to);
    if(user == NULL) {
        if(pkt->type & pkt_PRESENCE && pkt->type != pkt_PRESENCE_PROBE) {
            pkt_free(pkt);
            return;
        }

        if(pkt->type == pkt_PRESENCE_PROBE) {
            pkt_router(pkt_create(pkt->sm, "presence", "unsubscribed", jid_full(pkt->from), jid_full(pkt->to)));
            pkt_free(pkt);
            return;
        }

        pkt_router(pkt_error(pkt, stanza_err_SERVICE_UNAVAILABLE));
        return;
    }

    if (pkt->sm != NULL) {
        ret = mm_pkt_user(pkt->sm->mm, user, pkt);
        switch(ret) {
            case mod_HANDLED:
                break;
    
            case mod_PASS:
                /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */
                if(pkt->type == pkt_IQ_RESULT) {
                    pkt_free(pkt);
                    break;
                } else
                    ret = -stanza_err_FEATURE_NOT_IMPLEMENTED;

            default:
                pkt_router(pkt_error(pkt, -ret));

                break;
        }
    }

    /* if they have no sessions, they were only loaded to do delivery, so free them */
    if(user->sessions == NULL)
        user_free(user);
}
Exemple #4
0
static mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) {
    sm_t sm = mi->mod->mm->sm;
    int ns, iq, elem, attr;
    jid_t jid;
    sess_t sess = (sess_t) NULL;
    mod_ret_t ret;

    /* if we've got this namespace, its from a c2s */
    if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0)
        return mod_PASS;

    /* don't bother if its a failure */
    if(pkt->type & pkt_SESS_FAILED) {
        /* !!! check failed=1, handle */
        pkt_free(pkt);
        return mod_HANDLED;
    }

    /* session commands */
    if(pkt->type & pkt_SESS) {

        ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL);

        /* only end can get away without a target */
        attr = nad_find_attr(pkt->nad, 1, -1, "target", NULL);
        if(attr < 0 && pkt->type != pkt_SESS_END) {
            nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);

            return mod_HANDLED;
        }

        /* session start */
        if(pkt->type == pkt_SESS) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

            if(jid != NULL)
                sess = sess_start(sm, jid);

            if(jid == NULL || sess == NULL) {
                nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
                sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

                pkt->nad = NULL;
                pkt_free(pkt);
                if(jid != NULL)
                    jid_free(jid);

                return mod_HANDLED;
            }

            /* c2s component that is handling this session */
            strcpy(sess->c2s, pkt->rfrom->domain);

            /* remember what c2s calls us */
            attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
            snprintf(sess->c2s_id, sizeof(sess->c2s_id), "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));

            /* mark PBX session as fake */
            if(!strncmp("PBX", sess->c2s_id, 3)) {
                sess->fake = 1;
            }

            /* add our id */
            nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0);

            /* mark that it started OK */
            nad_set_attr(pkt->nad, 1, -1, "action", "started", 7);

			/* set this SM name */
			nad_set_attr(pkt->nad, 0, -1, "to", sm->id, 0);

			/* inform c2s */
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* user create */
        if(pkt->type == pkt_SESS_CREATE) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

            if(jid == NULL || user_create(sm, jid) != 0) {
                nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
                sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

                pkt->nad = NULL;
                pkt_free(pkt);
                if(jid != NULL)
                    jid_free(jid);

                return mod_HANDLED;
            }

            /* inform c2s */
            nad_set_attr(pkt->nad, 1, -1, "action", "created", 7);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* user delete */
        if(pkt->type == pkt_SESS_DELETE) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
            if(jid == NULL) {
                pkt_free(pkt);
                return mod_HANDLED;
            }

            user_delete(sm, jid);

            /* inform c2s */
            nad_set_attr(pkt->nad, 1, -1, "action", "deleted", 7);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* get the session id */
        attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL);
        if(attr < 0) {
            log_debug(ZONE, "no session id, bouncing");
            nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);

            return mod_HANDLED;
        }

        /* find the corresponding session */
        sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

        /* active check */
        if(sess == NULL) {
            log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
            nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);

            return mod_HANDLED;
        }

        /* make sure its from them */
        attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
        if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) {
            log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", pkt->rfrom->domain, sess->sm_id, sess->c2s_id);
            pkt_free(pkt);
            return mod_HANDLED;
        }

        /* session end */
        if(pkt->type == pkt_SESS_END) {
            sm_c2s_action(sess, "ended", NULL);
            sess_end(sess);

            pkt_free(pkt);
            return mod_HANDLED;
        }

        log_debug(ZONE, "unknown session packet, dropping");
        pkt_free(pkt);

        return mod_HANDLED;
    }

    /* otherwise, its a normal packet for the session */

/* #ifdef ENABLE_SUPERSEDED       // FIXME XXX TODO clients are not yet ready for this */
        /* check for RFC3920 session request *
         * with RFC3920bis it is unneeded *
         * session is activated by bind, so we just return back result */
        if((ns = nad_find_scoped_namespace(pkt->nad, uri_XSESSION, NULL)) >= 0 &&
           (iq = nad_find_elem(pkt->nad, 0, -1, "iq", 1)) >= 0 &&
           (elem = nad_find_elem(pkt->nad, iq, ns, "session", 1)) >= 0) {
            log_debug(ZONE, "session create request");
    
            /* build a result packet */
            nad_drop_elem(pkt->nad, elem);
            nad_set_attr(pkt->nad, iq, -1, "type", "result", 6);
    
            /* return the result */
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
    
            pkt->nad = NULL;
            pkt_free(pkt);
    
            return mod_HANDLED;
        }
/* #endif */
    /* get the session id */
    attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL);
    if(attr < 0) {
        log_debug(ZONE, "no session id, bouncing");
        nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
        sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

        pkt->nad = NULL;
        pkt_free(pkt);

        return mod_HANDLED;
    }

    /* find the corresponding session */
    sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

    /* active check */
    if(sess == NULL) {
        log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
        nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
        sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

        pkt->nad = NULL;
        pkt_free(pkt);

        return mod_HANDLED;
    }

    /* make sure its from them */
    attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
    if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) {
        log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", jid_full(pkt->rfrom), sess->sm_id, sess->c2s_id);
        pkt_free(pkt);
        return mod_HANDLED;
    }

    /* where it came from */
    pkt->source = sess;

    /* hand it to the modules */
    ret = mm_in_sess(pkt->sm->mm, sess, pkt);
    switch(ret) {
        case mod_HANDLED:
            break;

        case mod_PASS:
            /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */
            if(pkt->type == pkt_IQ_RESULT)
               break;
            else
               ret = -stanza_err_FEATURE_NOT_IMPLEMENTED;

        default:
            pkt_sess(pkt_error(pkt, -ret), sess);

            break;
    }

    return mod_HANDLED;
}
Exemple #5
0
/*
  Parse one logical MySQL packet

  This function has 6 parts:
    1. Parse error pkts
    2. Handle no last origin
    3. Handle client re-sending pkt (set state back to STATE_SLEEP)
    4. Set state and number of possible events for state
    5. Try to handle pkt given state and possible events
    6. Check if pkt was handled/parsed ok

  If the pkt fails to be handled, something is broken or missing because
  when 6 fails, it goes to 2 which acts as a kind of catch-all.
  But if 2 then fails and we get back to 6 a second time, a warning
  is printed ("Client pkt has no valid handler") and the function returns
  a failure.
*/
int parse_pkt(u_char *pkt, u_int len)
{
   u_short state;
   u_short event;
   u_short num_events;
   u_short have_failed_before = 0;
   PKT_HANDLER ha = 0;

   if(op.dump) {
      dump_pkt(pkt, len, 1);
      return PKT_PARSED_OK;
   }

   if(*pkt == 0xFF) { // Error
      pkt_error(pkt, len);
      tag->state = STATE_SLEEP;
      return PKT_PARSED_OK;
   }

   /*
     If there is no last origin, this usually means this is the first pkt
     we're seeing for this connection. However, this pkt could then be
     anything, so we have to wait for a reliable starting point which is
     any client > server command because a client will only send a command
     from a state of sleep (i.e, after the server is done responding).
   */
   if(!tag->last_origin) {
DETERMINE_PKT:
      if(tag->current_origin == ORIGIN_SERVER) {

         ha = state_map[STATE_NOT_CONNECTED].ha[0]; // server handshake pkt?
         if((*ha)(pkt, len) == PKT_HANDLED) {
            tag->state = state_map[STATE_NOT_CONNECTED].next_state[0];
            return PKT_PARSED_OK;
         }
         else {
            /*
              We're in the middle of a pre-established connection or something
              weird happened like the server responding for no reason (perhaps
              the client sent a TCP re-xmit?)
            */
            printf("Waiting for server to finish response... ");
            dump_pkt(pkt, len, 0);
            tag->state = STATE_SLEEP; // Will be asleep when done
            tag->last_origin = 0;
            return PKT_UNKNOWN_STATE; // Keeps multi_pkts() from setting tag->last_origin
         }

      }
      else { // pkt from client

         /*
           Since the MySQL protocol is purely request-response, if a pkt is from
           the client it must mean MySQL has finished responding and is asleep
           waiting for further commands.
         */
         tag->state = STATE_SLEEP;

         // Special cases
         if(len == 1) {
            if(*pkt == COM_STATISTICS) tag->state = STATE_ONE_STRING;
         }

      }
   }

   // Client re-sent pkt (MySQL probably didn't respond to the first pkt)
   if(tag->last_origin == ORIGIN_CLIENT &&
      tag->current_origin == ORIGIN_CLIENT &&
      tag->state != STATE_SLEEP)
   {
      printf("::RETRANSMIT:: ");
      tag->state = STATE_SLEEP;
   }

   // Safeguard
   if(tag->current_origin == ORIGIN_CLIENT &&
      tag->current_pkt_id == 0 &&
      tag->state != STATE_SLEEP)
   {
      tag->state = STATE_SLEEP;
   }

   state = tag->state; // Current state
   num_events = state_map[state].num_events; // Number of possible events for current state
   if(op.state) printf("state '%s' ", state_name[state]);

   // Try to handle the pkt...
   if(num_events == 1) {
      tag->event = state_map[state].event[0];
      ha = state_map[state].ha[0];

      if((*ha)(pkt, len))
         tag->state = state_map[state].next_state[0]; // pkt was handled
      else
         ha = 0;
   }
   else {
      for(event = 0; event < num_events; event++) {
         tag->event = state_map[state].event[event];
         ha = state_map[state].ha[event];

         if((*ha)(pkt, len)) {
            // pkt was handled
            tag->state = state_map[state].next_state[event];
            break;
         }
         else ha = 0;
      }
   }

   // ...Check if pkt was handled
   if(!ha) {
      printf("::Unhandled Event:: ");

      if(!have_failed_before) {
         have_failed_before = 1; // Prevent infinite loop
         goto DETERMINE_PKT;
      }
      else {
         printf("Client pkt has no valid handler ");
         dump_pkt(pkt, len, 1);
         return PKT_UNKNOWN_STATE;
      }
   }

   return PKT_PARSED_OK;
}