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.
17 #include "got_compat.h"
24 #include "got_error.h"
29 static const struct got_error
*
30 push(struct gotd_secrets
*s
, enum gotd_secret_type type
, const char *label
,
31 const char *user
, const char *pass
, const char *hmac
)
36 if (s
->len
== s
->cap
) {
38 t
= reallocarray(s
->secrets
, newcap
, sizeof(*s
->secrets
));
40 return got_error_from_errno("reallocarray");
46 memset(&s
->secrets
[i
], 0, sizeof(s
->secrets
[i
]));
47 s
->secrets
[i
].type
= type
;
48 s
->secrets
[i
].label
= strdup(label
);
49 if (s
->secrets
[i
].label
== NULL
)
50 return got_error_from_errno("strdup");
52 if (type
== GOTD_SECRET_AUTH
) {
53 s
->secrets
[i
].user
= strdup(user
);
54 if (s
->secrets
[i
].user
== NULL
)
55 return got_error_from_errno("strdup");
56 s
->secrets
[i
].pass
= strdup(pass
);
57 if (s
->secrets
[i
].pass
== NULL
)
58 return got_error_from_errno("strdup");
60 s
->secrets
[i
].hmac
= strdup(hmac
);
61 if (s
->secrets
[i
].hmac
== NULL
)
62 return got_error_from_errno("strdup");
70 read_word(char **word
, const char *path
, int lineno
, char *s
)
75 s
+= strspn(s
, " \t");
77 log_warnx("%s:%d syntax error", path
, lineno
);
102 if (*s
== '\'' || *s
== '\"') {
108 if (!quote
&& (*s
== ' ' || *s
== '\t')) {
117 log_warnx("%s:%d no closing quote", path
, lineno
);
122 log_warnx("%s:%d unterminated escape at end of line",
132 read_keyword(char **kw
, const char *path
, int lineno
, char *s
)
134 s
+= strspn(s
, " \t");
136 log_warnx("%s:%d syntax error", path
, lineno
);
141 s
+= strcspn(s
, " \t");
147 static const struct got_error
*
148 parse_line(struct gotd_secrets
*secrets
, const char *path
, int lineno
,
152 char *user
= NULL
, *pass
= NULL
, *hmac
= NULL
;
153 enum gotd_secret_type type
;
155 line
= read_keyword(&kw
, path
, lineno
, line
);
157 return got_error(GOT_ERR_PARSE_CONFIG
);
159 if (!strcmp(kw
, "auth"))
160 type
= GOTD_SECRET_AUTH
;
161 else if (!strcmp(kw
, "hmac"))
162 type
= GOTD_SECRET_HMAC
;
164 log_warnx("%s:%d syntax error", path
, lineno
);
165 return got_error(GOT_ERR_PARSE_CONFIG
);
168 line
= read_word(&label
, path
, lineno
, line
);
170 return got_error(GOT_ERR_PARSE_CONFIG
);
172 if (type
== GOTD_SECRET_AUTH
) {
173 line
= read_keyword(&kw
, path
, lineno
, line
);
175 return got_error(GOT_ERR_PARSE_CONFIG
);
176 if (strcmp(kw
, "user") != 0) {
177 log_warnx("%s:%d syntax error", path
, lineno
);
178 return got_error(GOT_ERR_PARSE_CONFIG
);
181 line
= read_word(&user
, path
, lineno
, line
);
183 return got_error(GOT_ERR_PARSE_CONFIG
);
185 line
= read_keyword(&kw
, path
, lineno
, line
);
187 return got_error(GOT_ERR_PARSE_CONFIG
);
188 if (strcmp(kw
, "password") != 0) {
189 log_warnx("%s:%d syntax error", path
, lineno
);
190 return got_error(GOT_ERR_PARSE_CONFIG
);
193 line
= read_word(&pass
, path
, lineno
, line
);
195 return got_error(GOT_ERR_PARSE_CONFIG
);
197 line
= read_word(&hmac
, path
, lineno
, line
);
199 return got_error(GOT_ERR_PARSE_CONFIG
);
202 line
+= strspn(line
, " \t");
204 log_warnx("%s:%d syntax error", path
, lineno
);
205 return got_error(GOT_ERR_PARSE_CONFIG
);
208 if (gotd_secrets_get(secrets
, type
, label
) != NULL
) {
209 log_warnx("%s:%d duplicate %s entry %s", path
, lineno
,
210 type
== GOTD_SECRET_AUTH
? "auth" : "hmac", label
);
211 return got_error(GOT_ERR_PARSE_CONFIG
);
214 return push(secrets
, type
, label
, user
, pass
, hmac
);
217 const struct got_error
*
218 gotd_secrets_parse(const char *path
, FILE *fp
, struct gotd_secrets
**s
)
220 const struct got_error
*err
= NULL
;
226 struct gotd_secrets
*secrets
;
230 secrets
= calloc(1, sizeof(*secrets
));
232 return got_error_from_errno("calloc");
234 while ((linelen
= getline(&line
, &linesize
, fp
)) != -1) {
236 if (line
[linelen
- 1] == '\n')
237 line
[--linelen
] = '\0';
239 for (t
= line
; *t
== ' ' || *t
== '\t'; ++t
)
242 if (*t
== '\0' || *t
== '#')
245 err
= parse_line(secrets
, path
, lineno
, t
);
250 if (ferror(fp
) && err
== NULL
)
251 err
= got_error_from_errno("getline");
254 gotd_secrets_free(secrets
);
263 gotd_secrets_get(struct gotd_secrets
*s
, enum gotd_secret_type type
,
268 for (i
= 0; i
< s
->len
; ++i
) {
269 if (s
->secrets
[i
].type
!= type
)
271 if (strcmp(s
->secrets
[i
].label
, label
) != 0)
273 return &s
->secrets
[i
];
280 gotd_secrets_free(struct gotd_secrets
*s
)
287 for (i
= 0; i
< s
->len
; ++i
) {
288 free(s
->secrets
[i
].label
);
289 free(s
->secrets
[i
].user
);
290 free(s
->secrets
[i
].pass
);
291 free(s
->secrets
[i
].hmac
);