static void *daemon_conn_thread(void *_sock_fd) { int sock_fd = (int)((char *)_sock_fd - (char *)NULL); struct expbuf_t buf = {}; unsigned char auth_token[NEVERBLEED_AUTH_TOKEN_SIZE]; /* authenticate */ if (read_nbytes(sock_fd, &auth_token, sizeof(auth_token)) != 0) { warnf("failed to receive authencication token from client"); goto Exit; } if (memcmp(auth_token, daemon_auth_token, NEVERBLEED_AUTH_TOKEN_SIZE) != 0) { warnf("client authentication failed"); goto Exit; } while (1) { char *cmd; if (expbuf_read(&buf, sock_fd) != 0) { if (errno != 0) warnf("read error"); break; } if ((cmd = expbuf_shift_str(&buf)) == NULL) { errno = 0; warnf("failed to parse request"); break; } if (strcmp(cmd, "priv_enc") == 0) { if (priv_enc_stub(&buf) != 0) break; } else if (strcmp(cmd, "priv_dec") == 0) { if (priv_dec_stub(&buf) != 0) break; } else if (strcmp(cmd, "sign") == 0) { if (sign_stub(&buf) != 0) break; } else if (strcmp(cmd, "load_key") == 0) { if (load_key_stub(&buf) != 0) break; } else if (strcmp(cmd, "setuidgid") == 0) { if (setuidgid_stub(&buf) != 0) break; } else { warnf("unknown command:%s", cmd); break; } if (expbuf_write(&buf, sock_fd) != 0) { warnf(errno != 0 ? "write error" : "connection closed by client"); break; } expbuf_dispose(&buf); } Exit: expbuf_dispose(&buf); close(sock_fd); return NULL; }
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 load_key_stub(struct expbuf_t *buf) { char *fn; FILE *fp = NULL; RSA *rsa = NULL; size_t key_index = SIZE_MAX; char *estr = NULL, *nstr = NULL, errbuf[NEVERBLEED_ERRBUF_SIZE] = ""; if ((fn = expbuf_shift_str(buf)) == NULL) { warnf("%s: failed to parse request", __FUNCTION__); return -1; } if ((fp = fopen(fn, "rt")) == NULL) { strerror_r(errno, errbuf, sizeof(errbuf)); goto Respond; } if ((rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) { snprintf(errbuf, sizeof(errbuf), "failed to parse the private key"); goto Respond; } key_index = daemon_set_rsa(rsa); estr = BN_bn2hex(rsa->e); nstr = BN_bn2hex(rsa->n); Respond: expbuf_dispose(buf); expbuf_push_num(buf, rsa != NULL); expbuf_push_num(buf, key_index); expbuf_push_str(buf, estr != NULL ? estr : ""); expbuf_push_str(buf, nstr != NULL ? nstr : ""); expbuf_push_str(buf, errbuf); if (rsa != NULL) RSA_free(rsa); if (estr != NULL) OPENSSL_free(estr); if (nstr != NULL) OPENSSL_free(nstr); if (fp != NULL) fclose(fp); return 0; }
static int setuidgid_stub(struct expbuf_t *buf) { const char *user; struct passwd pwbuf, *pw; char pwstrbuf[65536]; /* should be large enough */ int ret = -1; if ((user = expbuf_shift_str(buf)) == NULL) { 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 (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; }