xref: /illumos-gate/usr/src/lib/libsmbfs/smb/acl_api.c (revision 73a8c195d0dfb19a2b8814d9df1ae6459c88d5a6)
1  /*
2   * CDDL HEADER START
3   *
4   * The contents of this file are subject to the terms of the
5   * Common Development and Distribution License (the "License").
6   * You may not use this file except in compliance with the License.
7   *
8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9   * or http://www.opensolaris.org/os/licensing.
10   * See the License for the specific language governing permissions
11   * and limitations under the License.
12   *
13   * When distributing Covered Code, include this CDDL HEADER in each
14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15   * If applicable, add the following below this CDDL HEADER, with the
16   * fields enclosed by brackets "[]" replaced with your own identifying
17   * information: Portions Copyright [yyyy] [name of copyright owner]
18   *
19   * CDDL HEADER END
20   */
21  
22  /*
23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24   * Use is subject to license terms.
25   */
26  
27  /*
28   * ACL API for smbfs
29   */
30  
31  #include <sys/types.h>
32  #include <sys/errno.h>
33  #include <sys/cred.h>
34  #include <sys/cmn_err.h>
35  #include <sys/kmem.h>
36  #include <sys/sunddi.h>
37  #include <sys/acl.h>
38  #include <sys/vnode.h>
39  #include <sys/vfs.h>
40  #include <sys/byteorder.h>
41  
42  #include <errno.h>
43  #include <stdio.h>
44  #include <strings.h>
45  #include <unistd.h>
46  
47  #include <umem.h>
48  #include <idmap.h>
49  
50  #include <sys/fs/smbfs_ioctl.h>
51  
52  #include <netsmb/smb.h>
53  #include <netsmb/smb_lib.h>
54  #include <netsmb/smbfs_acl.h>
55  
56  #include "smbfs_ntacl.h"
57  #include "private.h"
58  
59  /* Sanity check SD sizes */
60  #define	MAX_RAW_SD_SIZE	32768
61  
62  /* XXX: acl_common.h */
63  acl_t *acl_alloc(enum acl_type);
64  void acl_free(acl_t *);
65  
66  
67  /*
68   * Get/set a Windows security descriptor (SD)
69   * using the (private) smbfs ioctl mechanism.
70   * Note: Get allocates mbp->mb_top
71   */
72  
73  /* ARGSUSED */
74  int
75  smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
76  {
77  	ioc_sdbuf_t	iocb;
78  	struct mbuf	*m;
79  	int		error;
80  
81  	error = mb_init_sz(mbp, MAX_RAW_SD_SIZE);
82  	if (error)
83  		return (error);
84  
85  	m = mbp->mb_top;
86  	iocb.addr = mtod(m, uintptr_t);
87  	iocb.alloc = m->m_maxlen;
88  	iocb.used = 0;
89  	iocb.selector = selector;
90  
91  	/*
92  	 * This does the OTW Get.
93  	 */
94  	if (ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
95  		error = errno;
96  		goto errout;
97  	}
98  
99  	m->m_len = iocb.used;
100  	return (0);
101  
102  errout:
103  	mb_done(mbp);
104  	return (error);
105  }
106  
107  /* ARGSUSED */
108  int
109  smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
110  {
111  	ioc_sdbuf_t	iocb;
112  	struct mbuf	*m;
113  	int		error;
114  
115  	/* Make the data contiguous. */
116  	error = m_lineup(mbp->mb_top, &m);
117  	if (error)
118  		return (error);
119  
120  	if (mbp->mb_top != m)
121  		mb_initm(mbp, m);
122  
123  	iocb.addr = mtod(m, uintptr_t);
124  	iocb.alloc = m->m_maxlen;
125  	iocb.used  = m->m_len;
126  	iocb.selector = selector;
127  
128  	/*
129  	 * This does the OTW Set.
130  	 */
131  	if (ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
132  		error = errno;
133  
134  	return (error);
135  }
136  
137  /*
138   * Get an NT SD from the open file via ioctl.
139   */
140  int
141  smbfs_acl_getsd(int fd, uint32_t selector, i_ntsd_t **sdp)
142  {
143  	mbdata_t *mbp, mb_store;
144  	int error;
145  
146  	mbp = &mb_store;
147  	bzero(mbp, sizeof (*mbp));
148  
149  	/*
150  	 * Get the raw Windows SD via ioctl.
151  	 * Returns allocated mbchain in mbp.
152  	 */
153  	error = smbfs_acl_iocget(fd, selector, mbp);
154  	if (error == 0) {
155  		/*
156  		 * Import the raw SD into "internal" form.
157  		 * (like "absolute" form per. NT docs)
158  		 * Returns allocated data in sdp
159  		 */
160  		error = md_get_ntsd(mbp, sdp);
161  	}
162  
163  	mb_done(mbp);
164  	return (error);
165  }
166  
167  /*
168   * Set an NT SD onto the open file via ioctl.
169   */
170  int
171  smbfs_acl_setsd(int fd, uint32_t selector, i_ntsd_t *sd)
172  {
173  	mbdata_t *mbp, mb_store;
174  	int error;
175  
176  	mbp = &mb_store;
177  	error = mb_init_sz(mbp, MAX_RAW_SD_SIZE);
178  	if (error)
179  		return (error);
180  
181  	/*
182  	 * Export the "internal" SD into an mb chain.
183  	 * (a.k.a "self-relative" form per. NT docs)
184  	 * Returns allocated mbchain in mbp.
185  	 */
186  	error = mb_put_ntsd(mbp, sd);
187  	if (error == 0) {
188  		/*
189  		 * Set the raw Windows SD via ioctl.
190  		 */
191  		error = smbfs_acl_iocset(fd, selector, mbp);
192  	}
193  
194  	mb_done(mbp);
195  
196  	return (error);
197  }
198  
199  
200  
201  /*
202   * Convenience function to Get security using a
203   * ZFS-style ACL (libsec acl, type=ACE_T)
204   * Intentionally similar to: facl_get(3SEC)
205   */
206  int
207  smbfs_acl_get(int fd, acl_t **aclp, uid_t *uidp, gid_t *gidp)
208  {
209  	i_ntsd_t *sd = NULL;
210  	acl_t *acl = NULL;
211  	uint32_t selector;
212  	int error;
213  
214  	/*
215  	 * Which parts of the SD are being requested?
216  	 * XXX: Should we request the SACL too?  If so,
217  	 * might that cause this access to be denied?
218  	 * Or maybe: if we get access denied, try the
219  	 * open/fetch again without the SACL bit.
220  	 */
221  	selector = 0;
222  	if (aclp)
223  		selector |= DACL_SECURITY_INFORMATION;
224  	if (uidp)
225  		selector |= OWNER_SECURITY_INFORMATION;
226  	if (gidp)
227  		selector |= GROUP_SECURITY_INFORMATION;
228  
229  	if (selector == 0)
230  		return (0);
231  
232  	/*
233  	 * Get the Windows SD via ioctl, in
234  	 * "internal" (absolute) form.
235  	 */
236  	error = smbfs_acl_getsd(fd, selector, &sd);
237  	if (error)
238  		return (error);
239  	/* Note: sd now holds allocated data. */
240  
241  	/*
242  	 * Convert the internal SD to a ZFS ACL.
243  	 * Get uid/gid too if pointers != NULL.
244  	 */
245  	if (aclp) {
246  		acl = acl_alloc(ACE_T);
247  		if (acl == NULL) {
248  			error = ENOMEM;
249  			goto out;
250  		}
251  	}
252  	error = smbfs_acl_sd2zfs(sd, acl, uidp, gidp);
253  	if (error)
254  		goto out;
255  
256  	/* Success! */
257  	if (aclp) {
258  		*aclp = acl;
259  		acl = NULL;
260  	}
261  
262  out:
263  	if (acl)
264  		acl_free(acl);
265  	smbfs_acl_free_sd(sd);
266  	return (error);
267  }
268  
269  /*
270   * Convenience function to Set security using a
271   * ZFS-style ACL (libsec acl, type=ACE_T)
272   * Intentionally similar to: facl_set(3SEC)
273   */
274  int
275  smbfs_acl_set(int fd, acl_t *acl, uid_t uid, gid_t gid)
276  {
277  	i_ntsd_t *sd = NULL;
278  	uint32_t selector;
279  	int error;
280  
281  	/*
282  	 * Which parts of the SD are being modified?
283  	 * XXX: Ditto comments above re. SACL.
284  	 */
285  	selector = 0;
286  	if (acl)
287  		selector |= DACL_SECURITY_INFORMATION;
288  	if (uid != (uid_t)-1)
289  		selector |= OWNER_SECURITY_INFORMATION;
290  	if (gid != (gid_t)-1)
291  		selector |= GROUP_SECURITY_INFORMATION;
292  	if (selector == 0)
293  		return (0);
294  
295  	if (acl && acl->acl_type != ACE_T)
296  		return (EINVAL);
297  
298  	/*
299  	 * Convert the ZFS ACL to an internal SD.
300  	 * Returns allocated data in sd
301  	 */
302  	error = smbfs_acl_zfs2sd(acl, uid, gid, &sd);
303  	if (error == 0)
304  		error = smbfs_acl_setsd(fd, selector, sd);
305  
306  	smbfs_acl_free_sd(sd);
307  
308  	return (error);
309  }
310