Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB2 POSIX code.
4 : Copyright (C) Jeremy Allison 2022
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "smbd/smbd.h"
22 : #include "passdb/lookup_sid.h"
23 : #include "librpc/gen_ndr/ndr_security.h"
24 :
25 : /*
26 : * SMB2 POSIX create context return details.
27 : */
28 0 : DATA_BLOB smb2_posix_cc_info(TALLOC_CTX *mem_ctx,
29 : connection_struct *conn,
30 : uint32_t reparse_tag,
31 : const SMB_STRUCT_STAT *psbuf)
32 : {
33 0 : DATA_BLOB ret_blob = data_blob_null;
34 : struct dom_sid sid_owner;
35 : struct dom_sid sid_group;
36 0 : size_t owner_sid_size = 0;
37 0 : size_t group_sid_size = 0;
38 0 : size_t b_size = 12;
39 :
40 0 : uid_to_sid(&sid_owner, psbuf->st_ex_uid);
41 0 : owner_sid_size = ndr_size_dom_sid(&sid_owner, 0);
42 0 : if (b_size + owner_sid_size < b_size) {
43 0 : return data_blob_null;
44 : }
45 0 : b_size += owner_sid_size;
46 :
47 0 : gid_to_sid(&sid_group, psbuf->st_ex_gid);
48 0 : group_sid_size = ndr_size_dom_sid(&sid_group, 0);
49 0 : if (b_size + group_sid_size < b_size) {
50 0 : return data_blob_null;
51 : }
52 0 : b_size += group_sid_size;
53 :
54 0 : ret_blob = data_blob_talloc(mem_ctx,
55 : NULL,
56 : b_size);
57 0 : if (ret_blob.data == NULL) {
58 0 : return data_blob_null;
59 : }
60 :
61 : /* number of hard links */
62 0 : PUSH_LE_U32(ret_blob.data, 0, psbuf->st_ex_nlink);
63 :
64 : /* Reparse tag if FILE_FLAG_REPARSE is set, else zero. */
65 0 : PUSH_LE_U32(ret_blob.data, 4, reparse_tag);
66 :
67 : /*
68 : * Remove type info from mode, leaving only the
69 : * permissions and setuid/gid bits.
70 : */
71 0 : PUSH_LE_U32(ret_blob.data,
72 : 8,
73 : unix_perms_to_wire(psbuf->st_ex_mode & ~S_IFMT));
74 :
75 : /* Now add in the owner and group sids. */
76 0 : sid_linearize(ret_blob.data + 12,
77 : b_size - 12,
78 : &sid_owner);
79 0 : sid_linearize(ret_blob.data + 12 + owner_sid_size,
80 0 : b_size - owner_sid_size - 12,
81 : &sid_group);
82 0 : return ret_blob;
83 : }
84 :
85 : /*
86 : * SMB2 POSIX info level.
87 : */
88 0 : DATA_BLOB store_smb2_posix_info(TALLOC_CTX *mem_ctx,
89 : connection_struct *conn,
90 : const SMB_STRUCT_STAT *psbuf,
91 : uint32_t reparse_tag,
92 : uint32_t dos_attributes)
93 : {
94 0 : uint64_t file_id = SMB_VFS_FS_FILE_ID(conn, psbuf);
95 0 : DATA_BLOB ret_blob = data_blob_null;
96 0 : DATA_BLOB cc = smb2_posix_cc_info(mem_ctx,
97 : conn,
98 : reparse_tag,
99 : psbuf);
100 0 : if (cc.data == NULL) {
101 0 : return data_blob_null;
102 : }
103 :
104 0 : if (cc.length + 68 < 68) {
105 0 : data_blob_free(&cc);
106 0 : return data_blob_null;
107 : }
108 :
109 0 : ret_blob = data_blob_talloc(mem_ctx,
110 : NULL,
111 : cc.length + 68);
112 0 : if (ret_blob.data == NULL) {
113 0 : data_blob_free(&cc);
114 0 : return data_blob_null;
115 : }
116 :
117 : /* Timestamps. */
118 :
119 : /* Birth (creation) time. */
120 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
121 0 : (char *)ret_blob.data+0,
122 : psbuf->st_ex_btime);
123 : /* Access time. */
124 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
125 0 : (char *)ret_blob.data+8,
126 : psbuf->st_ex_atime);
127 : /* Last write time. */
128 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
129 0 : (char *)ret_blob.data+16,
130 : psbuf->st_ex_mtime);
131 : /* Change time. */
132 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
133 0 : (char *)ret_blob.data+24,
134 : psbuf->st_ex_ctime);
135 :
136 : /* File size 64 Bit */
137 0 : SOFF_T(ret_blob.data,32, get_file_size_stat(psbuf));
138 :
139 : /* Number of bytes used on disk - 64 Bit */
140 0 : SOFF_T(ret_blob.data,40,SMB_VFS_GET_ALLOC_SIZE(conn,NULL,psbuf));
141 :
142 : /* DOS attributes */
143 0 : if (S_ISREG(psbuf->st_ex_mode)) {
144 0 : PUSH_LE_U32(ret_blob.data, 48, dos_attributes);
145 0 : } else if (S_ISDIR(psbuf->st_ex_mode)) {
146 0 : PUSH_LE_U32(ret_blob.data,
147 : 48,
148 : dos_attributes|FILE_ATTRIBUTE_DIRECTORY);
149 : } else {
150 : /*
151 : * All non-directory or regular files are reported
152 : * as reparse points. Client may or may not be able
153 : * to access these.
154 : */
155 0 : PUSH_LE_U32(ret_blob.data,
156 : 48,
157 : FILE_ATTRIBUTE_REPARSE_POINT);
158 : }
159 :
160 : /* Add the inode and dev (16 bytes). */
161 0 : PUSH_LE_U64(ret_blob.data, 52, file_id);
162 0 : PUSH_LE_U64(ret_blob.data, 60, psbuf->st_ex_dev);
163 :
164 : /*
165 : * Append a POSIX create context (variable bytes).
166 : */
167 0 : memcpy(ret_blob.data + 68, cc.data, cc.length);
168 0 : data_blob_free(&cc);
169 0 : return ret_blob;
170 : }
|