1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2025 Didi Technology Co., Tao Chen */ 3 4 #ifndef _GNU_SOURCE 5 #define _GNU_SOURCE 6 #endif 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <stdbool.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <mntent.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 18 #include "json_writer.h" 19 #include "main.h" 20 21 #define MOUNTS_FILE "/proc/mounts" 22 23 static bool has_delegate_options(const char *mnt_ops) 24 { 25 return strstr(mnt_ops, "delegate_cmds") || 26 strstr(mnt_ops, "delegate_maps") || 27 strstr(mnt_ops, "delegate_progs") || 28 strstr(mnt_ops, "delegate_attachs"); 29 } 30 31 static char *get_delegate_value(const char *opts, const char *key) 32 { 33 char *token, *rest, *ret = NULL; 34 char *opts_copy = strdup(opts); 35 36 if (!opts_copy) 37 return NULL; 38 39 for (token = strtok_r(opts_copy, ",", &rest); token; 40 token = strtok_r(NULL, ",", &rest)) { 41 if (strncmp(token, key, strlen(key)) == 0 && 42 token[strlen(key)] == '=') { 43 ret = token + strlen(key) + 1; 44 break; 45 } 46 } 47 free(opts_copy); 48 49 return ret; 50 } 51 52 static void print_items_per_line(const char *input, int items_per_line) 53 { 54 char *str, *rest, *strs; 55 int cnt = 0; 56 57 if (!input) 58 return; 59 60 strs = strdup(input); 61 if (!strs) 62 return; 63 64 for (str = strtok_r(strs, ":", &rest); str; 65 str = strtok_r(NULL, ":", &rest)) { 66 if (cnt % items_per_line == 0) 67 printf("\n\t "); 68 69 printf("%-20s", str); 70 cnt++; 71 } 72 73 free(strs); 74 } 75 76 #define ITEMS_PER_LINE 4 77 static void show_token_info_plain(struct mntent *mntent) 78 { 79 char *value; 80 81 printf("token_info %s", mntent->mnt_dir); 82 83 printf("\n\tallowed_cmds:"); 84 value = get_delegate_value(mntent->mnt_opts, "delegate_cmds"); 85 print_items_per_line(value, ITEMS_PER_LINE); 86 87 printf("\n\tallowed_maps:"); 88 value = get_delegate_value(mntent->mnt_opts, "delegate_maps"); 89 print_items_per_line(value, ITEMS_PER_LINE); 90 91 printf("\n\tallowed_progs:"); 92 value = get_delegate_value(mntent->mnt_opts, "delegate_progs"); 93 print_items_per_line(value, ITEMS_PER_LINE); 94 95 printf("\n\tallowed_attachs:"); 96 value = get_delegate_value(mntent->mnt_opts, "delegate_attachs"); 97 print_items_per_line(value, ITEMS_PER_LINE); 98 printf("\n"); 99 } 100 101 static void split_json_array_str(const char *input) 102 { 103 char *str, *rest, *strs; 104 105 if (!input) { 106 jsonw_start_array(json_wtr); 107 jsonw_end_array(json_wtr); 108 return; 109 } 110 111 strs = strdup(input); 112 if (!strs) 113 return; 114 115 jsonw_start_array(json_wtr); 116 for (str = strtok_r(strs, ":", &rest); str; 117 str = strtok_r(NULL, ":", &rest)) { 118 jsonw_string(json_wtr, str); 119 } 120 jsonw_end_array(json_wtr); 121 122 free(strs); 123 } 124 125 static void show_token_info_json(struct mntent *mntent) 126 { 127 char *value; 128 129 jsonw_start_object(json_wtr); 130 131 jsonw_string_field(json_wtr, "token_info", mntent->mnt_dir); 132 133 jsonw_name(json_wtr, "allowed_cmds"); 134 value = get_delegate_value(mntent->mnt_opts, "delegate_cmds"); 135 split_json_array_str(value); 136 137 jsonw_name(json_wtr, "allowed_maps"); 138 value = get_delegate_value(mntent->mnt_opts, "delegate_maps"); 139 split_json_array_str(value); 140 141 jsonw_name(json_wtr, "allowed_progs"); 142 value = get_delegate_value(mntent->mnt_opts, "delegate_progs"); 143 split_json_array_str(value); 144 145 jsonw_name(json_wtr, "allowed_attachs"); 146 value = get_delegate_value(mntent->mnt_opts, "delegate_attachs"); 147 split_json_array_str(value); 148 149 jsonw_end_object(json_wtr); 150 } 151 152 static int __show_token_info(struct mntent *mntent) 153 { 154 if (json_output) 155 show_token_info_json(mntent); 156 else 157 show_token_info_plain(mntent); 158 159 return 0; 160 } 161 162 static int show_token_info(void) 163 { 164 FILE *fp; 165 struct mntent *ent; 166 167 fp = setmntent(MOUNTS_FILE, "r"); 168 if (!fp) { 169 p_err("Failed to open: %s", MOUNTS_FILE); 170 return -1; 171 } 172 173 if (json_output) 174 jsonw_start_array(json_wtr); 175 176 while ((ent = getmntent(fp)) != NULL) { 177 if (strncmp(ent->mnt_type, "bpf", 3) == 0) { 178 if (has_delegate_options(ent->mnt_opts)) 179 __show_token_info(ent); 180 } 181 } 182 183 if (json_output) 184 jsonw_end_array(json_wtr); 185 186 endmntent(fp); 187 188 return 0; 189 } 190 191 static int do_show(int argc, char **argv) 192 { 193 if (argc) 194 return BAD_ARG(); 195 196 return show_token_info(); 197 } 198 199 static int do_help(int argc, char **argv) 200 { 201 if (json_output) { 202 jsonw_null(json_wtr); 203 return 0; 204 } 205 206 fprintf(stderr, 207 "Usage: %1$s %2$s { show | list }\n" 208 " %1$s %2$s help\n" 209 "\n" 210 "", 211 bin_name, argv[-2]); 212 return 0; 213 } 214 215 static const struct cmd cmds[] = { 216 { "show", do_show }, 217 { "list", do_show }, 218 { "help", do_help }, 219 { 0 } 220 }; 221 222 int do_token(int argc, char **argv) 223 { 224 return cmd_select(cmds, argc, argv, do_help); 225 } 226