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 99987 : int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen)
36 : {
37 : uint64_t id_auth;
38 : int i, ofs;
39 :
40 99987 : if (!sid) {
41 0 : strlcpy(buf, "(NULL SID)", buflen);
42 0 : return 10; /* strlen("(NULL SID)") */
43 : }
44 :
45 99987 : id_auth = (uint64_t)sid->id_auth[5] +
46 99987 : ((uint64_t)sid->id_auth[4] << 8) +
47 99987 : ((uint64_t)sid->id_auth[3] << 16) +
48 99987 : ((uint64_t)sid->id_auth[2] << 24) +
49 99987 : ((uint64_t)sid->id_auth[1] << 32) +
50 99987 : ((uint64_t)sid->id_auth[0] << 40);
51 :
52 99987 : ofs = snprintf(buf, buflen, "S-%hhu-", (unsigned char)sid->sid_rev_num);
53 99987 : 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 99987 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "%llu",
58 : (unsigned long long)id_auth);
59 : }
60 :
61 387945 : for (i = 0; i < sid->num_auths; i++) {
62 287958 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%u",
63 287958 : (unsigned int)sid->sub_auths[i]);
64 : }
65 99987 : 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 13981 : wbcErr wbcStringToSid(const char *str,
102 : struct wbcDomainSid *sid)
103 : {
104 : const char *p;
105 : char *q;
106 13981 : int error = 0;
107 : uint64_t x;
108 13981 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
109 :
110 13981 : 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 13981 : if (!str
118 13981 : || (str[0]!='S' && str[0]!='s')
119 12075 : || (str[1]!='-'))
120 : {
121 1906 : wbc_status = WBC_ERR_INVALID_PARAM;
122 1906 : BAIL_ON_WBC_ERROR(wbc_status);
123 : }
124 :
125 : /* Get the SID revision number */
126 :
127 12075 : p = str+2;
128 12075 : x = (uint64_t)smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
129 12075 : 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 12075 : 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 12075 : p = q+1;
141 12075 : x = smb_strtoull(p, &q, 0, &error, SMB_STR_STANDARD);
142 12075 : 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 12075 : sid->id_auth[5] = (x & 0x0000000000ffULL);
147 12075 : sid->id_auth[4] = (x & 0x00000000ff00ULL) >> 8;
148 12075 : sid->id_auth[3] = (x & 0x000000ff0000ULL) >> 16;
149 12075 : sid->id_auth[2] = (x & 0x0000ff000000ULL) >> 24;
150 12075 : sid->id_auth[1] = (x & 0x00ff00000000ULL) >> 32;
151 12075 : sid->id_auth[0] = (x & 0xff0000000000ULL) >> 40;
152 :
153 : /* now read the the subauthorities */
154 12075 : p = q +1;
155 12075 : sid->num_auths = 0;
156 39143 : while (sid->num_auths < WBC_MAXSUBAUTHS) {
157 39143 : x = smb_strtoull(p, &q, 10, &error, SMB_STR_ALLOW_NO_CONVERSION);
158 39143 : if (p == q)
159 0 : break;
160 39143 : if (x > UINT32_MAX || error != 0) {
161 0 : wbc_status = WBC_ERR_INVALID_SID;
162 0 : BAIL_ON_WBC_ERROR(wbc_status);
163 : }
164 39143 : sid->sub_auths[sid->num_auths++] = x;
165 :
166 39143 : if (*q != '-') {
167 12075 : break;
168 : }
169 27068 : p = q + 1;
170 : }
171 :
172 : /* IF we ended early, then the SID could not be converted */
173 :
174 12075 : if (q && *q!='\0') {
175 0 : wbc_status = WBC_ERR_INVALID_SID;
176 0 : BAIL_ON_WBC_ERROR(wbc_status);
177 : }
178 :
179 12075 : wbc_status = WBC_ERR_SUCCESS;
180 :
181 13981 : done:
182 13981 : 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 : int i;
533 : size_t len, ridbuf_size;
534 : char *ridlist;
535 : char *p;
536 22 : int error = 0;
537 : struct winbindd_request request;
538 : struct winbindd_response response;
539 22 : char *domain_name = NULL;
540 22 : const char **names = NULL;
541 22 : enum wbcSidType *types = NULL;
542 22 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
543 :
544 : /* Initialise request */
545 :
546 22 : ZERO_STRUCT(request);
547 22 : ZERO_STRUCT(response);
548 :
549 22 : if (!dom_sid || (num_rids == 0)) {
550 0 : wbc_status = WBC_ERR_INVALID_PARAM;
551 0 : BAIL_ON_WBC_ERROR(wbc_status);
552 : }
553 :
554 22 : wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
555 :
556 : /* Even if all the Rids were of maximum 32bit values,
557 : we would only have 11 bytes per rid in the final array
558 : ("4294967296" + \n). Add one more byte for the
559 : terminating '\0' */
560 :
561 22 : ridbuf_size = (sizeof(char)*11) * num_rids + 1;
562 :
563 22 : ridlist = (char *)malloc(ridbuf_size);
564 22 : BAIL_ON_PTR_ERROR(ridlist, wbc_status);
565 :
566 22 : len = 0;
567 46 : for (i=0; i<num_rids; i++) {
568 24 : len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
569 24 : rids[i]);
570 : }
571 22 : ridlist[len] = '\0';
572 22 : len += 1;
573 :
574 22 : request.extra_data.data = ridlist;
575 22 : request.extra_len = len;
576 :
577 22 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
578 : &request,
579 : &response);
580 22 : free(ridlist);
581 22 : BAIL_ON_WBC_ERROR(wbc_status);
582 :
583 2 : domain_name = wbcStrDup(response.data.domain_name);
584 2 : BAIL_ON_PTR_ERROR(domain_name, wbc_status);
585 :
586 2 : names = wbcAllocateStringArray(num_rids);
587 2 : BAIL_ON_PTR_ERROR(names, wbc_status);
588 :
589 2 : types = (enum wbcSidType *)wbcAllocateMemory(
590 : num_rids, sizeof(enum wbcSidType), NULL);
591 2 : BAIL_ON_PTR_ERROR(types, wbc_status);
592 :
593 2 : p = (char *)response.extra_data.data;
594 :
595 6 : for (i=0; i<num_rids; i++) {
596 : char *q;
597 :
598 4 : if (*p == '\0') {
599 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
600 0 : goto done;
601 : }
602 :
603 4 : types[i] = (enum wbcSidType)smb_strtoul(p,
604 : &q,
605 : 10,
606 : &error,
607 : SMB_STR_STANDARD);
608 :
609 4 : if (*q != ' ' || error != 0) {
610 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
611 0 : goto done;
612 : }
613 :
614 4 : p = q+1;
615 :
616 4 : if ((q = strchr(p, '\n')) == NULL) {
617 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
618 0 : goto done;
619 : }
620 :
621 4 : *q = '\0';
622 :
623 4 : names[i] = strdup(p);
624 4 : BAIL_ON_PTR_ERROR(names[i], wbc_status);
625 :
626 4 : p = q+1;
627 : }
628 :
629 2 : if (*p != '\0') {
630 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
631 0 : goto done;
632 : }
633 :
634 2 : wbc_status = WBC_ERR_SUCCESS;
635 :
636 22 : done:
637 22 : winbindd_free_response(&response);
638 :
639 22 : if (WBC_ERROR_IS_OK(wbc_status)) {
640 2 : *pp_domain_name = domain_name;
641 2 : *pnames = names;
642 2 : *ptypes = types;
643 : }
644 : else {
645 20 : wbcFreeMemory(domain_name);
646 20 : wbcFreeMemory(names);
647 20 : wbcFreeMemory(types);
648 : }
649 :
650 22 : return wbc_status;
651 : }
652 :
653 : _PUBLIC_
654 22 : wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
655 : int num_rids,
656 : uint32_t *rids,
657 : const char **pp_domain_name,
658 : const char ***pnames,
659 : enum wbcSidType **ptypes)
660 : {
661 22 : return wbcCtxLookupRids(NULL, dom_sid, num_rids, rids,
662 : pp_domain_name, pnames, ptypes);
663 : }
664 :
665 : /* Get the groups a user belongs to */
666 : _PUBLIC_
667 108 : wbcErr wbcCtxLookupUserSids(struct wbcContext *ctx,
668 : const struct wbcDomainSid *user_sid,
669 : bool domain_groups_only,
670 : uint32_t *num_sids,
671 : struct wbcDomainSid **_sids)
672 : {
673 : uint32_t i;
674 : const char *s;
675 : struct winbindd_request request;
676 : struct winbindd_response response;
677 108 : struct wbcDomainSid *sids = NULL;
678 108 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
679 : int cmd;
680 :
681 : /* Initialise request */
682 :
683 108 : ZERO_STRUCT(request);
684 108 : ZERO_STRUCT(response);
685 :
686 108 : if (!user_sid) {
687 0 : wbc_status = WBC_ERR_INVALID_PARAM;
688 0 : BAIL_ON_WBC_ERROR(wbc_status);
689 : }
690 :
691 108 : wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
692 :
693 108 : if (domain_groups_only) {
694 28 : cmd = WINBINDD_GETUSERDOMGROUPS;
695 : } else {
696 80 : cmd = WINBINDD_GETUSERSIDS;
697 : }
698 :
699 108 : wbc_status = wbcRequestResponse(ctx, cmd,
700 : &request,
701 : &response);
702 108 : BAIL_ON_WBC_ERROR(wbc_status);
703 :
704 74 : if (response.data.num_entries &&
705 74 : !response.extra_data.data) {
706 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
707 0 : BAIL_ON_WBC_ERROR(wbc_status);
708 : }
709 :
710 74 : sids = (struct wbcDomainSid *)wbcAllocateMemory(
711 74 : response.data.num_entries, sizeof(struct wbcDomainSid),
712 : NULL);
713 74 : BAIL_ON_PTR_ERROR(sids, wbc_status);
714 :
715 74 : s = (const char *)response.extra_data.data;
716 304 : for (i = 0; i < response.data.num_entries; i++) {
717 230 : char *n = strchr(s, '\n');
718 230 : if (n) {
719 230 : *n = '\0';
720 : }
721 230 : wbc_status = wbcStringToSid(s, &sids[i]);
722 230 : BAIL_ON_WBC_ERROR(wbc_status);
723 230 : s += strlen(s) + 1;
724 : }
725 :
726 74 : *num_sids = response.data.num_entries;
727 74 : *_sids = sids;
728 74 : sids = NULL;
729 74 : wbc_status = WBC_ERR_SUCCESS;
730 :
731 108 : done:
732 108 : winbindd_free_response(&response);
733 108 : if (sids) {
734 0 : wbcFreeMemory(sids);
735 : }
736 :
737 108 : return wbc_status;
738 : }
739 :
740 : _PUBLIC_
741 108 : wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
742 : bool domain_groups_only,
743 : uint32_t *num_sids,
744 : struct wbcDomainSid **_sids)
745 : {
746 108 : return wbcCtxLookupUserSids(NULL, user_sid, domain_groups_only,
747 : num_sids, _sids);
748 : }
749 :
750 : static inline
751 2 : wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
752 : {
753 2 : if (sid->num_auths < 1) {
754 0 : return WBC_ERR_INVALID_RESPONSE;
755 : }
756 2 : *rid = sid->sub_auths[sid->num_auths - 1];
757 :
758 2 : return WBC_ERR_SUCCESS;
759 : }
760 :
761 : /* Get alias membership for sids */
762 : _PUBLIC_
763 2 : wbcErr wbcCtxGetSidAliases(struct wbcContext *ctx,
764 : const struct wbcDomainSid *dom_sid,
765 : struct wbcDomainSid *sids,
766 : uint32_t num_sids,
767 : uint32_t **alias_rids,
768 : uint32_t *num_alias_rids)
769 : {
770 : uint32_t i;
771 : const char *s;
772 : struct winbindd_request request;
773 : struct winbindd_response response;
774 2 : ssize_t extra_data_len = 0;
775 2 : char * extra_data = NULL;
776 2 : ssize_t buflen = 0;
777 : struct wbcDomainSid sid;
778 2 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
779 2 : uint32_t * rids = NULL;
780 :
781 : /* Initialise request */
782 :
783 2 : ZERO_STRUCT(request);
784 2 : ZERO_STRUCT(response);
785 :
786 2 : if (!dom_sid) {
787 0 : wbc_status = WBC_ERR_INVALID_PARAM;
788 0 : goto done;
789 : }
790 :
791 2 : wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
792 :
793 : /* Lets assume each sid is around 57 characters
794 : * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
795 2 : buflen = 57 * num_sids;
796 2 : extra_data = (char *)malloc(buflen);
797 2 : if (!extra_data) {
798 0 : wbc_status = WBC_ERR_NO_MEMORY;
799 0 : goto done;
800 : }
801 :
802 : /* Build the sid list */
803 6 : for (i=0; i<num_sids; i++) {
804 : char sid_str[WBC_SID_STRING_BUFLEN];
805 : size_t sid_len;
806 :
807 4 : sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
808 :
809 4 : if (buflen < extra_data_len + sid_len + 2) {
810 0 : char * tmp_data = NULL;
811 0 : buflen *= 2;
812 0 : tmp_data = (char *)realloc(extra_data, buflen);
813 0 : if (!tmp_data) {
814 0 : wbc_status = WBC_ERR_NO_MEMORY;
815 0 : BAIL_ON_WBC_ERROR(wbc_status);
816 : }
817 0 : extra_data = tmp_data;
818 : }
819 :
820 4 : strncpy(&extra_data[extra_data_len], sid_str,
821 4 : buflen - extra_data_len);
822 4 : extra_data_len += sid_len;
823 4 : extra_data[extra_data_len++] = '\n';
824 4 : extra_data[extra_data_len] = '\0';
825 : }
826 2 : extra_data_len += 1;
827 :
828 2 : request.extra_data.data = extra_data;
829 2 : request.extra_len = extra_data_len;
830 :
831 2 : wbc_status = wbcRequestResponse(ctx, WINBINDD_GETSIDALIASES,
832 : &request,
833 : &response);
834 2 : BAIL_ON_WBC_ERROR(wbc_status);
835 :
836 2 : if (response.data.num_entries &&
837 2 : !response.extra_data.data) {
838 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
839 0 : goto done;
840 : }
841 :
842 2 : rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
843 : sizeof(uint32_t), NULL);
844 2 : BAIL_ON_PTR_ERROR(rids, wbc_status);
845 :
846 2 : s = (const char *)response.extra_data.data;
847 4 : for (i = 0; i < response.data.num_entries; i++) {
848 2 : char *n = strchr(s, '\n');
849 2 : if (n) {
850 2 : *n = '\0';
851 : }
852 2 : wbc_status = wbcStringToSid(s, &sid);
853 2 : BAIL_ON_WBC_ERROR(wbc_status);
854 2 : wbc_status = _sid_to_rid(&sid, &rids[i]);
855 2 : BAIL_ON_WBC_ERROR(wbc_status);
856 2 : s += strlen(s) + 1;
857 : }
858 :
859 2 : *num_alias_rids = response.data.num_entries;
860 2 : *alias_rids = rids;
861 2 : rids = NULL;
862 2 : wbc_status = WBC_ERR_SUCCESS;
863 :
864 2 : done:
865 2 : free(extra_data);
866 2 : winbindd_free_response(&response);
867 2 : wbcFreeMemory(rids);
868 2 : return wbc_status;
869 : }
870 :
871 : _PUBLIC_
872 2 : wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
873 : struct wbcDomainSid *sids,
874 : uint32_t num_sids,
875 : uint32_t **alias_rids,
876 : uint32_t *num_alias_rids)
877 : {
878 2 : return wbcCtxGetSidAliases(NULL, dom_sid, sids, num_sids,
879 : alias_rids, num_alias_rids);
880 : }
881 :
882 :
883 : /* Lists Users */
884 : _PUBLIC_
885 12 : wbcErr wbcCtxListUsers(struct wbcContext *ctx,
886 : const char *domain_name,
887 : uint32_t *_num_users,
888 : const char ***_users)
889 : {
890 12 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
891 : struct winbindd_request request;
892 : struct winbindd_response response;
893 12 : uint32_t num_users = 0;
894 12 : const char **users = NULL;
895 : const char *next;
896 :
897 : /* Initialise request */
898 :
899 12 : ZERO_STRUCT(request);
900 12 : ZERO_STRUCT(response);
901 :
902 12 : if (domain_name) {
903 12 : strncpy(request.domain_name, domain_name,
904 : sizeof(request.domain_name)-1);
905 : }
906 :
907 12 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_USERS,
908 : &request,
909 : &response);
910 12 : BAIL_ON_WBC_ERROR(wbc_status);
911 :
912 12 : users = wbcAllocateStringArray(response.data.num_entries);
913 12 : if (users == NULL) {
914 0 : return WBC_ERR_NO_MEMORY;
915 : }
916 :
917 : /* Look through extra data */
918 :
919 12 : next = (const char *)response.extra_data.data;
920 165 : while (next) {
921 : const char *current;
922 : char *k;
923 :
924 153 : if (num_users >= response.data.num_entries) {
925 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
926 0 : goto done;
927 : }
928 :
929 153 : current = next;
930 153 : k = strchr(next, ',');
931 :
932 153 : if (k) {
933 141 : k[0] = '\0';
934 141 : next = k+1;
935 : } else {
936 12 : next = NULL;
937 : }
938 :
939 153 : users[num_users] = strdup(current);
940 153 : BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
941 153 : num_users += 1;
942 : }
943 12 : if (num_users != response.data.num_entries) {
944 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
945 0 : goto done;
946 : }
947 :
948 12 : *_num_users = response.data.num_entries;
949 12 : *_users = users;
950 12 : users = NULL;
951 12 : wbc_status = WBC_ERR_SUCCESS;
952 :
953 12 : done:
954 12 : winbindd_free_response(&response);
955 12 : wbcFreeMemory(users);
956 12 : return wbc_status;
957 : }
958 :
959 : _PUBLIC_
960 12 : wbcErr wbcListUsers(const char *domain_name,
961 : uint32_t *_num_users,
962 : const char ***_users)
963 : {
964 12 : return wbcCtxListUsers(NULL, domain_name, _num_users, _users);
965 : }
966 :
967 : /* Lists Groups */
968 : _PUBLIC_
969 12 : wbcErr wbcCtxListGroups(struct wbcContext *ctx,
970 : const char *domain_name,
971 : uint32_t *_num_groups,
972 : const char ***_groups)
973 : {
974 12 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
975 : struct winbindd_request request;
976 : struct winbindd_response response;
977 12 : uint32_t num_groups = 0;
978 12 : const char **groups = NULL;
979 : const char *next;
980 :
981 : /* Initialise request */
982 :
983 12 : ZERO_STRUCT(request);
984 12 : ZERO_STRUCT(response);
985 :
986 12 : if (domain_name) {
987 12 : strncpy(request.domain_name, domain_name,
988 : sizeof(request.domain_name)-1);
989 : }
990 :
991 12 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_GROUPS,
992 : &request,
993 : &response);
994 12 : BAIL_ON_WBC_ERROR(wbc_status);
995 :
996 12 : groups = wbcAllocateStringArray(response.data.num_entries);
997 12 : if (groups == NULL) {
998 0 : return WBC_ERR_NO_MEMORY;
999 : }
1000 :
1001 : /* Look through extra data */
1002 :
1003 12 : next = (const char *)response.extra_data.data;
1004 230 : while (next) {
1005 : const char *current;
1006 : char *k;
1007 :
1008 218 : if (num_groups >= response.data.num_entries) {
1009 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
1010 0 : goto done;
1011 : }
1012 :
1013 218 : current = next;
1014 218 : k = strchr(next, ',');
1015 :
1016 218 : if (k) {
1017 206 : k[0] = '\0';
1018 206 : next = k+1;
1019 : } else {
1020 12 : next = NULL;
1021 : }
1022 :
1023 218 : groups[num_groups] = strdup(current);
1024 218 : BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
1025 218 : num_groups += 1;
1026 : }
1027 12 : if (num_groups != response.data.num_entries) {
1028 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
1029 0 : goto done;
1030 : }
1031 :
1032 12 : *_num_groups = response.data.num_entries;
1033 12 : *_groups = groups;
1034 12 : groups = NULL;
1035 12 : wbc_status = WBC_ERR_SUCCESS;
1036 :
1037 12 : done:
1038 12 : winbindd_free_response(&response);
1039 12 : wbcFreeMemory(groups);
1040 12 : return wbc_status;
1041 : }
1042 :
1043 : _PUBLIC_
1044 12 : wbcErr wbcListGroups(const char *domain_name,
1045 : uint32_t *_num_groups,
1046 : const char ***_groups)
1047 : {
1048 12 : return wbcCtxListGroups(NULL, domain_name, _num_groups, _groups);
1049 : }
1050 :
1051 : _PUBLIC_
1052 22 : wbcErr wbcCtxGetDisplayName(struct wbcContext *ctx,
1053 : const struct wbcDomainSid *sid,
1054 : char **pdomain,
1055 : char **pfullname,
1056 : enum wbcSidType *pname_type)
1057 : {
1058 : wbcErr wbc_status;
1059 22 : char *domain = NULL;
1060 22 : char *name = NULL;
1061 : enum wbcSidType name_type;
1062 :
1063 22 : wbc_status = wbcCtxLookupSid(ctx, sid, &domain, &name, &name_type);
1064 22 : BAIL_ON_WBC_ERROR(wbc_status);
1065 :
1066 22 : if (name_type == WBC_SID_NAME_USER) {
1067 : uid_t uid;
1068 : struct passwd *pwd;
1069 :
1070 22 : wbc_status = wbcCtxSidToUid(ctx, sid, &uid);
1071 22 : BAIL_ON_WBC_ERROR(wbc_status);
1072 :
1073 22 : wbc_status = wbcCtxGetpwuid(ctx, uid, &pwd);
1074 22 : BAIL_ON_WBC_ERROR(wbc_status);
1075 :
1076 22 : wbcFreeMemory(name);
1077 :
1078 22 : name = wbcStrDup(pwd->pw_gecos);
1079 22 : wbcFreeMemory(pwd);
1080 22 : BAIL_ON_PTR_ERROR(name, wbc_status);
1081 : }
1082 :
1083 22 : wbc_status = WBC_ERR_SUCCESS;
1084 :
1085 22 : done:
1086 22 : if (WBC_ERROR_IS_OK(wbc_status)) {
1087 22 : *pdomain = domain;
1088 22 : *pfullname = name;
1089 22 : *pname_type = name_type;
1090 : } else {
1091 0 : wbcFreeMemory(domain);
1092 0 : wbcFreeMemory(name);
1093 : }
1094 :
1095 22 : return wbc_status;
1096 : }
1097 :
1098 : _PUBLIC_
1099 22 : wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
1100 : char **pdomain,
1101 : char **pfullname,
1102 : enum wbcSidType *pname_type)
1103 : {
1104 22 : return wbcCtxGetDisplayName(NULL, sid, pdomain, pfullname, pname_type);
1105 : }
1106 :
1107 : _PUBLIC_
1108 216 : const char* wbcSidTypeString(enum wbcSidType type)
1109 : {
1110 216 : switch (type) {
1111 2 : case WBC_SID_NAME_USE_NONE: return "SID_NONE";
1112 162 : case WBC_SID_NAME_USER: return "SID_USER";
1113 8 : case WBC_SID_NAME_DOM_GRP: return "SID_DOM_GROUP";
1114 22 : case WBC_SID_NAME_DOMAIN: return "SID_DOMAIN";
1115 4 : case WBC_SID_NAME_ALIAS: return "SID_ALIAS";
1116 8 : case WBC_SID_NAME_WKN_GRP: return "SID_WKN_GROUP";
1117 2 : case WBC_SID_NAME_DELETED: return "SID_DELETED";
1118 2 : case WBC_SID_NAME_INVALID: return "SID_INVALID";
1119 2 : case WBC_SID_NAME_UNKNOWN: return "SID_UNKNOWN";
1120 2 : case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
1121 2 : case WBC_SID_NAME_LABEL: return "SID_LABEL";
1122 0 : default: return "Unknown type";
1123 : }
1124 : }
|