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 476032 : int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen)
36 : {
37 15746 : uint64_t id_auth;
38 15746 : int i, ofs;
39 :
40 476032 : if (!sid) {
41 0 : strlcpy(buf, "(NULL SID)", buflen);
42 0 : return 10; /* strlen("(NULL SID)") */
43 : }
44 :
45 476032 : id_auth = (uint64_t)sid->id_auth[5] +
46 476032 : ((uint64_t)sid->id_auth[4] << 8) +
47 476032 : ((uint64_t)sid->id_auth[3] << 16) +
48 476032 : ((uint64_t)sid->id_auth[2] << 24) +
49 476032 : ((uint64_t)sid->id_auth[1] << 32) +
50 476032 : ((uint64_t)sid->id_auth[0] << 40);
51 :
52 476032 : ofs = snprintf(buf, buflen, "S-%hhu-", (unsigned char)sid->sid_rev_num);
53 476032 : 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 476032 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "%llu",
58 : (unsigned long long)id_auth);
59 : }
60 :
61 1649622 : for (i = 0; i < sid->num_auths; i++) {
62 1173590 : ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%u",
63 1173590 : (unsigned int)sid->sub_auths[i]);
64 : }
65 460286 : return ofs;
66 : }
67 :
68 : /* Convert a binary SID to a character string */
69 : _PUBLIC_
70 468 : wbcErr wbcSidToString(const struct wbcDomainSid *sid,
71 : char **sid_string)
72 : {
73 0 : char buf[WBC_SID_STRING_BUFLEN];
74 0 : char *result;
75 0 : int len;
76 :
77 468 : if (!sid) {
78 0 : return WBC_ERR_INVALID_SID;
79 : }
80 :
81 468 : len = wbcSidToStringBuf(sid, buf, sizeof(buf));
82 :
83 468 : if (len >= WBC_SID_STRING_BUFLEN) {
84 0 : return WBC_ERR_INVALID_SID;
85 : }
86 :
87 468 : result = (char *)wbcAllocateMemory(len+1, 1, NULL);
88 468 : if (result == NULL) {
89 0 : return WBC_ERR_NO_MEMORY;
90 : }
91 468 : memcpy(result, buf, len+1);
92 :
93 468 : *sid_string = result;
94 468 : return WBC_ERR_SUCCESS;
95 : }
96 :
97 : #define AUTHORITY_MASK (~(0xffffffffffffULL))
98 :
99 : /* Convert a character string to a binary SID */
100 : _PUBLIC_
101 44248 : wbcErr wbcStringToSid(const char *str,
102 : struct wbcDomainSid *sid)
103 : {
104 2 : const char *p;
105 2 : char *q;
106 44248 : int error = 0;
107 2 : uint64_t x;
108 44248 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
109 :
110 44248 : 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 44248 : if (!str
118 44248 : || (str[0]!='S' && str[0]!='s')
119 30000 : || (str[1]!='-'))
120 : {
121 14252 : wbc_status = WBC_ERR_INVALID_PARAM;
122 14252 : BAIL_ON_WBC_ERROR(wbc_status);
123 : }
124 :
125 : /* Get the SID revision number */
126 :
127 29996 : p = str+2;
128 29996 : x = (uint64_t)smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
129 29996 : 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 29996 : 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 29996 : p = q+1;
141 29996 : x = smb_strtoull(p, &q, 0, &error, SMB_STR_STANDARD);
142 29996 : 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 29996 : sid->id_auth[5] = (x & 0x0000000000ffULL);
147 29996 : sid->id_auth[4] = (x & 0x00000000ff00ULL) >> 8;
148 29996 : sid->id_auth[3] = (x & 0x000000ff0000ULL) >> 16;
149 29996 : sid->id_auth[2] = (x & 0x0000ff000000ULL) >> 24;
150 29996 : sid->id_auth[1] = (x & 0x00ff00000000ULL) >> 32;
151 29996 : sid->id_auth[0] = (x & 0xff0000000000ULL) >> 40;
152 :
153 : /* now read the the subauthorities */
154 29996 : p = q +1;
155 29996 : sid->num_auths = 0;
156 99256 : while (sid->num_auths < WBC_MAXSUBAUTHS) {
157 99256 : x = smb_strtoull(p, &q, 10, &error, SMB_STR_ALLOW_NO_CONVERSION);
158 99256 : if (p == q)
159 0 : break;
160 99256 : if (x > UINT32_MAX || error != 0) {
161 0 : wbc_status = WBC_ERR_INVALID_SID;
162 0 : BAIL_ON_WBC_ERROR(wbc_status);
163 : }
164 99256 : sid->sub_auths[sid->num_auths++] = x;
165 :
166 99256 : if (*q != '-') {
167 29994 : break;
168 : }
169 69260 : p = q + 1;
170 : }
171 :
172 : /* IF we ended early, then the SID could not be converted */
173 :
174 29996 : if (q && *q!='\0') {
175 0 : wbc_status = WBC_ERR_INVALID_SID;
176 0 : BAIL_ON_WBC_ERROR(wbc_status);
177 : }
178 :
179 29994 : wbc_status = WBC_ERR_SUCCESS;
180 :
181 44248 : done:
182 44248 : return wbc_status;
183 :
184 : }
185 :
186 :
187 : /* Convert a domain and name to SID */
188 : _PUBLIC_
189 3228 : wbcErr wbcCtxLookupName(struct wbcContext *ctx,
190 : const char *domain,
191 : const char *name,
192 : struct wbcDomainSid *sid,
193 : enum wbcSidType *name_type)
194 : {
195 0 : struct winbindd_request request;
196 0 : struct winbindd_response response;
197 3228 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
198 :
199 3228 : 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 3228 : ZERO_STRUCT(request);
207 3228 : ZERO_STRUCT(response);
208 :
209 : /* dst is already null terminated from the memset above */
210 :
211 3228 : strncpy(request.data.name.dom_name, domain,
212 : sizeof(request.data.name.dom_name)-1);
213 3228 : strncpy(request.data.name.name, name,
214 : sizeof(request.data.name.name)-1);
215 :
216 3228 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPNAME,
217 : &request,
218 : &response);
219 3228 : BAIL_ON_WBC_ERROR(wbc_status);
220 :
221 2936 : wbc_status = wbcStringToSid(response.data.sid.sid, sid);
222 2936 : BAIL_ON_WBC_ERROR(wbc_status);
223 :
224 2936 : *name_type = (enum wbcSidType)response.data.sid.type;
225 :
226 2936 : wbc_status = WBC_ERR_SUCCESS;
227 :
228 3228 : done:
229 3228 : return wbc_status;
230 : }
231 :
232 : _PUBLIC_
233 3084 : wbcErr wbcLookupName(const char *domain,
234 : const char *name,
235 : struct wbcDomainSid *sid,
236 : enum wbcSidType *name_type)
237 : {
238 3084 : return wbcCtxLookupName(NULL, domain, name, sid, name_type);
239 : }
240 :
241 :
242 : /* Convert a SID to a domain and name */
243 : _PUBLIC_
244 838 : wbcErr wbcCtxLookupSid(struct wbcContext *ctx,
245 : const struct wbcDomainSid *sid,
246 : char **pdomain,
247 : char **pname,
248 : enum wbcSidType *pname_type)
249 : {
250 0 : struct winbindd_request request;
251 0 : struct winbindd_response response;
252 838 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
253 0 : char *domain, *name;
254 :
255 838 : if (!sid) {
256 0 : return WBC_ERR_INVALID_PARAM;
257 : }
258 :
259 : /* Initialize request */
260 :
261 838 : ZERO_STRUCT(request);
262 838 : ZERO_STRUCT(response);
263 :
264 838 : wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
265 :
266 : /* Make request */
267 :
268 838 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSID,
269 : &request,
270 : &response);
271 838 : if (!WBC_ERROR_IS_OK(wbc_status)) {
272 6 : return wbc_status;
273 : }
274 :
275 : /* Copy out result */
276 :
277 832 : wbc_status = WBC_ERR_NO_MEMORY;
278 832 : domain = NULL;
279 832 : name = NULL;
280 :
281 832 : domain = wbcStrDup(response.data.name.dom_name);
282 832 : if (domain == NULL) {
283 0 : goto done;
284 : }
285 832 : name = wbcStrDup(response.data.name.name);
286 832 : if (name == NULL) {
287 0 : goto done;
288 : }
289 832 : if (pdomain != NULL) {
290 832 : *pdomain = domain;
291 832 : domain = NULL;
292 : }
293 832 : if (pname != NULL) {
294 832 : *pname = name;
295 832 : name = NULL;
296 : }
297 832 : if (pname_type != NULL) {
298 832 : *pname_type = (enum wbcSidType)response.data.name.type;
299 : }
300 832 : wbc_status = WBC_ERR_SUCCESS;
301 832 : done:
302 832 : wbcFreeMemory(name);
303 832 : wbcFreeMemory(domain);
304 832 : return wbc_status;
305 : }
306 :
307 : _PUBLIC_
308 544 : wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
309 : char **pdomain,
310 : char **pname,
311 : enum wbcSidType *pname_type)
312 : {
313 544 : 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 0 : struct winbindd_request request;
344 0 : struct winbindd_response response;
345 0 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
346 0 : int buflen, i, extra_len, num_domains, num_names;
347 0 : 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 0 : int remaining;
363 0 : 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 158 : 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 0 : int i;
533 0 : size_t len, ridbuf_size;
534 0 : char *ridlist;
535 0 : char *p;
536 158 : int error = 0;
537 0 : struct winbindd_request request;
538 0 : struct winbindd_response response;
539 158 : char *domain_name = NULL;
540 158 : const char **names = NULL;
541 158 : enum wbcSidType *types = NULL;
542 158 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
543 :
544 : /* Initialise request */
545 :
546 158 : ZERO_STRUCT(request);
547 158 : ZERO_STRUCT(response);
548 :
549 158 : 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 158 : 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 158 : ridbuf_size = (sizeof(char)*11) * num_rids + 1;
562 :
563 158 : ridlist = (char *)malloc(ridbuf_size);
564 158 : BAIL_ON_PTR_ERROR(ridlist, wbc_status);
565 :
566 158 : len = 0;
567 324 : for (i=0; i<num_rids; i++) {
568 166 : len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
569 166 : rids[i]);
570 : }
571 158 : ridlist[len] = '\0';
572 158 : len += 1;
573 :
574 158 : request.extra_data.data = ridlist;
575 158 : request.extra_len = len;
576 :
577 158 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
578 : &request,
579 : &response);
580 158 : free(ridlist);
581 158 : BAIL_ON_WBC_ERROR(wbc_status);
582 :
583 8 : domain_name = wbcStrDup(response.data.domain_name);
584 8 : BAIL_ON_PTR_ERROR(domain_name, wbc_status);
585 :
586 8 : names = wbcAllocateStringArray(num_rids);
587 8 : BAIL_ON_PTR_ERROR(names, wbc_status);
588 :
589 8 : types = (enum wbcSidType *)wbcAllocateMemory(
590 : num_rids, sizeof(enum wbcSidType), NULL);
591 8 : BAIL_ON_PTR_ERROR(types, wbc_status);
592 :
593 8 : p = (char *)response.extra_data.data;
594 :
595 24 : for (i=0; i<num_rids; i++) {
596 0 : char *q;
597 :
598 16 : if (*p == '\0') {
599 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
600 0 : goto done;
601 : }
602 :
603 16 : types[i] = (enum wbcSidType)smb_strtoul(p,
604 : &q,
605 : 10,
606 : &error,
607 : SMB_STR_STANDARD);
608 :
609 16 : if (*q != ' ' || error != 0) {
610 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
611 0 : goto done;
612 : }
613 :
614 16 : p = q+1;
615 :
616 16 : if ((q = strchr(p, '\n')) == NULL) {
617 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
618 0 : goto done;
619 : }
620 :
621 16 : *q = '\0';
622 :
623 16 : names[i] = strdup(p);
624 16 : BAIL_ON_PTR_ERROR(names[i], wbc_status);
625 :
626 16 : p = q+1;
627 : }
628 :
629 8 : if (*p != '\0') {
630 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
631 0 : goto done;
632 : }
633 :
634 8 : wbc_status = WBC_ERR_SUCCESS;
635 :
636 158 : done:
637 158 : winbindd_free_response(&response);
638 :
639 158 : if (WBC_ERROR_IS_OK(wbc_status)) {
640 8 : *pp_domain_name = domain_name;
641 8 : *pnames = names;
642 8 : *ptypes = types;
643 : }
644 : else {
645 150 : wbcFreeMemory(domain_name);
646 150 : wbcFreeMemory(names);
647 150 : wbcFreeMemory(types);
648 : }
649 :
650 158 : return wbc_status;
651 : }
652 :
653 : _PUBLIC_
654 158 : 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 158 : 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 494 : 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 0 : uint32_t i;
674 0 : const char *s;
675 0 : struct winbindd_request request;
676 0 : struct winbindd_response response;
677 494 : struct wbcDomainSid *sids = NULL;
678 494 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
679 0 : int cmd;
680 :
681 : /* Initialise request */
682 :
683 494 : ZERO_STRUCT(request);
684 494 : ZERO_STRUCT(response);
685 :
686 494 : if (!user_sid) {
687 0 : wbc_status = WBC_ERR_INVALID_PARAM;
688 0 : BAIL_ON_WBC_ERROR(wbc_status);
689 : }
690 :
691 494 : wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
692 :
693 494 : if (domain_groups_only) {
694 230 : cmd = WINBINDD_GETUSERDOMGROUPS;
695 : } else {
696 264 : cmd = WINBINDD_GETUSERSIDS;
697 : }
698 :
699 494 : wbc_status = wbcRequestResponse(ctx, cmd,
700 : &request,
701 : &response);
702 494 : BAIL_ON_WBC_ERROR(wbc_status);
703 :
704 376 : if (response.data.num_entries &&
705 376 : !response.extra_data.data) {
706 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
707 0 : BAIL_ON_WBC_ERROR(wbc_status);
708 : }
709 :
710 376 : sids = (struct wbcDomainSid *)wbcAllocateMemory(
711 376 : response.data.num_entries, sizeof(struct wbcDomainSid),
712 : NULL);
713 376 : BAIL_ON_PTR_ERROR(sids, wbc_status);
714 :
715 376 : s = (const char *)response.extra_data.data;
716 1259 : for (i = 0; i < response.data.num_entries; i++) {
717 883 : char *n = strchr(s, '\n');
718 883 : if (n) {
719 883 : *n = '\0';
720 : }
721 883 : wbc_status = wbcStringToSid(s, &sids[i]);
722 883 : BAIL_ON_WBC_ERROR(wbc_status);
723 883 : s += strlen(s) + 1;
724 : }
725 :
726 376 : *num_sids = response.data.num_entries;
727 376 : *_sids = sids;
728 376 : sids = NULL;
729 376 : wbc_status = WBC_ERR_SUCCESS;
730 :
731 494 : done:
732 494 : winbindd_free_response(&response);
733 494 : if (sids) {
734 0 : wbcFreeMemory(sids);
735 : }
736 :
737 494 : return wbc_status;
738 : }
739 :
740 : _PUBLIC_
741 494 : wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
742 : bool domain_groups_only,
743 : uint32_t *num_sids,
744 : struct wbcDomainSid **_sids)
745 : {
746 494 : return wbcCtxLookupUserSids(NULL, user_sid, domain_groups_only,
747 : num_sids, _sids);
748 : }
749 :
750 : static inline
751 4 : wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
752 : {
753 4 : if (sid->num_auths < 1) {
754 0 : return WBC_ERR_INVALID_RESPONSE;
755 : }
756 4 : *rid = sid->sub_auths[sid->num_auths - 1];
757 :
758 4 : return WBC_ERR_SUCCESS;
759 : }
760 :
761 : /* Get alias membership for sids */
762 : _PUBLIC_
763 4 : 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 0 : uint32_t i;
771 0 : const char *s;
772 0 : struct winbindd_request request;
773 0 : struct winbindd_response response;
774 4 : ssize_t extra_data_len = 0;
775 4 : char * extra_data = NULL;
776 4 : ssize_t buflen = 0;
777 0 : struct wbcDomainSid sid;
778 4 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
779 4 : uint32_t * rids = NULL;
780 :
781 : /* Initialise request */
782 :
783 4 : ZERO_STRUCT(request);
784 4 : ZERO_STRUCT(response);
785 :
786 4 : if (!dom_sid) {
787 0 : wbc_status = WBC_ERR_INVALID_PARAM;
788 0 : goto done;
789 : }
790 :
791 4 : 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 4 : buflen = 57 * num_sids;
796 4 : extra_data = (char *)malloc(buflen);
797 4 : if (!extra_data) {
798 0 : wbc_status = WBC_ERR_NO_MEMORY;
799 0 : goto done;
800 : }
801 :
802 : /* Build the sid list */
803 12 : for (i=0; i<num_sids; i++) {
804 0 : char sid_str[WBC_SID_STRING_BUFLEN];
805 0 : size_t sid_len;
806 :
807 8 : sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
808 :
809 8 : 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 8 : strncpy(&extra_data[extra_data_len], sid_str,
821 8 : buflen - extra_data_len);
822 8 : extra_data_len += sid_len;
823 8 : extra_data[extra_data_len++] = '\n';
824 8 : extra_data[extra_data_len] = '\0';
825 : }
826 4 : extra_data_len += 1;
827 :
828 4 : request.extra_data.data = extra_data;
829 4 : request.extra_len = extra_data_len;
830 :
831 4 : wbc_status = wbcRequestResponse(ctx, WINBINDD_GETSIDALIASES,
832 : &request,
833 : &response);
834 4 : BAIL_ON_WBC_ERROR(wbc_status);
835 :
836 4 : if (response.data.num_entries &&
837 4 : !response.extra_data.data) {
838 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
839 0 : goto done;
840 : }
841 :
842 4 : rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
843 : sizeof(uint32_t), NULL);
844 4 : BAIL_ON_PTR_ERROR(rids, wbc_status);
845 :
846 4 : s = (const char *)response.extra_data.data;
847 8 : for (i = 0; i < response.data.num_entries; i++) {
848 4 : char *n = strchr(s, '\n');
849 4 : if (n) {
850 4 : *n = '\0';
851 : }
852 4 : wbc_status = wbcStringToSid(s, &sid);
853 4 : BAIL_ON_WBC_ERROR(wbc_status);
854 4 : wbc_status = _sid_to_rid(&sid, &rids[i]);
855 4 : BAIL_ON_WBC_ERROR(wbc_status);
856 4 : s += strlen(s) + 1;
857 : }
858 :
859 4 : *num_alias_rids = response.data.num_entries;
860 4 : *alias_rids = rids;
861 4 : rids = NULL;
862 4 : wbc_status = WBC_ERR_SUCCESS;
863 :
864 4 : done:
865 4 : free(extra_data);
866 4 : winbindd_free_response(&response);
867 4 : wbcFreeMemory(rids);
868 4 : return wbc_status;
869 : }
870 :
871 : _PUBLIC_
872 4 : 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 4 : return wbcCtxGetSidAliases(NULL, dom_sid, sids, num_sids,
879 : alias_rids, num_alias_rids);
880 : }
881 :
882 :
883 : /* Lists Users */
884 : _PUBLIC_
885 34 : wbcErr wbcCtxListUsers(struct wbcContext *ctx,
886 : const char *domain_name,
887 : uint32_t *_num_users,
888 : const char ***_users)
889 : {
890 34 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
891 0 : struct winbindd_request request;
892 0 : struct winbindd_response response;
893 34 : uint32_t num_users = 0;
894 34 : const char **users = NULL;
895 0 : const char *next;
896 :
897 : /* Initialise request */
898 :
899 34 : ZERO_STRUCT(request);
900 34 : ZERO_STRUCT(response);
901 :
902 34 : if (domain_name) {
903 24 : strncpy(request.domain_name, domain_name,
904 : sizeof(request.domain_name)-1);
905 : }
906 :
907 34 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_USERS,
908 : &request,
909 : &response);
910 34 : BAIL_ON_WBC_ERROR(wbc_status);
911 :
912 34 : users = wbcAllocateStringArray(response.data.num_entries);
913 34 : if (users == NULL) {
914 0 : return WBC_ERR_NO_MEMORY;
915 : }
916 :
917 : /* Look through extra data */
918 :
919 34 : next = (const char *)response.extra_data.data;
920 5296 : while (next) {
921 0 : const char *current;
922 0 : char *k;
923 :
924 5262 : if (num_users >= response.data.num_entries) {
925 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
926 0 : goto done;
927 : }
928 :
929 5262 : current = next;
930 5262 : k = strchr(next, ',');
931 :
932 5262 : if (k) {
933 5228 : k[0] = '\0';
934 5228 : next = k+1;
935 : } else {
936 34 : next = NULL;
937 : }
938 :
939 5262 : users[num_users] = strdup(current);
940 5262 : BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
941 5262 : num_users += 1;
942 : }
943 34 : if (num_users != response.data.num_entries) {
944 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
945 0 : goto done;
946 : }
947 :
948 34 : *_num_users = response.data.num_entries;
949 34 : *_users = users;
950 34 : users = NULL;
951 34 : wbc_status = WBC_ERR_SUCCESS;
952 :
953 34 : done:
954 34 : winbindd_free_response(&response);
955 34 : wbcFreeMemory(users);
956 34 : return wbc_status;
957 : }
958 :
959 : _PUBLIC_
960 34 : wbcErr wbcListUsers(const char *domain_name,
961 : uint32_t *_num_users,
962 : const char ***_users)
963 : {
964 34 : return wbcCtxListUsers(NULL, domain_name, _num_users, _users);
965 : }
966 :
967 : /* Lists Groups */
968 : _PUBLIC_
969 22 : wbcErr wbcCtxListGroups(struct wbcContext *ctx,
970 : const char *domain_name,
971 : uint32_t *_num_groups,
972 : const char ***_groups)
973 : {
974 22 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
975 0 : struct winbindd_request request;
976 0 : struct winbindd_response response;
977 22 : uint32_t num_groups = 0;
978 22 : const char **groups = NULL;
979 0 : const char *next;
980 :
981 : /* Initialise request */
982 :
983 22 : ZERO_STRUCT(request);
984 22 : ZERO_STRUCT(response);
985 :
986 22 : if (domain_name) {
987 22 : strncpy(request.domain_name, domain_name,
988 : sizeof(request.domain_name)-1);
989 : }
990 :
991 22 : wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_GROUPS,
992 : &request,
993 : &response);
994 22 : BAIL_ON_WBC_ERROR(wbc_status);
995 :
996 22 : groups = wbcAllocateStringArray(response.data.num_entries);
997 22 : if (groups == NULL) {
998 0 : return WBC_ERR_NO_MEMORY;
999 : }
1000 :
1001 : /* Look through extra data */
1002 :
1003 22 : next = (const char *)response.extra_data.data;
1004 1224 : while (next) {
1005 0 : const char *current;
1006 0 : char *k;
1007 :
1008 1202 : if (num_groups >= response.data.num_entries) {
1009 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
1010 0 : goto done;
1011 : }
1012 :
1013 1202 : current = next;
1014 1202 : k = strchr(next, ',');
1015 :
1016 1202 : if (k) {
1017 1180 : k[0] = '\0';
1018 1180 : next = k+1;
1019 : } else {
1020 22 : next = NULL;
1021 : }
1022 :
1023 1202 : groups[num_groups] = strdup(current);
1024 1202 : BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
1025 1202 : num_groups += 1;
1026 : }
1027 22 : if (num_groups != response.data.num_entries) {
1028 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
1029 0 : goto done;
1030 : }
1031 :
1032 22 : *_num_groups = response.data.num_entries;
1033 22 : *_groups = groups;
1034 22 : groups = NULL;
1035 22 : wbc_status = WBC_ERR_SUCCESS;
1036 :
1037 22 : done:
1038 22 : winbindd_free_response(&response);
1039 22 : wbcFreeMemory(groups);
1040 22 : return wbc_status;
1041 : }
1042 :
1043 : _PUBLIC_
1044 22 : wbcErr wbcListGroups(const char *domain_name,
1045 : uint32_t *_num_groups,
1046 : const char ***_groups)
1047 : {
1048 22 : return wbcCtxListGroups(NULL, domain_name, _num_groups, _groups);
1049 : }
1050 :
1051 : _PUBLIC_
1052 222 : wbcErr wbcCtxGetDisplayName(struct wbcContext *ctx,
1053 : const struct wbcDomainSid *sid,
1054 : char **pdomain,
1055 : char **pfullname,
1056 : enum wbcSidType *pname_type)
1057 : {
1058 0 : wbcErr wbc_status;
1059 222 : char *domain = NULL;
1060 222 : char *name = NULL;
1061 0 : enum wbcSidType name_type;
1062 :
1063 222 : wbc_status = wbcCtxLookupSid(ctx, sid, &domain, &name, &name_type);
1064 222 : BAIL_ON_WBC_ERROR(wbc_status);
1065 :
1066 222 : if (name_type == WBC_SID_NAME_USER) {
1067 0 : uid_t uid;
1068 0 : struct passwd *pwd;
1069 :
1070 222 : wbc_status = wbcCtxSidToUid(ctx, sid, &uid);
1071 222 : BAIL_ON_WBC_ERROR(wbc_status);
1072 :
1073 222 : wbc_status = wbcCtxGetpwuid(ctx, uid, &pwd);
1074 222 : BAIL_ON_WBC_ERROR(wbc_status);
1075 :
1076 222 : wbcFreeMemory(name);
1077 :
1078 222 : name = wbcStrDup(pwd->pw_gecos);
1079 222 : wbcFreeMemory(pwd);
1080 222 : BAIL_ON_PTR_ERROR(name, wbc_status);
1081 : }
1082 :
1083 222 : wbc_status = WBC_ERR_SUCCESS;
1084 :
1085 222 : done:
1086 222 : if (WBC_ERROR_IS_OK(wbc_status)) {
1087 222 : *pdomain = domain;
1088 222 : *pfullname = name;
1089 222 : *pname_type = name_type;
1090 : } else {
1091 0 : wbcFreeMemory(domain);
1092 0 : wbcFreeMemory(name);
1093 : }
1094 :
1095 222 : return wbc_status;
1096 : }
1097 :
1098 : _PUBLIC_
1099 222 : wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
1100 : char **pdomain,
1101 : char **pfullname,
1102 : enum wbcSidType *pname_type)
1103 : {
1104 222 : return wbcCtxGetDisplayName(NULL, sid, pdomain, pfullname, pname_type);
1105 : }
1106 :
1107 : _PUBLIC_
1108 376 : const char* wbcSidTypeString(enum wbcSidType type)
1109 : {
1110 376 : switch (type) {
1111 4 : case WBC_SID_NAME_USE_NONE: return "SID_NONE";
1112 284 : case WBC_SID_NAME_USER: return "SID_USER";
1113 14 : case WBC_SID_NAME_DOM_GRP: return "SID_DOM_GROUP";
1114 30 : case WBC_SID_NAME_DOMAIN: return "SID_DOMAIN";
1115 8 : case WBC_SID_NAME_ALIAS: return "SID_ALIAS";
1116 12 : case WBC_SID_NAME_WKN_GRP: return "SID_WKN_GROUP";
1117 4 : case WBC_SID_NAME_DELETED: return "SID_DELETED";
1118 4 : case WBC_SID_NAME_INVALID: return "SID_INVALID";
1119 8 : case WBC_SID_NAME_UNKNOWN: return "SID_UNKNOWN";
1120 4 : case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
1121 4 : case WBC_SID_NAME_LABEL: return "SID_LABEL";
1122 0 : default: return "Unknown type";
1123 : }
1124 : }
|