2 Unix SMB/CIFS implementation.
6 Copyright (C) Gerald (Jerry) Carter 2007
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 3 of the License, or (at your option) any later version.
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* Required Headers */
25 #include "nsswitch/winbind_nss_config.h"
26 #include "nsswitch/winbind_struct_protocol.h"
30 #define BAIL_ON_WBC_ERROR(x) do { if ((x) != WBC_ERR_SUCCESS) goto fail; } while(0);
32 /* From wb_common.c */
34 NSS_STATUS winbindd_request_response(int req_type,
35 struct winbindd_request *request,
36 struct winbindd_response *response);
38 /** @brief Free library allocated memory
40 * @param *p Pointer to free
45 void wbcFreeMemory(void *p)
51 /** @brief Convert a binary SID to a character string
53 * @param sid Binary Security Identifier
54 * @param **sid_string Resulting character string
59 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
62 wbcErr ret = WBC_ERR_UNKNOWN_FAILURE;
66 TALLOC_CTX *mem_ctx = NULL;
69 return WBC_ERR_INVALID_SID;
71 if ((mem_ctx=talloc_init("wbcSidToString")) == NULL )
72 return WBC_ERR_NO_MEMORY;
74 id_auth = sid->id_auth[5] +
75 (sid->id_auth[4] << 8) +
76 (sid->id_auth[3] << 16) +
77 (sid->id_auth[2] << 24);
79 tmp = talloc_asprintf(mem_ctx, "S-%d-%d", sid->sid_rev_num, id_auth );
81 ret = WBC_ERR_NO_MEMORY;
82 BAIL_ON_WBC_ERROR(ret);
85 for (i=0; i<sid->num_auths; i++) {
87 tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]);
89 ret = WBC_ERR_NO_MEMORY;
90 BAIL_ON_WBC_ERROR(ret);
95 if ((*sid_string=talloc_strdup(NULL, tmp)) == NULL ) {
96 ret = WBC_ERR_NO_MEMORY;
97 BAIL_ON_WBC_ERROR(ret);
100 ret = WBC_ERR_SUCCESS;
103 talloc_free(mem_ctx);
108 /** @brief Convert a character string to a binary SID
110 * @param *str Character string in the form of S-...
111 * @param sid Resulting binary SID
116 wbcErr wbcStringToSid(const char *str,
117 struct wbcDomainSid *sid)
124 return WBC_ERR_INVALID_PARAM;
126 /* Sanity check for either "S-" or "s-" */
129 || (str[0]!='S' && str[0]!='s')
133 return WBC_ERR_INVALID_SID;
136 /* Get the SID revision number */
139 x = (uint32_t)strtol(p, &q, 10);
140 if (x==0 || !q || *q!='-')
141 return WBC_ERR_INVALID_SID;
142 sid->sid_rev_num = (uint8_t)x;
144 /* Next the Identifier Authority. This is stored in big-endian
145 in a 6 byte array. */
148 x = (uint32_t)strtol(p, &q, 10);
149 if (x==0 || !q || *q!='-')
150 return WBC_ERR_INVALID_SID;
151 sid->id_auth[5] = (x & 0x000000ff);
152 sid->id_auth[4] = (x & 0x0000ff00) >> 8;
153 sid->id_auth[3] = (x & 0x00ff0000) >> 16;
154 sid->id_auth[2] = (x & 0xff000000) >> 24;
158 /* now read the the subauthorities */
162 while (sid->num_auths < MAXSUBAUTHS) {
163 if ((x=(uint32_t)strtoul(p, &q, 10)) == 0)
165 sid->sub_auths[sid->num_auths++] = x;
167 if (q && ((*q!='-') || (*q=='\0')))
172 /* IF we ended early, then the SID could not be converted */
175 return WBC_ERR_INVALID_SID;
177 return WBC_ERR_SUCCESS;
182 /** @brief Convert a domain and name to SID
184 * @param domain Domain name (possibly "")
185 * @param name User or group name
186 * @param *sid Pointer to the resolved domain SID
187 * @param *name_type Pointet to the SID type
193 wbcErr wbcLookupName(const char *domain,
195 struct wbcDomainSid *sid,
196 enum wbcSidType *name_type)
198 struct winbindd_request request;
199 struct winbindd_response response;
201 wbcErr wbc_ret = WBC_ERR_UNKNOWN_FAILURE;
203 if (!sid || !name_type)
204 return WBC_ERR_INVALID_PARAM;
206 /* Initialize request */
208 ZERO_STRUCT(request);
209 ZERO_STRUCT(response);
211 /* dst is already null terminated from the memset above */
213 strncpy(request.data.name.dom_name, domain,
214 sizeof(request.data.name.dom_name)-1);
215 strncpy(request.data.name.name, name,
216 sizeof(request.data.name.name)-1);
218 result = winbindd_request_response(WINBINDD_LOOKUPNAME,
221 if ( result != NSS_STATUS_SUCCESS) {
225 wbc_ret = wbcStringToSid(response.data.sid.sid, sid);
226 BAIL_ON_WBC_ERROR(wbc_ret);
228 *name_type = (enum wbcSidType)response.data.sid.type;
229 wbc_ret = WBC_ERR_SUCCESS;
235 /** @brief Convert a SID to a domain and name
237 * @param *sid Pointer to the domain SID to be resolved
238 * @param domain Resolved Domain name (possibly "")
239 * @param name Resolved User or group name
240 * @param *name_type Pointet to the resolved SID type
246 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
249 enum wbcSidType *name_type)
251 struct winbindd_request request;
252 struct winbindd_response response;
254 wbcErr wbc_ret = WBC_ERR_UNKNOWN_FAILURE;
255 char *sid_string = NULL;
260 /* Initialize request */
262 ZERO_STRUCT(request);
263 ZERO_STRUCT(response);
265 /* dst is already null terminated from the memset above */
267 wbc_ret = wbcSidToString(sid, &sid_string);
268 BAIL_ON_WBC_ERROR(wbc_ret);
270 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
275 result = winbindd_request_response(WINBINDD_LOOKUPSID,
279 if (result != NSS_STATUS_SUCCESS) {
283 /* Copy out result */
285 if (domain != NULL) {
286 if ((*domain = strdup(response.data.name.dom_name)) == NULL) {
287 wbc_ret = WBC_ERR_NO_MEMORY;
288 BAIL_ON_WBC_ERROR(wbc_ret);
293 if ((*name = strdup(response.data.name.name)) == NULL) {
294 wbc_ret = WBC_ERR_NO_MEMORY;
295 BAIL_ON_WBC_ERROR(wbc_ret);
300 *name_type = (enum wbcSidType)response.data.name.type;
302 wbc_ret = WBC_ERR_SUCCESS;
305 if (wbc_ret != WBC_ERR_SUCCESS) {
315 /** @brief Convert a Windows SID to a Unix uid
317 * @param *sid Pointer to the domain SID to be resolved
318 * @param *puid Pointer to the resolved uid_t value
324 wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid)
326 struct winbindd_request request;
327 struct winbindd_response response;
329 char *sid_string = NULL;
330 wbcErr wbc_ret = WBC_ERR_UNKNOWN_FAILURE;
335 /* Initialize request */
337 ZERO_STRUCT(request);
338 ZERO_STRUCT(response);
340 wbc_ret = wbcSidToString(sid, &sid_string);
341 BAIL_ON_WBC_ERROR(wbc_ret);
343 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
348 result = winbindd_request_response(WINBINDD_SID_TO_UID,
352 /* Copy out result */
354 if (result != NSS_STATUS_SUCCESS) {
355 return WBC_ERR_UNKNOWN_FAILURE;
358 *puid = response.data.uid;
359 wbc_ret = WBC_ERR_SUCCESS;
365 /** @brief Convert a Unix uid to a Windows SID
367 * @param uid Unix uid to be resolved
368 * @param *sid Pointer to the resolved domain SID
374 wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid)
376 struct winbindd_request request;
377 struct winbindd_response response;
383 /* Initialize request */
385 ZERO_STRUCT(request);
386 ZERO_STRUCT(response);
388 request.data.uid = uid;
392 result = winbindd_request_response(WINBINDD_UID_TO_SID,
396 /* Copy out result */
398 if (result != NSS_STATUS_SUCCESS) {
399 return WBC_ERR_UNKNOWN_FAILURE;
402 return wbcStringToSid(response.data.sid.sid, sid);
405 /** @brief Convert a Windows SID to a Unix gid
407 * @param *sid Pointer to the domain SID to be resolved
408 * @param *pgid Pointer to the resolved gid_t value
414 wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
416 struct winbindd_request request;
417 struct winbindd_response response;
419 wbcErr wbc_ret = WBC_ERR_UNKNOWN_FAILURE;
420 char *sid_string = NULL;
425 /* Initialize request */
427 ZERO_STRUCT(request);
428 ZERO_STRUCT(response);
430 wbc_ret = wbcSidToString(sid, &sid_string);
431 BAIL_ON_WBC_ERROR(wbc_ret);
433 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
438 result = winbindd_request_response(WINBINDD_SID_TO_GID,
442 /* Copy out result */
444 if (result != NSS_STATUS_SUCCESS) {
445 return WBC_ERR_UNKNOWN_FAILURE;
448 *pgid = response.data.gid;
449 wbc_ret = WBC_ERR_SUCCESS;
455 /** @brief Convert a Unix uid to a Windows SID
457 * @param gid Unix gid to be resolved
458 * @param *sid Pointer to the resolved domain SID
464 wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid)
466 struct winbindd_request request;
467 struct winbindd_response response;
473 /* Initialize request */
475 ZERO_STRUCT(request);
476 ZERO_STRUCT(response);
478 request.data.gid = gid;
482 result = winbindd_request_response(WINBINDD_GID_TO_SID,
487 /* Copy out result */
489 if (result != NSS_STATUS_SUCCESS) {
490 return WBC_ERR_UNKNOWN_FAILURE;
493 return wbcStringToSid(response.data.sid.sid, sid);
496 /** @brief Ping winbindd to see if the daemon is running
505 result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
507 if (result != NSS_STATUS_SUCCESS)
508 return WBC_ERR_UNKNOWN_FAILURE;
510 return WBC_ERR_SUCCESS;
513 /** @brief Lookup the current status of a trusted domain
515 * @param domain Domain to query
516 * @param *info Pointer to returned domain_info struct
520 * The char* members of the struct wbcDomainInfo* are malloc()'d
521 * and it the the responsibility of the caller to free the members
522 * before discarding the struct.
526 /**********************************************************************
527 result == NSS_STATUS_UNAVAIL: winbind not around
528 result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
530 Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off
531 and when winbind return WINBINDD_ERROR. So the semantics of this
532 routine depends on winbind_on. Grepping for winbind_off I just
533 found 3 places where winbind is turned off, and this does not conflict
534 (as far as I have seen) with the callers of is_trusted_domains.
537 **********************************************************************/
539 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo *info)
541 struct winbindd_request request;
542 struct winbindd_response response;
546 if (!domain || !info)
547 return WBC_ERR_INVALID_PARAM;
551 /* Initialize request */
553 ZERO_STRUCT(request);
554 ZERO_STRUCT(response);
556 strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
558 result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
562 /* Copy out result */
564 if (result != NSS_STATUS_SUCCESS) {
566 case NSS_STATUS_UNAVAIL:
567 return WBC_ERR_WINBIND_NOT_AVAILABLE;
569 case NSS_STATUS_NOTFOUND:
570 return WBC_ERR_DOMAIN_NOT_FOUND;
573 return WBC_ERR_UNKNOWN_FAILURE;
577 info->short_name = strdup(response.data.domain_info.name);
578 info->dns_name = strdup(response.data.domain_info.alt_name);
579 if (!info->short_name || !info->dns_name) {
580 ret = WBC_ERR_NO_MEMORY;
581 BAIL_ON_WBC_ERROR(ret);
584 ret = wbcStringToSid(response.data.domain_info.sid, &info->sid);
585 BAIL_ON_WBC_ERROR(ret);
587 if (response.data.domain_info.native_mode)
588 info->flags |= WBC_DOMINFO_NATIVE;
589 if (response.data.domain_info.active_directory)
590 info->flags |= WBC_DOMINFO_AD;
591 if (response.data.domain_info.primary)
592 info->flags |= WBC_DOMINFO_PRIMARY;
594 ret = WBC_ERR_SUCCESS;
597 if (ret != WBC_ERR_SUCCESS) {
598 if (info->short_name)
599 free(info->short_name);
601 free(info->dns_name);
607 /** @brief Translate a collection of RIDs within a domain to names
611 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
614 const char **domain_name,
616 enum wbcSidType **types)
618 size_t i, len, ridbuf_size;
621 struct winbindd_request request;
622 struct winbindd_response response;
624 char *sid_string = NULL;
628 return WBC_ERR_INVALID_PARAM;
631 /* Initialise request */
633 ZERO_STRUCT(request);
634 ZERO_STRUCT(response);
636 ret = wbcSidToString(dom_sid, &sid_string);
637 BAIL_ON_WBC_ERROR(ret);
639 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
641 /* Even if all the Rids were of maximum 32bit values,
642 we would only have 11 bytes per rid in the final array
643 ("4294967296" + \n). Add one more byte for the
646 ridbuf_size = (sizeof(char)*11) * num_rids + 1;
647 if ((ridlist = malloc(ridbuf_size)) == NULL)
648 return WBC_ERR_NO_MEMORY;
649 memset(ridlist, 0x0, ridbuf_size);
652 for (i=0; i<num_rids && (len-1)>0; i++) {
655 len = strlen(ridlist);
658 snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]);
659 strncat(p, ridstr, ridbuf_size-len-1);
662 request.extra_data.data = ridlist;
663 request.extra_len = strlen(ridlist)+1;
665 result = winbindd_request_response(WINBINDD_LOOKUPRIDS,
666 &request, &response);
670 if (result != NSS_STATUS_SUCCESS) {
671 return WBC_ERR_UNKNOWN_FAILURE;
674 *domain_name = strdup(response.data.domain_name);
676 *names = (const char**)malloc(sizeof(char*) * num_rids);
677 *types = (enum wbcSidType*)malloc(sizeof(enum wbcSidType) * num_rids);
679 if (!*names || !*types) {
680 ret = WBC_ERR_NO_MEMORY;
681 BAIL_ON_WBC_ERROR(ret);
684 p = (char *)response.extra_data.data;
686 for (i=0; i<num_rids; i++) {
690 ret = WCB_INVALID_RESPONSE;
691 BAIL_ON_WBC_ERROR(ret);
694 (*types)[i] = (enum wbcSidType)strtoul(p, &q, 10);
697 ret = WCB_INVALID_RESPONSE;
698 BAIL_ON_WBC_ERROR(ret);
703 if ((q = strchr(p, '\n')) == NULL) {
704 ret = WCB_INVALID_RESPONSE;
705 BAIL_ON_WBC_ERROR(ret);
710 (*names)[i] = strdup(p);
716 ret = WCB_INVALID_RESPONSE;
717 BAIL_ON_WBC_ERROR(ret);
720 free(response.extra_data.data);
722 ret = WBC_ERR_SUCCESS;
725 if (ret != WBC_ERR_SUCCESS) {
737 /** @brief Obtain a new uid from Winbind
739 * @param *puid *pointer to the allocated uid
744 wbcErr wbcAllocateUid(uid_t *puid)
746 struct winbindd_request request;
747 struct winbindd_response response;
751 return WBC_ERR_INVALID_PARAM;
753 /* Initialise request */
755 ZERO_STRUCT(request);
756 ZERO_STRUCT(response);
760 result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
761 &request, &response);
763 if (result != NSS_STATUS_SUCCESS)
764 return WBC_ERR_UNKNOWN_FAILURE;
766 /* Copy out result */
767 *puid = response.data.uid;
769 return WBC_ERR_SUCCESS;
772 /** @brief Obtain a new gid from Winbind
774 * @param *pgid Pointer to the allocated gid
779 wbcErr wbcAllocateGid(uid_t *pgid)
781 struct winbindd_request request;
782 struct winbindd_response response;
786 return WBC_ERR_INVALID_PARAM;
788 /* Initialise request */
790 ZERO_STRUCT(request);
791 ZERO_STRUCT(response);
795 result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
796 &request, &response);
798 if (result != NSS_STATUS_SUCCESS)
799 return WBC_ERR_UNKNOWN_FAILURE;
801 /* Copy out result */
802 *pgid = response.data.gid;
804 return WBC_ERR_SUCCESS;