Beispiel #1
0
static bool request_handler(struct restund_msgctx *ctx, int proto, void *sock,
			    const struct sa *src, const struct sa *dst,
			    const struct stun_msg *msg)
{
	struct stun_attr *mi, *user, *realm, *nonce;
	const time_t now = time(NULL);
	char nstr[NONCE_MAX_SIZE + 1];
	int err;
	(void)dst;

	if (ctx->key)
		return false;

	mi    = stun_msg_attr(msg, STUN_ATTR_MSG_INTEGRITY);
	user  = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	realm = stun_msg_attr(msg, STUN_ATTR_REALM);
	nonce = stun_msg_attr(msg, STUN_ATTR_NONCE);

	if (!mi) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (!user || !realm || !nonce) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  400, "Bad Request",
				  NULL, 0, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (!nonce_validate(nonce->v.nonce, now, src)) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  438, "Stale Nonce",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	ctx->key = mem_alloc(MD5_SIZE, NULL);
	if (!ctx->key) {
		restund_warning("auth: can't to allocate memory for MI key\n");
		err = stun_ereply(proto, sock, src, 0, msg,
				  500, "Server Error",
				  NULL, 0, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	ctx->keylen = MD5_SIZE;
	if (auth.sharedsecret_length > 0 || auth.sharedsecret2_length > 0) {
		if (!((sharedsecret_auth_calc_ha1(user, (uint8_t*) auth.sharedsecret, 
                                auth.sharedsecret_length, ctx->key)
			    && !stun_msg_chk_mi(msg, ctx->key, ctx->keylen))
			|| (sharedsecret_auth_calc_ha1(user, (uint8_t*) auth.sharedsecret2,
                                   auth.sharedsecret2_length, ctx->key)
			   && !stun_msg_chk_mi(msg, ctx->key, ctx->keylen)))) {
			restund_info("auth: shared secret auth for user '%s' (%j) failed\n",
				     user->v.username, src);
			err = stun_ereply(proto, sock, src, 0, msg,
					  401, "Unauthorized",
					  NULL, 0, ctx->fp, 3,
					  STUN_ATTR_REALM, restund_realm(),
					  STUN_ATTR_NONCE, mknonce(nstr, now, src),
					  STUN_ATTR_SOFTWARE, restund_software);
			goto unauth;
		} else {
            /*
			restund_info("auth: shared secret auth for user '%s' (%j) worked\n",
				     user->v.username, src);
            */
            if (STUN_METHOD_ALLOCATE == stun_msg_method(msg) && !sharedsecret_auth_check_timestamp(user, now)) {
                restund_info("auth: shared secret auth for user '%s' expired)\n",
                         user->v.username);
                err = stun_ereply(proto, sock, src, 0, msg,
                          401, "Unauthorized",
                          NULL, 0, ctx->fp, 3,
                          STUN_ATTR_REALM, restund_realm(),
                          STUN_ATTR_NONCE, mknonce(nstr, now, src),
                          STUN_ATTR_SOFTWARE, restund_software);
                goto unauth;
            }
		}
	} else if (restund_get_ha1(user->v.username, ctx->key)) {
		restund_info("auth: unknown user '%s' (%j)\n",
			     user->v.username, src);
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (stun_msg_chk_mi(msg, ctx->key, ctx->keylen)) {
		restund_info("auth: bad password for user '%s' (%j)\n",
			     user->v.username, src);
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	return false;

 unauth:
	if (err) {
		restund_warning("auth reply error: %m\n", err);
	}

	return true;
}
Beispiel #2
0
int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
		    struct stun_msg *req, size_t presz)
{
	struct icem *icem = comp->icem;
	struct ice *ice = icem->ice;
	struct stun_attr *attr;
	struct pl lu, ru;
	enum role rrole = ROLE_UNKNOWN;
	uint64_t tiebrk = 0;
	uint32_t prio_prflx;
	bool use_cand = false;
	int err;

	/* RFC 5389: Fingerprint errors are silently discarded */
	err = stun_msg_chk_fingerprint(req);
	if (err)
		return err;

	err = stun_msg_chk_mi(req, (uint8_t *)ice->lpwd, strlen(ice->lpwd));
	if (err) {
		if (err == EBADMSG)
			goto unauth;
		else
			goto badmsg;
	}

	attr = stun_msg_attr(req, STUN_ATTR_USERNAME);
	if (!attr)
		goto badmsg;

	err = re_regex(attr->v.username, strlen(attr->v.username),
		       "[^:]+:[^]+", &lu, &ru);
	if (err) {
		DEBUG_WARNING("could not parse USERNAME attribute (%s)\n",
			      attr->v.username);
		goto unauth;
	}
	if (pl_strcmp(&lu, ice->lufrag))
		goto unauth;
	if (str_isset(icem->rufrag) && pl_strcmp(&ru, icem->rufrag))
		goto unauth;

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLED);
	if (attr) {
		rrole = ROLE_CONTROLLED;
		tiebrk = attr->v.uint64;
	}

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLING);
	if (attr) {
		rrole = ROLE_CONTROLLING;
		tiebrk = attr->v.uint64;
	}

	if (rrole == ice->lrole) {
		if (ice->tiebrk >= tiebrk)
			ice_switch_local_role(ice);
		else
			goto conflict;
	}

	attr = stun_msg_attr(req, STUN_ATTR_PRIORITY);
	if (attr)
		prio_prflx = attr->v.uint32;
	else
		goto badmsg;

	attr = stun_msg_attr(req, STUN_ATTR_USE_CAND);
	if (attr)
		use_cand = true;

	err = handle_stun(ice, icem, comp, src, prio_prflx,
			  use_cand, presz > 0);
	if (err)
		goto badmsg;

	return stun_reply(icem->proto, comp->sock, src, presz, req,
			  (uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 2,
			  STUN_ATTR_XOR_MAPPED_ADDR, src,
			  STUN_ATTR_SOFTWARE, sw);

 badmsg:
	return stunsrv_ereply(comp, src, presz, req, 400, "Bad Request");

 unauth:
	return stunsrv_ereply(comp, src, presz, req, 401, "Unauthorized");

 conflict:
	return stunsrv_ereply(comp, src, presz, req, 487, "Role Conflict");
}
Beispiel #3
0
int test_stun_req(void)
{
	struct stun_msg *msg = NULL;
	struct mbuf *mb;
	struct stun_attr *attr;
	int err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_REQUEST,
			      tid, NULL,
			      (uint8_t *)password.p, password.l, true,
			      0x20, 4,
			      STUN_ATTR_SOFTWARE, client_sw,
			      STUN_ATTR_PRIORITY, &ice_prio,
			      STUN_ATTR_CONTROLLED, &ice_contr,
			      STUN_ATTR_USERNAME, username);
	if (err)
		goto out;

	TEST_MEMCMP(req, sizeof(req)-1, mb->buf, mb->end);

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	if (STUN_CLASS_REQUEST != stun_msg_class(msg))
		goto bad;

	if (STUN_METHOD_BINDING != stun_msg_method(msg))
		goto out;

	err = stun_msg_chk_mi(msg, (uint8_t *)password.p, password.l);
	if (err)
		goto out;

	err = stun_msg_chk_fingerprint(msg);
	if (err)
		goto out;

	attr = stun_msg_attr(msg, STUN_ATTR_PRIORITY);
	if (!attr || ice_prio != attr->v.priority)
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_CONTROLLED);
	if (!attr || ice_contr != attr->v.controlled)
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	if (!attr || strcmp(username, attr->v.username))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_SOFTWARE);
	if (!attr || strcmp(client_sw, attr->v.software))
		goto bad;

	goto out;

 bad:
	err = EBADMSG;

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
Beispiel #4
0
int test_stun_reqltc(void)
{
	struct stun_msg *msg = NULL;
	struct stun_attr *attr;
	struct mbuf *mb;
	uint8_t md5_hash[MD5_SIZE];
	int r, err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	/* use long-term credentials */
	err = md5_printf(md5_hash, "%s:%s:%s", username_ltc, realm_ltc,
			 password_ltc);
	if (err)
		goto out;

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_REQUEST,
			      tid_ltc, NULL,
			      md5_hash, sizeof(md5_hash),
			      false, 0x00, 3,
			      STUN_ATTR_USERNAME, username_ltc,
			      STUN_ATTR_NONCE, nonce_ltc,
			      STUN_ATTR_REALM, realm_ltc);
	if (err)
		goto out;

	r = memcmp(mb->buf, reqltc, mb->end);
	if ((sizeof(reqltc)-1) != mb->end || 0 != r) {
		err = EBADMSG;
		DEBUG_WARNING("compare failed (r=%d)\n", r);
		(void)re_printf("msg: [%02w]\n", mb->buf, mb->end);
		(void)re_printf("ref: [%02w]\n", reqltc, sizeof(reqltc)-1);
		goto out;
	}

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	if (STUN_CLASS_REQUEST != stun_msg_class(msg))
		goto bad;

	if (STUN_METHOD_BINDING != stun_msg_method(msg))
		goto bad;

	err = stun_msg_chk_mi(msg, md5_hash, sizeof(md5_hash));
	if (err)
		goto out;

	if (EPROTO != stun_msg_chk_fingerprint(msg))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	if (!attr || strcmp(username_ltc, attr->v.username))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_NONCE);
	if (!attr || strcmp(nonce_ltc, attr->v.nonce))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_REALM);
	if (!attr || strcmp(realm_ltc, attr->v.realm))
		goto bad;

	goto out;

 bad:
	err = EBADMSG;

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
Beispiel #5
0
static int test_resp(const struct pl *resp, const struct sa *addr)
{
	struct stun_msg *msg = NULL;
	struct stun_attr *attr;
	struct mbuf *mb = NULL;
	int err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_SUCCESS_RESP,
			      tid, NULL,
			      (uint8_t *)password.p, password.l, true,
			      0x20, 2,
                              STUN_ATTR_SOFTWARE, server_sw,
			      STUN_ATTR_XOR_MAPPED_ADDR, addr);
	if (err)
		goto out;

	if (resp->l != mb->end ||
	    0 != memcmp(mb->buf, resp->p, mb->end)) {
		err = EBADMSG;
		DEBUG_WARNING("compare failed (%J)\n", addr);
		(void)re_printf("msg: [%02w]\n", mb->buf, mb->end);
		(void)re_printf("ref: [%02w]\n", resp->p, resp->l);
		goto out;
	}

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	if (STUN_CLASS_SUCCESS_RESP != stun_msg_class(msg))
		goto bad;

	if (STUN_METHOD_BINDING != stun_msg_method(msg))
		goto bad;

	err = stun_msg_chk_mi(msg, (uint8_t *)password.p, password.l);
	if (err)
		goto out;

	err = stun_msg_chk_fingerprint(msg);
	if (err)
		goto out;

	attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
	if (!attr || !sa_cmp(&attr->v.xor_mapped_addr, addr, SA_ALL))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_SOFTWARE);
	if (!attr || strcmp(server_sw, attr->v.software))
		goto bad;

	goto out;

 bad:
	err = EBADMSG;

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
int trice_stund_recv(struct trice *icem, struct ice_lcand *lcand,
		    void *sock, const struct sa *src,
		    struct stun_msg *req, size_t presz)
{
	struct stun_attr *attr;
	struct pl lu, ru;
	bool remote_controlling;
	uint64_t tiebrk = 0;
	uint32_t prio_prflx;
	bool use_cand = false;
	int err;

	/* RFC 5389: Fingerprint errors are silently discarded */
	err = stun_msg_chk_fingerprint(req);
	if (err)
		return err;

	err = stun_msg_chk_mi(req, (uint8_t *)icem->lpwd, strlen(icem->lpwd));
	if (err) {
		DEBUG_WARNING("message-integrity failed (src=%J)\n", src);
		if (err == EBADMSG)
			goto unauth;
		else
			goto badmsg;
	}

	attr = stun_msg_attr(req, STUN_ATTR_USERNAME);
	if (!attr)
		goto badmsg;

	err = re_regex(attr->v.username, strlen(attr->v.username),
		       "[^:]+:[^]+", &lu, &ru);
	if (err) {
		DEBUG_WARNING("could not parse USERNAME attribute (%s)\n",
			      attr->v.username);
		goto unauth;
	}
	if (pl_strcmp(&lu, icem->lufrag)) {
		DEBUG_WARNING("local ufrag err (expected %s, actual %r)\n",
			      icem->lufrag, &lu);
		goto unauth;
	}
	if (str_isset(icem->rufrag) && pl_strcmp(&ru, icem->rufrag)) {
		DEBUG_WARNING("remote ufrag err (expected %s, actual %r)\n",
			      icem->rufrag, &ru);
		goto unauth;
	}

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLED);
	if (attr) {
		remote_controlling = false;
		tiebrk = attr->v.uint64;
	}

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLING);
	if (attr) {
		remote_controlling = true;
		tiebrk = attr->v.uint64;
	}

	if (remote_controlling == icem->controlling) {
		if (icem->tiebrk >= tiebrk)
			trice_switch_local_role(icem);
		else
			goto conflict;
	}

	attr = stun_msg_attr(req, STUN_ATTR_PRIORITY);
	if (attr)
		prio_prflx = attr->v.uint32;
	else
		goto badmsg;

	attr = stun_msg_attr(req, STUN_ATTR_USE_CAND);
	if (attr)
		use_cand = true;

	err = handle_stun_full(icem, lcand, sock, src, prio_prflx, use_cand);

	if (err)
		goto badmsg;

	trice_tracef(icem, 32,
		     "[%u] STUNSRV: Tx success respons [%H ---> %J]\n",
		     lcand->attr.compid,
		     trice_cand_print, lcand, src);

	return stun_reply(lcand->attr.proto, sock, src, presz, req,
			  (uint8_t *)icem->lpwd, strlen(icem->lpwd), true, 2,
			  STUN_ATTR_XOR_MAPPED_ADDR, src,
			  STUN_ATTR_SOFTWARE, icem->sw ? icem->sw : sw);


 badmsg:
	return stunsrv_ereply(icem, lcand, sock, src, presz, req,
			      400, "Bad Request");

 unauth:
	return stunsrv_ereply(icem, lcand, sock, src, presz, req,
			      401, "Unauthorized");

 conflict:
	return stunsrv_ereply(icem, lcand, sock, src, presz, req,
			      487, "Role Conflict");
}
Beispiel #7
0
static bool request_handler(struct restund_msgctx *ctx, int proto, void *sock,
			    const struct sa *src, const struct sa *dst,
			    const struct stun_msg *msg)
{
	struct stun_attr *mi, *user, *realm, *nonce;
	const uint32_t now = (uint32_t)time(NULL);
	char nstr[NONCE_SIZE + 1];
	int err;
	(void)dst;

	if (ctx->key)
		return false;

	mi    = stun_msg_attr(msg, STUN_ATTR_MSG_INTEGRITY);
	user  = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	realm = stun_msg_attr(msg, STUN_ATTR_REALM);
	nonce = stun_msg_attr(msg, STUN_ATTR_NONCE);

	if (!mi) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (!user || !realm || !nonce) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  400, "Bad Request",
				  NULL, 0, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (!nonce_validate(nonce->v.nonce, now, src)) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  438, "Stale Nonce",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	ctx->key = mem_alloc(MD5_SIZE, NULL);
	if (!ctx->key) {
		restund_warning("auth: can't to allocate memory for MI key\n");
		err = stun_ereply(proto, sock, src, 0, msg,
				  500, "Server Error",
				  NULL, 0, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	ctx->keylen = MD5_SIZE;

	if (restund_get_ha1(user->v.username, ctx->key)) {
		restund_info("auth: unknown user '%s'\n", user->v.username);
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (stun_msg_chk_mi(msg, ctx->key, ctx->keylen)) {
		restund_info("auth: bad passwd for '%s'\n", user->v.username);
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	return false;

 unauth:
	if (err) {
		restund_warning("auth reply error: %s\n", strerror(err));
	}

	return true;
}