8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / common / smbsrv / smb_sid.c
blob9d4dc978ae89abad161622556e36514d3e72fd1d
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
27 #include <stdio.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <syslog.h>
31 #else /* !_KERNEL && !_FAKE_KERNEL */
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/sunddi.h>
35 #endif /* !_KERNEL && !_FAKE_KERNEL */
37 #include <smbsrv/smb_sid.h>
39 static smb_sid_t *smb_sid_alloc(size_t);
42 * smb_sid_isvalid
44 * Performs a minimal SID validation.
46 boolean_t
47 smb_sid_isvalid(smb_sid_t *sid)
49 if (sid == NULL)
50 return (B_FALSE);
52 return ((sid->sid_revision == NT_SID_REVISION) &&
53 (sid->sid_subauthcnt < NT_SID_SUBAUTH_MAX));
57 * smb_sid_len
59 * Returns the number of bytes required to hold the sid.
61 int
62 smb_sid_len(smb_sid_t *sid)
64 if (sid == NULL)
65 return (0);
67 return (sizeof (smb_sid_t) - sizeof (uint32_t)
68 + (sid->sid_subauthcnt * sizeof (uint32_t)));
72 * smb_sid_dup
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.
78 smb_sid_t *
79 smb_sid_dup(smb_sid_t *sid)
81 smb_sid_t *new_sid;
82 int size;
84 if (sid == NULL)
85 return (NULL);
87 size = smb_sid_len(sid);
88 if ((new_sid = smb_sid_alloc(size)) == NULL)
89 return (NULL);
91 bcopy(sid, new_sid, size);
92 return (new_sid);
97 * smb_sid_splice
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.
103 smb_sid_t *
104 smb_sid_splice(smb_sid_t *domain_sid, uint32_t rid)
106 smb_sid_t *sid;
107 int size;
109 if (domain_sid == NULL)
110 return (NULL);
112 size = smb_sid_len(domain_sid);
113 if ((sid = smb_sid_alloc(size + sizeof (rid))) == NULL)
114 return (NULL);
116 bcopy(domain_sid, sid, size);
118 sid->sid_subauth[domain_sid->sid_subauthcnt] = rid;
119 ++sid->sid_subauthcnt;
121 return (sid);
125 * smb_sid_getrid
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))
136 return (-1);
138 *rid = sid->sid_subauth[sid->sid_subauthcnt - 1];
139 return (0);
143 * smb_sid_split
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.
150 smb_sid_t *
151 smb_sid_split(smb_sid_t *sid, uint32_t *rid)
153 smb_sid_t *domsid;
154 int size;
156 if (!smb_sid_isvalid(sid) || (sid->sid_subauthcnt == 0))
157 return (NULL);
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)
165 return (NULL);
167 bcopy(sid, domsid, size);
168 domsid->sid_subauthcnt = sid->sid_subauthcnt - 1;
170 if (rid)
171 *rid = sid->sid_subauth[sid->sid_subauthcnt - 1];
173 return (domsid);
177 * smb_sid_splitstr
179 * Takes a full sid in string form and split it into a domain sid and a
180 * relative id (rid).
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)
188 char *p;
190 if ((p = strrchr(strsid, '-')) == NULL)
191 return (-1);
193 *p++ = '\0';
194 if (rid) {
195 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
196 unsigned long sua = 0;
197 (void) ddi_strtoul(p, NULL, 10, &sua);
198 *rid = (uint32_t)sua;
199 #else
200 *rid = strtoul(p, NULL, 10);
201 #endif
204 return (0);
208 * smb_sid_cmp
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.
217 boolean_t
218 smb_sid_cmp(smb_sid_t *sid1, smb_sid_t *sid2)
220 int i;
222 if (sid1 == NULL || sid2 == NULL)
223 return (B_FALSE);
225 if (sid1->sid_subauthcnt != sid2->sid_subauthcnt ||
226 sid1->sid_revision != sid2->sid_revision)
227 return (B_FALSE);
229 for (i = sid1->sid_subauthcnt - 1; i >= 0; --i)
230 if (sid1->sid_subauth[i] != sid2->sid_subauth[i])
231 return (B_FALSE);
233 if (bcmp(&sid1->sid_authority, &sid2->sid_authority, NT_SID_AUTH_MAX))
234 return (B_FALSE);
236 return (B_TRUE);
240 * smb_sid_indomain
242 * Check if given SID is in given domain.
244 boolean_t
245 smb_sid_indomain(smb_sid_t *domain_sid, smb_sid_t *sid)
247 int i;
249 if (sid == NULL || domain_sid == NULL)
250 return (B_FALSE);
252 if (domain_sid->sid_revision != sid->sid_revision ||
253 sid->sid_subauthcnt < domain_sid->sid_subauthcnt)
254 return (B_FALSE);
256 for (i = domain_sid->sid_subauthcnt - 1; i >= 0; --i)
257 if (domain_sid->sid_subauth[i] != sid->sid_subauth[i])
258 return (B_FALSE);
260 if (bcmp(&domain_sid->sid_authority, &sid->sid_authority,
261 NT_SID_AUTH_MAX))
262 return (B_FALSE);
264 return (B_TRUE);
268 * smb_sid_tostr
270 * Fill in the passed buffer with the string form of the given
271 * binary sid.
273 void
274 smb_sid_tostr(const smb_sid_t *sid, char *strsid)
276 char *p = strsid;
277 int i;
279 if (sid == NULL || strsid == NULL)
280 return;
282 (void) sprintf(p, "S-%d-", sid->sid_revision);
283 while (*p)
284 p++;
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]);
289 while (*p)
290 p++;
294 for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
295 (void) sprintf(p, "-%u", sid->sid_subauth[i]);
296 while (*p)
297 p++;
302 * smb_sid_fromstr
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
313 * is returned.
315 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
316 smb_sid_t *
317 smb_sid_fromstr(const char *sidstr)
319 smb_sid_t *sid;
320 smb_sid_t *retsid;
321 const char *p;
322 int size;
323 uint8_t i;
324 unsigned long sua;
326 if (sidstr == NULL)
327 return (NULL);
329 if (strncmp(sidstr, "S-1-", 4) != 0)
330 return (NULL);
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;
336 sua = 0;
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 == '-')
342 ++p;
344 if (*p < '0' || *p > '9') {
345 kmem_free(sid, size);
346 return (NULL);
349 sua = 0;
350 (void) ddi_strtoul(p, 0, 10, &sua);
351 sid->sid_subauth[i] = (uint32_t)sua;
353 while (*p && *p != '-')
354 ++p;
357 sid->sid_subauthcnt = i;
358 retsid = smb_sid_dup(sid);
359 kmem_free(sid, size);
361 return (retsid);
363 #else /* _KERNEL */
364 smb_sid_t *
365 smb_sid_fromstr(const char *sidstr)
367 smb_sid_t *sid;
368 const char *p;
369 int size;
370 uint8_t i;
372 if (sidstr == NULL)
373 return (NULL);
375 if (strncmp(sidstr, "S-1-", 4) != 0)
376 return (NULL);
378 size = sizeof (smb_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t));
380 if ((sid = malloc(size)) == NULL)
381 return (NULL);
383 bzero(sid, size);
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 == '-')
389 ++p;
391 if (*p < '0' || *p > '9') {
392 free(sid);
393 return (NULL);
396 sid->sid_subauth[i] = strtoul(p, NULL, 10);
398 while (*p && *p != '-')
399 ++p;
402 sid->sid_subauthcnt = i;
403 return (sid);
405 #endif /* _KERNEL */
408 * smb_sid_type2str
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
412 * it refers.
414 char *
415 smb_sid_type2str(uint16_t snu_id)
417 static char *snu_name[] = {
418 "SidTypeSidPrefix",
419 "SidTypeUser",
420 "SidTypeGroup",
421 "SidTypeDomain",
422 "SidTypeAlias",
423 "SidTypeWellKnownGroup",
424 "SidTypeDeletedAccount",
425 "SidTypeInvalid",
426 "SidTypeUnknown",
427 "SidTypeComputer",
428 "SidTypeLabel"
431 if (snu_id < ((sizeof (snu_name)/sizeof (snu_name[0]))))
432 return (snu_name[snu_id]);
434 return (snu_name[SidTypeUnknown]);
437 static smb_sid_t *
438 smb_sid_alloc(size_t size)
440 smb_sid_t *sid;
441 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
442 sid = kmem_alloc(size, KM_SLEEP);
443 #else
444 sid = malloc(size);
445 #endif
446 return (sid);
449 void
450 smb_sid_free(smb_sid_t *sid)
452 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
453 if (sid == NULL)
454 return;
456 kmem_free(sid, smb_sid_len(sid));
457 #else
458 free(sid);
459 #endif