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 : #include "libcli/security/security.h"
25 :
26 : /*
27 : * SMB2 POSIX create context return details.
28 : */
29 0 : ssize_t smb2_posix_cc_info(
30 : connection_struct *conn,
31 : uint32_t reparse_tag,
32 : const SMB_STRUCT_STAT *psbuf,
33 : const struct dom_sid *owner,
34 : const struct dom_sid *group,
35 : uint8_t *buf,
36 : size_t buflen)
37 : {
38 0 : size_t owner_sid_size = ndr_size_dom_sid(owner, 0);
39 0 : size_t group_sid_size = ndr_size_dom_sid(group, 0);
40 0 : size_t b_size = 12;
41 :
42 0 : owner_sid_size = ndr_size_dom_sid(owner, 0);
43 0 : if (b_size + owner_sid_size < b_size) {
44 0 : return -1;
45 : }
46 0 : b_size += owner_sid_size;
47 :
48 0 : group_sid_size = ndr_size_dom_sid(group, 0);
49 0 : if (b_size + group_sid_size < b_size) {
50 0 : return -1;
51 : }
52 0 : b_size += group_sid_size;
53 :
54 0 : if (buflen < b_size) {
55 0 : return b_size;
56 : }
57 :
58 : /* number of hard links */
59 0 : PUSH_LE_U32(buf, 0, psbuf->st_ex_nlink);
60 :
61 : /* Reparse tag if FILE_FLAG_REPARSE is set, else zero. */
62 0 : PUSH_LE_U32(buf, 4, reparse_tag);
63 :
64 : /*
65 : * Remove type info from mode, leaving only the
66 : * permissions and setuid/gid bits.
67 : */
68 0 : PUSH_LE_U32(buf,
69 : 8,
70 : unix_perms_to_wire(psbuf->st_ex_mode & ~S_IFMT));
71 :
72 0 : buf += 12;
73 0 : buflen -= 12;
74 :
75 : /* Now add in the owner and group sids. */
76 0 : sid_linearize(buf, buflen, owner);
77 0 : buf += owner_sid_size;
78 0 : buflen -= owner_sid_size;
79 :
80 0 : sid_linearize(buf, buflen, group);
81 :
82 0 : return b_size;
83 : }
84 :
85 : /*
86 : * SMB2 POSIX info level.
87 : */
88 0 : ssize_t store_smb2_posix_info(
89 : connection_struct *conn,
90 : const SMB_STRUCT_STAT *psbuf,
91 : uint32_t reparse_tag,
92 : uint32_t dos_attributes,
93 : uint8_t *buf,
94 : size_t buflen)
95 : {
96 0 : uint64_t file_id = SMB_VFS_FS_FILE_ID(conn, psbuf);
97 0 : struct dom_sid owner = global_sid_NULL;
98 0 : struct dom_sid group = global_sid_NULL;
99 : ssize_t cc_len;
100 :
101 0 : if (psbuf->st_ex_uid != (uid_t)-1) {
102 0 : uid_to_sid(&owner, psbuf->st_ex_uid);
103 : }
104 0 : if (psbuf->st_ex_gid != (gid_t)-1) {
105 0 : gid_to_sid(&group, psbuf->st_ex_gid);
106 : }
107 :
108 0 : cc_len = smb2_posix_cc_info(
109 : conn, reparse_tag, psbuf, &owner, &group, NULL, 0);
110 :
111 0 : if (cc_len == -1) {
112 0 : return -1;
113 : }
114 :
115 0 : if (cc_len + 68 < 68) {
116 0 : return -1;
117 : }
118 :
119 0 : if (buflen < cc_len + 68) {
120 0 : return cc_len + 68;
121 : }
122 :
123 : /* Timestamps. */
124 :
125 : /* Birth (creation) time. */
126 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
127 : (char *)buf+0,
128 : psbuf->st_ex_btime);
129 : /* Access time. */
130 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
131 : (char *)buf+8,
132 : psbuf->st_ex_atime);
133 : /* Last write time. */
134 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
135 : (char *)buf+16,
136 : psbuf->st_ex_mtime);
137 : /* Change time. */
138 0 : put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,
139 : (char *)buf+24,
140 : psbuf->st_ex_ctime);
141 :
142 : /* File size 64 Bit */
143 0 : SOFF_T(buf,32, get_file_size_stat(psbuf));
144 :
145 : /* Number of bytes used on disk - 64 Bit */
146 0 : SOFF_T(buf,40,SMB_VFS_GET_ALLOC_SIZE(conn,NULL,psbuf));
147 :
148 : /* DOS attributes */
149 0 : if (S_ISREG(psbuf->st_ex_mode)) {
150 0 : PUSH_LE_U32(buf, 48, dos_attributes);
151 0 : } else if (S_ISDIR(psbuf->st_ex_mode)) {
152 0 : PUSH_LE_U32(buf, 48, dos_attributes|FILE_ATTRIBUTE_DIRECTORY);
153 : } else {
154 : /*
155 : * All non-directory or regular files are reported
156 : * as reparse points. Client may or may not be able
157 : * to access these.
158 : */
159 0 : PUSH_LE_U32(buf, 48, FILE_ATTRIBUTE_REPARSE_POINT);
160 : }
161 :
162 : /* Add the inode and dev (16 bytes). */
163 0 : PUSH_LE_U64(buf, 52, file_id);
164 0 : PUSH_LE_U64(buf, 60, psbuf->st_ex_dev);
165 :
166 : /*
167 : * Append a POSIX create context (variable bytes).
168 : */
169 0 : smb2_posix_cc_info(
170 : conn,
171 : reparse_tag,
172 : psbuf,
173 : &owner,
174 : &group,
175 : buf + 68,
176 : cc_len);
177 :
178 0 : return cc_len + 68;
179 : }
|