/src/samba/source3/lib/util_namearray.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Samba utility functions |
4 | | Copyright (C) Ralph Boehme 2024 |
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 "lib/util/strv.h" |
22 | | #include "libcli/security/security.h" |
23 | | #include "source3/lib/substitute.h" |
24 | | #include "passdb/lookup_sid.h" |
25 | | #include "auth.h" |
26 | | |
27 | | /* |
28 | | * No prefix means direct username |
29 | | * @name means netgroup first, then unix group |
30 | | * &name means netgroup |
31 | | * +name means unix group |
32 | | * + and & may be combined |
33 | | */ |
34 | | |
35 | | static bool do_group_checks(const char **name, const char **pattern) |
36 | 0 | { |
37 | 0 | if ((*name)[0] == '@') { |
38 | 0 | *pattern = "&+"; |
39 | 0 | *name += 1; |
40 | 0 | return True; |
41 | 0 | } |
42 | | |
43 | 0 | if (((*name)[0] == '+') && ((*name)[1] == '&')) { |
44 | 0 | *pattern = "+&"; |
45 | 0 | *name += 2; |
46 | 0 | return True; |
47 | 0 | } |
48 | | |
49 | 0 | if ((*name)[0] == '+') { |
50 | 0 | *pattern = "+"; |
51 | 0 | *name += 1; |
52 | 0 | return True; |
53 | 0 | } |
54 | | |
55 | 0 | if (((*name)[0] == '&') && ((*name)[1] == '+')) { |
56 | 0 | *pattern = "&+"; |
57 | 0 | *name += 2; |
58 | 0 | return True; |
59 | 0 | } |
60 | | |
61 | 0 | if ((*name)[0] == '&') { |
62 | 0 | *pattern = "&"; |
63 | 0 | *name += 1; |
64 | 0 | return True; |
65 | 0 | } |
66 | | |
67 | 0 | return False; |
68 | 0 | } |
69 | | |
70 | | bool token_contains_name(TALLOC_CTX *mem_ctx, |
71 | | const char *username, |
72 | | const char *domain, |
73 | | const char *sharename, |
74 | | const struct security_token *token, |
75 | | const char *name, |
76 | | bool *match) |
77 | 0 | { |
78 | 0 | const char *prefix; |
79 | 0 | struct dom_sid sid; |
80 | 0 | enum lsa_SidType type; |
81 | 0 | NTSTATUS status; |
82 | |
|
83 | 0 | *match = false; |
84 | |
|
85 | 0 | if (username != NULL) { |
86 | 0 | size_t domain_len = domain != NULL ? strlen(domain) : 0; |
87 | | |
88 | | /* Check if username starts with domain name */ |
89 | 0 | if (domain_len > 0) { |
90 | 0 | const char *sep = lp_winbind_separator(); |
91 | 0 | int cmp = strncasecmp_m(username, domain, domain_len); |
92 | 0 | if (cmp == 0 && sep[0] == username[domain_len]) { |
93 | | /* Move after the winbind separator */ |
94 | 0 | domain_len += 1; |
95 | 0 | } else { |
96 | 0 | domain_len = 0; |
97 | 0 | } |
98 | 0 | } |
99 | 0 | name = talloc_sub_basic(mem_ctx, |
100 | 0 | username + domain_len, |
101 | 0 | domain, |
102 | 0 | name); |
103 | 0 | } |
104 | 0 | if (sharename != NULL) { |
105 | 0 | name = talloc_string_sub(mem_ctx, name, "%S", sharename); |
106 | 0 | } |
107 | |
|
108 | 0 | if (name == NULL) { |
109 | 0 | return false; |
110 | 0 | } |
111 | | |
112 | 0 | if ( string_to_sid( &sid, name ) ) { |
113 | 0 | DEBUG(5,("token_contains_name: Checking for SID [%s] in token\n", name)); |
114 | 0 | *match = nt_token_check_sid( &sid, token ); |
115 | 0 | return true; |
116 | 0 | } |
117 | | |
118 | 0 | if (!do_group_checks(&name, &prefix)) { |
119 | 0 | status = lookup_name_smbconf_ex(mem_ctx, |
120 | 0 | name, |
121 | 0 | LOOKUP_NAME_ALL, |
122 | 0 | NULL, |
123 | 0 | NULL, |
124 | 0 | &sid, |
125 | 0 | &type); |
126 | 0 | if (!NT_STATUS_IS_OK(status)) { |
127 | 0 | DBG_ERR("lookup_name '%s' failed %s\n", |
128 | 0 | name, nt_errstr(status)); |
129 | 0 | return false; |
130 | 0 | } |
131 | 0 | if (type != SID_NAME_USER) { |
132 | 0 | DBG_WARNING("%s is a %s, expected a user\n", |
133 | 0 | name, sid_type_lookup(type)); |
134 | 0 | return true; |
135 | 0 | } |
136 | 0 | *match = nt_token_check_sid(&sid, token); |
137 | 0 | return true; |
138 | 0 | } |
139 | | |
140 | 0 | for (/* initialized above */ ; *prefix != '\0'; prefix++) { |
141 | 0 | if (*prefix == '+') { |
142 | 0 | status = lookup_name_smbconf_ex( |
143 | 0 | mem_ctx, |
144 | 0 | name, |
145 | 0 | LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, |
146 | 0 | NULL, |
147 | 0 | NULL, |
148 | 0 | &sid, |
149 | 0 | &type); |
150 | 0 | if (!NT_STATUS_IS_OK(status)) { |
151 | 0 | DBG_ERR("lookup_name '%s' failed %s\n", |
152 | 0 | name, nt_errstr(status)); |
153 | 0 | return false; |
154 | 0 | } |
155 | 0 | if ((type != SID_NAME_DOM_GRP) && |
156 | 0 | (type != SID_NAME_ALIAS) && |
157 | 0 | (type != SID_NAME_WKN_GRP)) { |
158 | 0 | DBG_WARNING("%s is a %s, expected a group\n", |
159 | 0 | name, sid_type_lookup(type)); |
160 | 0 | return true; |
161 | 0 | } |
162 | 0 | if (nt_token_check_sid(&sid, token)) { |
163 | 0 | *match = true; |
164 | 0 | return True; |
165 | 0 | } |
166 | 0 | continue; |
167 | 0 | } |
168 | 0 | if (*prefix == '&') { |
169 | 0 | if (username) { |
170 | 0 | if (user_in_netgroup(mem_ctx, username, name)) { |
171 | 0 | *match = true; |
172 | 0 | return True; |
173 | 0 | } |
174 | 0 | } |
175 | 0 | continue; |
176 | 0 | } |
177 | 0 | smb_panic("got invalid prefix from do_groups_check"); |
178 | 0 | } |
179 | 0 | return true; |
180 | 0 | } |
181 | | |
182 | | static size_t namearray_len(const struct name_compare_entry *array) |
183 | 0 | { |
184 | 0 | size_t i = 0; |
185 | |
|
186 | 0 | while (array[i].name != NULL) { |
187 | 0 | i += 1; |
188 | 0 | } |
189 | |
|
190 | 0 | return i; |
191 | 0 | } |
192 | | |
193 | | /******************************************************************* |
194 | | Strip a '/' separated list into an array of |
195 | | name_compare_entry structures suitable for |
196 | | passing to is_in_path(). We do this for |
197 | | speed so we can pre-parse all the names in the list |
198 | | and don't do it for each call to is_in_path(). |
199 | | We also check if the entry contains a wildcard to |
200 | | remove a potentially expensive call to mask_match |
201 | | if possible. |
202 | | ********************************************************************/ |
203 | | |
204 | | bool append_to_namearray(TALLOC_CTX *mem_ctx, |
205 | | const char *namelist_in, |
206 | | struct name_compare_entry **_name_array) |
207 | 0 | { |
208 | 0 | struct name_compare_entry *name_array = *_name_array; |
209 | 0 | size_t len; |
210 | 0 | char *namelist = NULL; |
211 | 0 | const char *p = NULL; |
212 | |
|
213 | 0 | if ((namelist_in == NULL) || (namelist_in[0] == '\0')) { |
214 | 0 | return true; |
215 | 0 | } |
216 | | |
217 | 0 | if (name_array == NULL) { |
218 | 0 | name_array = talloc_zero(mem_ctx, struct name_compare_entry); |
219 | 0 | if (name_array == NULL) { |
220 | 0 | return false; |
221 | 0 | } |
222 | 0 | } |
223 | 0 | len = namearray_len(name_array); |
224 | |
|
225 | 0 | namelist = path_to_strv(name_array, namelist_in); |
226 | 0 | if (namelist == NULL) { |
227 | 0 | DBG_ERR("path_to_strv failed\n"); |
228 | 0 | return false; |
229 | 0 | } |
230 | | |
231 | 0 | while ((p = strv_next(namelist, p)) != NULL) { |
232 | 0 | struct name_compare_entry *tmp = NULL; |
233 | |
|
234 | 0 | if (*p == '\0') { |
235 | | /* cope with multiple (useless) /s) */ |
236 | 0 | continue; |
237 | 0 | } |
238 | | |
239 | 0 | tmp = talloc_realloc(mem_ctx, |
240 | 0 | name_array, |
241 | 0 | struct name_compare_entry, |
242 | 0 | len + 2); |
243 | 0 | if (tmp == NULL) { |
244 | 0 | return false; |
245 | 0 | } |
246 | 0 | name_array = tmp; |
247 | |
|
248 | 0 | name_array[len] = (struct name_compare_entry){ |
249 | 0 | .name = p, |
250 | 0 | .is_wild = ms_has_wild(p), |
251 | 0 | }; |
252 | 0 | name_array[len + 1] = (struct name_compare_entry){}; |
253 | 0 | len += 1; |
254 | 0 | } |
255 | | |
256 | 0 | *_name_array = name_array; |
257 | 0 | return true; |
258 | 0 | } |
259 | | |
260 | | bool set_namearray(TALLOC_CTX *mem_ctx, |
261 | | const char *namelist_in, |
262 | | struct name_compare_entry **_name_array) |
263 | 0 | { |
264 | 0 | bool ret; |
265 | |
|
266 | 0 | *_name_array = NULL; |
267 | |
|
268 | 0 | ret = append_to_namearray(mem_ctx, namelist_in, _name_array); |
269 | 0 | return ret; |
270 | 0 | } |