1/*
2 * Copyright (c) 2009 - 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/mount.h>
25#include <sys/kauth.h>
26#include <sys/syslog.h>
27
28#include <sys/smb_byte_order.h>
29#include <sys/smb_apple.h>
30#include <sys/mchain.h>
31#include <sys/msfscc.h>
32
33#include <netsmb/smb.h>
34#include <netsmb/smb_2.h>
35#include <netsmb/smb_conn.h>
36#include <smbfs/smbfs.h>
37#include <smbfs/smbfs_node.h>
38#include <smbfs/smbfs_subr.h>
39#include <smbfs/smbfs_subr_2.h>
40#include <smbfs/smbfs_security.h>
41#include <smbfs/smb_rq_2.h>
42
43
44#define MAX_SID_PRINTBUFFER	256	/* Used to print out the sid in case of an error */
45#define DEBUG_ACLS 0
46
47/*
48 * Directory Service generates these UUIDs for SIDs that are unknown. These UUIDs
49 * are used so we can round trip a translation from SID-->UUID-->SID. The first
50 * 12 bytes are well known and allow us to tell if this is a temporary UUID.
51 */
52static const uint8_t tmpuuid1[12] = {	0xFF, 0xFF, 0xEE, 0xEE, 0xDD, 0xDD,
53										0xCC, 0xCC, 0xBB, 0xBB, 0xAA, 0xAA};
54static const uint8_t tmpuuid2[12] = {	0xAA, 0xAA, 0xBB, 0xBB, 0xCC, 0xCC,
55										0xDD, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF};
56
57static const ntsid_t unix_users_domsid =
58{ 1, 1, {0, 0, 0, 0, 0, 22}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} };
59
60static const ntsid_t unix_groups_domsid =
61{ 1, 1, {0, 0, 0, 0, 0, 22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} };
62
63static void * smb_sdoffset(struct ntsecdesc *w_secp, size_t w_seclen, int sd_type);
64
65#define sdowner(s, s_len) (struct ntsid *)smb_sdoffset(s, s_len, OWNER_SECURITY_INFORMATION)
66#define sdgroup(s, s_len) (struct ntsid *)smb_sdoffset(s, s_len, GROUP_SECURITY_INFORMATION)
67#define sdsacl(s, s_len) (struct ntacl *)smb_sdoffset(s, s_len, SACL_SECURITY_INFORMATION)
68#define sddacl(s, s_len) (struct ntacl *)smb_sdoffset(s, s_len, DACL_SECURITY_INFORMATION)
69
70#if DEBUG_ACLS
71static void
72smb_print_guid(guid_t *uuidp)
73{
74    char *user = NULL;
75    char *group = NULL;
76    uid_t uid = 0;
77    gid_t gid = 0;
78
79    SMB_MALLOC(user, char *, MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
80    if (user == NULL) {
81        SMBERROR("user failed malloc\n");
82        return;
83    }
84
85    SMB_MALLOC(group, char *, MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
86    if (group == NULL) {
87        SMBERROR("group failed malloc\n");
88        return;
89    }
90
91    if (is_memberd_tempuuid(uuidp)) {
92        SMBERROR("\tguid: TEMPUUID \n");
93    }
94    else {
95        SMBERROR("\tguid: 0x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x \n",
96                 uuidp->g_guid[0], uuidp->g_guid[1], uuidp->g_guid[2],
97                 uuidp->g_guid[3], uuidp->g_guid[4], uuidp->g_guid[5],
98                 uuidp->g_guid[6], uuidp->g_guid[7], uuidp->g_guid[8],
99                 uuidp->g_guid[9], uuidp->g_guid[10], uuidp->g_guid[11],
100                 uuidp->g_guid[12], uuidp->g_guid[13], uuidp->g_guid[14],
101                 uuidp->g_guid[15]
102                 );
103        kauth_cred_guid2uid(uuidp, &uid);
104        kauth_cred_guid2gid(uuidp, &gid);
105        kauth_cred_guid2pwnam(uuidp, user);
106        kauth_cred_guid2grnam(uuidp, group);
107        SMBERROR("\tuser/group: %s (%d)/%s (%d) \n", user, uid, group, gid);
108    }
109
110    if (user) {
111        SMB_FREE(user, M_TEMP);
112    }
113
114    if (group) {
115        SMB_FREE(group, M_TEMP);
116    }
117}
118
119
120static void
121smb_print_acl(struct smbnode *np, const char *function, struct kauth_acl *acl)
122{
123    uint32_t i;
124    char *buffer = NULL;
125    size_t buf_len = MAXPATHLEN * 2;
126
127    SMB_MALLOC(buffer, char *, buf_len, M_TEMP, M_WAITOK | M_ZERO);
128    if (buffer == NULL) {
129        SMBERROR("buffer failed malloc\n");
130        return;
131    }
132
133    if ((np == NULL) || (acl == NULL)) {
134        SMBERROR("node or acl is null \n");
135        return;
136    }
137
138    SMBERROR_LOCK(np, "function: %s node %s \n", function, np->n_name);
139
140    SMBERROR("acl_entrycount %d\n", acl->acl_entrycount);
141
142    bzero(buffer, buf_len);
143    if (acl->acl_flags & KAUTH_ACL_DEFER_INHERIT) {
144        strlcat(buffer, "defer_inherit ", buf_len);
145    }
146    if (acl->acl_flags & KAUTH_ACL_NO_INHERIT) {
147        strlcat(buffer, "no_inherit ", buf_len);
148    }
149    SMBERROR("acl_flags 0x%x ( %s) \n", acl->acl_flags, buffer);
150
151    if (acl->acl_entrycount != KAUTH_FILESEC_NOACL) {
152        for (i = 0; i < acl->acl_entrycount; i++) {
153            SMBERROR("ACE: %d \n", i);
154            smb_print_guid(&acl->acl_ace[i].ace_applicable);
155
156            /* Try to print out ace_flags in same order as ls does */
157            bzero(buffer, MAXPATHLEN);
158            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_INHERITED) {
159                strlcat(buffer, "inherited ", buf_len);
160            }
161            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_FILE_INHERIT) {
162                strlcat(buffer, "file_inherit ", buf_len);
163            }
164            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_DIRECTORY_INHERIT) {
165                strlcat(buffer, "dir_inherit ", buf_len);
166            }
167            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_LIMIT_INHERIT) {
168                strlcat(buffer, "limit_inherit ", buf_len);
169            }
170            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_ONLY_INHERIT) {
171                strlcat(buffer, "only_inherit ", buf_len);
172            }
173            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_SUCCESS) {
174                strlcat(buffer, "success ", buf_len);
175            }
176            if (acl->acl_ace[i].ace_flags & KAUTH_ACE_FAILURE) {
177                strlcat(buffer, "failure ", buf_len);
178            }
179            switch(acl->acl_ace[i].ace_flags & KAUTH_ACE_KINDMASK) {
180				case KAUTH_ACE_PERMIT:
181                    strlcat(buffer, "allow ", buf_len);
182					break;
183			    case KAUTH_ACE_DENY:
184                    strlcat(buffer, "deny ", buf_len);
185					break;
186			    case KAUTH_ACE_AUDIT:
187                    strlcat(buffer, "audit ", buf_len);
188					break;
189			    case KAUTH_ACE_ALARM:
190                    strlcat(buffer, "alarm ", buf_len);
191					break;
192			    default:
193                    strlcat(buffer, "unknown_kind ", buf_len);
194			}
195
196            SMBERROR("\tflags 0x%x ( %s) \n", acl->acl_ace[i].ace_flags,
197                     buffer);
198
199            /* Try to print out ace_rights in same order as ls does */
200            bzero(buffer, buf_len);
201            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_READ_DATA) {
202                strlcat(buffer, "read ", buf_len);
203            }
204            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_WRITE_DATA) {
205                strlcat(buffer, "write ", buf_len);
206            }
207            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_EXECUTE) {
208                strlcat(buffer, "execute ", buf_len);
209            }
210            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_DELETE) {
211                strlcat(buffer, "delete ", buf_len);
212            }
213            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_APPEND_DATA) {
214                strlcat(buffer, "append ", buf_len);
215            }
216            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_DELETE_CHILD) {
217                strlcat(buffer, "delete_child ", buf_len);
218            }
219            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_READ_ATTRIBUTES) {
220                strlcat(buffer, "read_attr ", buf_len);
221            }
222            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_WRITE_ATTRIBUTES) {
223                strlcat(buffer, "write_attr ", buf_len);
224            }
225            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_READ_EXTATTRIBUTES) {
226                strlcat(buffer, "read_ext_attr ", buf_len);
227            }
228            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_WRITE_EXTATTRIBUTES) {
229                strlcat(buffer, "write_ext_attr ", buf_len);
230            }
231            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_READ_SECURITY) {
232                strlcat(buffer, "read_security ", buf_len);
233            }
234            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_WRITE_SECURITY) {
235                strlcat(buffer, "write_security ", buf_len);
236            }
237            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_CHANGE_OWNER) {
238                strlcat(buffer, "change_owner ", buf_len);
239            }
240            if (acl->acl_ace[i].ace_rights & KAUTH_ACE_GENERIC_READ) {
241                strlcat(buffer, "generic_read ", buf_len);
242            }
243            if (acl->acl_ace[i].ace_rights & KAUTH_ACE_GENERIC_WRITE) {
244                strlcat(buffer, "generic_write ", buf_len);
245            }
246            if (acl->acl_ace[i].ace_rights & KAUTH_ACE_GENERIC_EXECUTE) {
247                strlcat(buffer, "generic_execute ", buf_len);
248            }
249            if (acl->acl_ace[i].ace_rights & KAUTH_ACE_GENERIC_ALL) {
250                strlcat(buffer, "generic_all ", buf_len);
251            }
252            if (acl->acl_ace[i].ace_rights & KAUTH_VNODE_SYNCHRONIZE) {
253                strlcat(buffer, "synchronize ", buf_len);
254            }
255            SMBERROR("\trights 0x%x ( %s) \n", acl->acl_ace[i].ace_rights,
256                     buffer);
257        }
258    }
259    else {
260        SMBERROR("No ACE's \n");
261    }
262
263    if (buffer) {
264        SMB_FREE(buffer, M_TEMP);
265    }
266}
267#endif
268
269/*
270 * Check to see if this is a temporary uuid, generated by Directory Service
271 */
272int
273is_memberd_tempuuid(const guid_t *uuidp)
274{
275	if ((bcmp(uuidp, tmpuuid1, sizeof(tmpuuid1)) == 0) ||
276		(bcmp(uuidp, tmpuuid2, sizeof(tmpuuid2)) == 0)) {
277		return TRUE;
278	}
279	return FALSE;
280}
281
282/*
283 * Free any memory and clear any value used by the acl caching
284 * We have a lock around this routine to make sure no one plays
285 * with these values until we are done.
286 */
287void
288smbfs_clear_acl_cache(struct smbnode *np)
289{
290	lck_mtx_lock(&np->f_ACLCacheLock);
291    if (np->acl_cache_data) {
292        SMB_FREE(np->acl_cache_data, M_TEMP);
293    }
294	np->acl_cache_data = NULL;
295	np->acl_cache_timer = 0;
296	np->acl_error = 0;
297	np->acl_cache_len = 0;
298	lck_mtx_unlock(&np->f_ACLCacheLock);
299}
300
301/*
302 * Get a pointer to the offset requested. Verify that the offset is
303 * is in bounds and the structure does not go past the end of the buffer.
304 */
305static void *
306smb_sdoffset(struct ntsecdesc *w_secp, size_t w_seclen, int sd_type)
307{
308	void	*rt_ptr;
309	int32_t	sd_off = 0;
310	int32_t	sd_len = 0;
311	int32_t	end_len = 0;
312
313	if (sd_type == OWNER_SECURITY_INFORMATION) {
314		sd_len = (int32_t)sizeof(struct ntsid);
315		sd_off = letohl(w_secp->OffsetOwner);
316	}
317	else if (sd_type == GROUP_SECURITY_INFORMATION) {
318		sd_len = (int32_t)sizeof(struct ntsid);
319		sd_off = letohl(w_secp->OffsetGroup);
320	}
321	else if (sd_type == DACL_SECURITY_INFORMATION) {
322		sd_len = (int32_t)sizeof(struct ntacl);
323		sd_off = letohl(w_secp->OffsetDacl);
324	}
325	else if (sd_type == SACL_SECURITY_INFORMATION) {
326		sd_len = (int32_t)sizeof(struct ntacl);
327		sd_off = letohl(w_secp->OffsetSacl);
328	}
329
330	/* Make sure w_seclen is reasonable, once typed cast */
331	if ((int32_t)w_seclen < 0)
332		return 	NULL;
333
334	/* Make sure the length is reasonable */
335	if (sd_len > (int32_t)w_seclen)
336		return 	NULL;
337
338	/*
339	 * Make sure the offset is reasonable. NOTE: We can get a zero offset which
340	 * is legal, just means no entry was sent. So we just return a null pointer
341	 * since that doesn't cause an error.
342	 */
343	if ((sd_off <= 0) || (sd_off > (int32_t)w_seclen))
344		return 	NULL;
345
346	/* Make sure adding them together is reasonable */
347	end_len = sd_off+sd_len;
348	if ((end_len < 0) || (end_len > (int32_t)w_seclen))
349		return 	NULL;
350
351	rt_ptr = sd_off+(uint8_t *)w_secp;
352
353	return 	rt_ptr;
354}
355
356/*
357 * Used for debugging and writing error messages into the system log. Still
358 * needs to have buffer checking done on it.
359 */
360static void
361smb_printsid(struct ntsid *sidptr, char *sidendptr, const char *printstr,
362				  const char *filename, int index, int error)
363{
364	char sidprintbuf[MAX_SID_PRINTBUFFER];
365	char *s = sidprintbuf;
366	int subs;
367	uint64_t auth = 0;
368	unsigned i, *ip;
369	size_t len;
370	uint32_t *subauthptr = (uint32_t *)((char *)sidptr + sizeof(struct ntsid));
371	char *subauthendptr;
372
373	bzero(sidprintbuf, MAX_SID_PRINTBUFFER);
374	for (i = 0; i < sizeof(sidptr->sid_authority); i++)
375		auth = (auth << 8) | sidptr->sid_authority[i];
376	s += snprintf(s, MAX_SID_PRINTBUFFER, "S-%u-%llu", sidptr->sid_revision, auth);
377
378	subs = sidptr->sid_subauthcount;
379	if (subs > KAUTH_NTSID_MAX_AUTHORITIES) {
380		SMBERROR("sid_subauthcount > KAUTH_NTSID_MAX_AUTHORITIES : %d\n", subs);
381		subs = KAUTH_NTSID_MAX_AUTHORITIES;
382	}
383	/*
384	 * We know that sid_subauthcount has to be less than or equal to
385	 * KAUTH_NTSID_MAX_AUTHORITIES which is currently 16. So the highest
386	 * this can go is 16 * sizeof(uint32_t) so no overflow problem here.
387	 */
388	subauthendptr = (char *)((char *)subauthptr + (subs * sizeof(uint32_t)));
389
390	if (subauthendptr > sidendptr) {
391		len = MAX_SID_PRINTBUFFER - (s - sidprintbuf);
392		(void)snprintf(s, len, " buffer overflow prevented: %p > %p",
393					   subauthendptr, sidendptr);
394		return;
395	}
396
397	for (ip = subauthptr; subs--; ip++)  {
398		len = MAX_SID_PRINTBUFFER - (s - sidprintbuf);
399		DBG_ASSERT(len > 0)
400		s += snprintf(s, len, "-%u", *ip);
401	}
402
403	if (error) {
404		SMBWARNING("%s: sid[%d] = %s error = %d %s%s\n", printstr, index,
405				   sidprintbuf, error, (filename) ? "for " : "", filename);
406	} else {
407		SMBWARNING("%s: sid[%d] = %s %s%s\n", printstr, index, sidprintbuf,
408				   (filename) ? "for " : "", filename);
409	}
410}
411
412static int
413smb_sid_is_equal(const ntsid_t * rhs, const ntsid_t * lhs)
414{
415	if (rhs->sid_kind != lhs->sid_kind) {
416		return 0;
417	}
418
419	if (rhs->sid_authcount != lhs->sid_authcount) {
420		return 0;
421	}
422
423	if (bcmp(rhs->sid_authority, lhs->sid_authority,
424			 sizeof(rhs->sid_authority)) != 0) {
425		return 0;
426	}
427
428	if (bcmp(rhs->sid_authorities, lhs->sid_authorities,
429			 sizeof(uint32_t) * rhs->sid_authcount) != 0) {
430		return 0;
431	}
432	return 1;
433}
434
435/*
436 * Return 1 or 0, depending on whether the SID is in the domain given by the
437 * domain SID.
438 */
439static int
440smb_sid_in_domain(const ntsid_t * domain, const ntsid_t * sid)
441{
442	ntsid_t tmp = *sid;
443
444	if (tmp.sid_authcount == 0) {
445		SMBDEBUG("Bogus network sid sid_authcount = %d\n", tmp.sid_authcount);
446		return 0;
447	}
448	tmp.sid_authcount -= 1;
449	return smb_sid_is_equal(domain, &tmp);
450}
451
452/*
453 * If a Windows Server 2008 R2 NFS share is configured to enable Unmapped UNIX
454 * User Access and there is no existing mapping available to the NFSserver (via
455 * either [MS-UNMP] or [RFC2307]) then the server will encode the owner, group,
456 * and mode of a file into a security descriptor directly using generated SIDs.
457 * The NFSserver uses a specific sub-authority (SECURITY_NFS_ID_BASE_RID == 0x00000058)
458 * relative to the well known authority "NT Authority" (SECURITY_NT_AUTHORITY == {0,0,0,0,0,5}).
459 * The NFSserver then uses further relative sub-authorities to build SIDs for
460 * different NfsTypes that represent the owner (0x00000001), the group (0x00000002),
461 * and the permissions mask (0x00000003) for the file. A further SID is also
462 * generated, which is used to store the other, or world access mask, within the
463 * security descriptor.
464 *
465 * "<NTSecurityAuthority>-<SECURITY_NFS_ID_BASE_RID>-<NfsSidType>-<NfsSidValue>"
466 *
467 * To construct a complete security descriptor, the NFSserver generates a set
468 * of NFS-specific SIDs based on the UID, GID, and mode bits to be represented:
469 *
470 * Owner SID based on the UID (for example, "S-1-5-88-1-<uid>")
471 * Group SID based on the GID (for example, "S-1-5-88-2-<gid>")
472 * Mode SID based on the UNIX mode bits (for example, "S-1-5-88-3-<mode>")
473 * Other SID, a constant value (for example, "S-1-5-88-4")
474 */
475static const uint8_t security_nt_authority[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05};
476#define SECURITY_NFS_ID_BASE_RID	0x00000058
477enum {
478	NfsSidTypeOwner = 1,
479	NfsSidTypeGroup = 2,
480	NfsSidTypeModes = 3,
481	NfsSidTypeOther = 4
482};
483
484static Boolean
485WindowsNfsSID(struct smbnode *np, ntsid_t *sidptr)
486{
487	if ((sidptr->sid_kind == 1) && (sidptr->sid_authcount == 3) &&
488		(memcmp(sidptr->sid_authority, security_nt_authority, sizeof(security_nt_authority)) == 0) &&
489		(sidptr->sid_authorities[0] == SECURITY_NFS_ID_BASE_RID)) {
490
491		switch (sidptr->sid_authorities[1]) {
492			case NfsSidTypeOwner:
493				SMB_LOG_ACCESS_LOCK(np, "%s has a NfsSidTypeOwner of %d\n",
494                                    np->n_name, sidptr->sid_authorities[2]);
495				np->n_nfs_uid = sidptr->sid_authorities[2];
496				break;
497			case NfsSidTypeGroup:
498				SMB_LOG_ACCESS_LOCK(np, "%s has a NfsSidTypeGroup of %d\n",
499                                    np->n_name, sidptr->sid_authorities[2]);
500				np->n_nfs_gid = sidptr->sid_authorities[2];
501				break;
502			case NfsSidTypeModes:
503				SMB_LOG_ACCESS_LOCK(np, "%s has a NfsSidTypeModes of O%o\n",
504                                    np->n_name, sidptr->sid_authorities[2]);
505				np->n_flag |= NHAS_POSIXMODES;
506				np->n_mode &= ~ACCESSPERMS;
507				np->n_mode |= (mode_t)(sidptr->sid_authorities[2] & ACCESSPERMS);
508				break;
509			case NfsSidTypeOther:
510				SMB_LOG_ACCESS_LOCK(np, "%s has a NfsSidTypeOther of O%o\n",
511                                    np->n_name, sidptr->sid_authorities[2]);
512				break;
513			default:
514				SMB_LOG_ACCESS_LOCK(np, "%s: unknown NfsSidType of 0x%x 0x%x\n", np->n_name,
515                                    sidptr->sid_authorities[1], sidptr->sid_authorities[2]);
516				break;
517		}
518		return TRUE;
519	}
520	return FALSE;
521}
522
523/*
524 * The calling routine will guarantee that sidptr has enough space to hold the
525 * ntsid structure, but we need to protect ourself from going pass the size
526 * of the ntsid structure and any values contain inside the ntsid structure.
527 *
528 * We no longer need to call smb_sid_endianize before calling this routine. We
529 * now do it place, should help with performance.
530 */
531static void
532smb_sid2sid16(struct ntsid *sidptr, ntsid_t *sid16ptr, char *sidendptr)
533{
534	uint8_t ii;
535	uint32_t *subauthptr = (uint32_t *)((char *)sidptr + sizeof(struct ntsid));
536	char *subauthendptr;
537
538	bzero(sid16ptr, sizeof(*sid16ptr));
539	if (sidptr->sid_subauthcount > KAUTH_NTSID_MAX_AUTHORITIES) {
540		SMBERROR("sidp->sid_subauthcount count too big: %d\n",
541				 sidptr->sid_subauthcount);
542		return;
543	}
544
545	/*
546	 * We know that sid_subauthcount has to be less than or equal to
547	 * KAUTH_NTSID_MAX_AUTHORITIES which is currently 16. So the highest
548	 * this can go is 16 * sizeof(uint32_t) so no overflow problem here.
549	 */
550	subauthendptr = (char *)((char *)subauthptr +
551							 (sidptr->sid_subauthcount * sizeof(uint32_t)));
552	if (subauthendptr > sidendptr) {
553		SMBERROR("Too many sid authorities: %p %p\n", subauthendptr, sidendptr);
554		return;
555	}
556	sid16ptr->sid_kind = sidptr->sid_revision;
557	sid16ptr->sid_authcount = sidptr->sid_subauthcount;
558
559	/* Why not just a bcopy? */
560	for (ii = 0; ii < sizeof(sid16ptr->sid_authority); ii++)
561		sid16ptr->sid_authority[ii] = sidptr->sid_authority[ii];
562
563	for (ii = 0; ii < sid16ptr->sid_authcount; ii++) {
564		sid16ptr->sid_authorities[ii] = letohl(*subauthptr);
565		subauthptr++;
566	}
567}
568
569/*
570 * The calling routine will guarantee that sidptr has enough space to hold the
571 * ntsid structure, but we need to protect ourself from going pass the size
572 * of the ntsid structure and any values contain inside the ntsid structure.
573 *
574 * Really over kill, but what the heck lets double check that the user land
575 * code didn't send us something bad.
576 */
577static void
578smb_sid_endianize(struct ntsid *sidptr, size_t len)
579{
580	char *sidendptr = (char *)sidptr + len;
581	uint32_t *subauthptr = (uint32_t *)((char *)sidptr + sizeof(struct ntsid));
582	char *subauthendptr;
583	int n;
584
585	/*
586	 * We know that sid_subauthcount has to be less than or equal to
587	 * KAUTH_NTSID_MAX_AUTHORITIES which is currently 16. So the highest
588	 * this can go is 16 * sizeof(uint32_t) so no overflow problem here.
589	 */
590	subauthendptr = (char *)((char *)subauthptr +
591							 (sidptr->sid_subauthcount * sizeof(uint32_t)));
592	if (subauthendptr > sidendptr) {
593		SMBERROR("Too many sid authorities: %p %p\n", subauthendptr, sidendptr);
594		return;
595	}
596
597	n = sidptr->sid_subauthcount;
598	while (n--) {
599		*subauthptr = letohl(*subauthptr);
600		subauthptr++;
601	}
602}
603
604/*
605 * This is the main routine that goes across the network to get our acl
606 * information. We now always ask for everything so we can make less calls. If
607 * the cache data is up to date then we will return that information. We also do
608 * negative caching, if the server returns an error we cache that fact and
609 * continue to return the error until the cache information times out.
610 *
611 * Remember that the vfs will help us with caching, but not in the negative case.
612 * Also it does not solve the problem of multiple different calls coming into us
613 * back to back. So in a typical case we will get the following calls and they
614 * will require an acl lookup for each item.
615 *
616 * UID and GID request
617 * Do we have write access
618 * Do we have read access
619 * Do we have search/excute access
620 *
621 * So by caching we are removing 12 network calls for each file in a directory.
622 * We only hold on to this cache for a very short time, because it has a memory
623 * cost that we don't want to pay for any real length of time. This is ok, becasue
624 * one we go through this process the vfs layer will handle the longer caching of
625 * these request.
626 */
627static int
628smbfs_update_acl_cache(struct smb_share *share, struct smbnode *np,
629					   vfs_context_t context, struct ntsecdesc **w_sec,
630					   size_t *seclen)
631{
632	uint32_t selector = OWNER_SECURITY_INFORMATION |
633						GROUP_SECURITY_INFORMATION |
634						DACL_SECURITY_INFORMATION;
635	SMBFID fid = 0;
636	struct timespec	ts;
637	struct ntsecdesc *acl_cache_data = NULL;
638	size_t acl_cache_len = 0;
639	int	error = 0;
640	time_t attrtimeo;
641	int use_cached_data = 0;
642
643    /* If we are in reconnect, use cached data if we have it */
644    if (np->acl_cache_timer != 0) {
645        use_cached_data = (share->ss_flags & SMBS_RECONNECTING);
646    }
647
648	/* Check to see if the cache has timed out */
649    SMB_CACHE_TIME(ts, np, attrtimeo);
650    if (((ts.tv_sec - np->acl_cache_timer) <= attrtimeo) ||
651        use_cached_data) {
652		/* Ok the cache is still good take a lock and retrieve the data */
653		lck_mtx_lock(&np->f_ACLCacheLock);
654
655        SMB_CACHE_TIME(ts, np, attrtimeo);
656        if (((ts.tv_sec - np->acl_cache_timer) <= attrtimeo) ||
657            use_cached_data) {
658			/* We have the lock and the cache is still good, use the cached ACL */
659			goto done;
660		}
661        else {
662			/*
663			 * Cache expired while we were waiting on the lock, release the lock
664			 * and get the ACL from the network.
665			 */
666			lck_mtx_unlock(&np->f_ACLCacheLock);
667		}
668    }
669
670    if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
671        /* Only open file if its SMB 1 */
672        error = smbfs_tmpopen(share, np, SMB2_READ_CONTROL, &fid, context);
673    }
674
675	if (error == 0) {
676		int cerror;
677
678        error = smbfs_smb_getsec(share, np, SMB2_READ_CONTROL | SMB2_SYNCHRONIZE, fid, selector,
679                                 (struct ntsecdesc **)&acl_cache_data,
680                                 &acl_cache_len, context);
681
682        if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
683            /* Only close file if its SMB 1 */
684            cerror = smbfs_tmpclose(share, np, fid, context);
685            if (cerror) {
686                SMBWARNING_LOCK(np, "error %d closing fid %llx file %s\n",
687                                cerror, fid, np->n_name);
688            }
689        }
690
691        if ((error == 0) && (acl_cache_data == NULL))
692			error = EBADRPC;
693	}
694
695	/* Don't let anyone play with the acl cache until we are done */
696	lck_mtx_lock(&np->f_ACLCacheLock);
697
698    if ((error == ETIMEDOUT) && (np->acl_cache_timer != 0)) {
699        /* Just return the cached data */
700        error = 0;
701        np->acl_error = error;
702        goto done;
703    }
704
705	/* Free the old data no longer needed */
706	if (np->acl_cache_data)
707		SMB_FREE(np->acl_cache_data, M_TEMP);
708
709	np->acl_cache_data = acl_cache_data;
710	np->acl_cache_len = acl_cache_len;
711	np->acl_error = error;
712
713	/* We have new information reset our timer  */
714    np->acl_cache_timer = ts.tv_sec;
715
716done:
717	if (np->acl_error || (np->acl_cache_data == NULL)) {
718		*w_sec = NULL;
719		*seclen = 0;
720		if (np->acl_error == 0)
721			np->acl_error =  EBADRPC; /* Should never happen, but just to be safe */
722	} else {
723		SMB_MALLOC(*w_sec, struct ntsecdesc *, np->acl_cache_len, M_TEMP, M_WAITOK);
724		if (*w_sec) {
725			*seclen = np->acl_cache_len;
726			bcopy(np->acl_cache_data, *w_sec, np->acl_cache_len);
727		} else {
728			*w_sec = np->acl_cache_data;
729			*seclen = np->acl_cache_len;
730			np->acl_cache_data = NULL;
731			np->acl_cache_len = 0;
732			np->acl_cache_timer = 0;
733		}
734	}
735	error = np->acl_error;
736	lck_mtx_unlock(&np->f_ACLCacheLock);
737	return error;
738}
739
740/*
741 * Universal routine for getting the UUID/GUID and setting the nodes
742 * uid/gid. We will get the nodes UUID and set its uid if the owner flag
743 * is set, otherwise we get the nodes GUID and set its gid.
744 */
745static void
746smbfs_set_node_identifier(struct smbnode *np, struct ntsecdesc *w_sec,
747						  size_t seclen, guid_t *unique_identifier, int owner)
748{
749	struct smbmount *smp = np->n_mount;
750	struct ntsid	*w_sidp = NULL;
751	ntsid_t			sid;
752	uid_t			*node_identifier;
753	int				error;
754
755	if (owner) {
756		if (w_sec)	/* Getting the security descriptor failed */
757			w_sidp = sdowner(w_sec, seclen);
758		node_identifier = &np->n_uid;
759	} else {
760		if (w_sec)	/* Getting the security descriptor failed */
761			w_sidp = sdgroup(w_sec, seclen);
762		node_identifier = &np->n_gid;
763	}
764
765	if (!w_sidp || !w_sec) {
766		SMB_LOG_ACCESS_LOCK(np, "no %s sid received, file %s\n",
767                            (owner) ? "user" : "group", np->n_name);
768		goto error_out;
769	}
770
771	smb_sid2sid16(w_sidp, &sid, (char*)w_sec+seclen);
772	/* We are mapping the owner id, so if its a match replace it with the local id */
773	if (owner && (smp->sm_flags & MNT_MAPS_NETWORK_LOCAL_USER) &&
774		(bcmp(&smp->ntwrk_sids[0], &sid, sizeof(sid)) == 0)) {
775		*unique_identifier = smp->sm_args.uuid;
776		*node_identifier = smp->sm_args.uid;
777		return; /* We are done */
778	}
779
780	error = kauth_cred_ntsid2guid(&sid, unique_identifier);
781	if (error) {
782		if (smbfs_loglevel == SMB_ACL_LOG_LEVEL) {
783            lck_rw_lock_shared(&np->n_name_rwlock);
784			smb_printsid(w_sidp, (char*)w_sec+seclen, "Owner/Group lookup failed",
785						 (const char  *)np->n_name, 0, error);
786            lck_rw_unlock_shared(&np->n_name_rwlock);
787        }
788		goto error_out;
789	}
790
791	/*
792	 * This is a cheap call since we lookup the uuid/guid above, so the kernel
793	 * will have the uid or gid in its cache. If we get a temp gid/uid and we
794	 * already have a uid/gid always use the one we already have.
795	 */
796	if (is_memberd_tempuuid(unique_identifier) &&
797		(*node_identifier != KAUTH_UID_NONE)) {
798		return; /* We already have a real uid/gid from the server keep using it */
799	}
800
801	if (owner)
802		error = kauth_cred_ntsid2uid(&sid, node_identifier);
803	else
804		error = kauth_cred_ntsid2gid(&sid, node_identifier);
805	if (error == 0)
806		return; /* We are done */
807
808error_out:
809	/* Not sure what else to do here, so we default to the mounted users uid/gid */
810	if (*node_identifier == KAUTH_UID_NONE)
811		*node_identifier = (owner) ? smp->sm_args.uid : smp->sm_args.gid;
812	/* Something bad happen and we didn't get the UUID/GUID */
813	if (kauth_guid_equal(unique_identifier, &kauth_null_guid)) {
814		/* At this point we have a uid/gid, so use it to get the UUID/GUID */
815		if (owner)
816			error = kauth_cred_uid2guid(*node_identifier, unique_identifier);
817		else
818			error = kauth_cred_gid2guid(*node_identifier, unique_identifier);
819		/* Should never error out in the case, but just in case lets log it */
820		if (error) {
821			SMB_LOG_ACCESS_LOCK(np, "%s couldn't translate the uid/gid %d to a UUID/GUID, error = %d\n",
822                                np->n_name, *node_identifier, error);
823		}
824	}
825}
826
827/*
828 * This routine will retrieve the owner, group and any ACLs associate with
829 * this node. We treat an access error the same as an empty security descriptor.
830 *
831 * The calling routine must hold a reference on the share
832 *
833 */
834int
835smbfs_getsecurity(struct smb_share *share, struct smbnode *np,
836                  struct vnode_attr *vap, vfs_context_t context)
837{
838	struct smbmount		*smp = np->n_mount;
839	int					error;
840	struct ntsecdesc	*w_sec;	/* Wire sec descriptor */
841	size_t				seclen = 0;
842	kauth_acl_t			res = NULL;	/* acl result buffer */
843
844	/* We do not support acl access on a stream node */
845	if (vnode_isnamedstream(np->n_vnode))
846		return EINVAL;
847
848    SMB_LOG_KTRACE(SMB_DBG_SMBFS_GET_SEC | DBG_FUNC_START, 0, 0, 0, 0, 0);
849
850	if (VATTR_IS_ACTIVE(vap, va_acl))
851		vap->va_acl = NULL;					/* default */
852
853	if (VATTR_IS_ACTIVE(vap, va_guuid))
854		vap->va_guuid = kauth_null_guid;	/* default */
855
856	if (VATTR_IS_ACTIVE(vap, va_uuuid))
857		vap->va_uuuid = kauth_null_guid;	/* default */
858
859	/* Check to make sure we have current acl information */
860	error = smbfs_update_acl_cache(share, np, context, &w_sec, &seclen);
861	if (error) {
862		if (w_sec)
863			SMB_FREE(w_sec, M_TEMP);
864		w_sec = NULL;
865		/*
866		 * When should we eat the error and when shouldn't we, that is the
867		 * real question? Any error here will fail the copy engine. Not sure
868		 * thats what we really want. We currently only ignore an access error,
869		 * but in the future we may want return all errors or none. The old
870		 * code ignored all errors, now we only ignore EACCES.
871		 */
872		if (error == EACCES) {
873			error = 0;
874		}
875        else {
876			SMB_LOG_ACCESS_LOCK(np, "smbfs_update_acl_cache of %s failed with error = %d\n",
877                                np->n_name, error);
878		}
879	}
880
881	/*
882	 * The smbfs_set_node_identifier routine will check to see if w_sec
883	 * is null. If null it will do what is need to return the correct
884	 * values.
885     *
886     * smbfs_set_node_identifier will set the np->n_uid/n_gid based on the
887     * ACL values returned by the server
888	 */
889	if (VATTR_IS_ACTIVE(vap, va_guuid)) {
890		smbfs_set_node_identifier(np, w_sec, seclen, &vap->va_guuid, FALSE);
891	}
892	if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
893		smbfs_set_node_identifier(np, w_sec, seclen, &vap->va_uuuid, TRUE);
894	}
895
896	if (VATTR_IS_ACTIVE(vap, va_acl)) {
897		struct ntacl		*w_dacl = NULL;
898		char				*endptr;
899		uint32_t			acecount, j, aflags;
900		struct ntsid		*w_sidp;	/* Wire SID */
901		struct ntace		*w_acep = NULL;	/* Wire ACE */
902		kauth_ace_rights_t	arights;
903		uint32_t			w_rights;
904		ntsid_t				sid;	/* temporary, for a kauth sid */
905
906		if (w_sec)
907			w_dacl = sddacl(w_sec, seclen);
908		if (!w_dacl || !w_sec)
909			goto exit;
910		/* Is there anything we can do to verify acecount, just not sure */
911		acecount = letohs(w_dacl->acl_acecount);
912		res = kauth_acl_alloc(acecount);
913		if (!res) {
914			error = ENOMEM;
915			goto exit;
916		}
917		/* Only count entries we add to the array, don't count dropped entries */
918		res->acl_entrycount = 0;
919		res->acl_flags = letohs(w_sec->ControlFlags);
920		if (res->acl_flags & SE_DACL_PROTECTED)
921			res->acl_flags |= KAUTH_FILESEC_NO_INHERIT;
922		else
923			res->acl_flags &= ~KAUTH_FILESEC_NO_INHERIT;
924
925		endptr = (char *)w_sec+seclen;
926
927		for (j = 0, w_acep = aclace(w_dacl); (((char *)acesid(w_acep) < endptr) &&
928				(j < acecount));  j++, w_acep = aceace(w_acep)) {
929			int	warn_error = 0;
930
931			switch(acetype(w_acep)) {
932			    case ACCESS_ALLOWED_ACE_TYPE:
933					aflags = KAUTH_ACE_PERMIT;
934					break;
935			    case ACCESS_DENIED_ACE_TYPE:
936					aflags = KAUTH_ACE_DENY;
937					break;
938			    case SYSTEM_AUDIT_ACE_TYPE:
939					aflags = KAUTH_ACE_AUDIT;
940					break;
941			    case SYSTEM_ALARM_ACE_TYPE:
942					aflags = KAUTH_ACE_ALARM;
943					break;
944			    default:
945					SMBERROR_LOCK(np, "ACE type %d file(%s)\n", acetype(w_acep), np->n_name);
946					error = EPROTO;	/* Should it be EIO */
947					goto exit;
948			}
949			w_sidp = acesid(w_acep);
950			if ((char *)w_sidp+sizeof(*w_sidp) > endptr) {
951				SMBERROR_LOCK(np, "ACE type %d file(%s) would have caused a buffer overrun!\n",
952                              acetype(w_acep), np->n_name);
953
954				error = EPROTO;	/* Should it be EIO */
955				goto exit;
956			}
957			smb_sid2sid16(w_sidp, &sid, (char*)w_sec+seclen);
958			if (WindowsNfsSID(np, &sid)) {
959				continue;
960			}
961			if ((smp->sm_flags & MNT_MAPS_NETWORK_LOCAL_USER) &&
962				(bcmp(&smp->ntwrk_sids[0], &sid, sizeof(sid)) == 0)) {
963				res->acl_ace[res->acl_entrycount].ace_applicable = smp->sm_args.uuid;
964			} else {
965				warn_error = kauth_cred_ntsid2guid(&sid, &res->acl_ace[res->acl_entrycount].ace_applicable);
966			}
967			if (warn_error) {
968				if (smbfs_loglevel == SMB_ACL_LOG_LEVEL) {
969                    lck_rw_lock_shared(&np->n_name_rwlock);
970					smb_printsid(w_sidp, (char*)w_sec+seclen, "ACL lookup failed",
971								 (const char  *)np->n_name, j, warn_error);
972                    lck_rw_unlock_shared(&np->n_name_rwlock);
973				}
974				continue;
975			}
976#if DEBUG_ACLS
977            else {
978                lck_rw_lock_shared(&np->n_name_rwlock);
979                smb_printsid(w_sidp, (char*)w_sec+seclen, "sid maps to",
980                             (const char  *)np->n_name, j, 0);
981                lck_rw_unlock_shared(&np->n_name_rwlock);
982                smb_print_guid(&res->acl_ace[res->acl_entrycount].ace_applicable);
983            }
984#endif
985
986			if (aceflags(w_acep) & OBJECT_INHERIT_ACE_FLAG)
987				aflags |= KAUTH_ACE_FILE_INHERIT;
988			if (aceflags(w_acep) & CONTAINER_INHERIT_ACE_FLAG)
989				aflags |= KAUTH_ACE_DIRECTORY_INHERIT;
990			if (aceflags(w_acep) & NO_PROPAGATE_INHERIT_ACE_FLAG)
991				aflags |= KAUTH_ACE_LIMIT_INHERIT;
992			if (aceflags(w_acep) & INHERIT_ONLY_ACE_FLAG)
993				aflags |= KAUTH_ACE_ONLY_INHERIT;
994			if (aceflags(w_acep) & INHERITED_ACE_FLAG)
995				aflags |= KAUTH_ACE_INHERITED;
996			if (aceflags(w_acep) & UNDEF_ACE_FLAG) {
997				SMBERROR_LOCK(np, "unknown ACE flag on file(%s)\n", np->n_name);
998            }
999			if (aceflags(w_acep) & SUCCESSFUL_ACCESS_ACE_FLAG)
1000				aflags |= KAUTH_ACE_SUCCESS;
1001			if (aceflags(w_acep) & FAILED_ACCESS_ACE_FLAG)
1002				aflags |= KAUTH_ACE_FAILURE;
1003			res->acl_ace[res->acl_entrycount].ace_flags = aflags;
1004
1005            w_rights = acerights(w_acep);
1006			arights = 0;
1007			if (w_rights & SMB2_GENERIC_READ)
1008				arights |= KAUTH_ACE_GENERIC_READ;
1009			if (w_rights & SMB2_GENERIC_WRITE)
1010				arights |= KAUTH_ACE_GENERIC_WRITE;
1011			if (w_rights & SMB2_GENERIC_EXECUTE)
1012				arights |= KAUTH_ACE_GENERIC_EXECUTE;
1013			if (w_rights & SMB2_GENERIC_ALL)
1014				arights |= KAUTH_ACE_GENERIC_ALL;
1015			if (w_rights & SMB2_SYNCHRONIZE)
1016				arights |= KAUTH_VNODE_SYNCHRONIZE;
1017			if (w_rights & SMB2_WRITE_OWNER)
1018				arights |= KAUTH_VNODE_CHANGE_OWNER;
1019			if (w_rights & SMB2_WRITE_DAC)
1020				arights |= KAUTH_VNODE_WRITE_SECURITY;
1021			if (w_rights & SMB2_READ_CONTROL)
1022				arights |= KAUTH_VNODE_READ_SECURITY;
1023			if (w_rights & SMB2_DELETE)
1024				arights |= KAUTH_VNODE_DELETE;
1025
1026			if (w_rights & SMB2_FILE_WRITE_ATTRIBUTES)
1027				arights |= KAUTH_VNODE_WRITE_ATTRIBUTES;
1028			if (w_rights & SMB2_FILE_READ_ATTRIBUTES)
1029				arights |= KAUTH_VNODE_READ_ATTRIBUTES;
1030			if (w_rights & SMB2_FILE_DELETE_CHILD)
1031				arights |= KAUTH_VNODE_DELETE_CHILD;
1032			if (w_rights & SMB2_FILE_EXECUTE)
1033				arights |= KAUTH_VNODE_EXECUTE;
1034			if (w_rights & SMB2_FILE_WRITE_EA)
1035				arights |= KAUTH_VNODE_WRITE_EXTATTRIBUTES;
1036			if (w_rights & SMB2_FILE_READ_EA)
1037				arights |= KAUTH_VNODE_READ_EXTATTRIBUTES;
1038			if (w_rights & SMB2_FILE_APPEND_DATA)
1039				arights |= KAUTH_VNODE_APPEND_DATA;
1040			if (w_rights & SMB2_FILE_WRITE_DATA)
1041				arights |= KAUTH_VNODE_WRITE_DATA;
1042			if (w_rights & SMB2_FILE_READ_DATA)
1043				arights |= KAUTH_VNODE_READ_DATA;
1044			res->acl_ace[res->acl_entrycount].ace_rights = arights;
1045
1046			/* Success we have an entry, now count it */
1047			res->acl_entrycount++;
1048		}
1049#if DEBUG_ACLS
1050        smb_print_acl(np, "smbfs_getsecurity", res);
1051#endif
1052
1053		/* Only return the acl if we have at least one ace. */
1054		if (res->acl_entrycount) {
1055			vap->va_acl = res;
1056			res = NULL;
1057		}
1058	}
1059
1060exit:
1061	if (VATTR_IS_ACTIVE(vap, va_acl))
1062		VATTR_SET_SUPPORTED(vap, va_acl);
1063	if (VATTR_IS_ACTIVE(vap, va_guuid))
1064		VATTR_SET_SUPPORTED(vap, va_guuid);
1065	if (VATTR_IS_ACTIVE(vap, va_uuuid))
1066		VATTR_SET_SUPPORTED(vap, va_uuuid);
1067
1068	if (res)
1069		kauth_acl_free(res);
1070
1071	if (w_sec)
1072		SMB_FREE(w_sec, M_TEMP);
1073
1074    SMB_LOG_KTRACE(SMB_DBG_SMBFS_GET_SEC | DBG_FUNC_END, error, 0, 0, 0, 0);
1075	return error;
1076}
1077
1078/*
1079 * Fill in the network ace used to describe the posix uid, gid and modes.
1080 */
1081static struct ntace *
1082set_nfs_ace(struct ntace *w_acep, ntsid_t *nfs_sid, size_t needed)
1083{
1084	struct ntsid	*w_sidp;
1085
1086	wset_acetype(w_acep, ACCESS_DENIED_ACE_TYPE);
1087	wset_aceflags(w_acep, 0);
1088	wset_acerights(w_acep, 0);
1089	w_sidp = acesid(w_acep);
1090	bcopy(nfs_sid, w_sidp, sizeof(ntsid_t));
1091	smb_sid_endianize(w_sidp, needed);
1092	wset_acelen(w_acep, sizeof(struct ntace) + sidlen(w_sidp));
1093	return aceace(w_acep);
1094}
1095
1096/*
1097 * This routine will set the owner, group and any ACLs associate with
1098 * this node.
1099 *
1100 * The calling routine must hold a reference on the share
1101 *
1102 */
1103int
1104smbfs_setsecurity(struct smb_share *share, vnode_t vp, struct vnode_attr *vap,
1105				  vfs_context_t context)
1106{
1107	struct smbnode *np = VTOSMB(vp);
1108	struct smbmount *smp = np->n_mount;
1109	uint32_t selector = 0, acecount;
1110	struct ntsid	*w_usr = NULL, *w_grp = NULL, *w_sidp;
1111	struct ntacl	*w_dacl = NULL;	/* Wire DACL */
1112	int error;
1113	struct ntace *w_acep, *start_acep;	/* Wire ACE */
1114	struct kauth_ace *acep;
1115	uint8_t aflags;
1116	uint32_t arights, openrights;
1117	size_t needed;
1118	uint16_t ControlFlags = 0;
1119	SMBFID	fid = 0;
1120	uuid_string_t out_str;
1121
1122	/* We do not support acl access on a stream node */
1123	if (vnode_isnamedstream(vp))
1124		return ENOTSUP;
1125
1126    SMB_LOG_KTRACE(SMB_DBG_SMBFS_SET_SEC | DBG_FUNC_START, 0, 0, 0, 0, 0);
1127
1128	openrights = SMB2_READ_CONTROL | SMB2_SYNCHRONIZE;
1129	error = 0;
1130
1131	if (VATTR_IS_ACTIVE(vap, va_guuid) &&  !kauth_guid_equal(&vap->va_guuid, &kauth_null_guid)) {
1132		SMB_MALLOC(w_grp, struct ntsid *, MAXSIDLEN, M_TEMP, M_WAITOK);
1133		bzero(w_grp, MAXSIDLEN);
1134		error = kauth_cred_guid2ntsid(&vap->va_guuid, (ntsid_t *)w_grp);
1135		if (error) {
1136			uuid_unparse(*((const uuid_t *)&vap->va_guuid), out_str);
1137			SMBERROR("kauth_cred_guid2ntsid failed with va_guuid %s and error %d\n",
1138					 out_str, error);
1139			goto exit;
1140		}
1141		smb_sid_endianize(w_grp, MAXSIDLEN);
1142		openrights |= SMB2_WRITE_OWNER;
1143		selector |= GROUP_SECURITY_INFORMATION;
1144	}
1145
1146	if (VATTR_IS_ACTIVE(vap, va_uuuid) && !kauth_guid_equal(&vap->va_uuuid, &kauth_null_guid)) {
1147		SMB_MALLOC(w_usr, struct ntsid *, MAXSIDLEN, M_TEMP, M_WAITOK);
1148		bzero(w_usr, MAXSIDLEN);
1149		/* We are mapping the owner id, so if its a match replace it with the network sid */
1150		if ((smp->sm_flags & MNT_MAPS_NETWORK_LOCAL_USER) &&
1151			(kauth_guid_equal(&smp->sm_args.uuid, &vap->va_uuuid))) {
1152			bcopy(&smp->ntwrk_sids[0], w_usr, sizeof(ntsid_t));
1153			error = 0;
1154		} else {
1155			error = kauth_cred_guid2ntsid(&vap->va_uuuid, (ntsid_t *)w_usr);
1156		}
1157		if (error) {
1158			uuid_unparse(*((const uuid_t *)&vap->va_uuuid), out_str);
1159			SMBERROR("kauth_cred_guid2ntsid failed with va_uuuid %s and error %d\n",
1160					 out_str, error);
1161			goto exit;
1162		}
1163		smb_sid_endianize(w_usr, MAXSIDLEN);
1164		openrights |= SMB2_WRITE_OWNER;
1165		selector |= OWNER_SECURITY_INFORMATION;
1166	}
1167
1168	if (VATTR_IS_ACTIVE(vap, va_acl)) {
1169		ntsid_t nfs_sid;
1170
1171		openrights |= SMB2_WRITE_DAC;
1172		selector |= DACL_SECURITY_INFORMATION;
1173
1174		if (vap->va_acl) {
1175#if DEBUG_ACLS
1176            smb_print_acl(np, "smbfs_setsecurity", vap->va_acl);
1177#endif
1178			if (vap->va_acl->acl_flags & KAUTH_FILESEC_NO_INHERIT) {
1179				selector |= PROTECTED_DACL_SECURITY_INFORMATION;
1180				ControlFlags |= SE_DACL_PROTECTED;
1181			} else {
1182				selector |= UNPROTECTED_DACL_SECURITY_INFORMATION;
1183				ControlFlags &= ~SE_DACL_PROTECTED;
1184			}
1185		}
1186
1187		if ((vap->va_acl == NULL) || (vap->va_acl->acl_entrycount == KAUTH_FILESEC_NOACL)) {
1188			ControlFlags |= SE_DACL_PRESENT;
1189			/* If we are removing the ACL nothing left to do but set it. */
1190			goto set_dacl;
1191		}
1192
1193		if (vap->va_acl->acl_entrycount > KAUTH_ACL_MAX_ENTRIES) {
1194			SMBERROR_LOCK(np, "acl_entrycount=%d, file(%s)\n",
1195                          vap->va_acl->acl_entrycount, np->n_name);
1196			error = EINVAL;
1197			goto exit;
1198		}
1199
1200		acecount = vap->va_acl->acl_entrycount;
1201		if (np->n_nfs_uid != KAUTH_UID_NONE) {
1202			/* Make room for the Windows NFS UID ACE */
1203			acecount += 1;
1204		}
1205
1206		if (np->n_nfs_gid != KAUTH_GID_NONE) {
1207			/* Make room for the Windows NFS GID ACE */
1208			acecount += 1;
1209		}
1210
1211		if (np->n_flag & NHAS_POSIXMODES) {
1212			/* Make room for the Windows NFS Modes ACE */
1213			acecount += 1;
1214		}
1215
1216		needed = sizeof(struct ntacl) + acecount * (sizeof(struct ntace) + MAXSIDLEN);
1217		SMB_MALLOC(w_dacl, struct ntacl *, needed, M_TEMP, M_WAITOK);
1218		bzero(w_dacl, needed);
1219		w_dacl->acl_revision = 0x02;
1220		wset_aclacecount(w_dacl, acecount);
1221
1222		start_acep = aclace(w_dacl);
1223		nfs_sid.sid_kind = 1;
1224		nfs_sid.sid_authcount = 3;
1225		memcpy(nfs_sid.sid_authority, security_nt_authority, sizeof(security_nt_authority));
1226		nfs_sid.sid_authorities[0] = SECURITY_NFS_ID_BASE_RID;
1227
1228		if (np->n_nfs_uid != KAUTH_UID_NONE) {
1229			/* Set the Windows nfs uid ace */
1230			nfs_sid.sid_authorities[1] = NfsSidTypeOwner;
1231			nfs_sid.sid_authorities[2] = np->n_nfs_uid;
1232			start_acep = set_nfs_ace(start_acep,&nfs_sid, needed);
1233			acecount--;
1234		}
1235
1236		if (np->n_nfs_gid != KAUTH_GID_NONE) {
1237			/* Set the Windows nfs gid ace */
1238			nfs_sid.sid_authorities[1] = NfsSidTypeGroup;
1239			nfs_sid.sid_authorities[2] = np->n_nfs_gid;
1240			start_acep = set_nfs_ace(start_acep,&nfs_sid, needed);
1241			acecount--;
1242		}
1243
1244		if (np->n_flag & NHAS_POSIXMODES) {
1245			/* Set the Windows nfs posix modes ace */
1246			nfs_sid.sid_authorities[1] = NfsSidTypeModes;
1247			nfs_sid.sid_authorities[2] = np->n_mode;
1248			start_acep = set_nfs_ace(start_acep,&nfs_sid, needed);
1249			acecount--;
1250		}
1251
1252		for (w_acep = start_acep, acep = &vap->va_acl->acl_ace[0];
1253		     acecount--; w_acep = aceace(w_acep), acep++) {
1254			switch(acep->ace_flags & KAUTH_ACE_KINDMASK) {
1255				case KAUTH_ACE_PERMIT:
1256					wset_acetype(w_acep, ACCESS_ALLOWED_ACE_TYPE);
1257					break;
1258			    case KAUTH_ACE_DENY:
1259					wset_acetype(w_acep, ACCESS_DENIED_ACE_TYPE);
1260					break;
1261			    case KAUTH_ACE_AUDIT:
1262					wset_acetype(w_acep, SYSTEM_AUDIT_ACE_TYPE);
1263					break;
1264			    case KAUTH_ACE_ALARM:
1265					wset_acetype(w_acep, SYSTEM_ALARM_ACE_TYPE);
1266					break;
1267			    default:
1268					SMBERROR_LOCK(np, "ace_flags=0x%x, file(%s)\n",
1269                                  acep->ace_flags, np->n_name);
1270					error = EINVAL;
1271					goto exit;
1272			}
1273			aflags = 0;
1274			if (acep->ace_flags & KAUTH_ACE_INHERITED)
1275				aflags |= INHERITED_ACE_FLAG;
1276			if (acep->ace_flags & KAUTH_ACE_FILE_INHERIT)
1277				aflags |= OBJECT_INHERIT_ACE_FLAG;
1278			if (acep->ace_flags & KAUTH_ACE_DIRECTORY_INHERIT)
1279				aflags |= CONTAINER_INHERIT_ACE_FLAG;
1280			if (acep->ace_flags & KAUTH_ACE_LIMIT_INHERIT)
1281				aflags |= NO_PROPAGATE_INHERIT_ACE_FLAG;
1282			if (acep->ace_flags & KAUTH_ACE_ONLY_INHERIT)
1283				aflags |= INHERIT_ONLY_ACE_FLAG;
1284			if (acep->ace_flags & KAUTH_ACE_SUCCESS)
1285				aflags |= SUCCESSFUL_ACCESS_ACE_FLAG;
1286			if (acep->ace_flags & KAUTH_ACE_FAILURE)
1287				aflags |= FAILED_ACCESS_ACE_FLAG;
1288			wset_aceflags(w_acep, aflags);
1289			arights = 0;
1290			if (acep->ace_rights & KAUTH_ACE_GENERIC_READ)
1291				arights |= SMB2_GENERIC_READ;
1292			if (acep->ace_rights & KAUTH_ACE_GENERIC_WRITE)
1293				arights |= SMB2_GENERIC_WRITE;
1294			if (acep->ace_rights & KAUTH_ACE_GENERIC_EXECUTE)
1295				arights |= SMB2_GENERIC_EXECUTE;
1296			if (acep->ace_rights & KAUTH_ACE_GENERIC_ALL)
1297				arights |= SMB2_GENERIC_ALL;
1298			if (acep->ace_rights & KAUTH_VNODE_SYNCHRONIZE)
1299				arights |= SMB2_SYNCHRONIZE;
1300			if (acep->ace_rights & KAUTH_VNODE_CHANGE_OWNER)
1301				arights |= SMB2_WRITE_OWNER;
1302			if (acep->ace_rights & KAUTH_VNODE_WRITE_SECURITY)
1303				arights |= SMB2_WRITE_DAC;
1304			if (acep->ace_rights & KAUTH_VNODE_READ_SECURITY)
1305				arights |= SMB2_READ_CONTROL;
1306			if (acep->ace_rights & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
1307				arights |= SMB2_FILE_WRITE_EA;
1308			if (acep->ace_rights & KAUTH_VNODE_READ_EXTATTRIBUTES)
1309				arights |= SMB2_FILE_READ_EA;
1310			if (acep->ace_rights & KAUTH_VNODE_WRITE_ATTRIBUTES)
1311				arights |= SMB2_FILE_WRITE_ATTRIBUTES;
1312			if (acep->ace_rights & KAUTH_VNODE_READ_ATTRIBUTES)
1313				arights |= SMB2_FILE_READ_ATTRIBUTES;
1314			if (acep->ace_rights & KAUTH_VNODE_DELETE_CHILD)
1315				arights |= SMB2_FILE_DELETE_CHILD;
1316			if (acep->ace_rights & KAUTH_VNODE_APPEND_DATA)
1317				arights |= SMB2_FILE_APPEND_DATA;
1318			if (acep->ace_rights & KAUTH_VNODE_DELETE)
1319				arights |= SMB2_DELETE;
1320			if (acep->ace_rights & KAUTH_VNODE_EXECUTE)
1321				arights |= SMB2_FILE_EXECUTE;
1322			if (acep->ace_rights & KAUTH_VNODE_WRITE_DATA)
1323				arights |= SMB2_FILE_WRITE_DATA;
1324			if (acep->ace_rights & KAUTH_VNODE_READ_DATA)
1325				arights |= SMB2_FILE_READ_DATA;
1326
1327            /* <15782523> Always set the Synchronize bit for now */
1328            arights |= SMB2_SYNCHRONIZE;
1329
1330			wset_acerights(w_acep, arights);
1331			w_sidp = acesid(w_acep);
1332
1333			if ((smp->sm_flags & MNT_MAPS_NETWORK_LOCAL_USER) &&
1334				(kauth_guid_equal(&smp->sm_args.uuid, &acep->ace_applicable))) {
1335				bcopy(&smp->ntwrk_sids[0], w_sidp, sizeof(ntsid_t));
1336			}
1337            else {
1338				error = kauth_cred_guid2ntsid(&acep->ace_applicable, (ntsid_t *)w_sidp);
1339			}
1340#if DEBUG_ACLS
1341            lck_rw_lock_shared(&np->n_name_rwlock);
1342            smb_printsid(w_sidp, (char*)w_sidp+sidlen(w_sidp), "guid maps to",
1343                             (const char  *)np->n_name, acecount, 0);
1344            lck_rw_unlock_shared(&np->n_name_rwlock);
1345
1346            smb_print_guid(&acep->ace_applicable);
1347#endif
1348
1349			if (error) {
1350				uuid_unparse(*((const uuid_t *)&acep->ace_applicable), out_str);
1351				SMBERROR("kauth_cred_guid2ntsid failed with va_acl %s and error %d\n",
1352						 out_str, error);
1353				goto exit;
1354			}
1355			smb_sid_endianize(w_sidp, needed);
1356			wset_acelen(w_acep, sizeof(struct ntace) + sidlen(w_sidp));
1357		}
1358		wset_acllen(w_dacl, ((char *)w_acep - (char *)w_dacl));
1359	}
1360
1361set_dacl:
1362    if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
1363        /* Only open file if its SMB 1 */
1364        error = smbfs_tmpopen(share, np, openrights, &fid, context);
1365    }
1366
1367	if (error == 0) {
1368        error = smbfs_smb_setsec(share, np, openrights,
1369                                 fid, selector, ControlFlags,
1370                                 w_usr, w_grp, NULL, w_dacl, context);
1371
1372        if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
1373            /* Only close file if its SMB 1 */
1374            (void)smbfs_tmpclose(share, np, fid, context);
1375        }
1376	}
1377exit:
1378    if (w_usr != NULL) {
1379        SMB_FREE(w_usr, M_TEMP);
1380    }
1381    if (w_grp != NULL) {
1382        SMB_FREE(w_grp, M_TEMP);
1383    }
1384    if (w_dacl != NULL) {
1385        SMB_FREE(w_dacl, M_TEMP);
1386    }
1387
1388	/* The current cache is out of date clear it */
1389	smbfs_clear_acl_cache(np);
1390
1391    SMB_LOG_KTRACE(SMB_DBG_SMBFS_SET_SEC | DBG_FUNC_END, error, 0, 0, 0, 0);
1392	return (error);
1393}
1394
1395/*
1396* The calling routine must hold a reference on the share
1397*/
1398void
1399smb_get_sid_list(struct smb_share *share, struct smbmount *smp, struct mdchain *mdp,
1400					  uint32_t ntwrk_sids_cnt, uint32_t ntwrk_sid_size)
1401{
1402	uint32_t ii;
1403	int error;
1404	void *sidbufptr = NULL;
1405	char *endsidbufptr;
1406	char *nextsidbufptr;
1407	struct ntsid *ntwrk_wire_sid;
1408	ntsid_t *ntwrk_sids = NULL;
1409	ntsid_t tmpsid;
1410	uint32_t sidCnt = 0;
1411
1412	if ((ntwrk_sids_cnt == 0) || (ntwrk_sid_size == 0)) {
1413		SMBDEBUG("ntwrk_sids_cnt = %d ntwrk_sid_size = %d\n",
1414				 ntwrk_sids_cnt, ntwrk_sid_size);
1415		goto done; /* Nothing to do here we are done */
1416	}
1417
1418	/* Never allocate more than we could have received in this message */
1419	if (ntwrk_sid_size > SSTOVC(share)->vc_txmax) {
1420		SMBDEBUG("Too big ntwrk_sid_size = %d\n", ntwrk_sid_size);
1421		goto done;
1422	}
1423
1424	/* Max number we will support, about 9K */
1425	if (ntwrk_sids_cnt > KAUTH_ACL_MAX_ENTRIES)
1426		ntwrk_sids_cnt = KAUTH_ACL_MAX_ENTRIES;
1427
1428	SMB_MALLOC(ntwrk_sids, void *, ntwrk_sids_cnt * sizeof(*ntwrk_sids) , M_TEMP,
1429		   M_WAITOK | M_ZERO);
1430	if (ntwrk_sids == NULL) {
1431		SMBDEBUG("ntwrk_sids malloc failed!\n");
1432		goto done;
1433	}
1434	SMB_MALLOC(sidbufptr, void *, ntwrk_sid_size, M_TEMP, M_WAITOK);
1435	if (sidbufptr == NULL) {
1436		SMBDEBUG("SID malloc failed!\n");
1437		goto done;
1438	}
1439	error = md_get_mem(mdp, sidbufptr, ntwrk_sid_size, MB_MSYSTEM);
1440	if (error) {
1441		SMBDEBUG("Could get the list of sids? error = %d\n", error);
1442		goto done;
1443	}
1444
1445	endsidbufptr = (char *)sidbufptr + ntwrk_sid_size;
1446	nextsidbufptr = sidbufptr;
1447	for (ii = 0; ii < ntwrk_sids_cnt; ii++) {
1448		ntwrk_wire_sid = (struct ntsid *)nextsidbufptr;
1449		nextsidbufptr += sizeof(*ntwrk_wire_sid);
1450		/* Make sure we don't overrun our buffer */
1451		if (nextsidbufptr > endsidbufptr) {
1452			SMBDEBUG("Network sid[%d] buffer to small start %p current %p end %p\n",
1453					 ii, sidbufptr, nextsidbufptr, endsidbufptr);
1454			break;
1455		}
1456		/*
1457		 * We are done with nextsidbufptr for this loop, reset it to the next
1458		 * entry. The smb_sid2sid16 routine will protect us from any buffer overruns,
1459		 * so no need to check here.
1460		 */
1461		nextsidbufptr += (ntwrk_wire_sid->sid_subauthcount * sizeof(uint32_t));
1462
1463		smb_sid2sid16(ntwrk_wire_sid, &tmpsid, endsidbufptr);
1464
1465		/* Don't store any unix_users or unix_groups sids */
1466		if (!smb_sid_in_domain(&unix_users_domsid, &tmpsid) &&
1467			!smb_sid_in_domain(&unix_groups_domsid, &tmpsid)) {
1468			ntwrk_sids[sidCnt++] = tmpsid;
1469		} else {
1470			SMBDEBUG("Skipping ntwrk_wire_sid entry %d\n", ii);
1471			continue;
1472		}
1473
1474		if (smbfs_loglevel == SMB_ACL_LOG_LEVEL) {
1475			smb_printsid(ntwrk_wire_sid, endsidbufptr, "WHOAMI network", NULL, ii, 0);
1476		}
1477	}
1478
1479	/* We skipped some unix_users or unix_groups, resize the buffer down */
1480	if (sidCnt != ntwrk_sids_cnt) {
1481		size_t sidarraysize = sidCnt * sizeof(*ntwrk_sids);
1482		ntsid_t *holdSids = ntwrk_sids;
1483
1484		ntwrk_sids = NULL;
1485		SMB_MALLOC(ntwrk_sids, void *, sidarraysize, M_TEMP, M_WAITOK | M_ZERO);
1486		if (ntwrk_sids) {
1487			bcopy(holdSids, ntwrk_sids, sidarraysize);
1488		}
1489		SMB_FREE(holdSids, M_TEMP);
1490	}
1491
1492	/*
1493	 * We found a list of sid returned by the server, we alway use those over
1494	 * the LSA ones. Remove the LSA ones and mark that we have WHOAMI SIDS.
1495	 */
1496	if (sidCnt && ntwrk_sids) {
1497		SMB_FREE(smp->ntwrk_sids, M_TEMP);
1498		smp->ntwrk_sids_cnt = sidCnt;
1499		smp->ntwrk_sids = ntwrk_sids;
1500		ntwrk_sids = NULL;
1501		UNIX_CAPS(share) |= UNIX_QFS_POSIX_WHOAMI_SID_CAP;
1502	}
1503
1504done:
1505	/* Just clean up */
1506	SMB_FREE(ntwrk_sids, M_TEMP);
1507	SMB_FREE(sidbufptr, M_TEMP);
1508}
1509
1510/*
1511 * Need to check to see if the maximum access rights needs to be updated. We
1512 * use the node's change time to determine when we need to update. We check to
1513 * see if the node's change time has changed since the last time we got the
1514 * maximum access rights. The change time is cached as part of the node's meta
1515 * data. So the maximum access rights is cached based on the node's meta cache
1516 * timer and the node's change time.
1517 *
1518 * Now we have some issues we need to deal with here. We can get the maximum
1519 * access rights from the extended open reply. Windows server always return the
1520 * correct maximum access rights, but some servers lie. Samba just returns that
1521 * you have full access. Also if the server doesn't support the extended open
1522 * reply we never test again and the cache never expired.
1523 *
1524 * For servers that supports the extended open reply we just believe they are
1525 * returning the correct information.
1526 *
1527 * If the server doesn't support the extended open reply, then we will set the
1528 * maximum access rights to full access. We mark that the call failed so we
1529 * don't need to update ever agian.
1530 *
1531 * The calling routine must hold a reference on the share
1532 *
1533 */
1534uint32_t
1535smbfs_get_maximum_access(struct smb_share *share, vnode_t vp, vfs_context_t context)
1536{
1537	struct smbnode *np;
1538	uint32_t maxAccessRights;
1539    int error;
1540    SMBFID	fid = 0;
1541
1542	/*
1543	 * Need to have the node locked while getting the maximum access rights. In
1544	 * the future we may want to only lock what we need.
1545	 */
1546	if (smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))
1547		return 0;
1548
1549    SMB_LOG_KTRACE(SMB_DBG_SMBFS_GET_MAX_ACCESS | DBG_FUNC_START, 0, 0, 0, 0, 0);
1550
1551	np = VTOSMB(vp);
1552	np->n_lastvop = smbfs_get_maximum_access;
1553
1554	/*
1555	 * We can't open a reparse point that has a Dfs tag, so don't even try. Let
1556	 * the server handle any security issues.
1557	 */
1558	if ((np->n_dosattr & SMB_EFA_REPARSE_POINT) &&
1559        (np->n_reparse_tag == IO_REPARSE_TAG_DFS)) {
1560		np->maxAccessRights = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
1561		goto done;
1562	}
1563
1564	/* This server doesn't support maximum access, just lie */
1565	if (np->n_flag & NO_EXTENDEDOPEN) {
1566        /* When smb1fs_smb_ntcreatex() sets NO_EXTENDEDOPEN, it also sets
1567         * np->maxAccessRights to "all access".  So we don't need to modify
1568         * np->maxAccessRights here.
1569         */
1570		goto done;
1571    }
1572
1573    /*
1574     * This server doesn't support extended security, so assume
1575     * it doesn't support maximum access. We grant all access and
1576     * let the server make the final call.
1577     */
1578	if (!(VC_CAPS(SSTOVC(share)) & SMB_CAP_EXT_SECURITY)) {
1579        np->maxAccessRights = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
1580		goto done;
1581    }
1582
1583	/* Cache is still good, return the last value we had */
1584	if (timespeccmp(&np->maxAccessRightChTime, &np->n_chtime, ==))
1585		goto done;
1586
1587    /*
1588	 * For Windows we only need to open and close the item. Need to see if
1589	 * we can write a routine that does a CreateAndX/close in one message.
1590	 * Also Windows server allow us to get the maximum access by opening the
1591	 * file without requesting access. This allows us to get the maximum
1592	 * access, even when we can't read the security descriptor. We need to
1593	 * test with other servers and see if they behave the same as windows or
1594	 * do we need to open them with SMB2_READ_CONTROL?
1595	 *
1596	 * <9874997> In Lion, we started using maximal access returned by the
1597	 * server. One odd setup with a Windows 2003 server where the maximal
1598	 * access returned in the Tree Connect response (share ACL) gave more
1599	 * access than the maximal access given by CreateAndX on the '\' folder
1600	 * (filesystem ACL).
1601	 * Treat the root folder as a special case.
1602	 * 1) If the CreateAndX fails on the root, then assume full access
1603	 * 2) If the CreateAndX works on the root, if no ReadAttr or Execute BUT
1604	 * the share ACL grants ReadAttr or Execute then assume '\' also has
1605	 * ReadAttr or Execute.
1606	 */
1607    /*
1608	 * We could solve a lot of headaches by testing for the servers that do
1609	 * not support opening the item with no access. Something like the following
1610	 * should work (accessOpenModes defaults to zero):
1611	 *
1612	 * error = smbfs_tmpopen(share, np, share->accessOpenModes, &fid, context);
1613	 * if (error && share->firstAccessOpen) {
1614	 *      share->accessOpenModes = SMB2_READ_CONTROL;
1615	 *      error = smbfs_tmpopen(share, np, share->accessOpenModes, &fid, context);
1616	 *  }
1617	 *  share->firstAccessOpen = TRUE;
1618	 *
1619	 * At this point we should just trust what they say, may want to make an exception
1620	 * for the root node, and non darwin Unix systems.
1621	 */
1622
1623	 if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
1624        struct smbfattr *fap = NULL;
1625        uint32_t desired_access = 0;
1626        enum vtype vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
1627        uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
1628        uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS;
1629        uint32_t ntstatus = 0;
1630
1631        /*
1632         * Do a compound create/close
1633         * Note: this always does a create/close over the wire and never
1634         * uses an existing open file like smbfs_tmpopen can do.
1635         */
1636        SMB_MALLOC(fap,
1637                    struct smbfattr *,
1638                    sizeof(struct smbfattr),
1639                    M_SMBTEMP,
1640                    M_WAITOK | M_ZERO);
1641        if (fap == NULL) {
1642            SMBERROR("SMB_MALLOC failed\n");
1643            error = ENOMEM;
1644        }
1645        else {
1646            /* Send a Create/Close */
1647            error = smb2fs_smb_cmpd_create(share, np,
1648                                           NULL, 0,
1649                                           NULL, 0,
1650                                           desired_access, vnode_type,
1651                                           share_access, FILE_OPEN,
1652                                           create_flags, &ntstatus,
1653                                           NULL, fap,
1654                                           NULL, context);
1655            /*
1656             * smb2fs_smb_cmpd_create() will update the vnodes
1657             * maxAccessRights
1658             */
1659
1660            SMB_FREE(fap, M_SMBTEMP);
1661        }
1662    }
1663    else {
1664        error = smbfs_tmpopen(share, np, 0, &fid, context);
1665        if (!error) {
1666            smbfs_tmpclose(share, np, fid, context);
1667        }
1668    }
1669
1670    if (error) {
1671        if (error != EACCES) {
1672            /* We have no idea why it failed, give them full access. */
1673            np->maxAccessRights = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
1674        } else {
1675            if (vnode_isvroot(np->n_vnode)) {
1676                np->maxAccessRights = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
1677            } else if (((!UNIX_SERVER(SSTOVC(share))) || (SSTOVC(share)->vc_flags & SMBV_DARWIN))) {
1678                /* Windows or Darwin Server and they told us we have no access. */
1679                np->maxAccessRights = 0;
1680            } else {
1681                np->maxAccessRights = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
1682            }
1683        }
1684
1685        SMB_LOG_ACCESS_LOCK(np, "Opening %s failed with error = %d, granting %s access\n",
1686                            np->n_name, error, (np->maxAccessRights) ? "full" : "no");
1687
1688        /*
1689         * The open call failed so the cache timer wasn't set, so do that
1690         * here
1691         */
1692        np->maxAccessRightChTime = np->n_chtime;
1693    }
1694    else {
1695        /* Special case the root vnode */
1696        if (vnode_isvroot(np->n_vnode)) {
1697            /*
1698             * its the root folder, if no Execute, but share grants
1699             * Execute then grant Execute to root folder
1700             */
1701            if ((!(np->maxAccessRights & SMB2_FILE_EXECUTE)) &&
1702                (share->maxAccessRights & SMB2_FILE_EXECUTE)) {
1703                np->maxAccessRights |= SMB2_FILE_EXECUTE;
1704            }
1705
1706            /*
1707             * its the root, if no ReadAttr, but share grants
1708             * ReadAttr then grant ReadAttr to root
1709             */
1710            if ((!(np->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) &&
1711                (share->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) {
1712                np->maxAccessRights |= SMB2_FILE_READ_ATTRIBUTES;
1713            }
1714        }
1715    }
1716
1717	SMB_LOG_ACCESS_LOCK(np, "%s maxAccessRights = 0x%x\n", np->n_name, np->maxAccessRights);
1718
1719done:
1720	maxAccessRights = np->maxAccessRights;
1721	smbnode_unlock(VTOSMB(vp));
1722
1723    SMB_LOG_KTRACE(SMB_DBG_SMBFS_GET_MAX_ACCESS | DBG_FUNC_END, 0, 0, 0, 0, 0);
1724    return maxAccessRights;
1725}
1726
1727/*
1728 * The composition:
1729 *
1730 * (RED, REA, RID, RIA) is what we receive with the vnop. Those are:
1731 *	RED - Requested Explicit Deny
1732 *	REA - Requested Explicit Allow
1733 *	RID - Requested Inherited Deny
1734 *	RIA - Requested Inherited Allow
1735 * That's the canonical order the ACEs should have arrived in, but in
1736 * reality we should never get inherited ACE here and the order could
1737 * be different depending on what the calling application is trying to
1738 * accomplish. If copying the item they may want to add a full ACE as
1739 * the first element and then remove it when they are done. We no longer
1740 * inforce the order at our level.
1741 *
1742 * (SED, SEA, SID, SIA) is what we receive from the server. Those are:
1743 *	SED - Server Explicit (defaulted) Deny
1744 *	SEA - Server Explicit (defaulted) Allow
1745 *	SID - Server Inherited Deny
1746 *	SIA - Server Inherited Allow
1747 *
1748 * This is the canonical order the ACEs should have arrived in, but in
1749 * reality we should only get inherited ACE here. Now Samba will send
1750 * us a DIRECT ACE that represents the POSIX MODES. We always trust that
1751 * the server has these stored in the correct canonical.
1752 *
1753 * NOTE: Windows normally has an allow-all ACE for the object owner and
1754 * another allow ACE for Local System.
1755 *
1756 * NOTE: If we were going the put these in canonical orer this is what
1757 * we would need to do. We would take the (RED, REA, RID, RIA) and the
1758 * (SED, SEA, SID, SIA) and write back (SED, RED, SEA, REA, SID, RID, SIA, RIA)
1759 * All non-deny ACEs, for instance audit or alarm types, can be
1760 * treated the same w/r/t canonicalizing the ACE order.
1761 *
1762 * With that said this is what we do here. We create a new ACL that is large
1763 * enough to hold both ACLS. We remove any inherited ACEs that are in the
1764 * VNOP ACL. We then combind the two set of ACEs into one set VNOP ACEs first
1765 * followed by the SERVER ACEs. Since we are only adding direct ACEs and the
1766 * server ACEs should all be inherited this sould be correct.
1767 */
1768int
1769smbfs_compose_create_acl(struct vnode_attr *vap, struct vnode_attr *svrva,
1770						 kauth_acl_t *savedacl)
1771{
1772	int32_t entries, allocated;
1773	struct kauth_ace *acep;
1774	kauth_acl_t newacl;
1775	uint32_t j;
1776
1777	allocated = vap->va_acl->acl_entrycount + svrva->va_acl->acl_entrycount;
1778	newacl = kauth_acl_alloc(allocated);
1779	if (newacl == NULL) {
1780		SMBERROR("kauth_acl_alloc, %d\n", allocated);
1781		return ENOMEM;
1782	}
1783
1784	newacl->acl_flags = svrva->va_acl->acl_flags;
1785	entries = 0;		/* output index for ACL we're building */
1786
1787	/* First add the vnop ACEs, skipping any inherited ACEs or dups */
1788	for (j = 0; j < vap->va_acl->acl_entrycount; j++) {
1789		acep = &vap->va_acl->acl_ace[j];
1790		if (acep->ace_flags & KAUTH_ACE_INHERITED) {
1791			SMBERROR("Skipping ACE becuase VNOP is trying to set an inherited ACE\n");
1792			continue;
1793		}
1794		newacl->acl_ace[entries++] = *acep;
1795		if (entries > allocated) {
1796			kauth_acl_free(newacl);
1797			return EINVAL;
1798		}
1799	}
1800
1801	/* Now add the create ACE assume they are all inherited. */
1802	for (j = 0; j < svrva->va_acl->acl_entrycount; j++) {
1803		acep = &svrva->va_acl->acl_ace[j];
1804		newacl->acl_ace[entries++] = *acep;
1805		if (entries > allocated) {
1806			kauth_acl_free(newacl);
1807			return EINVAL;
1808		}
1809	}
1810	newacl->acl_entrycount = entries;
1811	*savedacl = vap->va_acl;
1812	vap->va_acl = newacl;
1813	return 0;
1814}
1815
1816/*
1817 * Check to see if Directory Service understands this sid
1818 */
1819int
1820smbfs_is_sid_known(ntsid_t *sid)
1821{
1822	int error;
1823	guid_t unique_identifier;
1824	ntsid_t sidFromUUID;
1825
1826	/* See if DS can translate the SID into a UUID */
1827	error = kauth_cred_ntsid2guid(sid, &unique_identifier);
1828	if (error) {
1829		SMBDEBUG("kauth_cred_ntsid2guid failed error = %d\n", error);
1830		return FALSE;
1831	}
1832	/* See if DS gave us a temp UUID */
1833	if (is_memberd_tempuuid(&unique_identifier)) {
1834		return FALSE;
1835	}
1836	/* See if DS can translate the UUID back into a SID */
1837	error = kauth_cred_guid2ntsid(&unique_identifier, &sidFromUUID);
1838	if (error) {
1839		SMBDEBUG("kauth_cred_guid2ntsid failed error = %d\n", error);
1840		return FALSE;
1841	}
1842	/* Could we round trip the sid, nope the turn off ACLS */
1843	if (memcmp(&sidFromUUID, sid, sizeof(sidFromUUID)) != 0) {
1844		SMBWARNING("Couldn't round trip the SID\n");
1845		return FALSE;
1846	}
1847	return TRUE;
1848}
1849
1850/*
1851 * This items doesn't have any ACL, must only have posix modes. Just set the
1852 * posix ace.
1853 */
1854static int
1855smbfs_set_default_nfs_ace(struct smb_share *share, struct smbnode *np, vfs_context_t context)
1856{
1857	int error;
1858	SMBFID	fid = 0;
1859	ntsid_t nfs_sid;
1860	size_t needed;
1861	uint32_t acecount = 1;
1862	struct ntacl *w_dacl = NULL;	/* Wire DACL */
1863	struct ntace *w_acep;	/* Wire ACE */
1864
1865    if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
1866        /* Only open file if its SMB 1 */
1867        error = smbfs_tmpopen(share, np, SMB2_READ_CONTROL | SMB2_WRITE_DAC, &fid,
1868                              context);
1869        if (error) {
1870            return error;
1871        }
1872    }
1873
1874	needed = sizeof(struct ntacl) + acecount * (sizeof(struct ntace) + MAXSIDLEN);
1875	SMB_MALLOC(w_dacl, struct ntacl *, needed, M_TEMP, M_WAITOK | M_ZERO);
1876	w_dacl->acl_revision = 0x02;
1877	wset_aclacecount(w_dacl, acecount);
1878
1879	w_acep = aclace(w_dacl);
1880	nfs_sid.sid_kind = 1;
1881	nfs_sid.sid_authcount = 3;
1882	memcpy(nfs_sid.sid_authority, security_nt_authority, sizeof(security_nt_authority));
1883	nfs_sid.sid_authorities[0] = SECURITY_NFS_ID_BASE_RID;
1884	/* Set the Windows nfs posix modes ace */
1885	nfs_sid.sid_authorities[1] = NfsSidTypeModes;
1886	nfs_sid.sid_authorities[2] = np->n_mode;
1887	w_acep = set_nfs_ace(w_acep, &nfs_sid, needed);
1888	wset_acllen(w_dacl, ((char *)w_acep - (char *)w_dacl));
1889
1890	error = smbfs_smb_setsec(share, np, SMB2_READ_CONTROL | SMB2_WRITE_DAC | SMB2_SYNCHRONIZE,
1891                             fid, DACL_SECURITY_INFORMATION, 0, NULL, NULL,
1892                             NULL, w_dacl, context);
1893
1894    if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
1895        /* Only close file if its SMB 1 */
1896        (void)smbfs_tmpclose(share, np, fid, context);
1897    }
1898
1899    SMB_FREE(w_dacl, M_TEMP);
1900
1901	/* The current cache is out of date clear it */
1902	smbfs_clear_acl_cache(np);
1903	return error;
1904}
1905
1906/*
1907 * Use the Windows NFS ACE to hold the Posix modes. Should we store the UID and
1908 * GID? Currently no, we only care about the posix modes, use the OWNER and
1909 * GROUP ACE to handle the uid/gid.
1910 */
1911int
1912smbfs_set_ace_modes(struct smb_share *share, struct smbnode *np, uint64_t vamode, vfs_context_t context)
1913{
1914	int error;
1915	struct vnode_attr va;
1916	mode_t		save_mode = np->n_mode;
1917
1918	/* Get the ACL from the server, so we can do the set */
1919	memset(&va, 0, sizeof(va));
1920	VATTR_INIT(&va);
1921	VATTR_SET_ACTIVE(&va, va_acl);
1922	error = smbfs_getsecurity(share, np, &va, context);
1923	if (error) {
1924		return error;
1925	}
1926	/*
1927	 * Set that we have a Windows NFS posix mode ace, so the set acl routine
1928	 * will add them to the ACL.
1929	 */
1930	np->n_flag |= NHAS_POSIXMODES;
1931	np->n_mode &= ~ACCESSPERMS;
1932	np->n_mode |= (mode_t)(vamode & ACCESSPERMS);
1933	if (va.va_acl == NULL) {
1934		error = smbfs_set_default_nfs_ace(share, np,context);
1935	} else {
1936		VATTR_SET_ACTIVE(&va, va_acl);
1937		error = smbfs_setsecurity(share, np->n_vnode, &va, context);
1938	}
1939
1940	if (error) {
1941		/* Reset the posix modes back since we failed. */
1942		np->n_mode &= ~ACCESSPERMS;
1943		np->n_mode |= (mode_t)(save_mode & ACCESSPERMS);
1944	}
1945	/* Free any ACL we got from the smbfs_getsecurity routine */
1946	if (va.va_acl) {
1947		kauth_acl_free(va.va_acl);
1948	}
1949	return error;
1950}
1951