diff --git a/src/ceoc.c b/src/ceoc.c index d6ada68d8..dc9029d70 100644 --- a/src/ceoc.c +++ b/src/ceoc.c @@ -70,6 +70,7 @@ void run_remote(struct op *op, struct strbuf *in, struct strbuf *out) { int sock = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); struct sockaddr_in addr; struct sctp_meta response_meta; + struct strbuf in_cipher = STRBUF_INIT, out_cipher = STRBUF_INIT; if (!in->len) fatal("no data to send"); @@ -96,19 +97,26 @@ void run_remote(struct op *op, struct strbuf *in, struct strbuf *out) { client_acquire_creds("ceod", hostname); client_gss_auth(sock, (sa *)&addr, sizeof(addr)); - if (sctp_sendmsg(sock, in->buf, in->len, (struct sockaddr *)&addr, + gss_encipher(in, &in_cipher); + + if (sctp_sendmsg(sock, in_cipher.buf, in_cipher.len, (struct sockaddr *)&addr, sizeof(addr), op->id, 0, 0, 0, 0) < 0) fatalpe("sctp_sendmsg"); - if (!receive_one_message(sock, &response_meta, out)) + if (!receive_one_message(sock, &response_meta, &out_cipher)) fatal("no response received for op %s", op->name); + gss_decipher(&out_cipher, out); + if (response_meta.sinfo.sinfo_ppid != op->id) fatal("wrong ppid from server: expected %d got %d", op->id, response_meta.sinfo.sinfo_ppid); if (sctp_sendmsg(sock, NULL, 0, (struct sockaddr *)&addr, sizeof(addr), 0, SCTP_EOF, 0, 0 ,0) < 0) fatalpe("sctp_sendmsg"); + + strbuf_release(&in_cipher); + strbuf_release(&out_cipher); } int client_main(char *op_name) { diff --git a/src/dslave.c b/src/dslave.c index a5e915c56..8bd511f34 100644 --- a/src/dslave.c +++ b/src/dslave.c @@ -82,6 +82,7 @@ static void handle_auth_message(struct strbuf *in, struct strbuf *out) { static void handle_op_message(uint32_t in_type, struct strbuf *in, struct strbuf *out) { struct op *op = get_local_op(in_type); + struct strbuf in_plain = STRBUF_INIT, out_plain = STRBUF_INIT; char *envp[16]; if (!op) @@ -93,17 +94,23 @@ static void handle_op_message(uint32_t in_type, struct strbuf *in, struct strbuf if (!client_username()) fatal("unathenticated"); + gss_decipher(in, &in_plain); + make_env(envp, "LANG", "C", "CEO_USER", client_username(), "CEO_CONFIG_DIR", config_dir, NULL); char *argv[] = { op->path, NULL, }; - if (spawnvemu(op->path, argv, envp, in, out, 0, op->user)) + if (spawnvemu(op->path, argv, envp, &in_plain, &out_plain, 0, op->user)) fatal("child %s failed", op->path); + gss_encipher(&out_plain, out); + if (!out->len) fatal("no response from op"); free_env(envp); + strbuf_release(&in_plain); + strbuf_release(&out_plain); } static void handle_one_message(int sock, struct sctp_meta *in_meta, struct strbuf *in) { diff --git a/src/gss.c b/src/gss.c index c963d4856..12e6ac420 100644 --- a/src/gss.c +++ b/src/gss.c @@ -234,3 +234,51 @@ char *client_username(void) { return peer_username; } +void gss_encipher(struct strbuf *plain, struct strbuf *cipher) { + OM_uint32 maj_stat, min_stat; + gss_buffer_desc plain_tok, cipher_tok; + int conf_state; + + plain_tok.value = plain->buf; + plain_tok.length = plain->len; + + maj_stat = gss_wrap(&min_stat, context_handle, 1, GSS_C_QOP_DEFAULT, + &plain_tok, &conf_state, &cipher_tok); + if (maj_stat != GSS_S_COMPLETE) + gss_fatal("gss_wrap", maj_stat, min_stat); + + if (!conf_state) + fatal("gss_encipher: confidentiality service required"); + + strbuf_add(cipher, cipher_tok.value, cipher_tok.length); + + maj_stat = gss_release_buffer(&min_stat, &cipher_tok); + if (maj_stat != GSS_S_COMPLETE) + gss_fatal("gss_release_buffer", maj_stat, min_stat); +} + +void gss_decipher(struct strbuf *cipher, struct strbuf *plain) { + OM_uint32 maj_stat, min_stat; + gss_buffer_desc plain_tok, cipher_tok; + int conf_state; + gss_qop_t qop_state; + + cipher_tok.value = cipher->buf; + cipher_tok.length = cipher->len; + + maj_stat = gss_unwrap(&min_stat, context_handle, &cipher_tok, + &plain_tok, &conf_state, &qop_state); + if (maj_stat != GSS_S_COMPLETE) + gss_fatal("gss_unwrap", maj_stat, min_stat); + + if (!conf_state) + fatal("gss_encipher: confidentiality service required"); + + strbuf_add(plain, plain_tok.value, plain_tok.length); + + maj_stat = gss_release_buffer(&min_stat, &plain_tok); + if (maj_stat != GSS_S_COMPLETE) + gss_fatal("gss_release_buffer", maj_stat, min_stat); +} + + diff --git a/src/gss.h b/src/gss.h index 9a14a6162..a48464789 100644 --- a/src/gss.h +++ b/src/gss.h @@ -10,3 +10,6 @@ int initial_client_token(gss_buffer_t outgoing_tok); char *client_principal(void); char *client_username(void); void free_gss(void); + +void gss_encipher(struct strbuf *plain, struct strbuf *cipher); +void gss_decipher(struct strbuf *cipher, struct strbuf *plain);