aboutsummaryrefslogtreecommitdiff
path: root/clients
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-17 21:48:00 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-17 21:48:00 +0200
commit071b7e9b01e41d4048b1bbb3d9caaac4c8a526de (patch)
treeb0af0a71e0d9fff2ca166d6ca69167ff32cc2ccb /clients
parenta145684f0a556820a183db45d27e9b2dc715f056 (diff)
downloadbokf-071b7e9b01e41d4048b1bbb3d9caaac4c8a526de.tar.gz
bokf-071b7e9b01e41d4048b1bbb3d9caaac4c8a526de.zip
Add token login to bokfctl and enforce admin scope for tokensv0.1.3
- bokfctl: --token / BOKFD_TOKEN via client_token_login - tokens must carry the admin scope for admin commands (was bypassed) - docs: token-based snapshot for restic backups
Diffstat (limited to 'clients')
-rw-r--r--clients/bokfctl.c23
-rw-r--r--clients/client.c49
-rw-r--r--clients/client.h4
3 files changed, 64 insertions, 12 deletions
diff --git a/clients/bokfctl.c b/clients/bokfctl.c
index 1f1372c..b5ecf47 100644
--- a/clients/bokfctl.c
+++ b/clients/bokfctl.c
@@ -17,6 +17,7 @@ static void usage(void)
" (env BOKFD_SOCKET, default /run/bokfd/bokfd.sock)\n"
" --user NAME login user (env BOKFD_USER)\n"
" --password PW login password (env BOKFD_PASSWORD)\n"
+ " --token TOKEN API token instead of user/password (env BOKFD_TOKEN)\n"
" --org ID active org for this request\n"
" --version\n"
"\n"
@@ -39,6 +40,7 @@ int main(int argc, char **argv)
target = "/run/bokfd/bokfd.sock";
const char *user = getenv("BOKFD_USER");
const char *password = getenv("BOKFD_PASSWORD");
+ const char *token = getenv("BOKFD_TOKEN");
int64_t org = 0;
const char *cmd = NULL;
const char *args_json = NULL;
@@ -70,6 +72,14 @@ int main(int argc, char **argv)
return 2;
}
password = val;
+ } else if (!strncmp(a, "--token", 7) &&
+ (a[7] == '\0' || a[7] == '=')) {
+ val = a[7] == '=' ? a + 8 : (i + 1 < argc ? argv[++i] : NULL);
+ if (!val) {
+ fprintf(stderr, "bokfctl: --token requires a value\n");
+ return 2;
+ }
+ token = val;
} else if (!strncmp(a, "--org", 5) &&
(a[5] == '\0' || a[5] == '=')) {
val = a[5] == '=' ? a + 6 : (i + 1 < argc ? argv[++i] : NULL);
@@ -111,14 +121,19 @@ int main(int argc, char **argv)
char *session = NULL;
if (!is_local_cmd(cmd)) {
- if (!user || !password) {
+ char *lerr = NULL;
+ int login_rc;
+ if (token && *token) {
+ login_rc = client_token_login(&conn, token, &session, &lerr);
+ } else if (user && password) {
+ login_rc = client_login(&conn, user, password, &session, &lerr);
+ } else {
fprintf(stderr,
- "bokfctl: set BOKFD_USER and BOKFD_PASSWORD (or --user/--password) to log in\n");
+ "bokfctl: set BOKFD_TOKEN or BOKFD_USER/BOKFD_PASSWORD (or --token/--user/--password) to log in\n");
client_close(&conn);
return 2;
}
- char *lerr = NULL;
- if (client_login(&conn, user, password, &session, &lerr) != 0) {
+ if (login_rc != 0) {
fprintf(stderr, "%s\n", lerr ? lerr : "login failed");
int rc = lerr && lerr[0] == '{' ? 1 : 2;
free(lerr);
diff --git a/clients/client.c b/clients/client.c
index 8fb604b..fd119f1 100644
--- a/clients/client.c
+++ b/clients/client.c
@@ -361,18 +361,12 @@ char *client_rpc(struct client_conn *c, const char *cmd, const char *session,
return client_read_line(c);
}
-int client_login(struct client_conn *c, const char *user, const char *password,
- char **session_out, char **err_out)
+static int session_open(struct client_conn *c, const char *args,
+ char **session_out, char **err_out)
{
*session_out = NULL;
*err_out = NULL;
- char *args = client_make_login_args(user, password);
- if (!args) {
- *err_out = xstrdup("could not build login request");
- return -1;
- }
char *resp = client_rpc(c, "session.open", NULL, 0, args);
- free(args);
if (!resp) {
*err_out = xstrdup(client_last_error());
return -1;
@@ -396,6 +390,45 @@ int client_login(struct client_conn *c, const char *user, const char *password,
return 0;
}
+int client_login(struct client_conn *c, const char *user, const char *password,
+ char **session_out, char **err_out)
+{
+ char *args = client_make_login_args(user, password);
+ if (!args) {
+ *session_out = NULL;
+ *err_out = xstrdup("could not build login request");
+ return -1;
+ }
+ int rc = session_open(c, args, session_out, err_out);
+ free(args);
+ return rc;
+}
+
+int client_token_login(struct client_conn *c, const char *token,
+ char **session_out, char **err_out)
+{
+ yyjson_mut_doc *d = yyjson_mut_doc_new(NULL);
+ if (!d) {
+ *session_out = NULL;
+ *err_out = xstrdup("out of memory");
+ return -1;
+ }
+ yyjson_mut_val *o = yyjson_mut_obj(d);
+ yyjson_mut_doc_set_root(d, o);
+ yyjson_mut_obj_add_strcpy(d, o, "method", "token");
+ yyjson_mut_obj_add_strcpy(d, o, "token", token);
+ char *args = yyjson_mut_write(d, 0, NULL);
+ yyjson_mut_doc_free(d);
+ if (!args) {
+ *session_out = NULL;
+ *err_out = xstrdup("could not build token request");
+ return -1;
+ }
+ int rc = session_open(c, args, session_out, err_out);
+ free(args);
+ return rc;
+}
+
int client_ok(const char *response)
{
if (!response)
diff --git a/clients/client.h b/clients/client.h
index 9372e72..40a8669 100644
--- a/clients/client.h
+++ b/clients/client.h
@@ -36,6 +36,10 @@ char *client_rpc(struct client_conn *c, const char *cmd, const char *session,
int client_login(struct client_conn *c, const char *user, const char *password,
char **session_out, char **err_out);
+/* Token login (same contract as client_login). */
+int client_token_login(struct client_conn *c, const char *token,
+ char **session_out, char **err_out);
+
/* Convenience: true when the response line has "ok":true. */
int client_ok(const char *response);
/* Extract result.session into buf; returns 0 on success. */