static int priv_encdec_stub(const char *name, int (*func)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), struct expbuf_t *buf) { unsigned char *from, to[4096]; size_t flen; size_t key_index, padding; RSA *rsa; int ret; if ((from = expbuf_shift_bytes(buf, &flen)) == NULL || expbuf_shift_num(buf, &key_index) != 0 || expbuf_shift_num(buf, &padding) != 0) { errno = 0; warnf("%s: failed to parse request", name); return -1; } if ((rsa = daemon_get_rsa(key_index)) == NULL) { errno = 0; warnf("%s: invalid key index:%zu\n", name, key_index); return -1; } ret = func((int)flen, from, to, rsa, (int)padding); expbuf_dispose(buf); expbuf_push_num(buf, ret); expbuf_push_bytes(buf, to, ret > 0 ? ret : 0); return 0; }
static int sign_stub(struct expbuf_t *buf) { unsigned char *m, sigret[4096]; size_t type, m_len, key_index; RSA *rsa; unsigned siglen = 0; int ret; if (expbuf_shift_num(buf, &type) != 0 || (m = expbuf_shift_bytes(buf, &m_len)) == NULL || expbuf_shift_num(buf, &key_index) != 0) { errno = 0; warnf("%s: failed to parse request", __FUNCTION__); return -1; } if ((rsa = daemon_get_rsa(key_index)) == NULL) { errno = 0; warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); return -1; } ret = RSA_sign((int)type, m, (unsigned)m_len, sigret, &siglen, rsa); expbuf_dispose(buf); expbuf_push_num(buf, ret); expbuf_push_bytes(buf, sigret, ret == 1 ? siglen : 0); return 0; }
static int sign_proxy(int type, const unsigned char *m, unsigned int m_len, unsigned char *_sigret, unsigned *_siglen, const RSA *rsa) { struct st_neverbleed_rsa_exdata_t *exdata; struct st_neverbleed_thread_data_t *thdata; struct expbuf_t buf = {}; size_t ret, siglen; unsigned char *sigret; get_privsep_data(rsa, &exdata, &thdata); expbuf_push_str(&buf, "sign"); expbuf_push_num(&buf, type); expbuf_push_bytes(&buf, m, m_len); expbuf_push_num(&buf, exdata->key_index); if (expbuf_write(&buf, thdata->fd) != 0) dief(errno != 0 ? "write error" : "connection closed by daemon"); expbuf_dispose(&buf); if (expbuf_read(&buf, thdata->fd) != 0) dief(errno != 0 ? "read error" : "connection closed by daemon"); if (expbuf_shift_num(&buf, &ret) != 0 || (sigret = expbuf_shift_bytes(&buf, &siglen)) == NULL) { errno = 0; dief("failed to parse response"); } memcpy(_sigret, sigret, siglen); *_siglen = (unsigned)siglen; expbuf_dispose(&buf); return (int)ret; }
static int priv_encdec_proxy(const char *cmd, int flen, const unsigned char *from, unsigned char *_to, RSA *rsa, int padding) { struct st_neverbleed_rsa_exdata_t *exdata; struct st_neverbleed_thread_data_t *thdata; struct expbuf_t buf = {}; size_t ret; unsigned char *to; size_t tolen; get_privsep_data(rsa, &exdata, &thdata); expbuf_push_str(&buf, cmd); expbuf_push_bytes(&buf, from, flen); expbuf_push_num(&buf, exdata->key_index); expbuf_push_num(&buf, padding); if (expbuf_write(&buf, thdata->fd) != 0) dief(errno != 0 ? "write error" : "connection closed by daemon"); expbuf_dispose(&buf); if (expbuf_read(&buf, thdata->fd) != 0) dief(errno != 0 ? "read error" : "connection closed by daemon"); if (expbuf_shift_num(&buf, &ret) != 0 || (to = expbuf_shift_bytes(&buf, &tolen)) == NULL) { errno = 0; dief("failed to parse response"); } memcpy(_to, to, tolen); expbuf_dispose(&buf); return (int)ret; }
static void *expbuf_shift_bytes(struct expbuf_t *buf, size_t *l) { void *ret; if (expbuf_shift_num(buf, l) != 0) return NULL; if (expbuf_size(buf) < *l) return NULL; ret = buf->start; buf->start += *l; return ret; }
static int setuidgid_stub(struct expbuf_t *buf) { const char *user; size_t change_socket_ownership; struct passwd pwbuf, *pw; char pwstrbuf[65536]; /* should be large enough */ int ret = -1; if ((user = expbuf_shift_str(buf)) == NULL || expbuf_shift_num(buf, &change_socket_ownership) != 0) { errno = 0; warnf("%s: failed to parse request", __FUNCTION__); return -1; } errno = 0; if (getpwnam_r(user, &pwbuf, pwstrbuf, sizeof(pwstrbuf), &pw) != 0) { warnf("%s: getpwnam_r failed", __FUNCTION__); goto Respond; } if (pw == NULL) { warnf("%s: failed to obtain information of user:%s", __FUNCTION__, user); goto Respond; } if (change_socket_ownership) { char *dir; if (chown(daemon_vars.nb->sun_.sun_path, pw->pw_uid, pw->pw_gid) != 0) dief("chown failed for:%s", daemon_vars.nb->sun_.sun_path); dir = dirname(daemon_vars.nb->sun_.sun_path); if (chown(dir, pw->pw_uid, pw->pw_gid) != 0) dief("chown failed for:%s", dir); free(dir); } /* setuidgid */ if (setgid(pw->pw_gid) != 0) { warnf("%s: setgid(%d) failed", __FUNCTION__, (int)pw->pw_gid); goto Respond; } if (initgroups(pw->pw_name, pw->pw_gid) != 0) { warnf("%s: initgroups(%s, %d) failed", __FUNCTION__, pw->pw_name, (int)pw->pw_gid); goto Respond; } if (setuid(pw->pw_uid) != 0) { warnf("%s: setuid(%d) failed\n", __FUNCTION__, (int)pw->pw_uid); goto Respond; } ret = 0; Respond: expbuf_dispose(buf); expbuf_push_num(buf, ret); return 0; }
int neverbleed_load_private_key_file(neverbleed_t *nb, SSL_CTX *ctx, const char *fn, char *errbuf) { struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); struct expbuf_t buf = {}; size_t ret, key_index; char *estr, *nstr, *errstr; EVP_PKEY *pkey; expbuf_push_str(&buf, "load_key"); expbuf_push_str(&buf, fn); if (expbuf_write(&buf, thdata->fd) != 0) dief(errno != 0 ? "write error" : "connection closed by daemon"); expbuf_dispose(&buf); if (expbuf_read(&buf, thdata->fd) != 0) dief(errno != 0 ? "read error" : "connection closed by daemon"); if (expbuf_shift_num(&buf, &ret) != 0 || expbuf_shift_num(&buf, &key_index) != 0 || (estr = expbuf_shift_str(&buf)) == NULL || (nstr = expbuf_shift_str(&buf)) == NULL || (errstr = expbuf_shift_str(&buf)) == NULL) { errno = 0; dief("failed to parse response"); } if (ret != 1) { snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "%s", errstr); return -1; } /* success */ pkey = create_pkey(nb, key_index, estr, nstr); if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) { snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "SSL_CTX_use_PrivateKey failed"); ret = 0; } EVP_PKEY_free(pkey); return (int)ret; }
static int setuid_stub(struct expbuf_t *buf) { size_t uid; int ret; if (expbuf_shift_num(buf, &uid) != 0) { errno = 0; warnf("%s: failed to parse request", __FUNCTION__); return -1; } ret = setuid((uid_t)uid); expbuf_dispose(buf); expbuf_push_num(buf, ret); return 0; }
int neverbleed_setuidgid(neverbleed_t *nb, const char *user) { struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb); struct expbuf_t buf = {}; size_t ret; expbuf_push_str(&buf, "setuidgid"); expbuf_push_str(&buf, user); if (expbuf_write(&buf, thdata->fd) != 0) dief(errno != 0 ? "write error" : "connection closed by daemon"); expbuf_dispose(&buf); if (expbuf_read(&buf, thdata->fd) != 0) dief(errno != 0 ? "read error" : "connection closed by daemon"); if (expbuf_shift_num(&buf, &ret) != 0) { errno = 0; dief("failed to parse response"); } expbuf_dispose(&buf); return (int)ret; }