2 * Copyright (c) 2024 Omar Polo <op@openbsd.org>
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.
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.
22 #include "got_error.h"
27 static const struct got_error *
28 push(struct gotd_secrets *s, enum gotd_secret_type type, const char *label,
29 const char *user, const char *pass, const char *hmac)
34 if (s->len == s->cap) {
36 t = reallocarray(s->secrets, newcap, sizeof(*s->secrets));
38 return got_error_from_errno("reallocarray");
44 memset(&s->secrets[i], 0, sizeof(s->secrets[i]));
45 s->secrets[i].type = type;
46 s->secrets[i].label = strdup(label);
47 if (s->secrets[i].label == NULL)
48 return got_error_from_errno("strdup");
50 if (type == GOTD_SECRET_AUTH) {
51 s->secrets[i].user = strdup(user);
52 if (s->secrets[i].user == NULL)
53 return got_error_from_errno("strdup");
54 s->secrets[i].pass = strdup(pass);
55 if (s->secrets[i].pass == NULL)
56 return got_error_from_errno("strdup");
58 s->secrets[i].hmac = strdup(hmac);
59 if (s->secrets[i].hmac == NULL)
60 return got_error_from_errno("strdup");
68 read_word(char **word, const char *path, int lineno, char *s)
73 s += strspn(s, " \t");
75 log_warnx("%s:%d syntax error", path, lineno);
100 if (*s == '\'' || *s == '\"') {
106 if (!quote && (*s == ' ' || *s == '\t')) {
115 log_warnx("%s:%d no closing quote", path, lineno);
120 log_warnx("%s:%d unterminated escape at end of line",
130 read_keyword(char **kw, const char *path, int lineno, char *s)
132 s += strspn(s, " \t");
134 log_warnx("%s:%d syntax error", path, lineno);
139 s += strcspn(s, " \t");
145 static const struct got_error *
146 parse_line(struct gotd_secrets *secrets, const char *path, int lineno,
150 char *user = NULL, *pass = NULL, *hmac = NULL;
151 enum gotd_secret_type type;
153 line = read_keyword(&kw, path, lineno, line);
155 return got_error(GOT_ERR_PARSE_CONFIG);
157 if (!strcmp(kw, "auth"))
158 type = GOTD_SECRET_AUTH;
159 else if (!strcmp(kw, "hmac"))
160 type = GOTD_SECRET_HMAC;
162 log_warnx("%s:%d syntax error", path, lineno);
163 return got_error(GOT_ERR_PARSE_CONFIG);
166 line = read_word(&label, path, lineno, line);
168 return got_error(GOT_ERR_PARSE_CONFIG);
170 if (type == GOTD_SECRET_AUTH) {
171 line = read_keyword(&kw, path, lineno, line);
173 return got_error(GOT_ERR_PARSE_CONFIG);
174 if (strcmp(kw, "user") != 0) {
175 log_warnx("%s:%d syntax error", path, lineno);
176 return got_error(GOT_ERR_PARSE_CONFIG);
179 line = read_word(&user, path, lineno, line);
181 return got_error(GOT_ERR_PARSE_CONFIG);
183 line = read_keyword(&kw, path, lineno, line);
185 return got_error(GOT_ERR_PARSE_CONFIG);
186 if (strcmp(kw, "password") != 0) {
187 log_warnx("%s:%d syntax error", path, lineno);
188 return got_error(GOT_ERR_PARSE_CONFIG);
191 line = read_word(&pass, path, lineno, line);
193 return got_error(GOT_ERR_PARSE_CONFIG);
195 line = read_word(&hmac, path, lineno, line);
197 return got_error(GOT_ERR_PARSE_CONFIG);
200 line += strspn(line, " \t");
202 log_warnx("%s:%d syntax error", path, lineno);
203 return got_error(GOT_ERR_PARSE_CONFIG);
206 if (gotd_secrets_get(secrets, type, label) != NULL) {
207 log_warnx("%s:%d duplicate %s entry %s", path, lineno,
208 type == GOTD_SECRET_AUTH ? "auth" : "hmac", label);
209 return got_error(GOT_ERR_PARSE_CONFIG);
212 return push(secrets, type, label, user, pass, hmac);
215 const struct got_error *
216 gotd_secrets_parse(const char *path, FILE *fp, struct gotd_secrets **s)
218 const struct got_error *err = NULL;
224 struct gotd_secrets *secrets;
228 secrets = calloc(1, sizeof(*secrets));
230 return got_error_from_errno("calloc");
232 while ((linelen = getline(&line, &linesize, fp)) != -1) {
234 if (line[linelen - 1] == '\n')
235 line[--linelen] = '\0';
237 for (t = line; *t == ' ' || *t == '\t'; ++t)
240 if (*t == '\0' || *t == '#')
243 err = parse_line(secrets, path, lineno, t);
248 if (ferror(fp) && err == NULL)
249 err = got_error_from_errno("getline");
252 gotd_secrets_free(secrets);
261 gotd_secrets_get(struct gotd_secrets *s, enum gotd_secret_type type,
266 for (i = 0; i < s->len; ++i) {
267 if (s->secrets[i].type != type)
269 if (strcmp(s->secrets[i].label, label) != 0)
271 return &s->secrets[i];
278 gotd_secrets_free(struct gotd_secrets *s)
285 for (i = 0; i < s->len; ++i) {
286 free(s->secrets[i].label);
287 free(s->secrets[i].user);
288 free(s->secrets[i].pass);
289 free(s->secrets[i].hmac);