commit d35d2167be33e815e3cd3e27cfbabc900e53d254 from: Omar Polo date: Sat May 31 22:27:28 2025 UTC actually implement the token generation commit - 06efacffbc9efa9ab5a6f1337e8c7acbffa0e6ee commit + d35d2167be33e815e3cd3e27cfbabc900e53d254 blob - bde278404461202ccc124ec456b9c0009d3e7807 blob + e7ad89121d041135c012b97ce014e7fbc805ba10 --- gotwebd/auth.c +++ gotwebd/auth.c @@ -29,7 +29,9 @@ #include #include +#include #include +#include #include "got_error.h" #include "got_reference.h" @@ -49,10 +51,20 @@ struct gotwebd_auth_client { static volatile int client_cnt; static int inflight; +static char token_secret[32]; + +#if 0 +int +auth_init(void) +{ + arc4random_buf(token_secret); +} +#endif + /* * The token format is: * - * "v1"[issued at/64bit][expire/64bit][username]"\0"[host] + * "v1"[issued at/64bit][expire/64bit][username]"\0"[host]"\0" * * followed by the HMAC-SHA256 of it, all encoded in base64. */ @@ -75,6 +87,93 @@ auth_check_token(const char *token) return !strcmp(token, "42"); } +/* */ +static char * +auth_gen_token(const char *username, const char *hostname) +{ + BIO *bmem, *b64; + BUF_MEM *bufm; + char hmac[EVP_MAX_MD_SIZE]; + char *enc; + FILE *fp; + char *tok; + uint64_t issued, expire; /* assume size_t(time_t) == 8 */ + size_t siz, ulen, hlen; + unsigned int hmaclen; /* openssl... */ + + issued = time(NULL); + expire = issued + (24 * 60 * 60); /* now + 1 day */ + + fp = open_memstream(&tok, &siz); + if (fp == NULL) + return NULL; + + /* include NUL */ + ulen = strlen(username) + 1; + hlen = strlen(hostname) + 1; + + if (fwrite("v1", 1, 3, fp) != 3 || + fwrite(&issued, 1, 8, fp) != 8 || + fwrite(&expire, 1, 8, fp) != 8 || + fwrite(username, 1, ulen, fp) != ulen || + fwrite(hostname, 1, hlen, fp) != hlen) { + fclose(fp); + free(tok); + return NULL; + } + + if (fclose(fp) == EOF) { + free(tok); + return NULL; + } + + if (siz > INT_MAX) { + /* + * can't really happen, isn't it? yet, openssl + * sometimes likes to take ints so I'd prefer to + * assert. + */ + free(tok); + return NULL; + } + + if (HMAC(EVP_sha256(), token_secret, sizeof(token_secret), tok, siz, + hmac, &hmaclen) == NULL) { + free(tok); + return NULL; + } + + bmem = BIO_new(BIO_s_mem()); + if (bmem == NULL) { + free(tok); + return NULL; + } + + b64 = BIO_new(BIO_f_base64()); + if (b64 == NULL) { + free(tok); + return NULL; + } + + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + b64 = BIO_push(b64, bmem); + + if (BIO_write(b64, tok, siz) != (int)siz || + BIO_write(b64, hmac, hmaclen) != hmaclen || + BIO_flush(b64) <= 0) { + free(tok); + BIO_free_all(b64); + return NULL; + } + + BIO_get_mem_ptr(b64, &bufm); + enc = strndup(bufm->data, bufm->length); + + free(tok); + BIO_free_all(b64); + return enc; +} + static int auth_socket_listen(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid) @@ -234,7 +333,7 @@ client_read(struct bufferevent *bev, void *d) struct gotwebd_auth_client *client = d; struct evbuffer *in = EVBUFFER_INPUT(bev); struct evbuffer *out = EVBUFFER_OUTPUT(bev); - char *line, *cmd; + char *line, *cmd, *code; size_t linelen; const char *hostname; @@ -262,16 +361,22 @@ client_read(struct bufferevent *bev, void *d) cmd += strspn(cmd, " \t"); hostname = cmd; - /* do something with hostname */ - /* xxx */ - const char *code = "42"; + /* XXX */ + code = auth_gen_token("op", hostname); + if (code == NULL) { + log_warn("%s: auth_gen_token failed", __func__); + client_err(bev, EVBUFFER_READ, client); + return; + } if (evbuffer_add_printf(out, "ok https://%s/?login=%s\n", hostname, code) == -1) { log_warnx("%s: evbuffer_add_printf failed", __func__); client_err(bev, EVBUFFER_READ, client); + free(code); return; } + free(code); client->cmd_done = 1; return;