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