summaryrefslogtreecommitdiffstats
path: root/stream
diff options
context:
space:
mode:
Diffstat (limited to 'stream')
-rw-r--r--stream/stream.c61
-rw-r--r--stream/stream.h29
-rw-r--r--stream/stream_avdevice.c1
-rw-r--r--stream/stream_bluray.c3
-rw-r--r--stream/stream_cb.c1
-rw-r--r--stream/stream_cdda.c1
-rw-r--r--stream/stream_concat.c2
-rw-r--r--stream/stream_dvb.c1
-rw-r--r--stream/stream_dvdnav.c4
-rw-r--r--stream/stream_file.c2
-rw-r--r--stream/stream_lavf.c6
-rw-r--r--stream/stream_libarchive.c10
-rw-r--r--stream/stream_memory.c2
-rw-r--r--stream/stream_smb.c1
14 files changed, 87 insertions, 37 deletions
diff --git a/stream/stream.c b/stream/stream.c
index 271e268a1c..157776cd87 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -101,6 +101,7 @@ static const stream_info_t *const stream_list[] = {
struct stream_opts {
int64_t buffer_size;
+ int load_unsafe_playlists;
};
#define OPT_BASE_STRUCT struct stream_opts
@@ -109,6 +110,7 @@ const struct m_sub_options stream_conf = {
.opts = (const struct m_option[]){
OPT_BYTE_SIZE("stream-buffer-size", buffer_size, 0,
STREAM_MIN_BUFFER_SIZE, 512 * 1024 * 1024),
+ OPT_FLAG("load-unsafe-playlists", load_unsafe_playlists, 0),
{0}
},
.size = sizeof(struct stream_opts),
@@ -202,6 +204,30 @@ static const char *match_proto(const char *url, const char *proto)
return NULL;
}
+// src and new are both STREAM_ORIGIN_* values. This checks whether a stream
+// with flags "new" can be opened from the "src". On success, return
+// new origin, on incompatibility return 0.
+static int check_origin(int src, int new)
+{
+ switch (src) {
+ case STREAM_ORIGIN_DIRECT:
+ case STREAM_ORIGIN_UNSAFE:
+ // Allow anything, but constrain it to the new origin.
+ return new;
+ case STREAM_ORIGIN_FS:
+ // From unix FS, allow all but unsafe.
+ if (new == STREAM_ORIGIN_FS || new == STREAM_ORIGIN_NET)
+ return new;
+ break;
+ case STREAM_ORIGIN_NET:
+ // Allow only other network links.
+ if (new == STREAM_ORIGIN_NET)
+ return new;
+ break;
+ }
+ return 0;
+}
+
// Read len bytes from the start position, and wrap around as needed. Limit the
// actually read data to the size of the buffer. Return amount of copied bytes.
// len: max bytes to copy to dst
@@ -289,11 +315,6 @@ static int stream_create_instance(const stream_info_t *sinfo,
*ret = NULL;
- if (!sinfo->is_safe && (flags & STREAM_SAFE_ONLY))
- return STREAM_UNSAFE;
- if (!sinfo->is_network && (flags & STREAM_NETWORK_ONLY))
- return STREAM_UNSAFE;
-
const char *path = url;
for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
path = match_proto(url, sinfo->protocols[n]);
@@ -304,11 +325,9 @@ static int stream_create_instance(const stream_info_t *sinfo,
if (!path)
return STREAM_NO_MATCH;
- struct stream_opts *opts =
- mp_get_config_group(NULL, args->global, &stream_conf);
-
stream_t *s = talloc_zero(NULL, stream_t);
s->global = args->global;
+ struct stream_opts *opts = mp_get_config_group(s, s->global, &stream_conf);
if (flags & STREAM_SILENT) {
s->log = mp_null_log;
} else {
@@ -318,7 +337,6 @@ static int stream_create_instance(const stream_info_t *sinfo,
s->cancel = args->cancel;
s->url = talloc_strdup(s, url);
s->path = talloc_strdup(s, path);
- s->is_network = sinfo->is_network;
s->mode = flags & (STREAM_READ | STREAM_WRITE);
s->requested_buffer_size = opts->buffer_size;
@@ -326,8 +344,6 @@ static int stream_create_instance(const stream_info_t *sinfo,
mp_read_option_raw(s->global, "access-references", &m_option_type_flag, &opt);
s->access_references = opt;
- talloc_free(opts);
-
MP_VERBOSE(s, "Opening %s\n", url);
if (strlen(url) > INT_MAX / 8) {
@@ -342,6 +358,18 @@ static int stream_create_instance(const stream_info_t *sinfo,
return STREAM_NO_MATCH;
}
+ s->stream_origin = flags & STREAM_ORIGIN_MASK; // pass through by default
+ if (opts->load_unsafe_playlists) {
+ s->stream_origin = STREAM_ORIGIN_DIRECT;
+ } else if (sinfo->stream_origin) {
+ s->stream_origin = check_origin(s->stream_origin, sinfo->stream_origin);
+ }
+
+ if (!s->stream_origin) {
+ talloc_free(s);
+ return STREAM_UNSAFE;
+ }
+
int r = STREAM_UNSUPPORTED;
if (sinfo->open2) {
r = sinfo->open2(s, args);
@@ -429,14 +457,10 @@ struct stream *stream_create(const char *url, int flags,
return s;
}
-struct stream *stream_open(const char *filename, struct mpv_global *global)
-{
- return stream_create(filename, STREAM_READ, NULL, global);
-}
-
stream_t *open_output_stream(const char *filename, struct mpv_global *global)
{
- return stream_create(filename, STREAM_WRITE, NULL, global);
+ return stream_create(filename, STREAM_ORIGIN_DIRECT | STREAM_WRITE,
+ NULL, global);
}
// Read function bypassing the local stream buffer. This will not write into
@@ -787,7 +811,8 @@ struct bstr stream_read_file(const char *filename, void *talloc_ctx,
{
struct bstr res = {0};
char *fname = mp_get_user_path(NULL, global, filename);
- stream_t *s = stream_open(fname, global);
+ stream_t *s =
+ stream_create(fname, STREAM_ORIGIN_DIRECT | STREAM_READ, NULL, global);
if (s) {
res = stream_read_complete(s, talloc_ctx, max_size);
free_stream(s);
diff --git a/stream/stream.h b/stream/stream.h
index aa764818b7..c85aeffd73 100644
--- a/stream/stream.h
+++ b/stream/stream.h
@@ -32,14 +32,23 @@
// it's guaranteed that you can seek back by <= of this size again.
#define STREAM_BUFFER_SIZE 2048
+// flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE)
+
// stream->mode
-#define STREAM_READ 0
-#define STREAM_WRITE 1
+#define STREAM_READ 0
+#define STREAM_WRITE (1 << 0)
-// flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE)
-#define STREAM_SAFE_ONLY 4
-#define STREAM_NETWORK_ONLY 8
-#define STREAM_SILENT 16
+#define STREAM_SILENT (1 << 1)
+
+// Origin value for "security". This is an integer within the flags bit-field.
+#define STREAM_ORIGIN_DIRECT (1 << 2) // passed from cmdline or loadfile
+#define STREAM_ORIGIN_FS (2 << 2) // referenced from playlist on unix FS
+#define STREAM_ORIGIN_NET (3 << 2) // referenced from playlist on network
+#define STREAM_ORIGIN_UNSAFE (4 << 2) // from a grotesque source
+
+#define STREAM_ORIGIN_MASK (7 << 2) // for extracting origin value from flags
+
+// end flags for stream_open_ext (the naming convention sucks)
#define STREAM_UNSAFE -3
#define STREAM_NO_MATCH -2
@@ -100,8 +109,8 @@ typedef struct stream_info_st {
int (*open2)(struct stream *st, struct stream_open_args *args);
const char *const *protocols;
bool can_write; // correctly checks for READ/WRITE modes
- bool is_safe; // opening is no security issue, even with remote provided URLs
- bool is_network; // used to restrict remote playlist entries to remote URLs
+ int stream_origin; // 0 or set of STREAM_ORIGIN_*; if 0, the same origin
+ // is set, or the stream's open() function handles it
} stream_info_t;
typedef struct stream {
@@ -123,6 +132,7 @@ typedef struct stream {
int64_t pos;
int eof; // valid only after read calls that returned a short result
int mode; //STREAM_READ or STREAM_WRITE
+ int stream_origin; // any STREAM_ORIGIN_*
void *priv; // used for DVD, TV, RTSP etc
char *url; // filename/url (possibly including protocol prefix)
char *path; // filename (url without protocol prefix)
@@ -132,7 +142,7 @@ typedef struct stream {
bool streaming : 1; // known to be a network stream if true
bool seekable : 1; // presence of general byte seeking support
bool fast_skip : 1; // consider stream fast enough to fw-seek by skipping
- bool is_network : 1; // original stream_info_t.is_network flag
+ bool is_network : 1; // I really don't know what this is for
bool is_local_file : 1; // from the filesystem
bool is_directory : 1; // directory on the filesystem
bool access_references : 1; // open other streams
@@ -223,7 +233,6 @@ struct stream_open_args {
int stream_create_with_args(struct stream_open_args *args, struct stream **ret);
struct stream *stream_create(const char *url, int flags,
struct mp_cancel *c, struct mpv_global *global);
-struct stream *stream_open(const char *filename, struct mpv_global *global);
stream_t *open_output_stream(const char *filename, struct mpv_global *global);
void mp_url_unescape_inplace(char *buf);
diff --git a/stream/stream_avdevice.c b/stream/stream_avdevice.c
index 5185b7a844..3cfdfe1a53 100644
--- a/stream/stream_avdevice.c
+++ b/stream/stream_avdevice.c
@@ -30,4 +30,5 @@ const stream_info_t stream_info_avdevice = {
.name = "avdevice",
.open = open_f,
.protocols = (const char*const[]){ "avdevice", "av", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c
index 1d57730539..19e99a458b 100644
--- a/stream/stream_bluray.c
+++ b/stream/stream_bluray.c
@@ -512,12 +512,14 @@ const stream_info_t stream_info_bluray = {
.name = "bd",
.open = bluray_stream_open,
.protocols = (const char*const[]){ "bd", "br", "bluray", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
const stream_info_t stream_info_bdnav = {
.name = "bdnav",
.open = bluray_stream_open,
.protocols = (const char*const[]){ "bdnav", "brnav", "bluraynav", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
static bool check_bdmv(const char *path)
@@ -605,4 +607,5 @@ const stream_info_t stream_info_bdmv_dir = {
.name = "bdmv/bluray",
.open = bdmv_dir_stream_open,
.protocols = (const char*const[]){ "file", "", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
diff --git a/stream/stream_cb.c b/stream/stream_cb.c
index ba0b3e5da3..238dd1ac1c 100644
--- a/stream/stream_cb.c
+++ b/stream/stream_cb.c
@@ -106,4 +106,5 @@ static int open_cb(stream_t *stream)
const stream_info_t stream_info_cb = {
.name = "stream_callback",
.open = open_cb,
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
diff --git a/stream/stream_cdda.c b/stream/stream_cdda.c
index 158cfd0646..87be426992 100644
--- a/stream/stream_cdda.c
+++ b/stream/stream_cdda.c
@@ -401,4 +401,5 @@ const stream_info_t stream_info_cdda = {
.name = "cdda",
.open = open_cdda,
.protocols = (const char*const[]){"cdda", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
diff --git a/stream/stream_concat.c b/stream/stream_concat.c
index a10fee7912..060583a604 100644
--- a/stream/stream_concat.c
+++ b/stream/stream_concat.c
@@ -151,7 +151,7 @@ struct stream *stream_concat_open(struct mpv_global *global, struct mp_cancel *c
.global = global,
.cancel = c,
.url = "concat://",
- .flags = STREAM_READ | STREAM_SILENT,
+ .flags = STREAM_READ | STREAM_SILENT | STREAM_ORIGIN_DIRECT,
.sinfo = &stream_info_concat,
.special_arg = &arg,
};
diff --git a/stream/stream_dvb.c b/stream/stream_dvb.c
index d6907cb792..c14cce8420 100644
--- a/stream/stream_dvb.c
+++ b/stream/stream_dvb.c
@@ -1267,4 +1267,5 @@ const stream_info_t stream_info_dvb = {
.name = "dvbin",
.open = dvb_open,
.protocols = (const char *const[]){ "dvb", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c
index 619284f393..d858c51aca 100644
--- a/stream/stream_dvdnav.c
+++ b/stream/stream_dvdnav.c
@@ -575,7 +575,7 @@ static int open_s_internal(stream_t *stream)
if (!new_dvdnav_stream(stream, filename)) {
MP_ERR(stream, "Couldn't open DVD device: %s\n",
filename);
- return STREAM_UNSUPPORTED;
+ return STREAM_ERROR;
}
if (p->track == TITLE_LONGEST) { // longest
@@ -662,6 +662,7 @@ const stream_info_t stream_info_dvdnav = {
.name = "dvdnav",
.open = open_s,
.protocols = (const char*const[]){ "dvd", "dvdnav", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
static bool check_ifo(const char *path)
@@ -714,4 +715,5 @@ const stream_info_t stream_info_ifo_dvdnav = {
.name = "ifo_dvdnav",
.open = ifo_dvdnav_stream_open,
.protocols = (const char*const[]){ "file", "", NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
};
diff --git a/stream/stream_file.c b/stream/stream_file.c
index 1ad9a5c7f5..a79ef0e913 100644
--- a/stream/stream_file.c
+++ b/stream/stream_file.c
@@ -349,5 +349,5 @@ const stream_info_t stream_info_file = {
.protocols = (const char*const[]){ "file", "", "fd", "fdclose",
"appending", NULL },
.can_write = true,
- .is_safe = true,
+ .stream_origin = STREAM_ORIGIN_FS,
};
diff --git a/stream/stream_lavf.c b/stream/stream_lavf.c
index 604535c431..c20790a505 100644
--- a/stream/stream_lavf.c
+++ b/stream/stream_lavf.c
@@ -342,6 +342,8 @@ static int open_f(stream_t *stream)
stream->close = close_f;
// enable cache (should be avoided for files, but no way to detect this)
stream->streaming = true;
+ if (stream->info->stream_origin == STREAM_ORIGIN_NET)
+ stream->is_network = true;
res = STREAM_OK;
out:
@@ -418,8 +420,7 @@ const stream_info_t stream_info_ffmpeg = {
"gopher", "data",
NULL },
.can_write = true,
- .is_safe = true,
- .is_network = true,
+ .stream_origin = STREAM_ORIGIN_NET,
};
// Unlike above, this is not marked as safe, and can contain protocols which
@@ -433,6 +434,7 @@ const stream_info_t stream_info_ffmpeg_unsafe = {
"lavf", "ffmpeg", "udp", "ftp", "tcp", "tls", "unix", "sftp", "md5",
"concat",
NULL },
+ .stream_origin = STREAM_ORIGIN_UNSAFE,
.can_write = true,
};
diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c
index 2e300f3747..76b47e1633 100644
--- a/stream/stream_libarchive.c
+++ b/stream/stream_libarchive.c
@@ -93,7 +93,9 @@ static int open_cb(struct archive *arch, void *priv)
struct mp_archive_volume *vol = priv;
vol->seek_to = -1;
if (!vol->src) {
- vol->src = stream_create(vol->url, STREAM_READ,
+ vol->src = stream_create(vol->url,
+ STREAM_READ |
+ vol->mpa->primary_src->stream_origin,
vol->mpa->primary_src->cancel,
vol->mpa->primary_src->global);
return vol->src ? ARCHIVE_OK : ARCHIVE_FATAL;
@@ -207,7 +209,9 @@ static char **find_volumes(struct stream *primary_stream)
struct bstr base = bstr_splice(primary_url, 0, -strlen(pattern->match));
for (int i = pattern->start; i <= pattern->stop; i++) {
char* url = pattern->volume_url(res, pattern->format, base, i);
- struct stream *s = stream_create(url, STREAM_READ | STREAM_SAFE_ONLY,
+ struct stream *s = stream_create(url,
+ STREAM_READ |
+ primary_stream->stream_origin,
primary_stream->cancel,
primary_stream->global);
if (!s) {
@@ -490,7 +494,7 @@ static int archive_entry_open(stream_t *stream)
p->entry_name = name + 1;
mp_url_unescape_inplace(base);
- p->src = stream_create(base, STREAM_READ | STREAM_SAFE_ONLY,
+ p->src = stream_create(base, STREAM_READ | stream->stream_origin,
stream->cancel, stream->global);
if (!p->src) {
archive_entry_close(stream);
diff --git a/stream/stream_memory.c b/stream/stream_memory.c
index 7b1092a76d..01246cf33f 100644
--- a/stream/stream_memory.c
+++ b/stream/stream_memory.c
@@ -86,7 +86,7 @@ struct stream *stream_memory_open(struct mpv_global *global, void *data, int len
struct stream_open_args sargs = {
.global = global,
.url = "memory://",
- .flags = STREAM_READ | STREAM_SILENT,
+ .flags = STREAM_READ | STREAM_SILENT | STREAM_ORIGIN_DIRECT,
.sinfo = &stream_info_memory,
.special_arg = &(bstr){data, len},
};
diff --git a/stream/stream_smb.c b/stream/stream_smb.c
index 33928d4e61..1e52b55a37 100644
--- a/stream/stream_smb.c
+++ b/stream/stream_smb.c
@@ -151,4 +151,5 @@ const stream_info_t stream_info_smb = {
.open = open_f,
.protocols = (const char*const[]){"smb", NULL},
.can_write = true, //who's gonna do that?
+ .stream_origin = STREAM_ORIGIN_FS,
};