/* add a blob to a smb2_create attribute blob */ NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint32_t tag, DATA_BLOB add, BOOL last) { NTSTATUS status; uint32_t ofs = blob->length; uint8_t pad = smb2_padding_size(add.length, 8); status = data_blob_realloc(mem_ctx, blob, blob->length + 0x18 + add.length + pad); NT_STATUS_NOT_OK_RETURN(status); if (last) { SIVAL(blob->data, ofs+0x00, 0); } else { SIVAL(blob->data, ofs+0x00, 0x18 + add.length + pad); } SSVAL(blob->data, ofs+0x04, 0x10); /* offset of tag */ SIVAL(blob->data, ofs+0x06, 0x04); /* tag length */ SSVAL(blob->data, ofs+0x0A, 0x18); /* offset of data */ SIVAL(blob->data, ofs+0x0C, add.length); SIVAL(blob->data, ofs+0x10, tag); SIVAL(blob->data, ofs+0x14, 0); /* pad? */ memcpy(blob->data+ofs+0x18, add.data, add.length); memset(blob->data+ofs+0x18+add.length, 0, pad); return NT_STATUS_OK; }
/* add a blob to a smb2_create attribute blob */ static NTSTATUS smb2_create_blob_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer, const struct smb2_create_blob *blob, bool last) { uint32_t ofs = buffer->length; size_t tag_length = strlen(blob->tag); size_t blob_offset = 0; size_t blob_pad = 0; size_t next_offset = 0; size_t next_pad = 0; bool ok; blob_offset = 0x10 + tag_length; blob_pad = smb2_create_blob_padding(blob_offset, 8); next_offset = blob_offset + blob_pad + blob->data.length; if (!last) { next_pad = smb2_create_blob_padding(next_offset, 8); } ok = data_blob_realloc(mem_ctx, buffer, buffer->length + next_offset + next_pad); if (!ok) { return NT_STATUS_NO_MEMORY; } if (last) { SIVAL(buffer->data, ofs+0x00, 0); } else { SIVAL(buffer->data, ofs+0x00, next_offset + next_pad); } SSVAL(buffer->data, ofs+0x04, 0x10); /* offset of tag */ SIVAL(buffer->data, ofs+0x06, tag_length); /* tag length */ SSVAL(buffer->data, ofs+0x0A, blob_offset + blob_pad); /* offset of data */ SIVAL(buffer->data, ofs+0x0C, blob->data.length); memcpy(buffer->data+ofs+0x10, blob->tag, tag_length); if (blob_pad > 0) { memset(buffer->data+ofs+blob_offset, 0, blob_pad); blob_offset += blob_pad; } memcpy(buffer->data+ofs+blob_offset, blob->data.data, blob->data.length); if (next_pad > 0) { memset(buffer->data+ofs+next_offset, 0, next_pad); next_offset += next_pad; } return NT_STATUS_OK; }
/* 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); }
static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle, files_struct *fsp, const struct smb_filename *smb_fname_in, TALLOC_CTX *mem_ctx, DATA_BLOB *blob) { struct nfs4acl_config *config = NULL; const struct smb_filename *smb_fname = NULL; size_t allocsize = 256; ssize_t length; bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct nfs4acl_config, return NT_STATUS_INTERNAL_ERROR); *blob = data_blob_null; if (fsp == NULL && smb_fname_in == NULL) { return NT_STATUS_INTERNAL_ERROR; } smb_fname = smb_fname_in; if (smb_fname == NULL) { smb_fname = fsp->fsp_name; } if (smb_fname == NULL) { return NT_STATUS_INTERNAL_ERROR; } ok = nfs4acl_validate_blob(handle, smb_fname); if (!ok) { return NT_STATUS_INTERNAL_ERROR; } do { int saved_errno = 0; allocsize *= 4; ok = data_blob_realloc(mem_ctx, blob, allocsize); if (!ok) { return NT_STATUS_NO_MEMORY; } become_root(); if (fsp != NULL && fsp->fh->fd != -1) { length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, config->xattr_name, blob->data, blob->length); } else { length = SMB_VFS_NEXT_GETXATTR(handle, smb_fname, config->xattr_name, blob->data, blob->length); } if (length == -1) { saved_errno = errno; } unbecome_root(); if (saved_errno != 0) { errno = saved_errno; } } while (length == -1 && errno == ERANGE && allocsize <= 65536); if (length == -1) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK; }