commit - 06efacffbc9efa9ab5a6f1337e8c7acbffa0e6ee
commit + d35d2167be33e815e3cd3e27cfbabc900e53d254
blob - bde278404461202ccc124ec456b9c0009d3e7807
blob + e7ad89121d041135c012b97ce014e7fbc805ba10
--- gotwebd/auth.c
+++ gotwebd/auth.c
#include <unistd.h>
#include <openssl/bio.h>
+#include <openssl/buffer.h>
#include <openssl/evp.h>
+#include <openssl/hmac.h>
#include "got_error.h"
#include "got_reference.h"
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.
*/
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)
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;
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;