File: | libexec/got-read-gitconfig/got-read-gitconfig.c |
Warning: | line 240, column 8 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2019 Stefan Sperling <stsp@openbsd.org> | |||
3 | * | |||
4 | * Permission to use, copy, modify, and distribute this software for any | |||
5 | * purpose with or without fee is hereby granted, provided that the above | |||
6 | * copyright notice and this permission notice appear in all copies. | |||
7 | * | |||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
15 | */ | |||
16 | ||||
17 | #include <sys/types.h> | |||
18 | #include <sys/queue.h> | |||
19 | #include <sys/uio.h> | |||
20 | #include <sys/time.h> | |||
21 | ||||
22 | #include <stdint.h> | |||
23 | #include <imsg.h> | |||
24 | #include <limits.h> | |||
25 | #include <signal.h> | |||
26 | #include <stdio.h> | |||
27 | #include <stdlib.h> | |||
28 | #include <string.h> | |||
29 | #include <sha1.h> | |||
30 | #include <unistd.h> | |||
31 | #include <zlib.h> | |||
32 | ||||
33 | #include "got_error.h" | |||
34 | #include "got_object.h" | |||
35 | #include "got_repository.h" | |||
36 | ||||
37 | #include "got_lib_delta.h" | |||
38 | #include "got_lib_object.h" | |||
39 | #include "got_lib_privsep.h" | |||
40 | #include "got_lib_gitconfig.h" | |||
41 | ||||
42 | static volatile sig_atomic_t sigint_received; | |||
43 | ||||
44 | static void | |||
45 | catch_sigint(int signo) | |||
46 | { | |||
47 | sigint_received = 1; | |||
48 | } | |||
49 | ||||
50 | static const struct got_error * | |||
51 | send_gitconfig_int(struct imsgbuf *ibuf, int value) | |||
52 | { | |||
53 | if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_INT_VAL, 0, 0, -1, | |||
54 | &value, sizeof(value)) == -1) | |||
55 | return got_error_from_errno("imsg_compose GITCONFIG_INT_VAL"); | |||
56 | ||||
57 | return got_privsep_flush_imsg(ibuf); | |||
58 | } | |||
59 | ||||
60 | static const struct got_error * | |||
61 | gitconfig_num_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig, | |||
62 | char *section, char *tag, int def) | |||
63 | { | |||
64 | int value; | |||
65 | ||||
66 | if (gitconfig == NULL((void *)0)) | |||
67 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
68 | ||||
69 | value = got_gitconfig_get_num(gitconfig, section, tag, def); | |||
70 | return send_gitconfig_int(ibuf, value); | |||
71 | } | |||
72 | ||||
73 | static const struct got_error * | |||
74 | send_gitconfig_str(struct imsgbuf *ibuf, const char *value) | |||
75 | { | |||
76 | size_t len = value ? strlen(value) : 0; | |||
77 | ||||
78 | if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_STR_VAL, 0, 0, -1, | |||
79 | value, len) == -1) | |||
80 | return got_error_from_errno("imsg_compose GITCONFIG_STR_VAL"); | |||
81 | ||||
82 | return got_privsep_flush_imsg(ibuf); | |||
83 | } | |||
84 | ||||
85 | static const struct got_error * | |||
86 | gitconfig_str_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig, | |||
87 | char *section, char *tag) | |||
88 | { | |||
89 | char *value; | |||
90 | ||||
91 | if (gitconfig == NULL((void *)0)) | |||
92 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
93 | ||||
94 | value = got_gitconfig_get_str(gitconfig, section, tag); | |||
95 | return send_gitconfig_str(ibuf, value); | |||
96 | } | |||
97 | ||||
98 | static const struct got_error * | |||
99 | send_gitconfig_remotes(struct imsgbuf *ibuf, struct got_remote_repo *remotes, | |||
100 | int nremotes) | |||
101 | { | |||
102 | const struct got_error *err = NULL((void *)0); | |||
103 | struct got_imsg_remotes iremotes; | |||
104 | int i; | |||
105 | ||||
106 | iremotes.nremotes = nremotes; | |||
107 | if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_REMOTES, 0, 0, -1, | |||
108 | &iremotes, sizeof(iremotes)) == -1) | |||
109 | return got_error_from_errno("imsg_compose GITCONFIG_REMOTES"); | |||
110 | ||||
111 | err = got_privsep_flush_imsg(ibuf); | |||
112 | imsg_clear(ibuf); | |||
113 | if (err) | |||
114 | return err; | |||
115 | ||||
116 | for (i = 0; i < nremotes; i++) { | |||
117 | struct got_imsg_remote iremote; | |||
118 | size_t len = sizeof(iremote); | |||
119 | struct ibuf *wbuf; | |||
120 | ||||
121 | iremote.mirror_references = remotes[i].mirror_references; | |||
122 | iremote.name_len = strlen(remotes[i].name); | |||
123 | len += iremote.name_len; | |||
124 | iremote.url_len = strlen(remotes[i].url); | |||
125 | len += iremote.url_len; | |||
126 | ||||
127 | wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_REMOTE, 0, 0, len); | |||
128 | if (wbuf == NULL((void *)0)) | |||
129 | return got_error_from_errno( | |||
130 | "imsg_create GITCONFIG_REMOTE"); | |||
131 | ||||
132 | if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) { | |||
133 | err = got_error_from_errno( | |||
134 | "imsg_add GITCONFIG_REMOTE"); | |||
135 | ibuf_free(wbuf); | |||
136 | return err; | |||
137 | } | |||
138 | ||||
139 | if (imsg_add(wbuf, remotes[i].name, iremote.name_len) == -1) { | |||
140 | err = got_error_from_errno( | |||
141 | "imsg_add GITCONFIG_REMOTE"); | |||
142 | ibuf_free(wbuf); | |||
143 | return err; | |||
144 | } | |||
145 | if (imsg_add(wbuf, remotes[i].url, iremote.url_len) == -1) { | |||
146 | err = got_error_from_errno( | |||
147 | "imsg_add GITCONFIG_REMOTE"); | |||
148 | ibuf_free(wbuf); | |||
149 | return err; | |||
150 | } | |||
151 | ||||
152 | wbuf->fd = -1; | |||
153 | imsg_close(ibuf, wbuf); | |||
154 | err = got_privsep_flush_imsg(ibuf); | |||
155 | if (err) | |||
156 | return err; | |||
157 | } | |||
158 | ||||
159 | return NULL((void *)0); | |||
160 | } | |||
161 | ||||
162 | static int | |||
163 | get_boolean_val(char *val) | |||
164 | { | |||
165 | return (strcasecmp(val, "true") == 0 || | |||
166 | strcasecmp(val, "on") == 0 || | |||
167 | strcasecmp(val, "yes") == 0 || | |||
168 | strcmp(val, "1") == 0); | |||
169 | } | |||
170 | ||||
171 | static const struct got_error * | |||
172 | gitconfig_remotes_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) | |||
173 | { | |||
174 | const struct got_error *err = NULL((void *)0); | |||
175 | struct got_gitconfig_list *sections; | |||
176 | struct got_gitconfig_list_node *node; | |||
177 | struct got_remote_repo *remotes = NULL((void *)0); | |||
178 | int nremotes = 0, i; | |||
179 | ||||
180 | if (gitconfig == NULL((void *)0)) | |||
181 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
182 | ||||
183 | err = got_gitconfig_get_section_list(§ions, gitconfig); | |||
184 | if (err) | |||
185 | return err; | |||
186 | ||||
187 | TAILQ_FOREACH(node, §ions->fields, link)for((node) = ((§ions->fields)->tqh_first); (node ) != ((void *)0); (node) = ((node)->link.tqe_next)) { | |||
188 | if (strncasecmp("remote \"", node->field, 8) != 0) | |||
189 | continue; | |||
190 | nremotes++; | |||
191 | } | |||
192 | ||||
193 | if (nremotes
| |||
194 | err = send_gitconfig_remotes(ibuf, NULL((void *)0), 0); | |||
195 | goto done; | |||
196 | } | |||
197 | ||||
198 | remotes = recallocarray(NULL((void *)0), 0, nremotes, sizeof(*remotes)); | |||
199 | if (remotes == NULL((void *)0)) { | |||
200 | err = got_error_from_errno("recallocarray"); | |||
201 | goto done; | |||
202 | } | |||
203 | ||||
204 | i = 0; | |||
205 | TAILQ_FOREACH(node, §ions->fields, link)for((node) = ((§ions->fields)->tqh_first); (node ) != ((void *)0); (node) = ((node)->link.tqe_next)) { | |||
206 | char *name, *end, *mirror; | |||
207 | ||||
208 | if (strncasecmp("remote \"", node->field, 8) != 0) | |||
209 | continue; | |||
210 | ||||
211 | name = strdup(node->field + 8); | |||
212 | if (name == NULL((void *)0)) { | |||
213 | err = got_error_from_errno("strdup"); | |||
214 | goto done; | |||
215 | } | |||
216 | end = strrchr(name, '"'); | |||
217 | if (end) | |||
218 | *end = '\0'; | |||
219 | remotes[i].name = name; | |||
220 | ||||
221 | remotes[i].url = got_gitconfig_get_str(gitconfig, | |||
222 | node->field, "url"); | |||
223 | if (remotes[i].url == NULL((void *)0)) { | |||
224 | err = got_error(GOT_ERR_GITCONFIG_SYNTAX114); | |||
225 | goto done; | |||
226 | } | |||
227 | ||||
228 | remotes[i].mirror_references = 0; | |||
229 | mirror = got_gitconfig_get_str(gitconfig, node->field, | |||
230 | "mirror"); | |||
231 | if (mirror != NULL((void *)0) && get_boolean_val(mirror)) | |||
232 | remotes[i].mirror_references = 1; | |||
233 | ||||
234 | i++; | |||
235 | } | |||
236 | ||||
237 | err = send_gitconfig_remotes(ibuf, remotes, nremotes); | |||
238 | done: | |||
239 | for (i = 0; i < nremotes; i++) | |||
240 | free(remotes[i].name); | |||
| ||||
241 | free(remotes); | |||
242 | got_gitconfig_free_list(sections); | |||
243 | return err; | |||
244 | } | |||
245 | ||||
246 | static const struct got_error * | |||
247 | gitconfig_owner_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) | |||
248 | { | |||
249 | char *value; | |||
250 | ||||
251 | if (gitconfig == NULL((void *)0)) | |||
252 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
253 | ||||
254 | value = got_gitconfig_get_str(gitconfig, "gotweb", "owner"); | |||
255 | if (value) | |||
256 | return send_gitconfig_str(ibuf, value); | |||
257 | value = got_gitconfig_get_str(gitconfig, "gitweb", "owner"); | |||
258 | return send_gitconfig_str(ibuf, value); | |||
259 | } | |||
260 | ||||
261 | static const struct got_error * | |||
262 | gitconfig_extensions_request(struct imsgbuf *ibuf, | |||
263 | struct got_gitconfig *gitconfig) | |||
264 | { | |||
265 | const struct got_error *err = NULL((void *)0); | |||
266 | struct got_gitconfig_list *tags; | |||
267 | struct got_gitconfig_list_node *node; | |||
268 | int nextensions = 0; | |||
269 | char *val; | |||
270 | ||||
271 | if (gitconfig == NULL((void *)0)) | |||
272 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
273 | ||||
274 | tags = got_gitconfig_get_tag_list(gitconfig, "extensions"); | |||
275 | if (tags == NULL((void *)0)) | |||
276 | return send_gitconfig_int(ibuf, 0); | |||
277 | ||||
278 | TAILQ_FOREACH(node, &tags->fields, link)for((node) = ((&tags->fields)->tqh_first); (node) != ((void *)0); (node) = ((node)->link.tqe_next)) { | |||
279 | val = got_gitconfig_get_str(gitconfig, "extensions", | |||
280 | node->field); | |||
281 | if (get_boolean_val(val)) | |||
282 | nextensions++; | |||
283 | } | |||
284 | ||||
285 | err = send_gitconfig_int(ibuf, nextensions); | |||
286 | if (err) | |||
287 | goto done; | |||
288 | ||||
289 | TAILQ_FOREACH(node, &tags->fields, link)for((node) = ((&tags->fields)->tqh_first); (node) != ((void *)0); (node) = ((node)->link.tqe_next)) { | |||
290 | val = got_gitconfig_get_str(gitconfig, "extensions", | |||
291 | node->field); | |||
292 | if (get_boolean_val(val)) { | |||
293 | err = send_gitconfig_str(ibuf, node->field); | |||
294 | if (err) | |||
295 | goto done; | |||
296 | } | |||
297 | } | |||
298 | done: | |||
299 | got_gitconfig_free_list(tags); | |||
300 | return err; | |||
301 | } | |||
302 | ||||
303 | int | |||
304 | main(int argc, char *argv[]) | |||
305 | { | |||
306 | const struct got_error *err = NULL((void *)0); | |||
307 | struct imsgbuf ibuf; | |||
308 | size_t datalen; | |||
309 | struct got_gitconfig *gitconfig = NULL((void *)0); | |||
310 | #if 0 | |||
311 | static int attached; | |||
312 | ||||
313 | while (!attached) | |||
314 | sleep(1); | |||
315 | #endif | |||
316 | signal(SIGINT2, catch_sigint); | |||
317 | ||||
318 | imsg_init(&ibuf, GOT_IMSG_FD_CHILD(2 + 1)); | |||
319 | ||||
320 | #ifndef PROFILE | |||
321 | /* revoke access to most system calls */ | |||
322 | if (pledge("stdio recvfd", NULL((void *)0)) == -1) { | |||
| ||||
323 | err = got_error_from_errno("pledge"); | |||
324 | got_privsep_send_error(&ibuf, err); | |||
325 | return 1; | |||
326 | } | |||
327 | #endif | |||
328 | ||||
329 | for (;;) { | |||
330 | struct imsg imsg; | |||
331 | ||||
332 | memset(&imsg, 0, sizeof(imsg)); | |||
333 | imsg.fd = -1; | |||
334 | ||||
335 | if (sigint_received) { | |||
336 | err = got_error(GOT_ERR_CANCELLED49); | |||
337 | break; | |||
338 | } | |||
339 | ||||
340 | err = got_privsep_recv_imsg(&imsg, &ibuf, 0); | |||
341 | if (err) { | |||
342 | if (err->code == GOT_ERR_PRIVSEP_PIPE37) | |||
343 | err = NULL((void *)0); | |||
344 | break; | |||
345 | } | |||
346 | ||||
347 | if (imsg.hdr.type == GOT_IMSG_STOP) | |||
348 | break; | |||
349 | ||||
350 | switch (imsg.hdr.type) { | |||
351 | case GOT_IMSG_GITCONFIG_PARSE_REQUEST: | |||
352 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
353 | if (datalen != 0) { | |||
354 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
355 | break; | |||
356 | } | |||
357 | if (imsg.fd == -1){ | |||
358 | err = got_error(GOT_ERR_PRIVSEP_NO_FD38); | |||
359 | break; | |||
360 | } | |||
361 | ||||
362 | if (gitconfig
| |||
363 | got_gitconfig_close(gitconfig); | |||
364 | err = got_gitconfig_open(&gitconfig, imsg.fd); | |||
365 | break; | |||
366 | case GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST: | |||
367 | err = gitconfig_num_request(&ibuf, gitconfig, "core", | |||
368 | "repositoryformatversion", 0); | |||
369 | break; | |||
370 | case GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST: | |||
371 | err = gitconfig_extensions_request(&ibuf, gitconfig); | |||
372 | break; | |||
373 | case GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST: | |||
374 | err = gitconfig_str_request(&ibuf, gitconfig, "user", | |||
375 | "name"); | |||
376 | break; | |||
377 | case GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST: | |||
378 | err = gitconfig_str_request(&ibuf, gitconfig, "user", | |||
379 | "email"); | |||
380 | break; | |||
381 | case GOT_IMSG_GITCONFIG_REMOTES_REQUEST: | |||
382 | err = gitconfig_remotes_request(&ibuf, gitconfig); | |||
383 | break; | |||
384 | case GOT_IMSG_GITCONFIG_OWNER_REQUEST: | |||
385 | err = gitconfig_owner_request(&ibuf, gitconfig); | |||
386 | break; | |||
387 | default: | |||
388 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
389 | break; | |||
390 | } | |||
391 | ||||
392 | if (imsg.fd != -1) { | |||
393 | if (close(imsg.fd) == -1 && err == NULL((void *)0)) | |||
394 | err = got_error_from_errno("close"); | |||
395 | } | |||
396 | ||||
397 | imsg_free(&imsg); | |||
398 | if (err) | |||
399 | break; | |||
400 | } | |||
401 | ||||
402 | imsg_clear(&ibuf); | |||
403 | if (err) { | |||
404 | if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE37) { | |||
405 | fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), err->msg); | |||
406 | got_privsep_send_error(&ibuf, err); | |||
407 | } | |||
408 | } | |||
409 | if (close(GOT_IMSG_FD_CHILD(2 + 1)) == -1 && err == NULL((void *)0)) | |||
410 | err = got_error_from_errno("close"); | |||
411 | return err ? 1 : 0; | |||
412 | } |