]>
Commit | Line | Data |
---|---|---|
c29f2fcc | 1 | /* |
162e9b63 | 2 | * Copyright (c) 2004-2007 Apple Computer, Inc. All rights reserved. |
c29f2fcc A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
23 | #include "membership.h" | |
24 | #include "membershipPriv.h" | |
25 | #include "memberd.h" | |
26 | ||
27 | #include <sys/errno.h> | |
28 | #include <servers/bootstrap.h> | |
29 | #include <mach/mach.h> | |
30 | #include <stdlib.h> | |
162e9b63 | 31 | #include <libkern/OSByteOrder.h> |
c29f2fcc A |
32 | |
33 | static mach_port_t GetServerPort() | |
34 | { | |
35 | kern_return_t result; | |
162e9b63 A |
36 | static mach_port_t bsPort = 0; |
37 | static mach_port_t fServerPort = 0; | |
38 | ||
c29f2fcc A |
39 | if (bsPort == 0) |
40 | { | |
162e9b63 A |
41 | result = task_get_bootstrap_port(mach_task_self(), &bsPort); |
42 | result = bootstrap_look_up(bsPort, "com.apple.memberd", &fServerPort); | |
c29f2fcc A |
43 | } |
44 | ||
45 | return fServerPort; | |
46 | } | |
47 | ||
48 | int mbr_uid_to_uuid(uid_t id, uuid_t uu) | |
49 | { | |
50 | struct kauth_identity_extlookup request; | |
162e9b63 | 51 | security_token_t token; |
c29f2fcc A |
52 | int result = 0; |
53 | ||
162e9b63 A |
54 | token.val[0] = -1; |
55 | token.val[1] = -1; | |
56 | ||
c29f2fcc A |
57 | request.el_flags = KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_WANT_UGUID; |
58 | request.el_uid = id; | |
162e9b63 A |
59 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
60 | if (result != KERN_SUCCESS) return EIO; | |
61 | if (token.val[0] != 0) return EAUTH; | |
62 | ||
c29f2fcc A |
63 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) != 0) |
64 | memcpy(uu, &request.el_uguid, sizeof(guid_t)); | |
65 | else | |
66 | result = ENOENT; | |
67 | ||
68 | return result; | |
69 | } | |
70 | ||
71 | int mbr_gid_to_uuid(gid_t id, uuid_t uu) | |
72 | { | |
73 | struct kauth_identity_extlookup request; | |
162e9b63 | 74 | security_token_t token; |
c29f2fcc A |
75 | kern_return_t result; |
76 | int error = 0; | |
77 | ||
162e9b63 A |
78 | token.val[0] = -1; |
79 | token.val[1] = -1; | |
80 | ||
c29f2fcc A |
81 | request.el_flags = KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_GGUID; |
82 | request.el_gid = id; | |
162e9b63 A |
83 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
84 | if (result != KERN_SUCCESS) return EIO; | |
85 | if (token.val[0] != 0) return EAUTH; | |
86 | ||
c29f2fcc A |
87 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) != 0) |
88 | memcpy(uu, &request.el_gguid, sizeof(guid_t)); | |
89 | else | |
90 | error = ENOENT; | |
162e9b63 | 91 | |
c29f2fcc A |
92 | return error; |
93 | } | |
94 | ||
162e9b63 | 95 | int mbr_uuid_to_id(const uuid_t uu, uid_t *id, int *id_type) |
c29f2fcc A |
96 | { |
97 | struct kauth_identity_extlookup request; | |
162e9b63 | 98 | security_token_t token; |
c29f2fcc A |
99 | kern_return_t result; |
100 | int error = 0; | |
101 | ||
162e9b63 A |
102 | token.val[0] = -1; |
103 | token.val[1] = -1; | |
104 | ||
105 | request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID; | |
c29f2fcc A |
106 | memcpy(&request.el_uguid, uu, sizeof(guid_t)); |
107 | memcpy(&request.el_gguid, uu, sizeof(guid_t)); | |
162e9b63 A |
108 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
109 | if (result != KERN_SUCCESS) return EIO; | |
110 | if (token.val[0] != 0) return EAUTH; | |
111 | ||
c29f2fcc A |
112 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UID) != 0) |
113 | { | |
114 | *id = request.el_uid; | |
115 | *id_type = ID_TYPE_UID; | |
116 | } | |
117 | else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GID) != 0) | |
118 | { | |
119 | *id = request.el_gid; | |
120 | *id_type = ID_TYPE_GID; | |
121 | } | |
122 | else | |
162e9b63 | 123 | { |
c29f2fcc | 124 | error = ENOENT; |
162e9b63 A |
125 | } |
126 | ||
c29f2fcc A |
127 | return error; |
128 | } | |
129 | ||
162e9b63 | 130 | int mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu) |
c29f2fcc A |
131 | { |
132 | struct kauth_identity_extlookup request; | |
162e9b63 | 133 | security_token_t token; |
c29f2fcc A |
134 | kern_return_t result; |
135 | int error = 0; | |
136 | ||
162e9b63 A |
137 | token.val[0] = -1; |
138 | token.val[1] = -1; | |
139 | ||
c29f2fcc A |
140 | request.el_flags = KAUTH_EXTLOOKUP_VALID_GSID | KAUTH_EXTLOOKUP_WANT_GGUID; |
141 | memset(&request.el_gsid, 0, sizeof(ntsid_t)); | |
142 | memcpy(&request.el_gsid, sid, KAUTH_NTSID_SIZE(sid)); | |
162e9b63 A |
143 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
144 | if (result != KERN_SUCCESS) return EIO; | |
145 | if (token.val[0] != 0) return EAUTH; | |
146 | ||
c29f2fcc A |
147 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) != 0) |
148 | memcpy(uu, &request.el_gguid, sizeof(guid_t)); | |
149 | else | |
150 | error = ENOENT; | |
162e9b63 | 151 | |
c29f2fcc A |
152 | return error; |
153 | } | |
154 | ||
162e9b63 | 155 | int mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid) |
c29f2fcc A |
156 | { |
157 | struct kauth_identity_extlookup request; | |
162e9b63 | 158 | security_token_t token; |
c29f2fcc A |
159 | kern_return_t result; |
160 | int error = 0; | |
161 | ||
162e9b63 A |
162 | token.val[0] = -1; |
163 | token.val[1] = -1; | |
164 | ||
c29f2fcc A |
165 | request.el_flags = KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_GSID; |
166 | memcpy(&request.el_gguid, uu, sizeof(guid_t)); | |
162e9b63 A |
167 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
168 | if (result != KERN_SUCCESS) return EIO; | |
169 | if (token.val[0] != 0) return EAUTH; | |
170 | ||
c29f2fcc A |
171 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GSID) != 0) |
172 | memcpy(sid, &request.el_gsid, sizeof(nt_sid_t)); | |
173 | else | |
174 | error = ENOENT; | |
162e9b63 | 175 | |
c29f2fcc A |
176 | return error; |
177 | } | |
178 | ||
162e9b63 | 179 | int mbr_check_membership(uuid_t user, uuid_t group, int *ismember) |
c29f2fcc A |
180 | { |
181 | struct kauth_identity_extlookup request; | |
162e9b63 | 182 | security_token_t token; |
c29f2fcc A |
183 | kern_return_t result; |
184 | int error = 0; | |
185 | ||
162e9b63 A |
186 | token.val[0] = -1; |
187 | token.val[1] = -1; | |
188 | ||
189 | request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP; | |
c29f2fcc A |
190 | memcpy(&request.el_uguid, user, sizeof(guid_t)); |
191 | memcpy(&request.el_gguid, group, sizeof(guid_t)); | |
162e9b63 A |
192 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
193 | if (result != KERN_SUCCESS) return EIO; | |
194 | if (token.val[0] != 0) return EAUTH; | |
195 | ||
c29f2fcc | 196 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) != 0) |
c29f2fcc | 197 | *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0); |
c29f2fcc A |
198 | else |
199 | error = ENOENT; | |
162e9b63 | 200 | |
c29f2fcc A |
201 | return error; |
202 | } | |
203 | ||
162e9b63 | 204 | int mbr_check_membership_refresh(uuid_t user, uuid_t group, int *ismember) |
918ca66e A |
205 | { |
206 | struct kauth_identity_extlookup request; | |
162e9b63 | 207 | security_token_t token; |
918ca66e A |
208 | kern_return_t result; |
209 | int error = 0; | |
210 | ||
162e9b63 A |
211 | token.val[0] = -1; |
212 | token.val[1] = -1; | |
213 | ||
214 | request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP | (1 << 15); | |
918ca66e A |
215 | memcpy(&request.el_uguid, user, sizeof(guid_t)); |
216 | memcpy(&request.el_gguid, group, sizeof(guid_t)); | |
162e9b63 A |
217 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
218 | if (result != KERN_SUCCESS) return EIO; | |
219 | if (token.val[0] != 0) return EAUTH; | |
220 | ||
918ca66e | 221 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) != 0) |
918ca66e | 222 | *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0); |
918ca66e A |
223 | else |
224 | error = ENOENT; | |
162e9b63 | 225 | |
918ca66e A |
226 | return error; |
227 | } | |
228 | ||
162e9b63 | 229 | int mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember) |
c29f2fcc A |
230 | { |
231 | struct kauth_identity_extlookup request; | |
162e9b63 | 232 | security_token_t token; |
c29f2fcc A |
233 | kern_return_t result; |
234 | int error = 0; | |
235 | ||
162e9b63 A |
236 | token.val[0] = -1; |
237 | token.val[1] = -1; | |
238 | ||
239 | request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP; | |
c29f2fcc A |
240 | memcpy(&request.el_uguid, user, sizeof(guid_t)); |
241 | request.el_gid = group; | |
162e9b63 A |
242 | result = _mbr_DoMembershipCall(GetServerPort(), &request, &token); |
243 | if (result != KERN_SUCCESS) return EIO; | |
244 | if (token.val[0] != 0) return EAUTH; | |
245 | ||
c29f2fcc | 246 | if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) != 0) |
c29f2fcc | 247 | *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0); |
c29f2fcc A |
248 | else |
249 | error = ENOENT; | |
162e9b63 | 250 | |
c29f2fcc A |
251 | return error; |
252 | } | |
253 | ||
254 | int mbr_reset_cache() | |
255 | { | |
162e9b63 | 256 | security_token_t token; |
c29f2fcc | 257 | kern_return_t result; |
162e9b63 A |
258 | |
259 | token.val[0] = -1; | |
260 | token.val[1] = -1; | |
261 | ||
262 | result = _mbr_ClearCache(GetServerPort(), &token); | |
263 | if (result != KERN_SUCCESS) return EIO; | |
264 | if (token.val[0] != 0) return EAUTH; | |
265 | ||
c29f2fcc A |
266 | return 0; |
267 | } | |
268 | ||
162e9b63 | 269 | int mbr_user_name_to_uuid(const char *name, uuid_t uu) |
c29f2fcc | 270 | { |
162e9b63 | 271 | security_token_t token; |
c29f2fcc | 272 | kern_return_t result; |
162e9b63 A |
273 | |
274 | if (name == NULL) return EINVAL; | |
275 | if (strlen(name) > 255) return EINVAL; | |
276 | ||
277 | token.val[0] = -1; | |
278 | token.val[1] = -1; | |
279 | ||
280 | result = _mbr_MapName(GetServerPort(), 1, (char *)name, (guid_t *)uu, &token); | |
281 | if (result == KERN_FAILURE) return ENOENT; | |
282 | else if (result != KERN_SUCCESS) return EIO; | |
283 | ||
284 | if (token.val[0] != 0) return EAUTH; | |
285 | ||
c29f2fcc A |
286 | return 0; |
287 | } | |
288 | ||
162e9b63 | 289 | int mbr_group_name_to_uuid(const char *name, uuid_t uu) |
c29f2fcc | 290 | { |
162e9b63 | 291 | security_token_t token; |
c29f2fcc | 292 | kern_return_t result; |
162e9b63 A |
293 | |
294 | if (name == NULL) return EINVAL; | |
295 | if (strlen(name) > 255) return EINVAL; | |
296 | ||
297 | token.val[0] = -1; | |
298 | token.val[1] = -1; | |
299 | ||
300 | result = _mbr_MapName(GetServerPort(), 0, (char *)name, (guid_t *)uu, &token); | |
301 | if (result == KERN_FAILURE) return ENOENT; | |
302 | else if (result != KERN_SUCCESS) return EIO; | |
303 | ||
304 | if (token.val[0] != 0) return EAUTH; | |
305 | ||
c29f2fcc A |
306 | return 0; |
307 | } | |
308 | ||
162e9b63 | 309 | int mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember) |
c29f2fcc | 310 | { |
162e9b63 A |
311 | char *prefix = "com.apple.access_"; |
312 | char *all_services = "com.apple.access_all_services"; | |
c29f2fcc A |
313 | char groupName[256]; |
314 | uuid_t group_uu; | |
918ca66e | 315 | int result, dummy; |
162e9b63 A |
316 | |
317 | if (servicename == NULL) return EINVAL; | |
318 | if (strlen(servicename) > (255 - strlen(prefix))) return EINVAL; | |
319 | ||
320 | /* start by checking "all services" */ | |
c29f2fcc | 321 | result = mbr_group_name_to_uuid(all_services, group_uu); |
162e9b63 A |
322 | |
323 | if (result == EAUTH) return result; | |
324 | ||
c29f2fcc A |
325 | if (result == ENOENT) |
326 | { | |
162e9b63 | 327 | /* all_services group didn't exist, check individual group */ |
c29f2fcc A |
328 | memcpy(groupName, prefix, strlen(prefix)); |
329 | strcpy(groupName + strlen(prefix), servicename); | |
330 | result = mbr_group_name_to_uuid(groupName, group_uu); | |
331 | } | |
162e9b63 | 332 | |
c29f2fcc | 333 | if (result == 0) |
162e9b63 | 334 | { |
918ca66e | 335 | result = mbr_check_membership_refresh(user, group_uu, ismember); |
162e9b63 A |
336 | } |
337 | else if (result == EAUTH) | |
338 | { | |
339 | return result; | |
340 | } | |
918ca66e A |
341 | else |
342 | { | |
162e9b63 | 343 | /* just force cache update with bogus membership check */ |
918ca66e A |
344 | memset(group_uu, 0, sizeof(group_uu)); |
345 | mbr_check_membership_refresh(user, group_uu, &dummy); | |
346 | } | |
162e9b63 | 347 | |
c29f2fcc A |
348 | return result; |
349 | } | |
350 | ||
162e9b63 | 351 | static char *ConvertBytesToDecimal(char *buffer, unsigned long long value) |
c29f2fcc | 352 | { |
162e9b63 | 353 | char *temp; |
c29f2fcc A |
354 | buffer[24] = '\0'; |
355 | buffer[23] = '0'; | |
162e9b63 A |
356 | |
357 | if (value == 0) return &buffer[23]; | |
358 | ||
c29f2fcc A |
359 | temp = &buffer[24]; |
360 | while (value != 0) | |
361 | { | |
362 | temp--; | |
363 | *temp = '0' + (value % 10); | |
364 | value /= 10; | |
365 | } | |
162e9b63 | 366 | |
c29f2fcc A |
367 | return temp; |
368 | } | |
369 | ||
162e9b63 | 370 | int mbr_sid_to_string(const nt_sid_t *sid, char *string) |
c29f2fcc | 371 | { |
162e9b63 | 372 | char *current = string; |
c29f2fcc A |
373 | long long temp = 0; |
374 | int i; | |
375 | char tempBuffer[25]; | |
162e9b63 A |
376 | |
377 | if (sid->sid_authcount > NTSID_MAX_AUTHORITIES) return EINVAL; | |
378 | ||
918ca66e A |
379 | for (i = 0; i < 6; i++) |
380 | temp = (temp << 8) | sid->sid_authority[i]; | |
162e9b63 | 381 | |
c29f2fcc A |
382 | current[0] = 'S'; |
383 | current[1] = '-'; | |
384 | current += 2; | |
385 | strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_kind)); | |
386 | current = current + strlen(current); | |
387 | *current = '-'; | |
388 | current++; | |
389 | strcpy(current, ConvertBytesToDecimal(tempBuffer, temp)); | |
162e9b63 A |
390 | |
391 | for (i = 0; i < sid->sid_authcount; i++) | |
c29f2fcc A |
392 | { |
393 | current = current + strlen(current); | |
394 | *current = '-'; | |
395 | current++; | |
396 | strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_authorities[i])); | |
397 | } | |
162e9b63 | 398 | |
c29f2fcc A |
399 | return 0; |
400 | } | |
401 | ||
162e9b63 | 402 | int mbr_string_to_sid(const char *string, nt_sid_t *sid) |
c29f2fcc | 403 | { |
162e9b63 | 404 | char *current = string+2; |
c29f2fcc A |
405 | int count = 0; |
406 | long long temp; | |
407 | ||
408 | memset(sid, 0, sizeof(nt_sid_t)); | |
162e9b63 A |
409 | if ((string[0] != 'S') || (string[1] != '-')) return EINVAL; |
410 | ||
c29f2fcc A |
411 | sid->sid_kind = strtol(current, ¤t, 10); |
412 | if (*current == '\0') return EINVAL; | |
413 | current++; | |
414 | temp = strtoll(current, ¤t, 10); | |
162e9b63 A |
415 | |
416 | /* convert to BigEndian before copying */ | |
918ca66e | 417 | temp = OSSwapHostToBigInt64(temp); |
c29f2fcc | 418 | memcpy(sid->sid_authority, ((char*)&temp)+2, 6); |
162e9b63 | 419 | while ((*current != '\0') && (count < NTSID_MAX_AUTHORITIES)) |
c29f2fcc A |
420 | { |
421 | current++; | |
422 | sid->sid_authorities[count] = strtol(current, ¤t, 10); | |
423 | count++; | |
424 | } | |
162e9b63 A |
425 | |
426 | if (*current != '\0') return EINVAL; | |
427 | ||
c29f2fcc | 428 | sid->sid_authcount = count; |
162e9b63 | 429 | |
c29f2fcc A |
430 | return 0; |
431 | } | |
432 | ||
162e9b63 | 433 | static void ConvertBytesToHex(char **string, char **data, int numBytes) |
c29f2fcc A |
434 | { |
435 | int i; | |
162e9b63 A |
436 | |
437 | for (i = 0; i < numBytes; i++) | |
c29f2fcc A |
438 | { |
439 | unsigned char hi = ((**data) >> 4) & 0xf; | |
440 | unsigned char low = (**data) & 0xf; | |
441 | if (hi < 10) | |
442 | **string = '0' + hi; | |
443 | else | |
444 | **string = 'A' + hi - 10; | |
162e9b63 | 445 | |
c29f2fcc A |
446 | (*string)++; |
447 | ||
448 | if (low < 10) | |
449 | **string = '0' + low; | |
450 | else | |
451 | **string = 'A' + low - 10; | |
452 | ||
453 | (*string)++; | |
454 | (*data)++; | |
455 | } | |
456 | } | |
457 | ||
162e9b63 | 458 | int mbr_uuid_to_string(const uuid_t uu, char *string) |
c29f2fcc | 459 | { |
162e9b63 A |
460 | char *guid = (char *)uu; |
461 | char *strPtr = string; | |
c29f2fcc A |
462 | ConvertBytesToHex(&strPtr, &guid, 4); |
463 | *strPtr = '-'; strPtr++; | |
464 | ConvertBytesToHex(&strPtr, &guid, 2); | |
465 | *strPtr = '-'; strPtr++; | |
466 | ConvertBytesToHex(&strPtr, &guid, 2); | |
467 | *strPtr = '-'; strPtr++; | |
468 | ConvertBytesToHex(&strPtr, &guid, 2); | |
469 | *strPtr = '-'; strPtr++; | |
470 | ConvertBytesToHex(&strPtr, &guid, 6); | |
471 | *strPtr = '\0'; | |
162e9b63 | 472 | |
c29f2fcc A |
473 | return 0; |
474 | } | |
475 | ||
162e9b63 | 476 | int mbr_string_to_uuid(const char *string, uuid_t uu) |
c29f2fcc A |
477 | { |
478 | short dataIndex = 0; | |
479 | int isFirstNibble = 1; | |
162e9b63 | 480 | |
c29f2fcc A |
481 | if (strlen(string) > MBR_UU_STRING_SIZE) |
482 | return EINVAL; | |
162e9b63 | 483 | |
c29f2fcc A |
484 | while (*string != '\0' && dataIndex < 16) |
485 | { | |
486 | char nibble; | |
162e9b63 A |
487 | |
488 | if ((*string >= '0') && (*string <= '9')) | |
489 | { | |
c29f2fcc | 490 | nibble = *string - '0'; |
162e9b63 A |
491 | } |
492 | else if ((*string >= 'A') && (*string <= 'F')) | |
493 | { | |
c29f2fcc | 494 | nibble = *string - 'A' + 10; |
162e9b63 A |
495 | } |
496 | else if ((*string >= 'a') && (*string <= 'f')) | |
497 | { | |
c29f2fcc | 498 | nibble = *string - 'a' + 10; |
162e9b63 | 499 | } |
c29f2fcc A |
500 | else |
501 | { | |
162e9b63 | 502 | if (*string != '-') return EINVAL; |
c29f2fcc A |
503 | string++; |
504 | continue; | |
505 | } | |
162e9b63 | 506 | |
c29f2fcc A |
507 | if (isFirstNibble) |
508 | { | |
509 | uu[dataIndex] = nibble << 4; | |
510 | isFirstNibble = 0; | |
511 | } | |
512 | else | |
513 | { | |
514 | uu[dataIndex] |= nibble; | |
515 | dataIndex++; | |
516 | isFirstNibble = 1; | |
517 | } | |
162e9b63 | 518 | |
c29f2fcc A |
519 | string++; |
520 | } | |
162e9b63 A |
521 | |
522 | if (dataIndex != 16) return EINVAL; | |
523 | ||
c29f2fcc A |
524 | return 0; |
525 | } |