/* handle recv events on a smb_krb5 socket */ static void smb_krb5_socket_recv(struct smb_krb5_socket *smb_krb5) { TALLOC_CTX *tmp_ctx = talloc_new(smb_krb5); DATA_BLOB blob; size_t nread, dsize; smb_krb5->status = socket_pending(smb_krb5->sock, &dsize); if (!NT_STATUS_IS_OK(smb_krb5->status)) { talloc_free(tmp_ctx); return; } blob = data_blob_talloc(tmp_ctx, NULL, dsize); if (blob.data == NULL && dsize != 0) { smb_krb5->status = NT_STATUS_NO_MEMORY; talloc_free(tmp_ctx); return; } smb_krb5->status = socket_recv(smb_krb5->sock, blob.data, blob.length, &nread); if (!NT_STATUS_IS_OK(smb_krb5->status)) { talloc_free(tmp_ctx); return; } blob.length = nread; if (nread == 0) { smb_krb5->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; talloc_free(tmp_ctx); return; } DEBUG(4,("Received smb_krb5 packet of length %d\n", (int)blob.length)); talloc_steal(smb_krb5, blob.data); smb_krb5->reply = blob; talloc_free(tmp_ctx); }
/* handle recv events on a nbt dgram socket */ static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock) { TALLOC_CTX *tmp_ctx = talloc_new(dgmsock); NTSTATUS status; struct socket_address *src; DATA_BLOB blob; size_t nread, dsize; struct nbt_dgram_packet *packet; const char *mailslot_name; enum ndr_err_code ndr_err; status = socket_pending(dgmsock->sock, &dsize); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return; } blob = data_blob_talloc(tmp_ctx, NULL, dsize); if ((dsize != 0) && (blob.data == NULL)) { talloc_free(tmp_ctx); return; } status = socket_recvfrom(dgmsock->sock, blob.data, blob.length, &nread, tmp_ctx, &src); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return; } blob.length = nread; DEBUG(5,("Received dgram packet of length %d from %s:%d\n", (int)blob.length, src->addr, src->port)); packet = talloc(tmp_ctx, struct nbt_dgram_packet); if (packet == NULL) { talloc_free(tmp_ctx); return; } /* parse the request */ ndr_err = ndr_pull_struct_blob(&blob, packet, packet, (ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(2,("Failed to parse incoming NBT DGRAM packet - %s\n", nt_errstr(status))); talloc_free(tmp_ctx); return; } /* if this is a mailslot message, then see if we can dispatch it to a handler */ mailslot_name = dgram_mailslot_name(packet); if (mailslot_name) { struct dgram_mailslot_handler *dgmslot; dgmslot = dgram_mailslot_find(dgmsock, mailslot_name); if (dgmslot) { dgmslot->handler(dgmslot, packet, src); } else { DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name)); } } else { /* dispatch if there is a general handler */ if (dgmsock->incoming.handler) { dgmsock->incoming.handler(dgmsock, packet, src); } } talloc_free(tmp_ctx); }
/* call this when the socket becomes readable to kick off the whole stream parsing process */ _PUBLIC_ void packet_recv(struct packet_context *pc) { size_t npending; NTSTATUS status; size_t nread = 0; DATA_BLOB blob; bool recv_retry = false; if (pc->processing) { TEVENT_FD_NOT_READABLE(pc->fde); pc->processing++; return; } if (pc->recv_disable) { pc->recv_need_enable = true; TEVENT_FD_NOT_READABLE(pc->fde); return; } if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) { goto next_partial; } if (pc->packet_size != 0) { /* we've already worked out how long this next packet is, so skip the socket_pending() call */ npending = pc->packet_size - pc->num_read; } else if (pc->initial_read != 0) { npending = pc->initial_read - pc->num_read; } else { if (pc->sock) { status = socket_pending(pc->sock, &npending); } else { status = NT_STATUS_CONNECTION_DISCONNECTED; } if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; } } if (npending == 0) { packet_eof(pc); return; } again: if (npending + pc->num_read < npending) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } if (npending + pc->num_read < pc->num_read) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } /* possibly expand the partial packet buffer */ if (npending + pc->num_read > pc->partial.length) { if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } } if (pc->partial.length < pc->num_read + npending) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } status = socket_recv(pc->sock, pc->partial.data + pc->num_read, npending, &nread); if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; } if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { nread = 0; status = NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { return; } if (nread == 0 && !recv_retry) { packet_eof(pc); return; } pc->num_read += nread; if (pc->unreliable_select && nread != 0) { recv_retry = true; status = socket_pending(pc->sock, &npending); if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; } if (npending != 0) { goto again; } } next_partial: if (pc->partial.length != pc->num_read) { if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } } /* see if its a full request */ blob = pc->partial; blob.length = pc->num_read; status = pc->full_request(pc->private_data, blob, &pc->packet_size); if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; } if (!NT_STATUS_IS_OK(status)) { return; } if (pc->packet_size > pc->num_read) { /* the caller made an error */ DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n", (long)pc->packet_size, (long)pc->num_read)); packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } /* it is a full request - give it to the caller */ blob = pc->partial; blob.length = pc->num_read; if (pc->packet_size < pc->num_read) { pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, pc->num_read - pc->packet_size); if (pc->partial.data == NULL) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } /* Trunate the blob sent to the caller to only the packet length */ if (!data_blob_realloc(pc, &blob, pc->packet_size)) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } } else { pc->partial = data_blob(NULL, 0); } pc->num_read -= pc->packet_size; pc->packet_size = 0; if (pc->serialise) { pc->processing = 1; } pc->busy = true; status = pc->callback(pc->private_data, blob); pc->busy = false; if (pc->destructor_called) { talloc_free(pc); return; } if (pc->processing) { if (pc->processing > 1) { TEVENT_FD_READABLE(pc->fde); } pc->processing = 0; } if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; } /* Have we consumed the whole buffer yet? */ if (pc->partial.length == 0) { return; } /* we got multiple packets in one tcp read */ if (pc->ev == NULL) { goto next_partial; } blob = pc->partial; blob.length = pc->num_read; status = pc->full_request(pc->private_data, blob, &pc->packet_size); if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; } if (!NT_STATUS_IS_OK(status)) { return; } tevent_add_timer(pc->ev, pc, timeval_zero(), packet_next_event, pc); }
/* handle fd recv events on a KDC socket */ static void kdc_recv_handler(struct kdc_socket *kdc_socket) { NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(kdc_socket); DATA_BLOB blob; struct kdc_reply *rep; DATA_BLOB reply; size_t nread, dsize; struct socket_address *src; struct socket_address *my_addr; int ret; status = socket_pending(kdc_socket->sock, &dsize); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return; } blob = data_blob_talloc(tmp_ctx, NULL, dsize); if (blob.data == NULL) { /* hope this is a temporary low memory condition */ talloc_free(tmp_ctx); return; } status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread, tmp_ctx, &src); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return; } blob.length = nread; DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n", (long)blob.length, src->addr, (uint16_t)src->port)); my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx); if (!my_addr) { talloc_free(tmp_ctx); return; } /* Call krb5 */ ret = kdc_socket->process(kdc_socket->kdc, tmp_ctx, &blob, &reply, src, my_addr, 1 /* Datagram */); if (!ret) { talloc_free(tmp_ctx); return; } /* queue a pending reply */ rep = talloc(kdc_socket, struct kdc_reply); if (rep == NULL) { talloc_free(tmp_ctx); return; } rep->dest = talloc_steal(rep, src); rep->packet = reply; talloc_steal(rep, reply.data); if (rep->packet.data == NULL) { talloc_free(rep); talloc_free(tmp_ctx); return; } DLIST_ADD_END(kdc_socket->send_queue, rep, struct kdc_reply *); EVENT_FD_WRITEABLE(kdc_socket->fde); talloc_free(tmp_ctx); }