Blame


1 f0e62b85 2024-02-15 op /*
2 f0e62b85 2024-02-15 op * Copyright (c) 2024 Omar Polo <op@omarpolo.com>
3 f0e62b85 2024-02-15 op *
4 f0e62b85 2024-02-15 op * Permission to use, copy, modify, and distribute this software for any
5 f0e62b85 2024-02-15 op * purpose with or without fee is hereby granted, provided that the above
6 f0e62b85 2024-02-15 op * copyright notice and this permission notice appear in all copies.
7 f0e62b85 2024-02-15 op *
8 f0e62b85 2024-02-15 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 f0e62b85 2024-02-15 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 f0e62b85 2024-02-15 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 f0e62b85 2024-02-15 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 f0e62b85 2024-02-15 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 f0e62b85 2024-02-15 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 f0e62b85 2024-02-15 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 f0e62b85 2024-02-15 op */
16 f0e62b85 2024-02-15 op
17 f0e62b85 2024-02-15 op #include "compat.h"
18 f0e62b85 2024-02-15 op
19 f0e62b85 2024-02-15 op #include <limits.h>
20 f0e62b85 2024-02-15 op #include <stdio.h>
21 f0e62b85 2024-02-15 op #include <stdlib.h>
22 f0e62b85 2024-02-15 op #include <string.h>
23 f0e62b85 2024-02-15 op #include <tls.h>
24 f0e62b85 2024-02-15 op #include <unistd.h>
25 f0e62b85 2024-02-15 op
26 f0e62b85 2024-02-15 op #include "certs.h"
27 f0e62b85 2024-02-15 op #include "fs.h"
28 f0e62b85 2024-02-15 op #include "parser.h"
29 f0e62b85 2024-02-15 op #include "telescope.h"
30 f0e62b85 2024-02-15 op
31 f0e62b85 2024-02-15 op #ifndef nitems
32 f0e62b85 2024-02-15 op #define nitems(x) (sizeof(x) / sizeof((x)[0]))
33 f0e62b85 2024-02-15 op #endif
34 f0e62b85 2024-02-15 op
35 f0e62b85 2024-02-15 op struct cmd;
36 f0e62b85 2024-02-15 op
37 f0e62b85 2024-02-15 op static int cmd_generate(const struct cmd *, int, char **);
38 f0e62b85 2024-02-15 op static int cmd_remove(const struct cmd *, int, char **);
39 f0e62b85 2024-02-15 op static int cmd_import(const struct cmd *, int, char **);
40 f0e62b85 2024-02-15 op static int cmd_export(const struct cmd *, int, char **);
41 f0e62b85 2024-02-15 op static int cmd_list(const struct cmd *, int, char **);
42 f0e62b85 2024-02-15 op static int cmd_mappings(const struct cmd *, int, char **);
43 f0e62b85 2024-02-15 op static int cmd_use(const struct cmd *, int, char **);
44 f0e62b85 2024-02-15 op static int cmd_forget(const struct cmd *, int, char **);
45 f0e62b85 2024-02-15 op
46 f0e62b85 2024-02-15 op struct cmd {
47 f0e62b85 2024-02-15 op const char *name;
48 f0e62b85 2024-02-15 op int (*fn)(const struct cmd *, int argc, char **argv);
49 f0e62b85 2024-02-15 op const char *usage;
50 f0e62b85 2024-02-15 op };
51 f0e62b85 2024-02-15 op
52 f0e62b85 2024-02-15 op static const struct cmd cmds[] = {
53 f0e62b85 2024-02-15 op { "generate", cmd_generate, "[-t type] name" },
54 f0e62b85 2024-02-15 op { "remove", cmd_remove, "name" },
55 f0e62b85 2024-02-15 op { "import", cmd_import, "-C cert [-K key] name" },
56 e1ccda6c 2024-02-16 op { "export", cmd_export, "-C cert name" },
57 f0e62b85 2024-02-15 op { "list", cmd_list, "" },
58 f0e62b85 2024-02-15 op { "mappings", cmd_mappings, "" },
59 f0e62b85 2024-02-15 op { "use", cmd_use, "name host[:port][/path]" },
60 f0e62b85 2024-02-15 op { "forget", cmd_forget, "name host[:port][/path]" },
61 f0e62b85 2024-02-15 op };
62 f0e62b85 2024-02-15 op
63 f0e62b85 2024-02-15 op /*
64 f0e62b85 2024-02-15 op * Provide some symbols so that we can pull in some subsystems without
65 f0e62b85 2024-02-15 op * their the dependencies.
66 f0e62b85 2024-02-15 op */
67 f0e62b85 2024-02-15 op
68 f0e62b85 2024-02-15 op const uint8_t *about_about;
69 f0e62b85 2024-02-15 op size_t about_about_len;
70 f0e62b85 2024-02-15 op const uint8_t *about_blank;
71 f0e62b85 2024-02-15 op size_t about_blank_len;
72 f0e62b85 2024-02-15 op const uint8_t *about_crash;
73 f0e62b85 2024-02-15 op size_t about_crash_len;
74 f0e62b85 2024-02-15 op const uint8_t *about_help;
75 f0e62b85 2024-02-15 op size_t about_help_len;
76 f0e62b85 2024-02-15 op const uint8_t *about_license;
77 f0e62b85 2024-02-15 op size_t about_license_len;
78 f0e62b85 2024-02-15 op const uint8_t *about_new;
79 f0e62b85 2024-02-15 op size_t about_new_len;
80 f0e62b85 2024-02-15 op const uint8_t *bookmarks;
81 f0e62b85 2024-02-15 op size_t bookmarks_len;
82 f0e62b85 2024-02-15 op
83 f0e62b85 2024-02-15 op void gemtext_initparser(struct parser *p) { return; }
84 f0e62b85 2024-02-15 op void textpatch_initparser(struct parser *p) { return; }
85 f0e62b85 2024-02-15 op void textplain_initparser(struct parser *p) { return; }
86 f0e62b85 2024-02-15 op
87 f0e62b85 2024-02-15 op void load_page_from_str(struct tab *tab, const char *page) { return; }
88 f0e62b85 2024-02-15 op void erase_buffer(struct buffer *buffer) { return; }
89 f0e62b85 2024-02-15 op
90 f0e62b85 2024-02-15 op static void __dead
91 f0e62b85 2024-02-15 op usage(void)
92 f0e62b85 2024-02-15 op {
93 f0e62b85 2024-02-15 op size_t i;
94 f0e62b85 2024-02-15 op
95 f0e62b85 2024-02-15 op fprintf(stderr, "usage: %s command [args...]\n", getprogname());
96 f0e62b85 2024-02-15 op fprintf(stderr, "Available subcommands are:");
97 f0e62b85 2024-02-15 op for (i = 0; i < nitems(cmds); ++i)
98 f0e62b85 2024-02-15 op fprintf(stderr, " %s", cmds[i].name);
99 f0e62b85 2024-02-15 op fputs(".\n", stderr);
100 f0e62b85 2024-02-15 op exit(1);
101 f0e62b85 2024-02-15 op }
102 f0e62b85 2024-02-15 op
103 f0e62b85 2024-02-15 op static void __dead
104 f0e62b85 2024-02-15 op cmd_usage(const struct cmd *cmd)
105 f0e62b85 2024-02-15 op {
106 f0e62b85 2024-02-15 op fprintf(stderr, "usage: %s %s%s%s\n", getprogname(), cmd->name,
107 f0e62b85 2024-02-15 op *cmd->usage ? " " : "", cmd->usage);
108 f0e62b85 2024-02-15 op exit(1);
109 f0e62b85 2024-02-15 op }
110 f0e62b85 2024-02-15 op
111 f0e62b85 2024-02-15 op int
112 f0e62b85 2024-02-15 op main(int argc, char **argv)
113 f0e62b85 2024-02-15 op {
114 f0e62b85 2024-02-15 op const struct cmd *cmd;
115 f0e62b85 2024-02-15 op size_t i;
116 f0e62b85 2024-02-15 op
117 c3465169 2024-02-19 op /*
118 c3465169 2024-02-19 op * Can't use portably getopt() since there's no cross-platform
119 c3465169 2024-02-19 op * way of resetting it.
120 c3465169 2024-02-19 op */
121 f0e62b85 2024-02-15 op
122 f0e62b85 2024-02-15 op if (argc == 0)
123 f0e62b85 2024-02-15 op usage();
124 c3465169 2024-02-19 op argc--, argv++;
125 f0e62b85 2024-02-15 op
126 c3465169 2024-02-19 op if (argc == 0)
127 c3465169 2024-02-19 op usage();
128 c3465169 2024-02-19 op
129 c3465169 2024-02-19 op if (!strcmp(*argv, "--"))
130 c3465169 2024-02-19 op argc--, argv++;
131 c3465169 2024-02-19 op else if (**argv == '-')
132 c3465169 2024-02-19 op usage();
133 c3465169 2024-02-19 op
134 c3465169 2024-02-19 op if (argc == 0)
135 c3465169 2024-02-19 op usage();
136 c3465169 2024-02-19 op
137 f0e62b85 2024-02-15 op for (i = 0; i < nitems(cmds); ++i) {
138 f0e62b85 2024-02-15 op cmd = &cmds[i];
139 f0e62b85 2024-02-15 op
140 f0e62b85 2024-02-15 op if (strcmp(cmd->name, argv[0]) != 0)
141 f0e62b85 2024-02-15 op continue;
142 f0e62b85 2024-02-15 op
143 f0e62b85 2024-02-15 op fs_init();
144 f0e62b85 2024-02-15 op if (certs_init(certs_file) == -1)
145 f0e62b85 2024-02-15 op errx(1, "failed to initialize the cert store.");
146 f0e62b85 2024-02-15 op return (cmd->fn(cmd, argc, argv));
147 f0e62b85 2024-02-15 op }
148 f0e62b85 2024-02-15 op
149 e1ccda6c 2024-02-16 op warnx("unknown command: %s", argv[0]);
150 f0e62b85 2024-02-15 op usage();
151 f0e62b85 2024-02-15 op }
152 f0e62b85 2024-02-15 op
153 f0e62b85 2024-02-15 op static int
154 f0e62b85 2024-02-15 op cmd_generate(const struct cmd *cmd, int argc, char **argv)
155 f0e62b85 2024-02-15 op {
156 f0e62b85 2024-02-15 op const char *name;
157 f0e62b85 2024-02-15 op char path[PATH_MAX];
158 f0e62b85 2024-02-15 op int ch, r;
159 f0e62b85 2024-02-15 op int ec = 1;
160 f0e62b85 2024-02-15 op
161 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "t:")) != -1) {
162 f0e62b85 2024-02-15 op switch (ch) {
163 f0e62b85 2024-02-15 op case 't':
164 f0e62b85 2024-02-15 op if (!strcasecmp(optarg, "ec")) {
165 f0e62b85 2024-02-15 op ec = 1;
166 f0e62b85 2024-02-15 op break;
167 f0e62b85 2024-02-15 op }
168 f0e62b85 2024-02-15 op if (!strcasecmp(optarg, "rsa")) {
169 f0e62b85 2024-02-15 op ec = 0;
170 f0e62b85 2024-02-15 op break;
171 f0e62b85 2024-02-15 op }
172 f0e62b85 2024-02-15 op errx(1, "Unknown key type requested: %s", optarg);
173 f0e62b85 2024-02-15 op
174 f0e62b85 2024-02-15 op default:
175 f0e62b85 2024-02-15 op cmd_usage(cmd);
176 f0e62b85 2024-02-15 op }
177 f0e62b85 2024-02-15 op }
178 f0e62b85 2024-02-15 op argc -= optind;
179 f0e62b85 2024-02-15 op argv += optind;
180 f0e62b85 2024-02-15 op
181 f0e62b85 2024-02-15 op if (argc != 1)
182 f0e62b85 2024-02-15 op cmd_usage(cmd);
183 f0e62b85 2024-02-15 op
184 f0e62b85 2024-02-15 op name = *argv;
185 f0e62b85 2024-02-15 op
186 f0e62b85 2024-02-15 op r = snprintf(path, sizeof(path), "%s%s", cert_dir, name);
187 f0e62b85 2024-02-15 op if (r < 0 || (size_t)r >= sizeof(path))
188 f0e62b85 2024-02-15 op errx(1, "path too long");
189 f0e62b85 2024-02-15 op
190 f0e62b85 2024-02-15 op if (cert_new(name, path, ec) == -1)
191 f0e62b85 2024-02-15 op errx(1, "failure generating the key");
192 f0e62b85 2024-02-15 op
193 f0e62b85 2024-02-15 op return 0;
194 f0e62b85 2024-02-15 op }
195 f0e62b85 2024-02-15 op
196 f0e62b85 2024-02-15 op static int
197 f0e62b85 2024-02-15 op cmd_remove(const struct cmd *cmd, int argc, char **argv)
198 f0e62b85 2024-02-15 op {
199 f0e62b85 2024-02-15 op const char *name;
200 f0e62b85 2024-02-15 op char path[PATH_MAX];
201 f0e62b85 2024-02-15 op int ch, r;
202 f0e62b85 2024-02-15 op
203 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "")) != -1) {
204 f0e62b85 2024-02-15 op switch (ch) {
205 f0e62b85 2024-02-15 op default:
206 f0e62b85 2024-02-15 op cmd_usage(cmd);
207 f0e62b85 2024-02-15 op }
208 f0e62b85 2024-02-15 op }
209 f0e62b85 2024-02-15 op argc -= optind;
210 f0e62b85 2024-02-15 op argv += optind;
211 f0e62b85 2024-02-15 op
212 f0e62b85 2024-02-15 op if (argc != 1)
213 f0e62b85 2024-02-15 op cmd_usage(cmd);
214 f0e62b85 2024-02-15 op
215 f0e62b85 2024-02-15 op name = *argv;
216 f0e62b85 2024-02-15 op
217 f0e62b85 2024-02-15 op r = snprintf(path, sizeof(path), "%s%s", cert_dir, name);
218 f0e62b85 2024-02-15 op if (r < 0 || (size_t)r >= sizeof(path))
219 f0e62b85 2024-02-15 op errx(1, "path too long");
220 f0e62b85 2024-02-15 op
221 f0e62b85 2024-02-15 op if (unlink(path) == -1)
222 f0e62b85 2024-02-15 op err(1, "unlink %s", path);
223 f0e62b85 2024-02-15 op return 0;
224 f0e62b85 2024-02-15 op }
225 f0e62b85 2024-02-15 op
226 f0e62b85 2024-02-15 op static int
227 f0e62b85 2024-02-15 op cmd_import(const struct cmd *cmd, int argc, char **argv)
228 f0e62b85 2024-02-15 op {
229 f0e62b85 2024-02-15 op struct tls_config *conf;
230 f0e62b85 2024-02-15 op const char *key = NULL, *cert = NULL;
231 f0e62b85 2024-02-15 op char path[PATH_MAX], sfn[PATH_MAX];
232 f0e62b85 2024-02-15 op FILE *fp;
233 f0e62b85 2024-02-15 op uint8_t *keym, *certm;
234 f0e62b85 2024-02-15 op size_t keyl, certl;
235 f0e62b85 2024-02-15 op int ch, r, fd;
236 f0e62b85 2024-02-15 op int force = 0;
237 f0e62b85 2024-02-15 op
238 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "C:K:f")) != -1) {
239 f0e62b85 2024-02-15 op switch (ch) {
240 f0e62b85 2024-02-15 op case 'C':
241 f0e62b85 2024-02-15 op cert = optarg;
242 f0e62b85 2024-02-15 op break;
243 f0e62b85 2024-02-15 op case 'K':
244 f0e62b85 2024-02-15 op key = optarg;
245 f0e62b85 2024-02-15 op break;
246 f0e62b85 2024-02-15 op case 'f':
247 f0e62b85 2024-02-15 op force = 1;
248 f0e62b85 2024-02-15 op break;
249 f0e62b85 2024-02-15 op default:
250 f0e62b85 2024-02-15 op cmd_usage(cmd);
251 f0e62b85 2024-02-15 op }
252 f0e62b85 2024-02-15 op }
253 f0e62b85 2024-02-15 op argc -= optind;
254 f0e62b85 2024-02-15 op argv += optind;
255 f0e62b85 2024-02-15 op
256 f0e62b85 2024-02-15 op if (argc != 1)
257 f0e62b85 2024-02-15 op cmd_usage(cmd);
258 f0e62b85 2024-02-15 op
259 f0e62b85 2024-02-15 op if (key == NULL)
260 f0e62b85 2024-02-15 op key = cert;
261 f0e62b85 2024-02-15 op if (cert == NULL)
262 f0e62b85 2024-02-15 op cmd_usage(cmd);
263 f0e62b85 2024-02-15 op
264 f0e62b85 2024-02-15 op if ((keym = tls_load_file(key, &keyl, NULL)) == NULL)
265 f0e62b85 2024-02-15 op err(1, "can't open %s", key);
266 f0e62b85 2024-02-15 op if ((certm = tls_load_file(cert, &certl, NULL)) == NULL)
267 f0e62b85 2024-02-15 op err(1, "can't open %s", cert);
268 f0e62b85 2024-02-15 op
269 f0e62b85 2024-02-15 op if ((conf = tls_config_new()) == NULL)
270 f0e62b85 2024-02-15 op err(1, "tls_config_new");
271 f0e62b85 2024-02-15 op
272 f0e62b85 2024-02-15 op if (tls_config_set_keypair_mem(conf, certm, certl, keym, keyl) == -1)
273 f0e62b85 2024-02-15 op errx(1, "failed to load the keypair: %s",
274 f0e62b85 2024-02-15 op tls_config_error(conf));
275 f0e62b85 2024-02-15 op
276 f0e62b85 2024-02-15 op tls_config_free(conf);
277 f0e62b85 2024-02-15 op
278 f0e62b85 2024-02-15 op r = snprintf(path, sizeof(path), "%s/%s", cert_dir, *argv);
279 f0e62b85 2024-02-15 op if (r < 0 || (size_t)r >= sizeof(path))
280 f0e62b85 2024-02-15 op err(1, "identity name too long");
281 f0e62b85 2024-02-15 op
282 f0e62b85 2024-02-15 op strlcpy(sfn, cert_dir_tmp, sizeof(sfn));
283 f0e62b85 2024-02-15 op if ((fd = mkstemp(sfn)) == -1 ||
284 f0e62b85 2024-02-15 op (fp = fdopen(fd, "w")) == NULL) {
285 f0e62b85 2024-02-15 op if (fd != -1) {
286 f0e62b85 2024-02-15 op warn("fdopen");
287 f0e62b85 2024-02-15 op unlink(sfn);
288 f0e62b85 2024-02-15 op close(fd);
289 f0e62b85 2024-02-15 op } else
290 f0e62b85 2024-02-15 op warn("mkstamp");
291 f0e62b85 2024-02-15 op return 1;
292 f0e62b85 2024-02-15 op }
293 f0e62b85 2024-02-15 op
294 f0e62b85 2024-02-15 op if (fwrite(certm, 1, certl, fp) != certl) {
295 f0e62b85 2024-02-15 op warn("fwrite");
296 f0e62b85 2024-02-15 op unlink(sfn);
297 f0e62b85 2024-02-15 op fclose(fp);
298 f0e62b85 2024-02-15 op return 1;
299 f0e62b85 2024-02-15 op }
300 f0e62b85 2024-02-15 op if (strcmp(key, cert) != 0 &&
301 f0e62b85 2024-02-15 op fwrite(keym, 1, keyl, fp) != keyl) {
302 f0e62b85 2024-02-15 op warn("fwrite");
303 f0e62b85 2024-02-15 op unlink(sfn);
304 f0e62b85 2024-02-15 op fclose(fp);
305 f0e62b85 2024-02-15 op return 1;
306 f0e62b85 2024-02-15 op }
307 f0e62b85 2024-02-15 op
308 f0e62b85 2024-02-15 op if (fflush(fp) == EOF) {
309 f0e62b85 2024-02-15 op warn("fflush");
310 f0e62b85 2024-02-15 op unlink(sfn);
311 f0e62b85 2024-02-15 op fclose(fp);
312 f0e62b85 2024-02-15 op return 1;
313 f0e62b85 2024-02-15 op }
314 f0e62b85 2024-02-15 op fclose(fp);
315 f0e62b85 2024-02-15 op
316 f0e62b85 2024-02-15 op if (!force && access(path, F_OK) == 0) {
317 f0e62b85 2024-02-15 op warnx("identity %s already exists", *argv);
318 f0e62b85 2024-02-15 op unlink(sfn);
319 f0e62b85 2024-02-15 op return 1;
320 f0e62b85 2024-02-15 op }
321 f0e62b85 2024-02-15 op
322 f0e62b85 2024-02-15 op if (rename(sfn, path) == -1) {
323 f0e62b85 2024-02-15 op warn("can't rename");
324 f0e62b85 2024-02-15 op unlink(sfn);
325 f0e62b85 2024-02-15 op return 1;
326 f0e62b85 2024-02-15 op }
327 f0e62b85 2024-02-15 op
328 f0e62b85 2024-02-15 op return (0);
329 f0e62b85 2024-02-15 op }
330 f0e62b85 2024-02-15 op
331 f0e62b85 2024-02-15 op static int
332 f0e62b85 2024-02-15 op cmd_export(const struct cmd *cmd, int argc, char **argv)
333 f0e62b85 2024-02-15 op {
334 f0e62b85 2024-02-15 op FILE *fp, *outfp;
335 f0e62b85 2024-02-15 op const char *cert = NULL;
336 f0e62b85 2024-02-15 op const char *identity = NULL;
337 f0e62b85 2024-02-15 op char path[PATH_MAX];
338 f0e62b85 2024-02-15 op char buf[BUFSIZ];
339 f0e62b85 2024-02-15 op size_t l;
340 f0e62b85 2024-02-15 op int ch, r;
341 f0e62b85 2024-02-15 op
342 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "C:")) != -1) {
343 f0e62b85 2024-02-15 op switch (ch) {
344 f0e62b85 2024-02-15 op case 'C':
345 f0e62b85 2024-02-15 op cert = optarg;
346 f0e62b85 2024-02-15 op break;
347 f0e62b85 2024-02-15 op default:
348 f0e62b85 2024-02-15 op cmd_usage(cmd);
349 f0e62b85 2024-02-15 op }
350 f0e62b85 2024-02-15 op }
351 f0e62b85 2024-02-15 op argc -= optind;
352 f0e62b85 2024-02-15 op argv += optind;
353 f0e62b85 2024-02-15 op if (argc != 1)
354 f0e62b85 2024-02-15 op cmd_usage(cmd);
355 f0e62b85 2024-02-15 op identity = argv[0];
356 f0e62b85 2024-02-15 op
357 f0e62b85 2024-02-15 op if (cert == NULL)
358 f0e62b85 2024-02-15 op cmd_usage(cmd);
359 f0e62b85 2024-02-15 op
360 f0e62b85 2024-02-15 op r = snprintf(path, sizeof(path), "%s/%s", cert_dir, identity);
361 f0e62b85 2024-02-15 op if (r < 0 || (size_t)r >= sizeof(path))
362 f0e62b85 2024-02-15 op err(1, "path too long");
363 f0e62b85 2024-02-15 op if ((fp = fopen(path, "r")) == NULL)
364 f0e62b85 2024-02-15 op err(1, "can't open %s", path);
365 f0e62b85 2024-02-15 op
366 f0e62b85 2024-02-15 op if ((outfp = fopen(cert, "w")) == NULL)
367 f0e62b85 2024-02-15 op err(1, "can't open %s", cert);
368 f0e62b85 2024-02-15 op
369 f0e62b85 2024-02-15 op for (;;) {
370 f0e62b85 2024-02-15 op l = fread(buf, 1, sizeof(buf), fp);
371 f0e62b85 2024-02-15 op if (l == 0)
372 f0e62b85 2024-02-15 op break;
373 f0e62b85 2024-02-15 op if (fwrite(buf, 1, l, outfp) != l)
374 f0e62b85 2024-02-15 op err(1, "fwrite");
375 f0e62b85 2024-02-15 op }
376 f0e62b85 2024-02-15 op if (ferror(fp))
377 f0e62b85 2024-02-15 op err(1, "fread");
378 f0e62b85 2024-02-15 op
379 f0e62b85 2024-02-15 op return 0;
380 f0e62b85 2024-02-15 op }
381 f0e62b85 2024-02-15 op
382 f0e62b85 2024-02-15 op static int
383 f0e62b85 2024-02-15 op cmd_list(const struct cmd *cmd, int argc, char **argv)
384 f0e62b85 2024-02-15 op {
385 f0e62b85 2024-02-15 op char **id;
386 f0e62b85 2024-02-15 op int ch;
387 f0e62b85 2024-02-15 op
388 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "")) != -1) {
389 f0e62b85 2024-02-15 op switch (ch) {
390 f0e62b85 2024-02-15 op default:
391 f0e62b85 2024-02-15 op cmd_usage(cmd);
392 f0e62b85 2024-02-15 op }
393 f0e62b85 2024-02-15 op }
394 f0e62b85 2024-02-15 op argc -= optind;
395 f0e62b85 2024-02-15 op argv += optind;
396 f0e62b85 2024-02-15 op if (argc != 0)
397 f0e62b85 2024-02-15 op cmd_usage(cmd);
398 f0e62b85 2024-02-15 op
399 f0e62b85 2024-02-15 op for (id = identities; *id; ++id)
400 f0e62b85 2024-02-15 op puts(*id);
401 f0e62b85 2024-02-15 op
402 f0e62b85 2024-02-15 op return (0);
403 f0e62b85 2024-02-15 op }
404 f0e62b85 2024-02-15 op
405 f0e62b85 2024-02-15 op static int
406 f0e62b85 2024-02-15 op cmd_mappings(const struct cmd *cmd, int argc, char **argv)
407 f0e62b85 2024-02-15 op {
408 e1ccda6c 2024-02-16 op struct ccert *c;
409 e1ccda6c 2024-02-16 op const char *id = NULL;
410 f0e62b85 2024-02-15 op int ch, defport;
411 f0e62b85 2024-02-15 op size_t i;
412 f0e62b85 2024-02-15 op
413 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "")) != -1) {
414 f0e62b85 2024-02-15 op switch (ch) {
415 f0e62b85 2024-02-15 op default:
416 f0e62b85 2024-02-15 op cmd_usage(cmd);
417 f0e62b85 2024-02-15 op }
418 f0e62b85 2024-02-15 op }
419 f0e62b85 2024-02-15 op argc -= optind;
420 f0e62b85 2024-02-15 op argv += optind;
421 e1ccda6c 2024-02-16 op if (argc == 1) {
422 e1ccda6c 2024-02-16 op if ((id = ccert(*argv)) == NULL)
423 e1ccda6c 2024-02-16 op errx(1, "unknown identity %s", *argv);
424 e1ccda6c 2024-02-16 op argc--, argv++;
425 e1ccda6c 2024-02-16 op }
426 f0e62b85 2024-02-15 op if (argc != 0)
427 f0e62b85 2024-02-15 op cmd_usage(cmd);
428 f0e62b85 2024-02-15 op
429 f0e62b85 2024-02-15 op for (i = 0; i < cert_store.len; ++i) {
430 e1ccda6c 2024-02-16 op c = &cert_store.certs[i];
431 e1ccda6c 2024-02-16 op
432 e1ccda6c 2024-02-16 op if (id && strcmp(id, c->cert) != 0)
433 e1ccda6c 2024-02-16 op continue;
434 f0e62b85 2024-02-15 op
435 e1ccda6c 2024-02-16 op defport = !strcmp(c->port, "1965");
436 f0e62b85 2024-02-15 op
437 e1ccda6c 2024-02-16 op printf("%s\t%s%s%s%s\n", c->cert, c->host,
438 e1ccda6c 2024-02-16 op defport ? "" : ":", defport ? "" : c->port,
439 e1ccda6c 2024-02-16 op c->path);
440 f0e62b85 2024-02-15 op }
441 f0e62b85 2024-02-15 op
442 f0e62b85 2024-02-15 op return (0);
443 f0e62b85 2024-02-15 op }
444 f0e62b85 2024-02-15 op
445 f0e62b85 2024-02-15 op static struct iri *
446 f0e62b85 2024-02-15 op parseiri(char *spec)
447 f0e62b85 2024-02-15 op {
448 f0e62b85 2024-02-15 op static struct iri iri;
449 f0e62b85 2024-02-15 op const char *errstr;
450 f0e62b85 2024-02-15 op char *host, *port = NULL, *path = NULL;
451 f0e62b85 2024-02-15 op
452 f0e62b85 2024-02-15 op memset(&iri, 0, sizeof(iri));
453 f0e62b85 2024-02-15 op
454 f0e62b85 2024-02-15 op host = spec;
455 f0e62b85 2024-02-15 op
456 f0e62b85 2024-02-15 op port = host + strcspn(host, ":/");
457 f0e62b85 2024-02-15 op if (*port == ':') {
458 f0e62b85 2024-02-15 op *port++ = '\0';
459 f0e62b85 2024-02-15 op if ((path = strchr(port, '/')) != NULL)
460 f0e62b85 2024-02-15 op *path++ = '\0';
461 f0e62b85 2024-02-15 op } else if (*port == '/') {
462 f0e62b85 2024-02-15 op *port++ = '\0';
463 f0e62b85 2024-02-15 op path = port;
464 f0e62b85 2024-02-15 op port = NULL;
465 f0e62b85 2024-02-15 op } else
466 f0e62b85 2024-02-15 op port = NULL;
467 f0e62b85 2024-02-15 op
468 f0e62b85 2024-02-15 op strlcpy(iri.iri_host, host, sizeof(iri.iri_host));
469 f0e62b85 2024-02-15 op strlcpy(iri.iri_portstr, port ? port : "1965", sizeof(iri.iri_portstr));
470 f0e62b85 2024-02-15 op strlcpy(iri.iri_path, path ? path : "/", sizeof(iri.iri_path));
471 f0e62b85 2024-02-15 op
472 f0e62b85 2024-02-15 op iri.iri_port = strtonum(iri.iri_portstr, 0, UINT16_MAX, &errstr);
473 f0e62b85 2024-02-15 op if (errstr)
474 f0e62b85 2024-02-15 op err(1, "port number is %s: %s", errstr, iri.iri_portstr);
475 f0e62b85 2024-02-15 op
476 f0e62b85 2024-02-15 op return &iri;
477 f0e62b85 2024-02-15 op }
478 f0e62b85 2024-02-15 op
479 f0e62b85 2024-02-15 op static int
480 f0e62b85 2024-02-15 op cmd_use(const struct cmd *cmd, int argc, char **argv)
481 f0e62b85 2024-02-15 op {
482 f0e62b85 2024-02-15 op char *cert, *spec;
483 f0e62b85 2024-02-15 op int ch;
484 f0e62b85 2024-02-15 op
485 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "")) != -1) {
486 f0e62b85 2024-02-15 op switch (ch) {
487 f0e62b85 2024-02-15 op default:
488 f0e62b85 2024-02-15 op cmd_usage(cmd);
489 f0e62b85 2024-02-15 op }
490 f0e62b85 2024-02-15 op }
491 f0e62b85 2024-02-15 op argc -= optind;
492 f0e62b85 2024-02-15 op argv += optind;
493 f0e62b85 2024-02-15 op if (argc != 2)
494 f0e62b85 2024-02-15 op cmd_usage(cmd);
495 f0e62b85 2024-02-15 op
496 f0e62b85 2024-02-15 op cert = argv[0];
497 f0e62b85 2024-02-15 op spec = argv[1];
498 f0e62b85 2024-02-15 op
499 f0e62b85 2024-02-15 op if (ccert(cert) == NULL)
500 f0e62b85 2024-02-15 op err(1, "unknown identity %s", cert);
501 f0e62b85 2024-02-15 op
502 f0e62b85 2024-02-15 op if (cert_save_for(cert, parseiri(spec), 1) == -1)
503 f0e62b85 2024-02-15 op errx(1, "failed to save the certificate");
504 f0e62b85 2024-02-15 op
505 f0e62b85 2024-02-15 op return 0;
506 f0e62b85 2024-02-15 op }
507 f0e62b85 2024-02-15 op
508 f0e62b85 2024-02-15 op static int
509 f0e62b85 2024-02-15 op cmd_forget(const struct cmd *cmd, int argc, char **argv)
510 f0e62b85 2024-02-15 op {
511 f0e62b85 2024-02-15 op char *cert, *spec;
512 f0e62b85 2024-02-15 op int ch;
513 f0e62b85 2024-02-15 op
514 f0e62b85 2024-02-15 op while ((ch = getopt(argc, argv, "")) != -1) {
515 f0e62b85 2024-02-15 op switch (ch) {
516 f0e62b85 2024-02-15 op default:
517 f0e62b85 2024-02-15 op cmd_usage(cmd);
518 f0e62b85 2024-02-15 op }
519 f0e62b85 2024-02-15 op }
520 f0e62b85 2024-02-15 op argc -= optind;
521 f0e62b85 2024-02-15 op argv += optind;
522 f0e62b85 2024-02-15 op if (argc != 2)
523 f0e62b85 2024-02-15 op cmd_usage(cmd);
524 f0e62b85 2024-02-15 op
525 f0e62b85 2024-02-15 op cert = argv[0];
526 f0e62b85 2024-02-15 op spec = argv[1];
527 f0e62b85 2024-02-15 op
528 f0e62b85 2024-02-15 op if (ccert(cert) == NULL)
529 f0e62b85 2024-02-15 op err(1, "unknown identity %s", cert);
530 f0e62b85 2024-02-15 op
531 f0e62b85 2024-02-15 op if (cert_delete_for(cert, parseiri(spec), 1) == -1)
532 f0e62b85 2024-02-15 op errx(1, "failed to save the certificate");
533 f0e62b85 2024-02-15 op
534 f0e62b85 2024-02-15 op return 0;
535 f0e62b85 2024-02-15 op }
536 f0e62b85 2024-02-15 op