Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Winbind client API
5 :
6 : Copyright (C) Gerald (Jerry) Carter 2007
7 : Copyright (C) Volker Lendecke 2010
8 :
9 :
10 : This library is free software; you can redistribute it and/or
11 : modify it under the terms of the GNU Lesser General Public
12 : License as published by the Free Software Foundation; either
13 : version 3 of the License, or (at your option) any later version.
14 :
15 : This library is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : Library General Public License for more details.
19 :
20 : You should have received a copy of the GNU Lesser General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : /* Required Headers */
25 :
26 : #include "replace.h"
27 : #include "libwbclient.h"
28 : #include "../winbind_client.h"
29 : #include "lib/util/smb_strtox.h"
30 :
31 : /* Convert a sid to a string into a buffer. Return the string
32 : * length. If buflen is too small, return the string length that would
33 : * result if it was long enough. */
34 : _PUBLIC_
35 99839 : int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen)
36 : {
37 : uint64_t id_auth;
38 : int i, ofs;
39 :
40 99839 : if (!sid) {
41 0 : strlcpy(buf, "(NULL SID)", buflen);
42 0 : return 10; /* strlen("(NULL SID)") */
43 : }
44 :
45 252227 : id_auth = (uint64_t)sid->id_auth[5] +
46 176033 : ((uint64_t)sid->id_auth[4] << 8) +
47 176033 : ((uint64_t)sid->id_auth[3] << 16) +
48 176033 : ((uint64_t)sid->id_auth[2] << 24) +
49 99839 : ((uint64_t)sid->id_auth[1] << 32) +
50 99839 : ((uint64_t)sid->id_auth[0] << 40);
51 :
52 99839 : ofs = snprintf(buf, buflen, "S-%hhu-", (unsigned char)sid->sid_rev_num);
53 99839 : if (id_auth >= UINT32_MAX) {
54 0 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "0x%llx",
55 : (unsigned long long)id_auth);
56 : } else {
57 99839 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "%llu",
58 : (unsigned long long)id_auth);
59 : }
60 :
61 387409 : for (i = 0; i < sid->num_auths; i++) {
62 287570 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%u",
63 287570 : (unsigned int)sid->sub_auths[i]);
64 : }
65 99839 : return ofs;
66 : }
67 :
68 : /* Convert a binary SID to a character string */
69 : _PUBLIC_
70 64 : wbcErr wbcSidToString(const struct wbcDomainSid *sid,
71 : char **sid_string)
72 : {
73 : char buf[WBC_SID_STRING_BUFLEN];
74 : char *result;
75 : int len;
76 :
77 64 : if (!sid) {
78 0 : return WBC_ERR_INVALID_SID;
79 : }
80 :
81 64 : len = wbcSidToStringBuf(sid, buf, sizeof(buf));
82 :
83 64 : if (len >= WBC_SID_STRING_BUFLEN) {
84 0 : return WBC_ERR_INVALID_SID;
85 : }
86 :
87 64 : result = (char *)wbcAllocateMemory(len+1, 1, NULL);
88 64 : if (result == NULL) {
89 0 : return WBC_ERR_NO_MEMORY;
90 : }
91 64 : memcpy(result, buf, len+1);
92 :
93 64 : *sid_string = result;
94 64 : return WBC_ERR_SUCCESS;
95 : }
96 :
97 : #define AUTHORITY_MASK (~(0xffffffffffffULL))
98 :
99 : /* Convert a character string to a binary SID */
100 : _PUBLIC_
101 11913 : wbcErr wbcStringToSid(const char *str,
102 : struct wbcDomainSid *sid)
103 : {
104 : const char *p;
105 : char *q;
106 11913 : int error = 0;
107 : uint64_t x;
108 11913 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
109 :
110 11913 : if (!sid) {
111 0 : wbc_status = WBC_ERR_INVALID_PARAM;
112 0 : BAIL_ON_WBC_ERROR(wbc_status);
113 : }
114 :
115 : /* Sanity check for either "S-" or "s-" */
116 :
117 11913 : if (!str
118 11913 : || (str[0]!='S' && str[0]!='s')
119 9858 : || (str[1]!='-'))
120 : {
121 2055 : wbc_status = WBC_ERR_INVALID_PARAM;
122 2055 : BAIL_ON_WBC_ERROR(wbc_status);
123 : }
124 :
125 : /* Get the SID revision number */
126 :
127 9858 : p = str+2;
128 9858 : x = (uint64_t)smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
129 9858 : if (x == 0 || x > UINT8_MAX || !q || *q != '-' || error != 0) {
130 0 : wbc_status = WBC_ERR_INVALID_SID;
131 0 : BAIL_ON_WBC_ERROR(wbc_status);
132 : }
133 9858 : sid->sid_rev_num = (uint8_t)x;
134 :
135 : /*
136 : * Next the Identifier Authority. This is stored big-endian in a
137 : * 6 byte array. If the authority value is >= UINT_MAX, then it should
138 : * be expressed as a hex value, according to MS-DTYP.
139 : */
140 9858 : p = q+1;
141 9858 : x = smb_strtoull(p, &q, 0, &error, SMB_STR_STANDARD);
142 9858 : if (!q || *q != '-' || (x & AUTHORITY_MASK) || error != 0) {
143 0 : wbc_status = WBC_ERR_INVALID_SID;
144 0 : BAIL_ON_WBC_ERROR(wbc_status);
145 : }
146 9858 : sid->id_auth[5] = (x & 0x0000000000ffULL);
147 9858 : sid->id_auth[4] = (x & 0x00000000ff00ULL) >> 8;
148 9858 : sid->id_auth[3] = (x & 0x000000ff0000ULL) >> 16;
149 9858 : sid->id_auth[2] = (x & 0x0000ff000000ULL) >> 24;
150 9858 : sid->id_auth[1] = (x & 0x00ff00000000ULL) >> 32;
151 9858 : sid->id_auth[0] = (x & 0xff0000000000ULL) >> 40;
152 :
153 : /* now read the the subauthorities */
154 9858 : p = q +1;
155 9858 : sid->num_auths = 0;
156 42818 : while (sid->num_auths < WBC_MAXSUBAUTHS) {
157 34701 : x = smb_strtoull(p, &q, 10, &error, SMB_STR_ALLOW_NO_CONVERSION);
158 34701 : if (p == q)
159 0 : break;
160 34701 : if (x > UINT32_MAX || error != 0) {
161 0 : wbc_status = WBC_ERR_INVALID_SID;
162 0 : BAIL_ON_WBC_ERROR(wbc_status);
163 : }
164 34701 : sid->sub_auths[sid->num_auths++] = x;
165 :
166 34701 : if (*q != '-') {
167 9858 : break;
168 : }
169 24843 : p = q + 1;
170 : }
171 :
172 : /* IF we ended early, then the SID could not be converted */
173 :
174 9858 : if (q && *q!='\0') {
175 0 : wbc_status = WBC_ERR_INVALID_SID;
176 0 : BAIL_ON_WBC_ERROR(wbc_status);
177 : }
178 :
179 9858 : wbc_status = WBC_ERR_SUCCESS;
180 :
181 11913 : done:
182 11913 : return wbc_status;
183 :
184 : }
185 :
186 :
187 : /* Convert a domain and name to SID */
188 : _PUBLIC_
189 758 : wbcErr wbcCtxLookupName(struct wbcContext *ctx,
190 : const char *domain,
191 : const char *name,
192 : struct wbcDomainSid *sid,
193 : enum wbcSidType *name_type)
194 : {
195 : struct winbindd_request request;
196 : struct winbindd_response response;
197 758 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
198 :
199 758 : if (!sid || !name_type) {
200 0 : wbc_status = WBC_ERR_INVALID_PARAM;
201 0 : BAIL_ON_WBC_ERROR(wbc_status);
202 : }
203 :
204 : /* Initialize request */
205 :
206 758 : ZERO_STRUCT(request);
207 758 : ZERO_STRUCT(response);
208 :
209 : /* dst is already null terminated from the memset above */
210 :
211 758 : strncpy(request.data.name.dom_name, domain,
212 : sizeof(request.data.name.dom_name)-1);
213 758 : strncpy(request.data.name.name, name,
214 : sizeof(request.data.name.name)-1);
215 :
216 758 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPNAME,
217 : &request,
218 : &response);
219 758 : BAIL_ON_WBC_ERROR(wbc_status);
220 :
221 580 : wbc_status = wbcStringToSid(response.data.sid.sid, sid);
222 580 : BAIL_ON_WBC_ERROR(wbc_status);
223 :
224 580 : *name_type = (enum wbcSidType)response.data.sid.type;
225 :
226 580 : wbc_status = WBC_ERR_SUCCESS;
227 :
228 758 : done:
229 758 : return wbc_status;
230 : }
231 :
232 : _PUBLIC_
233 614 : wbcErr wbcLookupName(const char *domain,
234 : const char *name,
235 : struct wbcDomainSid *sid,
236 : enum wbcSidType *name_type)
237 : {
238 614 : return wbcCtxLookupName(NULL, domain, name, sid, name_type);
239 : }
240 :
241 :
242 : /* Convert a SID to a domain and name */
243 : _PUBLIC_
244 220 : wbcErr wbcCtxLookupSid(struct wbcContext *ctx,
245 : const struct wbcDomainSid *sid,
246 : char **pdomain,
247 : char **pname,
248 : enum wbcSidType *pname_type)
249 : {
250 : struct winbindd_request request;
251 : struct winbindd_response response;
252 220 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
253 : char *domain, *name;
254 :
255 220 : if (!sid) {
256 0 : return WBC_ERR_INVALID_PARAM;
257 : }
258 :
259 : /* Initialize request */
260 :
261 220 : ZERO_STRUCT(request);
262 220 : ZERO_STRUCT(response);
263 :
264 220 : wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
265 :
266 : /* Make request */
267 :
268 220 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSID,
269 : &request,
270 : &response);
271 220 : if (!WBC_ERROR_IS_OK(wbc_status)) {
272 6 : return wbc_status;
273 : }
274 :
275 : /* Copy out result */
276 :
277 214 : wbc_status = WBC_ERR_NO_MEMORY;
278 214 : domain = NULL;
279 214 : name = NULL;
280 :
281 214 : domain = wbcStrDup(response.data.name.dom_name);
282 214 : if (domain == NULL) {
283 0 : goto done;
284 : }
285 214 : name = wbcStrDup(response.data.name.name);
286 214 : if (name == NULL) {
287 0 : goto done;
288 : }
289 214 : if (pdomain != NULL) {
290 214 : *pdomain = domain;
291 214 : domain = NULL;
292 : }
293 214 : if (pname != NULL) {
294 214 : *pname = name;
295 214 : name = NULL;
296 : }
297 214 : if (pname_type != NULL) {
298 214 : *pname_type = (enum wbcSidType)response.data.name.type;
299 : }
300 214 : wbc_status = WBC_ERR_SUCCESS;
301 214 : done:
302 214 : wbcFreeMemory(name);
303 214 : wbcFreeMemory(domain);
304 214 : return wbc_status;
305 : }
306 :
307 : _PUBLIC_
308 126 : wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
309 : char **pdomain,
310 : char **pname,
311 : enum wbcSidType *pname_type)
312 : {
313 126 : return wbcCtxLookupSid(NULL, sid, pdomain, pname, pname_type);
314 : }
315 :
316 0 : static void wbcDomainInfosDestructor(void *ptr)
317 : {
318 0 : struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
319 :
320 0 : while (i->short_name != NULL) {
321 0 : wbcFreeMemory(i->short_name);
322 0 : wbcFreeMemory(i->dns_name);
323 0 : i += 1;
324 : }
325 0 : }
326 :
327 0 : static void wbcTranslatedNamesDestructor(void *ptr)
328 : {
329 0 : struct wbcTranslatedName *n = (struct wbcTranslatedName *)ptr;
330 :
331 0 : while (n->name != NULL) {
332 0 : wbcFreeMemory(n->name);
333 0 : n += 1;
334 : }
335 0 : }
336 :
337 : _PUBLIC_
338 0 : wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
339 : const struct wbcDomainSid *sids, int num_sids,
340 : struct wbcDomainInfo **pdomains, int *pnum_domains,
341 : struct wbcTranslatedName **pnames)
342 : {
343 : struct winbindd_request request;
344 : struct winbindd_response response;
345 0 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
346 : int buflen, i, extra_len, num_domains, num_names;
347 : char *sidlist, *p, *q, *extra_data;
348 0 : struct wbcDomainInfo *domains = NULL;
349 0 : struct wbcTranslatedName *names = NULL;
350 0 : int error = 0;
351 :
352 0 : buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
353 :
354 0 : sidlist = (char *)malloc(buflen);
355 0 : if (sidlist == NULL) {
356 0 : return WBC_ERR_NO_MEMORY;
357 : }
358 :
359 0 : p = sidlist;
360 :
361 0 : for (i=0; i<num_sids; i++) {
362 : int remaining;
363 : int len;
364 :
365 0 : remaining = buflen - (p - sidlist);
366 :
367 0 : len = wbcSidToStringBuf(&sids[i], p, remaining);
368 0 : if (len > remaining) {
369 0 : free(sidlist);
370 0 : return WBC_ERR_UNKNOWN_FAILURE;
371 : }
372 :
373 0 : p += len;
374 0 : *p++ = '\n';
375 : }
376 0 : *p++ = '\0';
377 :
378 0 : ZERO_STRUCT(request);
379 0 : ZERO_STRUCT(response);
380 :
381 0 : request.extra_data.data = sidlist;
382 0 : request.extra_len = p - sidlist;
383 :
384 0 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSIDS,
385 : &request, &response);
386 0 : free(sidlist);
387 0 : if (!WBC_ERROR_IS_OK(wbc_status)) {
388 0 : return wbc_status;
389 : }
390 :
391 0 : extra_len = response.length - sizeof(struct winbindd_response);
392 0 : extra_data = (char *)response.extra_data.data;
393 :
394 0 : if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
395 0 : goto wbc_err_invalid;
396 : }
397 :
398 0 : p = extra_data;
399 :
400 0 : num_domains = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
401 0 : if (*q != '\n' || error != 0) {
402 0 : goto wbc_err_invalid;
403 : }
404 0 : p = q+1;
405 :
406 0 : domains = (struct wbcDomainInfo *)wbcAllocateMemory(
407 0 : num_domains+1, sizeof(struct wbcDomainInfo),
408 : wbcDomainInfosDestructor);
409 0 : if (domains == NULL) {
410 0 : wbc_status = WBC_ERR_NO_MEMORY;
411 0 : goto fail;
412 : }
413 :
414 0 : for (i=0; i<num_domains; i++) {
415 :
416 0 : q = strchr(p, ' ');
417 0 : if (q == NULL) {
418 0 : goto wbc_err_invalid;
419 : }
420 0 : *q = '\0';
421 0 : wbc_status = wbcStringToSid(p, &domains[i].sid);
422 0 : if (!WBC_ERROR_IS_OK(wbc_status)) {
423 0 : goto fail;
424 : }
425 0 : p = q+1;
426 :
427 0 : q = strchr(p, '\n');
428 0 : if (q == NULL) {
429 0 : goto wbc_err_invalid;
430 : }
431 0 : *q = '\0';
432 0 : domains[i].short_name = wbcStrDup(p);
433 0 : if (domains[i].short_name == NULL) {
434 0 : wbc_status = WBC_ERR_NO_MEMORY;
435 0 : goto fail;
436 : }
437 0 : p = q+1;
438 : }
439 :
440 0 : num_names = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
441 0 : if (*q != '\n' || error != 0) {
442 0 : goto wbc_err_invalid;
443 : }
444 0 : p = q+1;
445 :
446 0 : if (num_names != num_sids) {
447 0 : goto wbc_err_invalid;
448 : }
449 :
450 0 : names = (struct wbcTranslatedName *)wbcAllocateMemory(
451 0 : num_names+1, sizeof(struct wbcTranslatedName),
452 : wbcTranslatedNamesDestructor);
453 0 : if (names == NULL) {
454 0 : wbc_status = WBC_ERR_NO_MEMORY;
455 0 : goto fail;
456 : }
457 :
458 0 : for (i=0; i<num_names; i++) {
459 :
460 0 : names[i].domain_index = smb_strtoul(p,
461 : &q,
462 : 10,
463 : &error,
464 : SMB_STR_STANDARD);
465 0 : if (names[i].domain_index < 0 || error != 0) {
466 0 : goto wbc_err_invalid;
467 : }
468 0 : if (names[i].domain_index >= num_domains) {
469 0 : goto wbc_err_invalid;
470 : }
471 :
472 0 : if (*q != ' ') {
473 0 : goto wbc_err_invalid;
474 : }
475 0 : p = q+1;
476 :
477 0 : names[i].type = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
478 0 : if (*q != ' ' || error != 0) {
479 0 : goto wbc_err_invalid;
480 : }
481 0 : p = q+1;
482 :
483 0 : q = strchr(p, '\n');
484 0 : if (q == NULL) {
485 0 : goto wbc_err_invalid;
486 : }
487 0 : *q = '\0';
488 0 : names[i].name = wbcStrDup(p);
489 0 : if (names[i].name == NULL) {
490 0 : wbc_status = WBC_ERR_NO_MEMORY;
491 0 : goto fail;
492 : }
493 0 : p = q+1;
494 : }
495 0 : if (*p != '\0') {
496 0 : goto wbc_err_invalid;
497 : }
498 :
499 0 : *pdomains = domains;
500 0 : *pnames = names;
501 0 : winbindd_free_response(&response);
502 0 : return WBC_ERR_SUCCESS;
503 :
504 0 : wbc_err_invalid:
505 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
506 0 : fail:
507 0 : winbindd_free_response(&response);
508 0 : wbcFreeMemory(domains);
509 0 : wbcFreeMemory(names);
510 0 : return wbc_status;
511 : }
512 :
513 : _PUBLIC_
514 0 : wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids,
515 : struct wbcDomainInfo **pdomains, int *pnum_domains,
516 : struct wbcTranslatedName **pnames)
517 : {
518 0 : return wbcCtxLookupSids(NULL, sids, num_sids, pdomains,
519 : pnum_domains, pnames);
520 : }
521 :
522 : /* Translate a collection of RIDs within a domain to names */
523 :
524 : _PUBLIC_
525 22 : wbcErr wbcCtxLookupRids(struct wbcContext *ctx, struct wbcDomainSid *dom_sid,
526 : int num_rids,
527 : uint32_t *rids,
528 : const char **pp_domain_name,
529 : const char ***pnames,
530 : enum wbcSidType **ptypes)
531 : {
532 : size_t i, len, ridbuf_size;
533 : char *ridlist;
534 : char *p;
535 22 : int error = 0;
536 : struct winbindd_request request;
537 : struct winbindd_response response;
538 22 : char *domain_name = NULL;
539 22 : const char **names = NULL;
540 22 : enum wbcSidType *types = NULL;
541 22 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
542 :
543 : /* Initialise request */
544 :
545 22 : ZERO_STRUCT(request);
546 22 : ZERO_STRUCT(response);
547 :
548 22 : if (!dom_sid || (num_rids == 0)) {
549 0 : wbc_status = WBC_ERR_INVALID_PARAM;
550 0 : BAIL_ON_WBC_ERROR(wbc_status);
551 : }
552 :
553 22 : wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
554 :
555 : /* Even if all the Rids were of maximum 32bit values,
556 : we would only have 11 bytes per rid in the final array
557 : ("4294967296" + \n). Add one more byte for the
558 : terminating '\0' */
559 :
560 22 : ridbuf_size = (sizeof(char)*11) * num_rids + 1;
561 :
562 22 : ridlist = (char *)malloc(ridbuf_size);
563 22 : BAIL_ON_PTR_ERROR(ridlist, wbc_status);
564 :
565 22 : len = 0;
566 46 : for (i=0; i<num_rids; i++) {
567 24 : len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
568 24 : rids[i]);
569 : }
570 22 : ridlist[len] = '\0';
571 22 : len += 1;
572 :
573 22 : request.extra_data.data = ridlist;
574 22 : request.extra_len = len;
575 :
576 22 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
577 : &request,
578 : &response);
579 22 : free(ridlist);
580 22 : BAIL_ON_WBC_ERROR(wbc_status);
581 :
582 2 : domain_name = wbcStrDup(response.data.domain_name);
583 2 : BAIL_ON_PTR_ERROR(domain_name, wbc_status);
584 :
585 2 : names = wbcAllocateStringArray(num_rids);
586 2 : BAIL_ON_PTR_ERROR(names, wbc_status);
587 :
588 2 : types = (enum wbcSidType *)wbcAllocateMemory(
589 : num_rids, sizeof(enum wbcSidType), NULL);
590 2 : BAIL_ON_PTR_ERROR(types, wbc_status);
591 :
592 2 : p = (char *)response.extra_data.data;
593 :
594 9 : for (i=0; i<num_rids; i++) {
595 : char *q;
596 :
597 4 : if (*p == '\0') {
598 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
599 0 : goto done;
600 : }
601 :
602 4 : types[i] = (enum wbcSidType)smb_strtoul(p,
603 : &q,
604 : 10,
605 : &error,
606 : SMB_STR_STANDARD);
607 :
608 4 : if (*q != ' ' || error != 0) {
609 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
610 0 : goto done;
611 : }
612 :
613 4 : p = q+1;
614 :
615 4 : if ((q = strchr(p, '\n')) == NULL) {
616 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
617 0 : goto done;
618 : }
619 :
620 4 : *q = '\0';
621 :
622 4 : names[i] = strdup(p);
623 4 : BAIL_ON_PTR_ERROR(names[i], wbc_status);
624 :
625 4 : p = q+1;
626 : }
627 :
628 2 : if (*p != '\0') {
629 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
630 0 : goto done;
631 : }
632 :
633 2 : wbc_status = WBC_ERR_SUCCESS;
634 :
635 22 : done:
636 22 : winbindd_free_response(&response);
637 :
638 22 : if (WBC_ERROR_IS_OK(wbc_status)) {
639 2 : *pp_domain_name = domain_name;
640 2 : *pnames = names;
641 2 : *ptypes = types;
642 : }
643 : else {
644 20 : wbcFreeMemory(domain_name);
645 20 : wbcFreeMemory(names);
646 20 : wbcFreeMemory(types);
647 : }
648 :
649 22 : return wbc_status;
650 : }
651 :
652 : _PUBLIC_
653 22 : wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
654 : int num_rids,
655 : uint32_t *rids,
656 : const char **pp_domain_name,
657 : const char ***pnames,
658 : enum wbcSidType **ptypes)
659 : {
660 22 : return wbcCtxLookupRids(NULL, dom_sid, num_rids, rids,
661 : pp_domain_name, pnames, ptypes);
662 : }
663 :
664 : /* Get the groups a user belongs to */
665 : _PUBLIC_
666 108 : wbcErr wbcCtxLookupUserSids(struct wbcContext *ctx,
667 : const struct wbcDomainSid *user_sid,
668 : bool domain_groups_only,
669 : uint32_t *num_sids,
670 : struct wbcDomainSid **_sids)
671 : {
672 : uint32_t i;
673 : const char *s;
674 : struct winbindd_request request;
675 : struct winbindd_response response;
676 108 : struct wbcDomainSid *sids = NULL;
677 108 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
678 : int cmd;
679 :
680 : /* Initialise request */
681 :
682 108 : ZERO_STRUCT(request);
683 108 : ZERO_STRUCT(response);
684 :
685 108 : if (!user_sid) {
686 0 : wbc_status = WBC_ERR_INVALID_PARAM;
687 0 : BAIL_ON_WBC_ERROR(wbc_status);
688 : }
689 :
690 108 : wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
691 :
692 108 : if (domain_groups_only) {
693 28 : cmd = WINBINDD_GETUSERDOMGROUPS;
694 : } else {
695 80 : cmd = WINBINDD_GETUSERSIDS;
696 : }
697 :
698 108 : wbc_status = wbcRequestResponse(ctx, cmd,
699 : &request,
700 : &response);
701 108 : BAIL_ON_WBC_ERROR(wbc_status);
702 :
703 114 : if (response.data.num_entries &&
704 74 : !response.extra_data.data) {
705 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
706 0 : BAIL_ON_WBC_ERROR(wbc_status);
707 : }
708 :
709 74 : sids = (struct wbcDomainSid *)wbcAllocateMemory(
710 74 : response.data.num_entries, sizeof(struct wbcDomainSid),
711 : NULL);
712 74 : BAIL_ON_PTR_ERROR(sids, wbc_status);
713 :
714 74 : s = (const char *)response.extra_data.data;
715 304 : for (i = 0; i < response.data.num_entries; i++) {
716 230 : char *n = strchr(s, '\n');
717 230 : if (n) {
718 230 : *n = '\0';
719 : }
720 230 : wbc_status = wbcStringToSid(s, &sids[i]);
721 230 : BAIL_ON_WBC_ERROR(wbc_status);
722 230 : s += strlen(s) + 1;
723 : }
724 :
725 74 : *num_sids = response.data.num_entries;
726 74 : *_sids = sids;
727 74 : sids = NULL;
728 74 : wbc_status = WBC_ERR_SUCCESS;
729 :
730 108 : done:
731 108 : winbindd_free_response(&response);
732 108 : if (sids) {
733 0 : wbcFreeMemory(sids);
734 : }
735 :
736 108 : return wbc_status;
737 : }
738 :
739 : _PUBLIC_
740 108 : wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
741 : bool domain_groups_only,
742 : uint32_t *num_sids,
743 : struct wbcDomainSid **_sids)
744 : {
745 108 : return wbcCtxLookupUserSids(NULL, user_sid, domain_groups_only,
746 : num_sids, _sids);
747 : }
748 :
749 : static inline
750 2 : wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
751 : {
752 2 : if (sid->num_auths < 1) {
753 0 : return WBC_ERR_INVALID_RESPONSE;
754 : }
755 2 : *rid = sid->sub_auths[sid->num_auths - 1];
756 :
757 2 : return WBC_ERR_SUCCESS;
758 : }
759 :
760 : /* Get alias membership for sids */
761 : _PUBLIC_
762 2 : wbcErr wbcCtxGetSidAliases(struct wbcContext *ctx,
763 : const struct wbcDomainSid *dom_sid,
764 : struct wbcDomainSid *sids,
765 : uint32_t num_sids,
766 : uint32_t **alias_rids,
767 : uint32_t *num_alias_rids)
768 : {
769 : uint32_t i;
770 : const char *s;
771 : struct winbindd_request request;
772 : struct winbindd_response response;
773 2 : ssize_t extra_data_len = 0;
774 2 : char * extra_data = NULL;
775 2 : ssize_t buflen = 0;
776 : struct wbcDomainSid sid;
777 2 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
778 2 : uint32_t * rids = NULL;
779 :
780 : /* Initialise request */
781 :
782 2 : ZERO_STRUCT(request);
783 2 : ZERO_STRUCT(response);
784 :
785 2 : if (!dom_sid) {
786 0 : wbc_status = WBC_ERR_INVALID_PARAM;
787 0 : goto done;
788 : }
789 :
790 2 : wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
791 :
792 : /* Lets assume each sid is around 57 characters
793 : * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
794 2 : buflen = 57 * num_sids;
795 2 : extra_data = (char *)malloc(buflen);
796 2 : if (!extra_data) {
797 0 : wbc_status = WBC_ERR_NO_MEMORY;
798 0 : goto done;
799 : }
800 :
801 : /* Build the sid list */
802 9 : for (i=0; i<num_sids; i++) {
803 : char sid_str[WBC_SID_STRING_BUFLEN];
804 : size_t sid_len;
805 :
806 4 : sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
807 :
808 4 : if (buflen < extra_data_len + sid_len + 2) {
809 0 : char * tmp_data = NULL;
810 0 : buflen *= 2;
811 0 : tmp_data = (char *)realloc(extra_data, buflen);
812 0 : if (!tmp_data) {
813 0 : wbc_status = WBC_ERR_NO_MEMORY;
814 0 : BAIL_ON_WBC_ERROR(wbc_status);
815 : }
816 0 : extra_data = tmp_data;
817 : }
818 :
819 4 : strncpy(&extra_data[extra_data_len], sid_str,
820 4 : buflen - extra_data_len);
821 4 : extra_data_len += sid_len;
822 4 : extra_data[extra_data_len++] = '\n';
823 4 : extra_data[extra_data_len] = '\0';
824 : }
825 2 : extra_data_len += 1;
826 :
827 2 : request.extra_data.data = extra_data;
828 2 : request.extra_len = extra_data_len;
829 :
830 2 : wbc_status = wbcRequestResponse(ctx, WINBINDD_GETSIDALIASES,
831 : &request,
832 : &response);
833 2 : BAIL_ON_WBC_ERROR(wbc_status);
834 :
835 3 : if (response.data.num_entries &&
836 2 : !response.extra_data.data) {
837 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
838 0 : goto done;
839 : }
840 :
841 2 : rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
842 : sizeof(uint32_t), NULL);
843 2 : BAIL_ON_PTR_ERROR(rids, wbc_status);
844 :
845 2 : s = (const char *)response.extra_data.data;
846 4 : for (i = 0; i < response.data.num_entries; i++) {
847 2 : char *n = strchr(s, '\n');
848 2 : if (n) {
849 2 : *n = '\0';
850 : }
851 2 : wbc_status = wbcStringToSid(s, &sid);
852 2 : BAIL_ON_WBC_ERROR(wbc_status);
853 2 : wbc_status = _sid_to_rid(&sid, &rids[i]);
854 2 : BAIL_ON_WBC_ERROR(wbc_status);
855 2 : s += strlen(s) + 1;
856 : }
857 :
858 2 : *num_alias_rids = response.data.num_entries;
859 2 : *alias_rids = rids;
860 2 : rids = NULL;
861 2 : wbc_status = WBC_ERR_SUCCESS;
862 :
863 2 : done:
864 2 : free(extra_data);
865 2 : winbindd_free_response(&response);
866 2 : wbcFreeMemory(rids);
867 2 : return wbc_status;
868 : }
869 :
870 : _PUBLIC_
871 2 : wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
872 : struct wbcDomainSid *sids,
873 : uint32_t num_sids,
874 : uint32_t **alias_rids,
875 : uint32_t *num_alias_rids)
876 : {
877 2 : return wbcCtxGetSidAliases(NULL, dom_sid, sids, num_sids,
878 : alias_rids, num_alias_rids);
879 : }
880 :
881 :
882 : /* Lists Users */
883 : _PUBLIC_
884 12 : wbcErr wbcCtxListUsers(struct wbcContext *ctx,
885 : const char *domain_name,
886 : uint32_t *_num_users,
887 : const char ***_users)
888 : {
889 12 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
890 : struct winbindd_request request;
891 : struct winbindd_response response;
892 12 : uint32_t num_users = 0;
893 12 : const char **users = NULL;
894 : const char *next;
895 :
896 : /* Initialise request */
897 :
898 12 : ZERO_STRUCT(request);
899 12 : ZERO_STRUCT(response);
900 :
901 12 : if (domain_name) {
902 12 : strncpy(request.domain_name, domain_name,
903 : sizeof(request.domain_name)-1);
904 : }
905 :
906 12 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_USERS,
907 : &request,
908 : &response);
909 12 : BAIL_ON_WBC_ERROR(wbc_status);
910 :
911 12 : users = wbcAllocateStringArray(response.data.num_entries);
912 12 : if (users == NULL) {
913 0 : return WBC_ERR_NO_MEMORY;
914 : }
915 :
916 : /* Look through extra data */
917 :
918 12 : next = (const char *)response.extra_data.data;
919 173 : while (next) {
920 : const char *current;
921 : char *k;
922 :
923 153 : if (num_users >= response.data.num_entries) {
924 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
925 0 : goto done;
926 : }
927 :
928 153 : current = next;
929 153 : k = strchr(next, ',');
930 :
931 153 : if (k) {
932 141 : k[0] = '\0';
933 141 : next = k+1;
934 : } else {
935 12 : next = NULL;
936 : }
937 :
938 153 : users[num_users] = strdup(current);
939 153 : BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
940 153 : num_users += 1;
941 : }
942 12 : if (num_users != response.data.num_entries) {
943 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
944 0 : goto done;
945 : }
946 :
947 12 : *_num_users = response.data.num_entries;
948 12 : *_users = users;
949 12 : users = NULL;
950 12 : wbc_status = WBC_ERR_SUCCESS;
951 :
952 12 : done:
953 12 : winbindd_free_response(&response);
954 12 : wbcFreeMemory(users);
955 12 : return wbc_status;
956 : }
957 :
958 : _PUBLIC_
959 12 : wbcErr wbcListUsers(const char *domain_name,
960 : uint32_t *_num_users,
961 : const char ***_users)
962 : {
963 12 : return wbcCtxListUsers(NULL, domain_name, _num_users, _users);
964 : }
965 :
966 : /* Lists Groups */
967 : _PUBLIC_
968 12 : wbcErr wbcCtxListGroups(struct wbcContext *ctx,
969 : const char *domain_name,
970 : uint32_t *_num_groups,
971 : const char ***_groups)
972 : {
973 12 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
974 : struct winbindd_request request;
975 : struct winbindd_response response;
976 12 : uint32_t num_groups = 0;
977 12 : const char **groups = NULL;
978 : const char *next;
979 :
980 : /* Initialise request */
981 :
982 12 : ZERO_STRUCT(request);
983 12 : ZERO_STRUCT(response);
984 :
985 12 : if (domain_name) {
986 12 : strncpy(request.domain_name, domain_name,
987 : sizeof(request.domain_name)-1);
988 : }
989 :
990 12 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_GROUPS,
991 : &request,
992 : &response);
993 12 : BAIL_ON_WBC_ERROR(wbc_status);
994 :
995 12 : groups = wbcAllocateStringArray(response.data.num_entries);
996 12 : if (groups == NULL) {
997 0 : return WBC_ERR_NO_MEMORY;
998 : }
999 :
1000 : /* Look through extra data */
1001 :
1002 12 : next = (const char *)response.extra_data.data;
1003 238 : while (next) {
1004 : const char *current;
1005 : char *k;
1006 :
1007 218 : if (num_groups >= response.data.num_entries) {
1008 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
1009 0 : goto done;
1010 : }
1011 :
1012 218 : current = next;
1013 218 : k = strchr(next, ',');
1014 :
1015 218 : if (k) {
1016 206 : k[0] = '\0';
1017 206 : next = k+1;
1018 : } else {
1019 12 : next = NULL;
1020 : }
1021 :
1022 218 : groups[num_groups] = strdup(current);
1023 218 : BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
1024 218 : num_groups += 1;
1025 : }
1026 12 : if (num_groups != response.data.num_entries) {
1027 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
1028 0 : goto done;
1029 : }
1030 :
1031 12 : *_num_groups = response.data.num_entries;
1032 12 : *_groups = groups;
1033 12 : groups = NULL;
1034 12 : wbc_status = WBC_ERR_SUCCESS;
1035 :
1036 12 : done:
1037 12 : winbindd_free_response(&response);
1038 12 : wbcFreeMemory(groups);
1039 12 : return wbc_status;
1040 : }
1041 :
1042 : _PUBLIC_
1043 12 : wbcErr wbcListGroups(const char *domain_name,
1044 : uint32_t *_num_groups,
1045 : const char ***_groups)
1046 : {
1047 12 : return wbcCtxListGroups(NULL, domain_name, _num_groups, _groups);
1048 : }
1049 :
1050 : _PUBLIC_
1051 22 : wbcErr wbcCtxGetDisplayName(struct wbcContext *ctx,
1052 : const struct wbcDomainSid *sid,
1053 : char **pdomain,
1054 : char **pfullname,
1055 : enum wbcSidType *pname_type)
1056 : {
1057 : wbcErr wbc_status;
1058 22 : char *domain = NULL;
1059 22 : char *name = NULL;
1060 : enum wbcSidType name_type;
1061 :
1062 22 : wbc_status = wbcCtxLookupSid(ctx, sid, &domain, &name, &name_type);
1063 22 : BAIL_ON_WBC_ERROR(wbc_status);
1064 :
1065 22 : if (name_type == WBC_SID_NAME_USER) {
1066 : uid_t uid;
1067 : struct passwd *pwd;
1068 :
1069 22 : wbc_status = wbcCtxSidToUid(ctx, sid, &uid);
1070 22 : BAIL_ON_WBC_ERROR(wbc_status);
1071 :
1072 22 : wbc_status = wbcCtxGetpwuid(ctx, uid, &pwd);
1073 22 : BAIL_ON_WBC_ERROR(wbc_status);
1074 :
1075 22 : wbcFreeMemory(name);
1076 :
1077 22 : name = wbcStrDup(pwd->pw_gecos);
1078 22 : wbcFreeMemory(pwd);
1079 22 : BAIL_ON_PTR_ERROR(name, wbc_status);
1080 : }
1081 :
1082 22 : wbc_status = WBC_ERR_SUCCESS;
1083 :
1084 22 : done:
1085 22 : if (WBC_ERROR_IS_OK(wbc_status)) {
1086 22 : *pdomain = domain;
1087 22 : *pfullname = name;
1088 22 : *pname_type = name_type;
1089 : } else {
1090 0 : wbcFreeMemory(domain);
1091 0 : wbcFreeMemory(name);
1092 : }
1093 :
1094 22 : return wbc_status;
1095 : }
1096 :
1097 : _PUBLIC_
1098 22 : wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
1099 : char **pdomain,
1100 : char **pfullname,
1101 : enum wbcSidType *pname_type)
1102 : {
1103 22 : return wbcCtxGetDisplayName(NULL, sid, pdomain, pfullname, pname_type);
1104 : }
1105 :
1106 : _PUBLIC_
1107 216 : const char* wbcSidTypeString(enum wbcSidType type)
1108 : {
1109 216 : switch (type) {
1110 2 : case WBC_SID_NAME_USE_NONE: return "SID_NONE";
1111 162 : case WBC_SID_NAME_USER: return "SID_USER";
1112 8 : case WBC_SID_NAME_DOM_GRP: return "SID_DOM_GROUP";
1113 22 : case WBC_SID_NAME_DOMAIN: return "SID_DOMAIN";
1114 4 : case WBC_SID_NAME_ALIAS: return "SID_ALIAS";
1115 8 : case WBC_SID_NAME_WKN_GRP: return "SID_WKN_GROUP";
1116 2 : case WBC_SID_NAME_DELETED: return "SID_DELETED";
1117 2 : case WBC_SID_NAME_INVALID: return "SID_INVALID";
1118 2 : case WBC_SID_NAME_UNKNOWN: return "SID_UNKNOWN";
1119 2 : case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
1120 2 : case WBC_SID_NAME_LABEL: return "SID_LABEL";
1121 0 : default: return "Unknown type";
1122 : }
1123 : }
|