Exemplo n.º 1
0
static bool sharedsecret_auth_calc_ha1(const struct stun_attr *user, const uint8_t *secret, const size_t secret_length, uint8_t *key) 
{
	uint8_t expected[SHA_DIGEST_LENGTH];
	char expected_base64[SHA_DIGEST_LENGTH/2*3];
	size_t b64len;

	uint8_t ha1[MD5_SIZE];
	int retval;
	if (!secret_length) {
        /*
		restund_warning("auth: calc_ha1 no secret length %s\n", secret);
        */
		return false;
	}

	hmac_sha1(secret, secret_length,
		  (uint8_t *) user->v.username, strlen(user->v.username),
		  expected, SHA_DIGEST_LENGTH);
	b64len = sizeof expected_base64;
	if ((retval = base64_encode(expected, SHA_DIGEST_LENGTH, expected_base64, &b64len)) != 0) {
		restund_warning("auth: failed to base64 encode hmac, error %d\n", retval);
		return false;	
	}
	expected_base64[b64len] = 0;
	if ((retval = md5_printf(ha1, "%s:%s:%s", user->v.username, restund_realm(), expected_base64)) != 0) {
		restund_warning("auth: failed to md5_printf ha1, error %d\n", retval);
		return false;
	}
	memcpy(key, &ha1, MD5_SIZE);
	return true;
}
Exemplo n.º 2
0
static int module_init(void)
{
	struct sa laddr_udp, laddr_http;
	struct pl addr;
	uint32_t port;
	int err;

	/* UDP bind address */
	if (conf_get(restund_conf(), "status_udp_addr", &addr))
		pl_set_str(&addr, "127.0.0.1");

	if (conf_get_u32(restund_conf(), "status_udp_port", &port))
		port = 33000;

	err = sa_set(&laddr_udp, &addr, port);
	if (err) {
		restund_error("status: bad udp bind address: %r:%u",
			      &addr, port);
		goto out;
	}

	/* HTTP bind address */
	if (conf_get(restund_conf(), "status_http_addr", &addr))
		pl_set_str(&addr, "127.0.0.1");

	if (conf_get_u32(restund_conf(), "status_http_port", &port))
		port = 8080;

	err = sa_set(&laddr_http, &addr, port);
	if (err) {
		restund_error("status: bad http bind address: %r:%u",
			      &addr, port);
		goto out;
	}

	err = udp_listen(&stg.us, &laddr_udp, udp_recv, NULL);
	if (err) {
		restund_warning("status: udp_listen: %m\n", err);
		goto out;
	}

	err = httpd_alloc(&stg.httpd, &laddr_http, httpd_handler);
	if (err) {
		restund_warning("status: httpd: %m\n", err);
		goto out;
	}

	stg.start = time(NULL);

	restund_debug("status: module loaded (udp=%J http=%J)\n",
		      &laddr_udp, &laddr_http);

 out:
	if (err) {
		stg.us = mem_deref(stg.us);
		stg.httpd = mem_deref(stg.httpd);
	}

	return err;
}
Exemplo n.º 3
0
static int listen_handler(const struct pl *addrport, void *arg)
{
    uint32_t sockbuf_size = *(uint32_t *)arg;
    struct udp_lstnr *ul = NULL;
    int err = ENOMEM;

    ul = mem_zalloc(sizeof(*ul), destructor);
    if (!ul) {
        restund_warning("udp listen error: %s\n", strerror(err));
        goto out;
    }

    list_append(&lstnrl, &ul->le, ul);

    err = sa_decode(&ul->bnd_addr, addrport->p, addrport->l);
    if (err || sa_is_any(&ul->bnd_addr) || !sa_port(&ul->bnd_addr)) {
        restund_warning("bad udp_listen directive: '%r'\n", addrport);
        err = EINVAL;
        goto out;
    }

    err = udp_listen(&ul->us, &ul->bnd_addr, udp_recv, ul);
    if (err) {
        restund_warning("udp listen %J: %s\n", &ul->bnd_addr,
                        strerror(err));
        goto out;
    }

    if (sockbuf_size > 0)
        (void)udp_sockbuf_set(ul->us, sockbuf_size);

    restund_debug("udp listen: %J\n", &ul->bnd_addr);

out:
    if (err)
        mem_deref(ul);

    return err;
}
Exemplo n.º 4
0
static int accounts_getall(const char *realm, restund_db_account_h *acch,
			   void *arg)
{
	MYSQL_RES *res;
	int err = 0;

	if (!realm || !acch)
		return EINVAL;

	switch (my.version) {

	case 2:
		err = query(&res,
			    "SELECT auth_username, ha1 "
			    "FROM credentials WHERE realm = '%s';",
			    realm);
		break;

	default:
		err = query(&res,
			    "SELECT username, ha1 "
			    "FROM subscriber where domain = '%s';",
			    realm);
		break;
	}

	if (err) {
		restund_warning("mysql: unable to select accounts: %s\n",
				mysql_error(&my.mysql));
		return err;
	}

	for (;!err;) {
		MYSQL_ROW row;

		row = mysql_fetch_row(res);
		if (!row)
			break;

		err = acch(row[0] ? row[0] : "", row[1] ? row[1] : "", arg);
	}

	mysql_free_result(res);

	return err;
}
Exemplo n.º 5
0
static int accounts_count(const char *realm, uint32_t *n)
{
	MYSQL_RES *res;
	MYSQL_ROW row;
	int err = 0;

	if (!realm || !n)
		return EINVAL;

	switch (my.version) {

	case 2:
		err = query(&res,
			    "SELECT COUNT(*) "
			    "FROM credentials WHERE realm = '%s';",
			    realm);
		break;

	default:
		err = query(&res,
			    "SELECT COUNT(*) "
			    "FROM subscriber where domain = '%s';",
			    realm);
		break;
	}

	if (err) {
		restund_warning("mysql: unable to select nr of accounts: %s\n",
				mysql_error(&my.mysql));
		return err;
	}

	row = mysql_fetch_row(res);
	if (row)
		*n = atoi(row[0]);
	else
		err = ENOENT;

	mysql_free_result(res);

	return err;
}
Exemplo n.º 6
0
static int module_handler(const struct pl *val, void *arg)
{
	struct pl *modpath = arg;
	char filepath[256];
	struct mod *mod;
	int err;

	if (val->p && val->l && (*val->p == '/'))
		(void)re_snprintf(filepath, sizeof(filepath), "%r", val);
	else
		(void)re_snprintf(filepath, sizeof(filepath), "%r/%r",
				  modpath, val);

	err = mod_load(&mod, filepath);
	if (err) {
		restund_warning("can't load module %s (%m)\n",
				filepath, err);
		goto out;
	}

 out:
	return err;
}
Exemplo n.º 7
0
void chanbind_request(struct allocation *al, struct restund_msgctx *ctx,
		      int proto, void *sock, const struct sa *src,
		      const struct stun_msg *msg)
{
	struct chan *chan = NULL, *ch_numb = NULL, *ch_peer;
	struct perm *perm = NULL, *permx = NULL;
	struct stun_attr *chnr, *peer;
	int err = ENOMEM, rerr;

	chnr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER);
	peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);

	if (!chnr || !chan_numb_valid(chnr->v.channel_number) || !peer) {
		restund_info("turn: bad chanbind attributes\n");
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   400, "Bad Attributes",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (sa_af(&peer->v.xor_peer_addr) != sa_af(&al->rel_addr)) {
		restund_info("turn: chanbind peer address family mismatch\n");
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   443, "Peer Address Family Mismatch",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	ch_numb = chan_numb_find(al->chans, chnr->v.channel_number);
	ch_peer = chan_peer_find(al->chans, &peer->v.xor_peer_addr);

	if (ch_numb != ch_peer) {
		restund_info("turn: channel %p/peer %p already bound\n",
			     ch_numb, ch_peer);
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   400, "Channel/Peer Already Bound",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (!ch_numb) {
		chan = chan_create(al->chans, chnr->v.channel_number,
				   &peer->v.xor_peer_addr, al);
		if (!chan) {
			restund_info("turn: unable to create channel\n");
			rerr = stun_ereply(proto, sock, src, 0, msg,
					  500, "Server Error",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	permx = perm_find(al->perms, &peer->v.xor_peer_addr);
	if (!permx) {
		perm = perm_create(al->perms, &peer->v.xor_peer_addr, al);
		if (!perm) {
			restund_info("turn: unable to create permission\n");
			rerr = stun_ereply(proto, sock, src, 0, msg,
					  500, "Server Error",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	err = rerr = stun_reply(proto, sock, src, 0, msg,
				ctx->key, ctx->keylen, ctx->fp, 1,
				STUN_ATTR_SOFTWARE, restund_software);
 out:
	if (rerr)
		restund_warning("turn: chanbind reply: %m\n", rerr);

	if (err) {
		mem_deref(chan);
		mem_deref(perm);
	}
	else {
		chan_refresh(ch_numb);
		perm_refresh(permx);
	}
}
Exemplo n.º 8
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)
{
	const uint16_t met = stun_msg_method(msg);
	struct allocation *al;
	int err = 0;

	switch (met) {

	case STUN_METHOD_ALLOCATE:
	case STUN_METHOD_REFRESH:
	case STUN_METHOD_CREATEPERM:
	case STUN_METHOD_CHANBIND:
		break;

	default:
		return false;
	}

	if (ctx->ua.typec > 0) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  420, "Unknown Attribute",
				  ctx->key, ctx->keylen, ctx->fp, 2,
				  STUN_ATTR_UNKNOWN_ATTR, &ctx->ua,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	al = allocation_find(proto, src, dst);

	if (!al && met != STUN_METHOD_ALLOCATE) {
		restund_debug("turn: allocation does not exist\n");
		err = stun_ereply(proto, sock, src, 0, msg,
				  437, "Allocation Mismatch",
				  ctx->key, ctx->keylen, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (al && al->username && ctx->key) {

		struct stun_attr *usr = stun_msg_attr(msg, STUN_ATTR_USERNAME);

		if (!usr || strcmp(usr->v.username, al->username)) {
			restund_debug("turn: wrong credetials\n");
			err = stun_ereply(proto, sock, src, 0, msg,
					  441, "Wrong Credentials",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	switch (met) {

	case STUN_METHOD_ALLOCATE:
		allocate_request(&turnd, al, ctx, proto, sock, src, dst, msg);
		break;

	case STUN_METHOD_REFRESH:
		refresh_request(&turnd, al, ctx, proto, sock, src, msg);
		break;

	case STUN_METHOD_CREATEPERM:
		createperm_request(al, ctx, proto, sock, src, msg);
		break;

	case STUN_METHOD_CHANBIND:
		chanbind_request(al, ctx, proto, sock, src, msg);
		break;
	}

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

	return true;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
int main(int argc, char *argv[])
{
	bool daemon = true;
	int err = 0;
	struct pl opt;

	(void)sys_coredump_set(true);

#ifdef HAVE_GETOPT
	for (;;) {

		const int c = getopt(argc, argv, "dhnf:");
		if (0 > c)
			break;

		switch (c) {

		case 'd':
			force_debug = true;
			restund_log_enable_debug(true);
			break;

		case 'f':
			configfile = optarg;
			break;

		case 'n':
			daemon = false;
			break;

		case '?':
			err = EINVAL;
			/*@fallthrough@*/
		case 'h':
			usage();
			return err;
		}
	}
#else
	(void)argc;
	(void)argv;
#endif

	restund_cmd_subscribe(&cmd_reload);

	err = fd_setsize(4096);
	if (err) {
		restund_warning("fd_setsize error: %m\n", err);
		goto out;
	}

	err = libre_init();
	if (err) {
		restund_error("re init failed: %m\n", err);
		goto out;
	}

	/* configuration file */
	err = conf_alloc(&conf, configfile);
	if (err) {
		restund_error("error loading configuration: %s: %m\n",
			      configfile, err);
		goto out;
	}

	/* debug config */
	if (!conf_get(conf, "debug", &opt) && !pl_strcasecmp(&opt, "yes"))
		restund_log_enable_debug(true);

	/* udp */
	err = restund_udp_init();
	if (err)
		goto out;

	/* tcp */
	err = restund_tcp_init();
	if (err)
		goto out;

	/* daemon config */
	if (!conf_get(conf, "daemon", &opt) && !pl_strcasecmp(&opt, "no"))
		daemon = false;

	/* module config */
	if (conf_get(conf, "module_path", &opt))
		pl_set_str(&opt, ".");

	err = conf_apply(conf, "module", module_handler, &opt);
	if (err)
		goto out;

	/* daemon */
	if (daemon) {
		err = sys_daemon();
		if (err) {
			restund_error("daemon error: %m\n", err);
			goto out;
 		}

		restund_log_enable_stderr(false);
	}

	/* database */
	err = restund_db_init();
	if (err) {
		restund_warning("database error: %m\n", err);
		goto out;
	}

	restund_info("stun server ready\n");

	/* main loop */
	err = re_main(signal_handler);

 out:
	restund_db_close();
	mod_close();
	restund_udp_close();
	restund_tcp_close();
	conf = mem_deref(conf);

	libre_close();

	restund_cmd_unsubscribe(&cmd_reload);

	/* check for memory leaks */
	tmr_debug();
	mem_debug();

	return err;
}
Exemplo n.º 11
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;
}