]> git.proxmox.com Git - pve-cluster.git/commitdiff
pmxcfs: add verify_token IPC request
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Tue, 21 Jan 2020 12:53:57 +0000 (13:53 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 27 Jan 2020 16:45:07 +0000 (17:45 +0100)
Add a new IPC request which takes a token string and matches it with
the priv/token.cfg shadow file, this allows non-root processes with
the privilege of doing IPC requests, to verify tokens without being
able to read the full token list itself.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
[ Thomas: solved merge conflict in observer files struct ]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
data/PVE/Cluster.pm
data/src/cfs-ipc-ops.h
data/src/server.c
data/src/status.c

index 414e0278adb79967c42cd2b4934e154f5de47bde..068d626facb7e0fdf15c4b8fb06de57a1e080374 100644 (file)
@@ -53,6 +53,7 @@ my $observed = {
     'domains.cfg' => 1,
     'priv/shadow.cfg' => 1,
     'priv/tfa.cfg' => 1,
+    'priv/token.cfg' => 1,
     '/qemu-server/' => 1,
     '/openvz/' => 1,
     '/lxc/' => 1,
@@ -187,6 +188,18 @@ my $ipcc_get_cluster_log = sub {
     return &$ipcc_send_rec(CFS_IPC_GET_CLUSTER_LOG, $bindata);
 };
 
+my $ipcc_verify_token = sub {
+    my ($full_token) = @_;
+
+    my $bindata = pack "Z*", $full_token;
+    my $res = PVE::IPCC::ipcc_send_rec(CFS_IPC_VERIFY_TOKEN, $bindata);
+
+    return 1 if $! == 0;
+    return 0 if $! == ENOENT;
+
+    die "$!\n";
+};
+
 my $ccache = {};
 
 sub cfs_update {
@@ -447,6 +460,12 @@ sub get_cluster_log {
     return &$ipcc_get_cluster_log($user, $max);
 }
 
+sub verify_token {
+    my ($userid, $token) = @_;
+
+    return &$ipcc_verify_token("$userid $token");
+}
+
 my $file_info = {};
 
 sub cfs_register_file {
index e4026ad7c195a29747f405396cda82037ea5324a..9d788bc12af7c3bbe214c89bfe77e71feaf7937b 100644 (file)
@@ -41,4 +41,6 @@
 
 #define CFS_IPC_GET_GUEST_CONFIG_PROPERTY 11
 
+#define CFS_IPC_VERIFY_TOKEN 12
+
 #endif
index 36acc1d0763a42f961639bd6bed9af47b1e9f0ba..8519001d4bd2c6bb2c255be91c94bb2604c009e2 100644 (file)
@@ -89,6 +89,11 @@ typedef struct {
        char property[];
 } cfs_guest_config_propery_get_request_header_t;
 
+typedef struct {
+       struct qb_ipc_request_header req_header;
+       char token[];
+} cfs_verify_token_request_header_t;
+
 struct s1_context {
        int32_t client_pid;
        uid_t uid;
@@ -343,6 +348,56 @@ static int32_t s1_msg_process_fn(
 
                        result = cfs_create_guest_conf_property_msg(outbuf, memdb, rh->property, rh->vmid);
                }
+       } else if (request_id == CFS_IPC_VERIFY_TOKEN) {
+
+               cfs_verify_token_request_header_t *rh = (cfs_verify_token_request_header_t *) data;
+               int tokenlen = request_size - G_STRUCT_OFFSET(cfs_verify_token_request_header_t, token) - 1;
+
+               if (tokenlen <= 0) {
+                       cfs_debug("tokenlen <= 0, %d", tokenlen);
+                       result = -EINVAL;
+               } else if (memchr(rh->token, '\n', tokenlen) != NULL) {
+                       cfs_debug("token contains newline");
+                       result = -EINVAL;
+               } else if (rh->token[tokenlen] != '\0') {
+                       cfs_debug("token not NULL-terminated");
+                       result = -EINVAL;
+               } else if (strnlen(rh->token, tokenlen) != tokenlen) {
+                       cfs_debug("token contains NULL-byte");
+                       result = -EINVAL;
+               } else {
+                       cfs_debug("cfs_verify_token: basic validity checked, reading token.cfg");
+                       gpointer tmp = NULL;
+                       int bytes_read = memdb_read(memdb, "priv/token.cfg", &tmp);
+                       size_t remaining = bytes_read > 0 ? bytes_read : 0;
+                       if (tmp != NULL && remaining >= tokenlen) {
+                               char *line = (char *) tmp;
+                               char *next_line;
+                               const char *const end = line + remaining;
+                               size_t linelen;
+
+                               while (line != NULL) {
+                                       next_line = memchr(line, '\n', remaining);
+                                       linelen = next_line == NULL ? remaining : next_line - line;
+                                       if (linelen == tokenlen && strncmp(line, rh->token, linelen) == 0) {
+                                               result = 0;
+                                               break;
+                                       }
+                                       line = next_line;
+                                       if (line != NULL) {
+                                               line += 1;
+                                               remaining = end - line;
+                                       }
+                               }
+                               if (line == NULL) {
+                                       result = -ENOENT;
+                               }
+                               g_free(tmp);
+                       } else {
+                               cfs_debug("token: token.cfg does not exist - ENOENT");
+                               result = -ENOENT;
+                       }
+               }
        }
 
        cfs_debug("process result %d", result);
index 811d978756cec9c48a7e5908fc8c3ff634467225..5e0cebea4a23a1e70c76ee8372a6a701fdd337bb 100644 (file)
@@ -84,6 +84,7 @@ static memdb_change_t memdb_change_array[] = {
        { .path = "domains.cfg" },
        { .path = "priv/shadow.cfg" },
        { .path = "priv/tfa.cfg" },
+       { .path = "priv/token.cfg" },
        { .path = "datacenter.cfg" },
        { .path = "vzdump.cron" },
        { .path = "ha/crm_commands" },