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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/sunddi.h>
37 #include <smbsrv/smb_sid.h>
39 static smb_sid_t
*smb_sid_alloc(size_t);
44 * Performs a minimal SID validation.
47 smb_sid_isvalid(smb_sid_t
*sid
)
52 return ((sid
->sid_revision
== NT_SID_REVISION
) &&
53 (sid
->sid_subauthcnt
< NT_SID_SUBAUTH_MAX
));
59 * Returns the number of bytes required to hold the sid.
62 smb_sid_len(smb_sid_t
*sid
)
67 return (sizeof (smb_sid_t
) - sizeof (uint32_t)
68 + (sid
->sid_subauthcnt
* sizeof (uint32_t)));
74 * Make a duplicate of the specified sid. The memory for the new sid
75 * should be freed by calling smb_sid_free().
76 * A pointer to the new sid is returned.
79 smb_sid_dup(smb_sid_t
*sid
)
87 size
= smb_sid_len(sid
);
88 if ((new_sid
= smb_sid_alloc(size
)) == NULL
)
91 bcopy(sid
, new_sid
, size
);
99 * Make a full sid from a domain sid and a relative id (rid).
100 * The memory for the result sid should be freed by calling
101 * smb_sid_free(). A pointer to the new sid is returned.
104 smb_sid_splice(smb_sid_t
*domain_sid
, uint32_t rid
)
109 if (domain_sid
== NULL
)
112 size
= smb_sid_len(domain_sid
);
113 if ((sid
= smb_sid_alloc(size
+ sizeof (rid
))) == NULL
)
116 bcopy(domain_sid
, sid
, size
);
118 sid
->sid_subauth
[domain_sid
->sid_subauthcnt
] = rid
;
119 ++sid
->sid_subauthcnt
;
127 * Return the Relative Id (RID) of the specified SID. It is the
128 * caller's responsibility to ensure that this is an appropriate SID.
129 * All we do here is return the last sub-authority from the SID.
132 smb_sid_getrid(smb_sid_t
*sid
, uint32_t *rid
)
134 if (!smb_sid_isvalid(sid
) || (rid
== NULL
) ||
135 (sid
->sid_subauthcnt
== 0))
138 *rid
= sid
->sid_subauth
[sid
->sid_subauthcnt
- 1];
145 * Take a full sid and split it into a domain sid and a relative id (rid).
146 * The domain SID is allocated and a pointer to it will be returned. The
147 * RID value is passed back in 'rid' arg if it's not NULL. The allocated
148 * memory for the domain SID must be freed by caller.
151 smb_sid_split(smb_sid_t
*sid
, uint32_t *rid
)
156 if (!smb_sid_isvalid(sid
) || (sid
->sid_subauthcnt
== 0))
160 * We will reduce sid_subauthcnt by one, because
161 * the domain SID does not include the RID.
163 size
= smb_sid_len(sid
) - sizeof (uint32_t);
164 if ((domsid
= smb_sid_alloc(size
)) == NULL
)
167 bcopy(sid
, domsid
, size
);
168 domsid
->sid_subauthcnt
= sid
->sid_subauthcnt
- 1;
171 *rid
= sid
->sid_subauth
[sid
->sid_subauthcnt
- 1];
179 * Takes a full sid in string form and split it into a domain sid and a
182 * IMPORTANT: The original sid is modified in place. This function assumes
183 * given SID is in valid string format.
186 smb_sid_splitstr(char *strsid
, uint32_t *rid
)
190 if ((p
= strrchr(strsid
, '-')) == NULL
)
196 unsigned long sua
= 0;
197 (void) ddi_strtoul(p
, NULL
, 10, &sua
);
198 *rid
= (uint32_t)sua
;
200 *rid
= strtoul(p
, NULL
, 10);
210 * Compare two SIDs and return a boolean result. The checks are ordered
211 * such that components that are more likely to differ are checked
212 * first. For example, after checking that the SIDs contain the same
213 * sid_subauthcnt, we check the sub-authorities in reverse order because
214 * the RID is the most likely differentiator between two SIDs, i.e.
215 * they are probably going to be in the same domain.
218 smb_sid_cmp(smb_sid_t
*sid1
, smb_sid_t
*sid2
)
222 if (sid1
== NULL
|| sid2
== NULL
)
225 if (sid1
->sid_subauthcnt
!= sid2
->sid_subauthcnt
||
226 sid1
->sid_revision
!= sid2
->sid_revision
)
229 for (i
= sid1
->sid_subauthcnt
- 1; i
>= 0; --i
)
230 if (sid1
->sid_subauth
[i
] != sid2
->sid_subauth
[i
])
233 if (bcmp(&sid1
->sid_authority
, &sid2
->sid_authority
, NT_SID_AUTH_MAX
))
242 * Check if given SID is in given domain.
245 smb_sid_indomain(smb_sid_t
*domain_sid
, smb_sid_t
*sid
)
249 if (sid
== NULL
|| domain_sid
== NULL
)
252 if (domain_sid
->sid_revision
!= sid
->sid_revision
||
253 sid
->sid_subauthcnt
< domain_sid
->sid_subauthcnt
)
256 for (i
= domain_sid
->sid_subauthcnt
- 1; i
>= 0; --i
)
257 if (domain_sid
->sid_subauth
[i
] != sid
->sid_subauth
[i
])
260 if (bcmp(&domain_sid
->sid_authority
, &sid
->sid_authority
,
270 * Fill in the passed buffer with the string form of the given
274 smb_sid_tostr(const smb_sid_t
*sid
, char *strsid
)
279 if (sid
== NULL
|| strsid
== NULL
)
282 (void) sprintf(p
, "S-%d-", sid
->sid_revision
);
286 for (i
= 0; i
< NT_SID_AUTH_MAX
; ++i
) {
287 if (sid
->sid_authority
[i
] != 0 || i
== NT_SID_AUTH_MAX
- 1) {
288 (void) sprintf(p
, "%d", sid
->sid_authority
[i
]);
294 for (i
= 0; i
< sid
->sid_subauthcnt
&& i
< NT_SID_SUBAUTH_MAX
; ++i
) {
295 (void) sprintf(p
, "-%u", sid
->sid_subauth
[i
]);
304 * Converts a SID in string form to a SID structure. There are lots of
305 * simplifying assumptions in here. The memory for the SID is allocated
306 * as if it was the largest possible SID; the caller is responsible for
307 * freeing the memory when it is no longer required. We assume that the
308 * string starts with "S-1-" and that the authority is held in the last
309 * byte, which should be okay for most situations. It also assumes the
310 * sub-authorities are in decimal format.
312 * On success, a pointer to a SID is returned. Otherwise a null pointer
317 smb_sid_fromstr(const char *sidstr
)
329 if (strncmp(sidstr
, "S-1-", 4) != 0)
332 size
= sizeof (smb_sid_t
) + (NT_SID_SUBAUTH_MAX
* sizeof (uint32_t));
333 sid
= kmem_zalloc(size
, KM_SLEEP
);
335 sid
->sid_revision
= NT_SID_REVISION
;
337 (void) ddi_strtoul(&sidstr
[4], 0, 10, &sua
);
338 sid
->sid_authority
[5] = (uint8_t)sua
;
340 for (i
= 0, p
= &sidstr
[5]; i
< NT_SID_SUBAUTH_MAX
&& *p
; ++i
) {
341 while (*p
&& *p
== '-')
344 if (*p
< '0' || *p
> '9') {
345 kmem_free(sid
, size
);
350 (void) ddi_strtoul(p
, 0, 10, &sua
);
351 sid
->sid_subauth
[i
] = (uint32_t)sua
;
353 while (*p
&& *p
!= '-')
357 sid
->sid_subauthcnt
= i
;
358 retsid
= smb_sid_dup(sid
);
359 kmem_free(sid
, size
);
365 smb_sid_fromstr(const char *sidstr
)
375 if (strncmp(sidstr
, "S-1-", 4) != 0)
378 size
= sizeof (smb_sid_t
) + (NT_SID_SUBAUTH_MAX
* sizeof (uint32_t));
380 if ((sid
= malloc(size
)) == NULL
)
384 sid
->sid_revision
= NT_SID_REVISION
;
385 sid
->sid_authority
[5] = atoi(&sidstr
[4]);
387 for (i
= 0, p
= &sidstr
[5]; i
< NT_SID_SUBAUTH_MAX
&& *p
; ++i
) {
388 while (*p
&& *p
== '-')
391 if (*p
< '0' || *p
> '9') {
396 sid
->sid_subauth
[i
] = strtoul(p
, NULL
, 10);
398 while (*p
&& *p
!= '-')
402 sid
->sid_subauthcnt
= i
;
410 * Returns the text name for a SID_NAME_USE value. The SID_NAME_USE
411 * provides the context for a SID, i.e. the type of resource to which
415 smb_sid_type2str(uint16_t snu_id
)
417 static char *snu_name
[] = {
423 "SidTypeWellKnownGroup",
424 "SidTypeDeletedAccount",
431 if (snu_id
< ((sizeof (snu_name
)/sizeof (snu_name
[0]))))
432 return (snu_name
[snu_id
]);
434 return (snu_name
[SidTypeUnknown
]);
438 smb_sid_alloc(size_t size
)
442 sid
= kmem_alloc(size
, KM_SLEEP
);
450 smb_sid_free(smb_sid_t
*sid
)
456 kmem_free(sid
, smb_sid_len(sid
));