static NTSTATUS common_gensec_encrypt_buffer(struct gensec_security *gensec, uint16_t enc_ctx_num, char *buf, char **ppbuf_out) { NTSTATUS status; DATA_BLOB in_buf, out_buf; size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */ TALLOC_CTX *frame; *ppbuf_out = NULL; if (buf_len < 8) { return NT_STATUS_BUFFER_TOO_SMALL; } in_buf = data_blob_const(buf + 8, buf_len - 8); frame = talloc_stackframe(); status = gensec_wrap(gensec, frame, &in_buf, &out_buf); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("common_gensec_encrypt_buffer: gensec_wrap failed. Error %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */ if (!*ppbuf_out) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } memcpy(*ppbuf_out+8, out_buf.data, out_buf.length); smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num); TALLOC_FREE(frame); return NT_STATUS_OK; }
static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state, uint16_t enc_ctx_num, char *buf, char **ppbuf_out) { gss_ctx_id_t gss_ctx = gss_state->gss_ctx; OM_uint32 ret = 0; OM_uint32 minor = 0; int flags_got = 0; gss_buffer_desc in_buf, out_buf; size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */ *ppbuf_out = NULL; if (buf_len < 8) { return NT_STATUS_BUFFER_TOO_SMALL; } in_buf.value = buf + 8; in_buf.length = buf_len - 8; ret = gss_wrap(&minor, gss_ctx, true, /* we want sign+seal. */ GSS_C_QOP_DEFAULT, &in_buf, &flags_got, /* did we get sign+seal ? */ &out_buf); if (ret != GSS_S_COMPLETE) { NTSTATUS status = NT_STATUS_ACCESS_DENIED; char *gss_err; gss_err = gssapi_error_string(talloc_tos(), ret, minor, GSS_C_NULL_OID); DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. " "Error [%d/%d] - %s - %s\n", ret, minor, nt_errstr(status), gss_err ? gss_err : "<unknown>")); talloc_free(gss_err); return status; } if (!flags_got) { /* Sign+seal not supported. */ gss_release_buffer(&minor, &out_buf); return NT_STATUS_NOT_SUPPORTED; } /* Ya see - this is why I *hate* gss-api. I don't * want to have to malloc another buffer of the * same size + 8 bytes just to get a continuous * header + buffer, but gss won't let me pass in * a pre-allocated buffer. Bastards (and you know * who you are....). I might fix this by * going to "encrypt_and_send" passing in a file * descriptor and doing scatter-gather write with * TCP cork on Linux. But I shouldn't have to * bother :-*(. JRA. */ *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */ if (!*ppbuf_out) { gss_release_buffer(&minor, &out_buf); return NT_STATUS_NO_MEMORY; } memcpy(*ppbuf_out+8, out_buf.value, out_buf.length); smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num); gss_release_buffer(&minor, &out_buf); return NT_STATUS_OK; }