/* Called when the stream ends so that the authentication engine can do * any authentication cleanup */ void auth_stream_end (mount_proxy *mountinfo, const char *mount) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_end) { auth_client *auth_user = auth_client_setup (mount, NULL); auth_user->process = stream_end_callback; INFO1 ("request source end for \"%s\"", mount); queue_auth_client (auth_user, mountinfo); } }
/* Called when a source client connects and requires authentication via the * authenticator. This is called for both source clients and admin requests * that work on a specified mountpoint. */ int auth_stream_authenticate (client_t *client, const char *mount, mount_proxy *mountinfo) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_auth) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = stream_auth_callback; ICECAST_LOG_INFO("request source auth for \"%s\"", mount); queue_auth_client (auth_user, mountinfo); return 1; } return 0; }
/* Called when a source client connects and requires authentication via the * authenticator. This is called for both source clients and admin requests * that work on a specified mountpoint. */ int auth_stream_authenticate (client_t *client, const char *mount, mount_proxy *mountinfo) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_auth) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = stream_auth_callback; INFO1 ("request source auth for \"%s\"", mount); client->flags &= ~CLIENT_ACTIVE; queue_auth_client (auth_user, mountinfo); return 1; } return 0; }
/* Called when the stream ends so that the authentication engine can do * any authentication cleanup */ void auth_stream_end (mount_proxy *mountinfo, source_t *source) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_end) { client_t *client = source->client; const char *agent = httpp_getvar (client->parser, "user-agent"), *mount = source->mount; auth_client *auth_user = auth_client_setup (mount, NULL); // use a blank client copy to avoid a race auth_user->client = calloc (1, sizeof (client_t)); auth_user->client->connection.ip = strdup (client->connection.ip); if (agent) auth_user->client->shared_data = strdup (agent); auth_user->process = stream_end_callback; INFO1 ("request stream end for \"%s\"", mount); queue_auth_client (auth_user, mountinfo); } }
/* General listener client shutdown function. Here we free up the passed client but * if the client is authenticated and there's auth available then queue it. */ int auth_release_listener (client_t *client, const char *mount, mount_proxy *mountinfo) { if (client->flags & CLIENT_AUTHENTICATED) { client_set_queue (client, NULL); if (mount && mountinfo && mountinfo->auth && mountinfo->auth->release_listener) { auth_client *auth_user = auth_client_setup (mount, client); client->flags &= ~CLIENT_ACTIVE; if (client->worker) client->ops = &auth_release_ops; // put into a wait state auth_user->process = auth_remove_listener; queue_auth_client (auth_user, mountinfo); return 0; } client->flags &= ~CLIENT_AUTHENTICATED; } return client_send_404 (client, NULL); }
/* determine whether we need to process this client further. This * involves any auth exit, typically for external auth servers. */ int auth_release_listener (client_t *client) { if (client->authenticated) { const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI); /* drop any queue reference here, we do not want a race between the source thread * and the auth/fserve thread */ client_set_queue (client, NULL); if (mount && client->auth && client->auth->release_listener) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = auth_remove_listener; queue_auth_client (auth_user, NULL); return 1; } client->authenticated = 0; } return 0; }
/* called when the stream starts, so that authentication engine can do any * cleanup/initialisation. */ void auth_stream_start (mount_proxy *mountinfo, source_t *source) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_start) { client_t *client = source->client; const char *agent = httpp_getvar (client->parser, "user-agent"), *mount = source->mount; auth_client *auth_user = auth_client_setup (mount, NULL); auth_user->process = stream_start_callback; // use a blank client copy to avoid a race as slower callbacks could occur // after a short lived source. auth_user->client = calloc (1, sizeof (client_t)); auth_user->client->connection.ip = strdup (client->connection.ip); if (agent) auth_user->client->shared_data = strdup (agent); INFO1 ("request stream startup for \"%s\"", mount); queue_auth_client (auth_user, mountinfo); } }
/* Add a listener. Check for any mount information that states any * authentication to be used. */ void auth_add_listener (const char *mount, client_t *client) { mount_proxy *mountinfo; ice_config_t *config = config_get_config(); mountinfo = config_find_mount (config, mount, MOUNT_TYPE_NORMAL); if (mountinfo && mountinfo->no_mount) { config_release_config (); client_send_403 (client, "mountpoint unavailable"); return; } if (mountinfo && mountinfo->auth) { auth_client *auth_user; if (mountinfo->auth->pending_count > 100) { config_release_config (); ICECAST_LOG_WARN("too many clients awaiting authentication"); client_send_403 (client, "busy, please try again later"); return; } auth_user = auth_client_setup (mount, client); auth_user->process = auth_new_listener; ICECAST_LOG_INFO("adding client for authentication"); queue_auth_client (auth_user, mountinfo); config_release_config (); } else { int ret = add_authenticated_listener (mount, mountinfo, client); config_release_config (); if (ret < 0) client_send_403 (client, "max listeners reached"); } }
/* Add a listener. Check for any mount information that states any * authentication to be used. */ int auth_add_listener (const char *mount, client_t *client) { int ret = 0, need_auth = 1; ice_config_t *config = config_get_config(); mount_proxy *mountinfo = config_find_mount (config, mount); if (client->flags & CLIENT_AUTHENTICATED) need_auth = 0; else { const char *range = httpp_getvar (client->parser, "range"); if (range) { uint64_t pos1 = 0, pos2 = (uint64_t)-1; if (strncmp (range, "bytes=", 6) == 0) { if (sscanf (range+6, "-%" SCNuMAX, &pos2) < 1) if (sscanf (range+6, "%" SCNuMAX "-%" SCNuMAX, &pos1, &pos2) < 1) pos2 = 0; } else pos2 = 0; if (pos2 > 0 && pos1 < pos2) { client->intro_offset = pos1; client->connection.discon.offset = pos2; client->flags |= CLIENT_RANGE_END; if (pos2 - pos1 < 10) need_auth = 0; // avoid auth check if range is very small, player hack } else WARN2 ("client range invalid (%" PRIu64 ", %" PRIu64 "), ignoring", pos1, pos2); } } if (client->parser->req_type == httpp_req_head) { client->flags &= ~CLIENT_AUTHENTICATED; need_auth = 0; } if (need_auth) { if (mountinfo) { auth_t *auth = mountinfo->auth; if (mountinfo->skip_accesslog) client->flags |= CLIENT_SKIP_ACCESSLOG; if (mountinfo->ban_client) { if (mountinfo->ban_client < 0) client->flags |= CLIENT_IP_BAN_LIFT; connection_add_banned_ip (client->connection.ip, mountinfo->ban_client); } if (mountinfo->no_mount) { config_release_config (); return client_send_403 (client, "mountpoint unavailable"); } if (mountinfo->redirect) { char buffer [4096] = ""; unsigned int len = sizeof buffer; if (util_expand_pattern (mount, mountinfo->redirect, buffer, &len) == 0) { config_release_config (); return client_send_302 (client, buffer); } WARN3 ("failed to expand %s on %s for %s", mountinfo->redirect, mountinfo->mountname, mount); return client_send_501 (client); } do { if (auth == NULL) break; if ((auth->flags & AUTH_RUNNING) == 0) break; if (auth->pending_count > 400) { if (auth->flags & AUTH_SKIP_IF_SLOW) break; config_release_config (); WARN0 ("too many clients awaiting authentication"); if (global.new_connections_slowdown < 10) global.new_connections_slowdown++; return client_send_403 (client, "busy, please try again later"); } if (auth->authenticate) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = auth_new_listener; client->flags &= ~CLIENT_ACTIVE; DEBUG0 ("adding client for authentication"); queue_auth_client (auth_user, mountinfo); config_release_config (); return 0; } } while (0); } else { if (strcmp (mount, "/admin/streams") == 0) { config_release_config (); return client_send_401 (client, NULL); } } } ret = add_authenticated_listener (mount, mountinfo, client); config_release_config (); return ret; }
/* Add a listener. Check for any mount information that states any * authentication to be used. */ int auth_add_listener (const char *mount, client_t *client) { int ret = 0; ice_config_t *config = config_get_config(); mount_proxy *mountinfo = config_find_mount (config, mount); if ((client->flags & CLIENT_AUTHENTICATED) == 0) { if (mountinfo) { auth_t *auth = mountinfo->auth; if (mountinfo->skip_accesslog) client->flags |= CLIENT_SKIP_ACCESSLOG; if (mountinfo->ban_client) { if (mountinfo->ban_client < 0) client->flags |= CLIENT_IP_BAN_LIFT; connection_add_banned_ip (client->connection.ip, mountinfo->ban_client); } if (mountinfo->no_mount) { config_release_config (); return client_send_403 (client, "mountpoint unavailable"); } if (mountinfo->redirect) { int len = strlen (mountinfo->redirect) + strlen (mount) + 3; char *addr = alloca (len); snprintf (addr, len, "%s%s", mountinfo->redirect, mount); config_release_config (); return client_send_302 (client, addr); } do { if (auth == NULL) break; if ((auth->flags & AUTH_RUNNING) == 0) break; if (auth->pending_count > 400) { if (auth->flags & AUTH_SKIP_IF_SLOW) break; config_release_config (); WARN0 ("too many clients awaiting authentication"); if (global.new_connections_slowdown < 10) global.new_connections_slowdown++; return client_send_403 (client, "busy, please try again later"); } if (auth->authenticate) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = auth_new_listener; client->flags &= ~CLIENT_ACTIVE; DEBUG0 ("adding client for authentication"); queue_auth_client (auth_user, mountinfo); config_release_config (); return 0; } } while (0); } else { if (strcmp (mount, "/admin/streams") == 0) { config_release_config (); return client_send_401 (client, NULL); } } } ret = add_authenticated_listener (mount, mountinfo, client); config_release_config (); return ret; }