xref: /linux/tools/bpf/bpftool/token.c (revision 2d812311c2b28cc9096e29862a957aeb32bfdb76)
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