Separate kiosk mode from restrict mode
Restrict mode will focus on sandboxing, while kiosk will continue to restrict IRC access through a public kiosk. Kiosk mode without restrict mode allows execution of man 1 catgirl with /help, assuming external sandboxing. The /list and /part commands are also added to the list of disabled commands in kiosk mode, since they are pointless without access to /join.master
parent
6ee0aea9e5
commit
95bb627ffb
39
catgirl.1
39
catgirl.1
|
@ -1,4 +1,4 @@
|
||||||
.Dd January 16, 2021
|
.Dd January 22, 2021
|
||||||
.Dt CATGIRL 1
|
.Dt CATGIRL 1
|
||||||
.Os
|
.Os
|
||||||
.
|
.
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
.
|
.
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl Relv
|
.Op Fl KRelv
|
||||||
.Op Fl C Ar copy
|
.Op Fl C Ar copy
|
||||||
.Op Fl H Ar hash
|
.Op Fl H Ar hash
|
||||||
.Op Fl I Ar highlight
|
.Op Fl I Ar highlight
|
||||||
|
@ -123,6 +123,20 @@ The commands which can be filtered are:
|
||||||
.Sy QUIT ,
|
.Sy QUIT ,
|
||||||
.Sy SETNAME .
|
.Sy SETNAME .
|
||||||
.
|
.
|
||||||
|
.It Fl K , Cm kiosk
|
||||||
|
Disable the
|
||||||
|
.Ic /copy ,
|
||||||
|
.Ic /debug ,
|
||||||
|
.Ic /exec ,
|
||||||
|
.Ic /join ,
|
||||||
|
.Ic /list ,
|
||||||
|
.Ic /msg ,
|
||||||
|
.Ic /open ,
|
||||||
|
.Ic /part ,
|
||||||
|
.Ic /query ,
|
||||||
|
.Ic /quote
|
||||||
|
commands.
|
||||||
|
.
|
||||||
.It Fl N Ar util , Cm notify = Ar util
|
.It Fl N Ar util , Cm notify = Ar util
|
||||||
Send notifications using a utility.
|
Send notifications using a utility.
|
||||||
Use more than once to add arguments to
|
Use more than once to add arguments to
|
||||||
|
@ -145,14 +159,19 @@ The default is the first available of
|
||||||
.It Fl R , Cm restrict
|
.It Fl R , Cm restrict
|
||||||
Disable the
|
Disable the
|
||||||
.Ic /copy ,
|
.Ic /copy ,
|
||||||
.Ic /debug ,
|
.Ic /exec
|
||||||
.Ic /exec ,
|
and
|
||||||
.Ic /join ,
|
.Ic /open
|
||||||
.Ic /msg ,
|
commands,
|
||||||
.Ic /open ,
|
as well as viewing this manual with
|
||||||
.Ic /query ,
|
.Ic /help .
|
||||||
.Ic /quote
|
On
|
||||||
commands.
|
.Ox ,
|
||||||
|
restrict system operations
|
||||||
|
and filesystem access with
|
||||||
|
.Xr pledge 2
|
||||||
|
and
|
||||||
|
.Xr unveil 2 .
|
||||||
.
|
.
|
||||||
.It Fl S Ar host , Cm bind = Ar host
|
.It Fl S Ar host , Cm bind = Ar host
|
||||||
Bind to source address
|
Bind to source address
|
||||||
|
|
8
chat.c
8
chat.c
|
@ -159,7 +159,6 @@ static void sandbox(const char *trust, const char *cert, const char *priv) {
|
||||||
const char *path;
|
const char *path;
|
||||||
const char *perm;
|
const char *perm;
|
||||||
} paths[] = {
|
} paths[] = {
|
||||||
{ "/usr/bin/man", "x" },
|
|
||||||
{ "/usr/share/terminfo", "r" },
|
{ "/usr/share/terminfo", "r" },
|
||||||
{ tls_default_ca_cert_file(), "r" },
|
{ tls_default_ca_cert_file(), "r" },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
|
@ -200,6 +199,7 @@ int main(int argc, char *argv[]) {
|
||||||
{ .val = 'C', .name = "copy", required_argument },
|
{ .val = 'C', .name = "copy", required_argument },
|
||||||
{ .val = 'H', .name = "hash", required_argument },
|
{ .val = 'H', .name = "hash", required_argument },
|
||||||
{ .val = 'I', .name = "highlight", required_argument },
|
{ .val = 'I', .name = "highlight", required_argument },
|
||||||
|
{ .val = 'K', .name = "kiosk", no_argument },
|
||||||
{ .val = 'N', .name = "notify", required_argument },
|
{ .val = 'N', .name = "notify", required_argument },
|
||||||
{ .val = 'O', .name = "open", required_argument },
|
{ .val = 'O', .name = "open", required_argument },
|
||||||
{ .val = 'R', .name = "restrict", no_argument },
|
{ .val = 'R', .name = "restrict", no_argument },
|
||||||
|
@ -236,6 +236,7 @@ int main(int argc, char *argv[]) {
|
||||||
break; case 'C': utilPush(&urlCopyUtil, optarg);
|
break; case 'C': utilPush(&urlCopyUtil, optarg);
|
||||||
break; case 'H': parseHash(optarg);
|
break; case 'H': parseHash(optarg);
|
||||||
break; case 'I': filterAdd(Hot, optarg);
|
break; case 'I': filterAdd(Hot, optarg);
|
||||||
|
break; case 'K': self.kiosk = true;
|
||||||
break; case 'N': utilPush(&uiNotifyUtil, optarg);
|
break; case 'N': utilPush(&uiNotifyUtil, optarg);
|
||||||
break; case 'O': utilPush(&urlOpenUtil, optarg);
|
break; case 'O': utilPush(&urlOpenUtil, optarg);
|
||||||
break; case 'R': self.restricted = true;
|
break; case 'R': self.restricted = true;
|
||||||
|
@ -325,7 +326,8 @@ int main(int argc, char *argv[]) {
|
||||||
sig_t cursesWinch = signal(SIGWINCH, signalHandler);
|
sig_t cursesWinch = signal(SIGWINCH, signalHandler);
|
||||||
|
|
||||||
fcntl(irc, F_SETFD, FD_CLOEXEC);
|
fcntl(irc, F_SETFD, FD_CLOEXEC);
|
||||||
if (!self.restricted) {
|
bool pipes = !self.kiosk && !self.restricted;
|
||||||
|
if (pipes) {
|
||||||
int error = pipe(utilPipe);
|
int error = pipe(utilPipe);
|
||||||
if (error) err(EX_OSERR, "pipe");
|
if (error) err(EX_OSERR, "pipe");
|
||||||
|
|
||||||
|
@ -345,7 +347,7 @@ int main(int argc, char *argv[]) {
|
||||||
{ .events = POLLIN, .fd = execPipe[0] },
|
{ .events = POLLIN, .fd = execPipe[0] },
|
||||||
};
|
};
|
||||||
while (!self.quit) {
|
while (!self.quit) {
|
||||||
int nfds = poll(fds, (self.restricted ? 2 : ARRAY_LEN(fds)), -1);
|
int nfds = poll(fds, (pipes ? ARRAY_LEN(fds) : 2), -1);
|
||||||
if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll");
|
if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll");
|
||||||
if (nfds > 0) {
|
if (nfds > 0) {
|
||||||
if (fds[0].revents) uiRead();
|
if (fds[0].revents) uiRead();
|
||||||
|
|
1
chat.h
1
chat.h
|
@ -183,6 +183,7 @@ enum Cap {
|
||||||
|
|
||||||
extern struct Self {
|
extern struct Self {
|
||||||
bool debug;
|
bool debug;
|
||||||
|
bool kiosk;
|
||||||
bool restricted;
|
bool restricted;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
enum Cap caps;
|
enum Cap caps;
|
||||||
|
|
38
command.c
38
command.c
|
@ -457,6 +457,10 @@ static void commandHelp(uint id, char *params) {
|
||||||
replies[ReplyHelp]++;
|
replies[ReplyHelp]++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (self.restricted) {
|
||||||
|
uiFormat(id, Warm, NULL, "See catgirl(1) or /help index");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uiHide();
|
uiHide();
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
@ -474,7 +478,8 @@ static void commandHelp(uint id, char *params) {
|
||||||
|
|
||||||
enum Flag {
|
enum Flag {
|
||||||
BIT(Multiline),
|
BIT(Multiline),
|
||||||
BIT(Restricted),
|
BIT(Restrict),
|
||||||
|
BIT(Kiosk),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct Handler {
|
static const struct Handler {
|
||||||
|
@ -485,37 +490,37 @@ static const struct Handler {
|
||||||
{ "/away", commandAway, 0 },
|
{ "/away", commandAway, 0 },
|
||||||
{ "/ban", commandBan, 0 },
|
{ "/ban", commandBan, 0 },
|
||||||
{ "/close", commandClose, 0 },
|
{ "/close", commandClose, 0 },
|
||||||
{ "/copy", commandCopy, Restricted },
|
{ "/copy", commandCopy, Restrict | Kiosk },
|
||||||
{ "/cs", commandCS, 0 },
|
{ "/cs", commandCS, 0 },
|
||||||
{ "/debug", commandDebug, Restricted },
|
{ "/debug", commandDebug, Kiosk },
|
||||||
{ "/deop", commandDeop, 0 },
|
{ "/deop", commandDeop, 0 },
|
||||||
{ "/devoice", commandDevoice, 0 },
|
{ "/devoice", commandDevoice, 0 },
|
||||||
{ "/except", commandExcept, 0 },
|
{ "/except", commandExcept, 0 },
|
||||||
{ "/exec", commandExec, Multiline | Restricted },
|
{ "/exec", commandExec, Multiline | Restrict },
|
||||||
{ "/help", commandHelp, 0 },
|
{ "/help", commandHelp, 0 }, // Restrict special case.
|
||||||
{ "/highlight", commandHighlight, 0 },
|
{ "/highlight", commandHighlight, 0 },
|
||||||
{ "/ignore", commandIgnore, 0 },
|
{ "/ignore", commandIgnore, 0 },
|
||||||
{ "/invex", commandInvex, 0 },
|
{ "/invex", commandInvex, 0 },
|
||||||
{ "/invite", commandInvite, 0 },
|
{ "/invite", commandInvite, 0 },
|
||||||
{ "/join", commandJoin, Restricted },
|
{ "/join", commandJoin, Kiosk },
|
||||||
{ "/kick", commandKick, 0 },
|
{ "/kick", commandKick, 0 },
|
||||||
{ "/list", commandList, 0 },
|
{ "/list", commandList, Kiosk },
|
||||||
{ "/me", commandMe, 0 },
|
{ "/me", commandMe, 0 },
|
||||||
{ "/mode", commandMode, 0 },
|
{ "/mode", commandMode, 0 },
|
||||||
{ "/move", commandMove, 0 },
|
{ "/move", commandMove, 0 },
|
||||||
{ "/msg", commandMsg, Multiline | Restricted },
|
{ "/msg", commandMsg, Multiline | Kiosk },
|
||||||
{ "/names", commandNames, 0 },
|
{ "/names", commandNames, 0 },
|
||||||
{ "/nick", commandNick, 0 },
|
{ "/nick", commandNick, 0 },
|
||||||
{ "/notice", commandNotice, Multiline },
|
{ "/notice", commandNotice, Multiline },
|
||||||
{ "/ns", commandNS, 0 },
|
{ "/ns", commandNS, 0 },
|
||||||
{ "/o", commandOpen, Restricted },
|
{ "/o", commandOpen, Restrict | Kiosk },
|
||||||
{ "/op", commandOp, 0 },
|
{ "/op", commandOp, 0 },
|
||||||
{ "/open", commandOpen, Restricted },
|
{ "/open", commandOpen, Restrict | Kiosk },
|
||||||
{ "/ops", commandOps, 0 },
|
{ "/ops", commandOps, 0 },
|
||||||
{ "/part", commandPart, 0 },
|
{ "/part", commandPart, Kiosk },
|
||||||
{ "/query", commandQuery, Restricted },
|
{ "/query", commandQuery, Kiosk },
|
||||||
{ "/quit", commandQuit, 0 },
|
{ "/quit", commandQuit, 0 },
|
||||||
{ "/quote", commandQuote, Multiline | Restricted },
|
{ "/quote", commandQuote, Multiline | Kiosk },
|
||||||
{ "/say", commandPrivmsg, Multiline },
|
{ "/say", commandPrivmsg, Multiline },
|
||||||
{ "/setname", commandSetname, 0 },
|
{ "/setname", commandSetname, 0 },
|
||||||
{ "/topic", commandTopic, 0 },
|
{ "/topic", commandTopic, 0 },
|
||||||
|
@ -584,8 +589,11 @@ void command(uint id, char *input) {
|
||||||
uiFormat(id, Warm, NULL, "No such command %s", cmd);
|
uiFormat(id, Warm, NULL, "No such command %s", cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (self.restricted && handler->flags & Restricted) {
|
if (
|
||||||
uiFormat(id, Warm, NULL, "Command %s is restricted", cmd);
|
(self.restricted && handler->flags & Restrict) ||
|
||||||
|
(self.kiosk && handler->flags & Kiosk)
|
||||||
|
) {
|
||||||
|
uiFormat(id, Warm, NULL, "Command %s is unavailable", cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue