Merge branch 'osc52-clear-selection-on-invalid-payload' into master

This commit is contained in:
Daniel Eklöf 2020-09-10 07:36:19 +02:00
commit fc510d423b
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
4 changed files with 109 additions and 31 deletions

View file

@ -112,6 +112,8 @@
* Handling of multi-column composed characters while reflowing.
* Escape sequences sent for key combinations with `Return`, that did
**not** include `Alt`.
* Clipboard (or primary selection) is now cleared when receiving an
OSC-52 command with an invalid base64 encoded payload.
### Security

79
osc.c
View file

@ -23,17 +23,6 @@ static void
osc_to_clipboard(struct terminal *term, const char *target,
const char *base64_data)
{
char *decoded = base64_decode(base64_data);
if (decoded == NULL) {
if (errno == EINVAL)
LOG_WARN("OSC: invalid clipboard data: %s", base64_data);
else
LOG_ERRNO("base64_decode() failed");
return;
}
LOG_DBG("decoded: %s", decoded);
bool to_clipboard = false;
bool to_primary = false;
@ -71,6 +60,22 @@ osc_to_clipboard(struct terminal *term, const char *target,
return;
}
char *decoded = base64_decode(base64_data);
if (decoded == NULL) {
if (errno == EINVAL)
LOG_WARN("OSC: invalid clipboard data: %s", base64_data);
else
LOG_ERRNO("base64_decode() failed");
if (to_clipboard)
selection_clipboard_unset(seat);
if (to_primary)
selection_primary_unset(seat);
return;
}
LOG_DBG("decoded: %s", decoded);
if (to_clipboard) {
char *copy = xstrdup(decoded);
if (!text_to_clipboard(seat, term, copy, seat->kbd.serial))
@ -157,20 +162,6 @@ from_clipboard_done(void *user)
static void
osc_from_clipboard(struct terminal *term, const char *source)
{
/* Use clipboard if no source has been specified */
char src = source[0] == '\0' ? 'c' : 0;
for (const char *s = source; *s != '\0'; s++) {
if (*s == 'c' || *s == 'p' || *s == 's') {
src = *s;
break;
} else
LOG_WARN("unimplemented: clipboard source '%c'", *s);
}
if (src == 0)
return;
/* Find a seat in which the terminal has focus */
struct seat *seat = NULL;
tll_foreach(term->wl->seats, it) {
@ -185,6 +176,35 @@ osc_from_clipboard(struct terminal *term, const char *source)
return;
}
/* Use clipboard if no source has been specified */
char src = source[0] == '\0' ? 'c' : 0;
bool from_clipboard = src == 'c';
bool from_primary = false;
for (const char *s = source;
*s != '\0' && !from_clipboard && !from_primary;
s++)
{
if (*s == 'c' || *s == 'p' || *s == 's') {
src = *s;
switch (src) {
case 'c':
from_clipboard = selection_clipboard_has_data(seat);
break;
case 's':
case 'p':
from_primary = selection_primary_has_data(seat);
break;
}
} else
LOG_WARN("unimplemented: clipboard source '%c'", *s);
}
if (!from_clipboard && !from_primary)
return;
term_to_slave(term, "\033]52;", 5);
term_to_slave(term, &src, 1);
term_to_slave(term, ";", 1);
@ -192,17 +212,14 @@ osc_from_clipboard(struct terminal *term, const char *source)
struct clip_context *ctx = xmalloc(sizeof(*ctx));
*ctx = (struct clip_context) {.seat = seat, .term = term};
switch (src) {
case 'c':
if (from_clipboard) {
text_from_clipboard(
seat, term, &from_clipboard_cb, &from_clipboard_done, ctx);
break;
}
case 's':
case 'p':
if (from_primary) {
text_from_primary(
seat, term, &from_clipboard_cb, &from_clipboard_done, ctx);
break;
}
}

View file

@ -661,6 +661,59 @@ selection_cancel(struct terminal *term)
term->selection.ongoing = false;
}
bool
selection_clipboard_has_data(const struct seat *seat)
{
return seat->clipboard.data_offer != NULL;
}
bool
selection_primary_has_data(const struct seat *seat)
{
return seat->primary.data_offer != NULL;
}
void
selection_clipboard_unset(struct seat *seat)
{
struct wl_clipboard *clipboard = &seat->clipboard;
if (clipboard->data_source == NULL)
return;
/* Kill previous data source */
assert(clipboard->serial != 0);
wl_data_device_set_selection(seat->data_device, NULL, clipboard->serial);
wl_data_source_destroy(clipboard->data_source);
clipboard->data_source = NULL;
clipboard->serial = 0;
free(clipboard->text);
clipboard->text = NULL;
}
void
selection_primary_unset(struct seat *seat)
{
struct wl_primary *primary = &seat->primary;
if (primary->data_source == NULL)
return;
assert(primary->serial != 0);
zwp_primary_selection_device_v1_set_selection(
seat->primary_selection_device, NULL, primary->serial);
zwp_primary_selection_source_v1_destroy(primary->data_source);
free(primary->text);
primary->data_source = NULL;
primary->serial = 0;
free(primary->text);
primary->text = NULL;
}
void
selection_mark_word(struct seat *seat, struct terminal *term, int col, int row,
bool spaces_only, uint32_t serial)

View file

@ -30,6 +30,12 @@ void selection_mark_word(
void selection_mark_row(
struct seat *seat, struct terminal *term, int row, uint32_t serial);
void selection_clipboard_unset(struct seat *seat);
void selection_primary_unset(struct seat *seat);
bool selection_clipboard_has_data(const struct seat *seat);
bool selection_primary_has_data(const struct seat *seat);
char *selection_to_text(const struct terminal *term);
void selection_to_clipboard(
struct seat *seat, struct terminal *term, uint32_t serial);