From patchwork Tue Jan 29 06:53:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 1032527 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43pcfq590Kz9sDB for ; Tue, 29 Jan 2019 17:54:11 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725446AbfA2GyK (ORCPT ); Tue, 29 Jan 2019 01:54:10 -0500 Received: from mx1.redhat.com ([209.132.183.28]:60828 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725267AbfA2GyK (ORCPT ); Tue, 29 Jan 2019 01:54:10 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id ADBE1C073D7D; Tue, 29 Jan 2019 06:54:08 +0000 (UTC) Received: from test1135.test.redhat.com (vpn2-54-117.bne.redhat.com [10.64.54.117]) by smtp.corp.redhat.com (Postfix) with ESMTP id 64FE95C25D; Tue, 29 Jan 2019 06:54:07 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH] smbinfo: Add more File*Information classes Date: Tue, 29 Jan 2019 16:53:57 +1000 Message-Id: <20190129065357.3935-2-lsahlber@redhat.com> In-Reply-To: <20190129065357.3935-1-lsahlber@redhat.com> References: <20190129065357.3935-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 29 Jan 2019 06:54:08 +0000 (UTC) Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- smbinfo.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- smbinfo.rst | 34 ++++- 2 files changed, 497 insertions(+), 20 deletions(-) diff --git a/smbinfo.c b/smbinfo.c index b1c129b..de9ebf6 100644 --- a/smbinfo.c +++ b/smbinfo.c @@ -66,6 +66,447 @@ usage(char *name) } static void +win_to_timeval(uint64_t smb2_time, struct timeval *tv) +{ + tv->tv_usec = (smb2_time / 10) % 1000000; + tv->tv_sec = (smb2_time - 116444736000000000) / 10000000; +} + +struct bit_string { + unsigned int bit; + char *string; +}; + +struct bit_string directory_access_mask[] = { + { 0x00000001, "LIST_DIRECTORY" }, + { 0x00000002, "ADD_FILE" }, + { 0x00000004, "ADD_SUBDIRECTORY" }, + { 0x00000008, "READ_EA" }, + { 0x00000010, "WRITE_EA" }, + { 0x00000020, "TRAVERSE" }, + { 0x00000040, "DELETE_CHILD" }, + { 0x00000080, "READ_ATTRIBUTES" }, + { 0x00000100, "WRITE_ATTRIBUTES" }, + { 0x00010000, "DELETE" }, + { 0x00020000, "READ_CONTROL" }, + { 0x00040000, "WRITE_DAC" }, + { 0x00080000, "WRITE_OWNER" }, + { 0x00100000, "SYNCHRONIZER" }, + { 0x01000000, "ACCESS_SYSTEM_SECURITY" }, + { 0x02000000, "MAXIMUM_ALLOWED" }, + { 0x10000000, "GENERIC_ALL" }, + { 0x20000000, "GENERIC_EXECUTE" }, + { 0x40000000, "GENERIC_WRITE" }, + { 0x80000000, "GENERIC_READ" }, + { 0, NULL } +}; + +struct bit_string file_access_mask[] = { + { 0x00000001, "READ_DATA" }, + { 0x00000002, "WRITE_DATA" }, + { 0x00000004, "APPEND_DATA" }, + { 0x00000008, "READ_EA" }, + { 0x00000010, "WRITE_EA" }, + { 0x00000020, "EXECUTE" }, + { 0x00000040, "DELETE_CHILD" }, + { 0x00000080, "READ_ATTRIBUTES" }, + { 0x00000100, "WRITE_ATTRIBUTES" }, + { 0x00010000, "DELETE" }, + { 0x00020000, "READ_CONTROL" }, + { 0x00040000, "WRITE_DAC" }, + { 0x00080000, "WRITE_OWNER" }, + { 0x00100000, "SYNCHRONIZER" }, + { 0x01000000, "ACCESS_SYSTEM_SECURITY" }, + { 0x02000000, "MAXIMUM_ALLOWED" }, + { 0x10000000, "GENERIC_ALL" }, + { 0x20000000, "GENERIC_EXECUTE" }, + { 0x40000000, "GENERIC_WRITE" }, + { 0x80000000, "GENERIC_READ" }, + { 0, NULL } +}; + +static void +print_bits(uint32_t mask, struct bit_string *bs) +{ + while (bs->string) { + if (mask & bs->bit) + printf("%s ", bs->string); + bs++; + } +} + +static void +print_fileaccessinfo(uint8_t *sd, int type) +{ + uint32_t access_flags; + + memcpy(&access_flags, &sd[0], 4); + access_flags = le32toh(access_flags); + + if (type == S_IFDIR) { + printf("Directory access flags 0x%08x: ", access_flags); + print_bits(access_flags, directory_access_mask); + } else { + printf("File/Printer access flags 0x%08x: ", access_flags); + print_bits(access_flags, file_access_mask); + } + printf("\n"); +} + +static void +fileaccessinfo(int f) +{ + struct smb_query_info *qi; + struct stat st; + + fstat(f, &st); + + qi = malloc(sizeof(struct smb_query_info) + 4); + memset(qi, 0, sizeof(qi) + 4); + qi->info_type = 0x01; + qi->file_info_class = 8; + qi->additional_information = 0; + qi->input_buffer_length = 4; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_fileaccessinfo((uint8_t *)(&qi[1]), st.st_mode & S_IFMT); + free(qi); +} + +static void +print_filealigninfo(uint8_t *sd) +{ + uint32_t mask; + + memcpy(&mask, &sd[0], 4); + mask = le32toh(mask); + + printf("File alignment: "); + if (mask == 0) + printf("BYTE_ALIGNMENT"); + else if (mask == 1) + printf("WORD_ALIGNMENT"); + else if (mask == 3) + printf("LONG_ALIGNMENT"); + else if (mask == 7) + printf("QUAD_ALIGNMENT"); + else if (mask == 15) + printf("OCTA_ALIGNMENT"); + else if (mask == 31) + printf("32_bit_ALIGNMENT"); + else if (mask == 63) + printf("64_bit_ALIGNMENT"); + else if (mask == 127) + printf("128_bit_ALIGNMENT"); + else if (mask == 255) + printf("254_bit_ALIGNMENT"); + else if (mask == 511) + printf("512_bit_ALIGNMENT"); + + printf("\n"); +} + +static void +filealigninfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 4); + memset(qi, 0, sizeof(qi) + 4); + qi->info_type = 0x01; + qi->file_info_class = 17; + qi->additional_information = 0; + qi->input_buffer_length = 4; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_filealigninfo((uint8_t *)(&qi[1])); + free(qi); +} + +struct bit_string file_attributes_mask[] = { + { 0x00000001, "READ_ONLY" }, + { 0x00000002, "HIDDEN" }, + { 0x00000004, "SYSTEM" }, + { 0x00000010, "DIRECTORY" }, + { 0x00000020, "ARCHIVE" }, + { 0x00000080, "NORMAL" }, + { 0x00000100, "TEMPORARY" }, + { 0x00000200, "SPARSE_FILE" }, + { 0x00000400, "REPARSE_POINT" }, + { 0x00000800, "COMPRESSED" }, + { 0x00001000, "OFFLINE" }, + { 0x00002000, "NOT_CONTENT_INDEXED" }, + { 0x00004000, "ENCRYPTED" }, + { 0x00008000, "INTEGRITY_STREAM" }, + { 0x00020000, "NO_SCRUB_DATA" }, + { 0, NULL } +}; + +static void +print_filebasicinfo(uint8_t *sd) +{ + struct timeval tv; + uint64_t u64; + uint32_t u32; + + memcpy(&u64, &sd[0], 8); + win_to_timeval(le64toh(u64), &tv); + printf("Creation Time %s", ctime(&tv.tv_sec)); + + memcpy(&u64, &sd[8], 8); + win_to_timeval(le64toh(u64), &tv); + printf("Last Access Time %s", ctime(&tv.tv_sec)); + + memcpy(&u64, &sd[16], 8); + win_to_timeval(le64toh(u64), &tv); + printf("Last Write Time %s", ctime(&tv.tv_sec)); + + memcpy(&u64, &sd[24], 8); + win_to_timeval(le64toh(u64), &tv); + printf("Last Change Time %s", ctime(&tv.tv_sec)); + + memcpy(&u32, &sd[32], 4); + u32 = le32toh(u32); + printf("File Attributes 0x%08x: ", u32); + print_bits(u32, file_attributes_mask); + printf("\n"); +} + +static void +filebasicinfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 40); + memset(qi, 0, sizeof(qi) + 40); + qi->info_type = 0x01; + qi->file_info_class = 4; + qi->additional_information = 0; + qi->input_buffer_length = 40; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_filebasicinfo((uint8_t *)(&qi[1])); + free(qi); +} + +static void +print_filestandardinfo(uint8_t *sd) +{ + uint64_t u64; + uint32_t u32; + + memcpy(&u64, &sd[0], 8); + printf("Allocation Size %" PRIu64 "\n", le64toh(u64)); + + memcpy(&u64, &sd[8], 8); + printf("End Of File %" PRIu64 "\n", le64toh(u64)); + + memcpy(&u32, &sd[16], 4); + printf("Number Of Links %" PRIu32 "\n", le32toh(u32)); + + printf("Delete Pending %d\n", sd[20]); + printf("Delete Directory %d\n", sd[21]); +} + +static void +filestandardinfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 24); + memset(qi, 0, sizeof(qi) + 24); + qi->info_type = 0x01; + qi->file_info_class = 5; + qi->additional_information = 0; + qi->input_buffer_length = 24; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_filestandardinfo((uint8_t *)(&qi[1])); + free(qi); +} + +static void +print_fileinternalinfo(uint8_t *sd) +{ + uint64_t u64; + + memcpy(&u64, &sd[0], 8); + printf("Index Number %" PRIu64 "\n", le64toh(u64)); +} + +static void +fileinternalinfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 8); + memset(qi, 0, sizeof(qi) + 8); + qi->info_type = 0x01; + qi->file_info_class = 6; + qi->additional_information = 0; + qi->input_buffer_length = 8; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_fileinternalinfo((uint8_t *)(&qi[1])); + free(qi); +} + +struct bit_string file_mode_mask[] = { + { 0x00000002, "WRITE_THROUGH" }, + { 0x00000004, "SEQUENTIAL_ONLY" }, + { 0x00000008, "NO_INTERMEDIATE_BUFFERING" }, + { 0x00000010, "SYNCHRONOUS_IO_ALERT" }, + { 0x00000020, "SYNCHRONOUS_IO_NONALERT" }, + { 0x00001000, "DELETE_ON_CLOSE" }, + { 0, NULL } +}; + +static void +print_filemodeinfo(uint8_t *sd) +{ + uint32_t u32; + + memcpy(&u32, &sd[32], 4); + u32 = le32toh(u32); + printf("Mode 0x%08x: ", u32); + print_bits(u32, file_mode_mask); + printf("\n"); +} + +static void +filemodeinfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 4); + memset(qi, 0, sizeof(qi) + 4); + qi->info_type = 0x01; + qi->file_info_class = 16; + qi->additional_information = 0; + qi->input_buffer_length = 4; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_filemodeinfo((uint8_t *)(&qi[1])); + free(qi); +} + +static void +print_filepositioninfo(uint8_t *sd) +{ + uint64_t u64; + + memcpy(&u64, &sd[0], 8); + printf("Current Byte Offset %" PRIu64 "\n", le64toh(u64)); +} + +static void +filepositioninfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 8); + memset(qi, 0, sizeof(qi) + 8); + qi->info_type = 0x01; + qi->file_info_class = 14; + qi->additional_information = 0; + qi->input_buffer_length = 8; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_filepositioninfo((uint8_t *)(&qi[1])); + free(qi); +} + +static void +print_fileeainfo(uint8_t *sd) +{ + uint32_t u32; + + memcpy(&u32, &sd[0], 4); + printf("Ea Size %" PRIu32 "\n", le32toh(u32)); +} + +static void +fileeainfo(int f) +{ + struct smb_query_info *qi; + + qi = malloc(sizeof(struct smb_query_info) + 4); + memset(qi, 0, sizeof(qi) + 4); + qi->info_type = 0x01; + qi->file_info_class = 7; + qi->additional_information = 0; + qi->input_buffer_length = 4; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_fileeainfo((uint8_t *)(&qi[1])); + free(qi); +} + +static void +fileallinfo(int f) +{ + struct smb_query_info *qi; + struct stat st; + + fstat(f, &st); + + qi = malloc(sizeof(struct smb_query_info) + INPUT_BUFFER_LENGTH); + memset(qi, 0, sizeof(qi) + INPUT_BUFFER_LENGTH); + qi->info_type = 0x01; + qi->file_info_class = 18; + qi->additional_information = 0; + qi->input_buffer_length = INPUT_BUFFER_LENGTH; + + if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) { + fprintf(stderr, "ioctl failed with %s\n", strerror(errno)); + exit(1); + } + + print_filebasicinfo((uint8_t *)(&qi[1])); + print_filestandardinfo((uint8_t *)(&qi[1]) + 40); + print_fileinternalinfo((uint8_t *)(&qi[1]) + 64); + print_fileeainfo((uint8_t *)(&qi[1]) + 72); + print_fileaccessinfo((uint8_t *)(&qi[1]) + 76, st.st_mode & S_IFMT); + print_filepositioninfo((uint8_t *)(&qi[1]) + 80); + print_filemodeinfo((uint8_t *)(&qi[1]) + 88); + print_filealigninfo((uint8_t *)(&qi[1]) + 92); + // SMB2 servers like Win16 does not seem to return name info + free(qi); +} + +static void print_sid(unsigned char *sd) { int i; @@ -152,10 +593,13 @@ print_sd(uint8_t *sd) } } -void secdesc(int f) { +static void +secdesc(int f) +{ struct smb_query_info *qi; qi = malloc(sizeof(struct smb_query_info) + INPUT_BUFFER_LENGTH); + memset(qi, 0, sizeof(qi) + INPUT_BUFFER_LENGTH); qi->info_type = 0x03; qi->file_info_class = 0; qi->additional_information = 0x00000007; /* Owner, Group, Dacl */ @@ -167,13 +611,7 @@ void secdesc(int f) { } print_sd((uint8_t *)(&qi[1])); -} - -void -win_to_timeval(uint64_t smb2_time, struct timeval *tv) -{ - tv->tv_usec = (smb2_time / 10) % 1000000; - tv->tv_sec = (smb2_time - 116444736000000000) / 10000000; + free(qi); } static void @@ -236,7 +674,9 @@ print_quota(unsigned char *sd) } } -void quota(int f) { +static void +quota(int f) +{ struct smb_query_info *qi; char *buf; int i; @@ -264,6 +704,7 @@ void quota(int f) { } print_quota((unsigned char *)(&qi[1])); + free(qi); } int main(int argc, char *argv[]) @@ -290,11 +731,29 @@ int main(int argc, char *argv[]) } - if (!strcmp(argv[1], "secdesc")) { + if (!strcmp(argv[1], "fileaccessinfo")) + fileaccessinfo(f); + else if (!strcmp(argv[1], "filealigninfo")) + filealigninfo(f); + else if (!strcmp(argv[1], "fileallinfo")) + fileallinfo(f); + else if (!strcmp(argv[1], "filebasicinfo")) + filebasicinfo(f); + else if (!strcmp(argv[1], "fileeainfo")) + fileeainfo(f); + else if (!strcmp(argv[1], "fileinternalinfo")) + fileinternalinfo(f); + else if (!strcmp(argv[1], "filemodeinfo")) + filemodeinfo(f); + else if (!strcmp(argv[1], "filepositioninfo")) + filepositioninfo(f); + else if (!strcmp(argv[1], "filestandardinfo")) + filestandardinfo(f); + else if (!strcmp(argv[1], "secdesc")) secdesc(f); - } else if (!strcmp(argv[1], "quota")) { + else if (!strcmp(argv[1], "quota")) quota(f); - } else { + else { fprintf(stderr, "Unknown command %s\n", argv[optind]); exit(1); } diff --git a/smbinfo.rst b/smbinfo.rst index e37c709..2119f93 100644 --- a/smbinfo.rst +++ b/smbinfo.rst @@ -39,14 +39,23 @@ OPTIONS COMMAND ******* -`secdesc`: Print the security descriptor in the form -- Revision -- Control -- Owner SID -- Group SID -- ACL -- File types -- File flags +`fileaccessinfo`: Prints the FileAccessInformation class + +`filealigninfo`: Prints the FileAlignmentInformation class + +`fileallinfo`: Prints the FileAllInformation class + +`filebasicinfo`: Prints the FileBasicInformation class + +`fileeainfo`: Prints the FileEaInformation class + +`fileinternalinfo`: Prints the FileInternalInformation class + +`filemodeinfo`: Prints the FileModeInformation class + +`filepositioninfo`: Prints the FilePositionInformation class + +`filestandardinfo`: Prints the FileStandardInformation class `quota`: Print the quota for the volume in the form - SID Length @@ -56,6 +65,15 @@ COMMAND - Quota Limit - SID +`secdesc`: Print the security descriptor in the form +- Revision +- Control +- Owner SID +- Group SID +- ACL +- File types +- File flags + ***** NOTES *****