static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf) { 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. */ if (buf_len < 8) { return NT_STATUS_BUFFER_TOO_SMALL; } in_buf.value = buf + 8; in_buf.length = buf_len - 8; ret = gss_unwrap(&minor, gss_ctx, &in_buf, &out_buf, &flags_got, /* did we get sign+seal ? */ (gss_qop_t *) NULL); 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_decrypt_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 (out_buf.length > in_buf.length) { DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap size (%u) too large (%u) !\n", (unsigned int)out_buf.length, (unsigned int)in_buf.length )); gss_release_buffer(&minor, &out_buf); return NT_STATUS_INVALID_PARAMETER; } memcpy(buf + 8, out_buf.value, out_buf.length); /* Reset the length and overwrite the header. */ smb_setlen_nbt(buf, out_buf.length + 4); gss_release_buffer(&minor, &out_buf); return NT_STATUS_OK; }
NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num) { if (smb_len_nbt(buf) < 8) { return NT_STATUS_INVALID_BUFFER_SIZE; } if (buf[4] == 0xFF) { if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') { /* Not an encrypted buffer. */ return NT_STATUS_NOT_FOUND; } if (buf[5] == 'E') { *p_enc_ctx_num = SVAL(buf,6); return NT_STATUS_OK; } } return NT_STATUS_INVALID_NETWORK_RESPONSE; }
static NTSTATUS common_gensec_decrypt_buffer(struct gensec_security *gensec, char *buf) { NTSTATUS status; size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */ DATA_BLOB in_buf, out_buf; TALLOC_CTX *frame; if (buf_len < 8) { return NT_STATUS_BUFFER_TOO_SMALL; } frame = talloc_stackframe(); in_buf = data_blob_const(buf + 8, buf_len - 8); status = gensec_unwrap(gensec, frame, &in_buf, &out_buf); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap failed. Error %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } if (out_buf.length > in_buf.length) { DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap size (%u) too large (%u) !\n", (unsigned int)out_buf.length, (unsigned int)in_buf.length )); TALLOC_FREE(frame); return NT_STATUS_INVALID_PARAMETER; } memcpy(buf + 8, out_buf.data, out_buf.length); /* Reset the length and overwrite the header. */ smb_setlen_nbt(buf, out_buf.length + 4); TALLOC_FREE(frame); return NT_STATUS_OK; }
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; }