/* Convert a binary SID to a character string */ wbcErr wbcSidToString(const struct wbcDomainSid *sid, char **sid_string) { char buf[WBC_SID_STRING_BUFLEN]; char *result; int len; if (!sid) { return WBC_ERR_INVALID_SID; } len = wbcSidToStringBuf(sid, buf, sizeof(buf)); if (len+1 > sizeof(buf)) { return WBC_ERR_INVALID_SID; } result = (char *)wbcAllocateMemory(len+1, 1, NULL); if (result == NULL) { return WBC_ERR_NO_MEMORY; } memcpy(result, buf, len+1); *sid_string = result; return WBC_ERR_SUCCESS; }
static wbcErr wbc_create_error_info(const struct winbindd_response *resp, struct wbcAuthErrorInfo **_e) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcAuthErrorInfo *e; e = (struct wbcAuthErrorInfo *)wbcAllocateMemory( 1, sizeof(struct wbcAuthErrorInfo), wbcAuthErrorInfoDestructor); BAIL_ON_PTR_ERROR(e, wbc_status); e->nt_status = resp->data.auth.nt_status; e->pam_error = resp->data.auth.pam_error; e->authoritative = resp->data.auth.authoritative; e->nt_string = strdup(resp->data.auth.nt_status_string); BAIL_ON_PTR_ERROR(e->nt_string, wbc_status); e->display_string = strdup(resp->data.auth.error_string); BAIL_ON_PTR_ERROR(e->display_string, wbc_status); *_e = e; e = NULL; done: wbcFreeMemory(e); return wbc_status; }
static wbcErr wbc_create_domain_controller_info_ex(const struct winbindd_response *resp, struct wbcDomainControllerInfoEx **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcDomainControllerInfoEx *i; struct wbcGuid guid; i = (struct wbcDomainControllerInfoEx *)wbcAllocateMemory( 1, sizeof(struct wbcDomainControllerInfoEx), wbcDomainControllerInfoExDestructor); BAIL_ON_PTR_ERROR(i, wbc_status); i->dc_unc = strdup(resp->data.dsgetdcname.dc_unc); BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status); i->dc_address = strdup(resp->data.dsgetdcname.dc_address); BAIL_ON_PTR_ERROR(i->dc_address, wbc_status); i->dc_address_type = resp->data.dsgetdcname.dc_address_type; wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid); if (WBC_ERROR_IS_OK(wbc_status)) { i->domain_guid = (struct wbcGuid *)malloc( sizeof(struct wbcGuid)); BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status); *i->domain_guid = guid; } i->domain_name = strdup(resp->data.dsgetdcname.domain_name); BAIL_ON_PTR_ERROR(i->domain_name, wbc_status); if (resp->data.dsgetdcname.forest_name[0] != '\0') { i->forest_name = strdup(resp->data.dsgetdcname.forest_name); BAIL_ON_PTR_ERROR(i->forest_name, wbc_status); } i->dc_flags = resp->data.dsgetdcname.dc_flags; if (resp->data.dsgetdcname.dc_site_name[0] != '\0') { i->dc_site_name = strdup(resp->data.dsgetdcname.dc_site_name); BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status); } if (resp->data.dsgetdcname.client_site_name[0] != '\0') { i->client_site_name = strdup( resp->data.dsgetdcname.client_site_name); BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status); } *_i = i; i = NULL; done: if (i != NULL) { wbcFreeMemory(i); } return wbc_status; }
/* Initialize a named blob and add to list of blobs */ wbcErr wbcAddNamedBlob(size_t *num_blobs, struct wbcNamedBlob **pblobs, const char *name, uint32_t flags, uint8_t *data, size_t length) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcNamedBlob *blobs, *blob; if (name == NULL) { return WBC_ERR_INVALID_PARAM; } /* * Overallocate the b->name==NULL terminator for * wbcNamedBlobDestructor */ blobs = (struct wbcNamedBlob *)wbcAllocateMemory( *num_blobs + 2, sizeof(struct wbcNamedBlob), wbcNamedBlobDestructor); if (blobs == NULL) { return WBC_ERR_NO_MEMORY; } if (*pblobs != NULL) { struct wbcNamedBlob *old = *pblobs; memcpy(blobs, old, sizeof(struct wbcNamedBlob) * (*num_blobs)); if (*num_blobs != 0) { /* end indicator for wbcNamedBlobDestructor */ old[0].name = NULL; } wbcFreeMemory(old); } *pblobs = blobs; blob = &blobs[*num_blobs]; blob->name = strdup(name); BAIL_ON_PTR_ERROR(blob->name, wbc_status); blob->flags = flags; blob->blob.length = length; blob->blob.data = (uint8_t *)malloc(length); BAIL_ON_PTR_ERROR(blob->blob.data, wbc_status); memcpy(blob->blob.data, data, length); *num_blobs += 1; *pblobs = blobs; blobs = NULL; wbc_status = WBC_ERR_SUCCESS; done: wbcFreeMemory(blobs); return wbc_status; }
wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainInfo *info = NULL; if (!domain || !dinfo) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); strncpy(request.domain_name, domain, sizeof(request.domain_name)-1); wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); info = (struct wbcDomainInfo *)wbcAllocateMemory( 1, sizeof(struct wbcDomainInfo), wbcDomainInfoDestructor); BAIL_ON_PTR_ERROR(info, wbc_status); info->short_name = strdup(response.data.domain_info.name); BAIL_ON_PTR_ERROR(info->short_name, wbc_status); info->dns_name = strdup(response.data.domain_info.alt_name); BAIL_ON_PTR_ERROR(info->dns_name, wbc_status); wbc_status = wbcStringToSid(response.data.domain_info.sid, &info->sid); BAIL_ON_WBC_ERROR(wbc_status); if (response.data.domain_info.native_mode) info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE; if (response.data.domain_info.active_directory) info->domain_flags |= WBC_DOMINFO_DOMAIN_AD; if (response.data.domain_info.primary) info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY; *dinfo = info; info = NULL; wbc_status = WBC_ERR_SUCCESS; done: wbcFreeMemory(info); return wbc_status; }
/* * Trigger a no-op NETLOGON call. Lightweight version of * wbcCheckTrustCredentials, optionally return attempted DC */ wbcErr wbcPingDc2(const char *domain, struct wbcAuthErrorInfo **error, char **dcname) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (domain) { /* * the current protocol doesn't support * specifying a domain */ wbc_status = WBC_ERR_NOT_IMPLEMENTED; BAIL_ON_WBC_ERROR(wbc_status); } ZERO_STRUCT(request); ZERO_STRUCT(response); /* Send request */ wbc_status = wbcRequestResponse(WINBINDD_PING_DC, &request, &response); if (dcname && response.extra_data.data) { size_t len; len = response.length - sizeof(struct winbindd_response); *dcname = wbcAllocateMemory(1, len, NULL); BAIL_ON_PTR_ERROR(*dcname, wbc_status); strlcpy(*dcname, response.extra_data.data, len); } if (response.data.auth.nt_status != 0) { if (error) { wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } wbc_status = WBC_ERR_AUTH_ERROR; BAIL_ON_WBC_ERROR(wbc_status); } BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
/* Enumerate the domain trusts known by Winbind */ wbcErr wbcLookupDomainController(const char *domain, uint32_t flags, struct wbcDomainControllerInfo **dc_info) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; struct wbcDomainControllerInfo *dc = NULL; /* validate input params */ if (!domain || !dc_info) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } ZERO_STRUCT(request); ZERO_STRUCT(response); strncpy(request.data.dsgetdcname.domain_name, domain, sizeof(request.data.dsgetdcname.domain_name)-1); request.flags = flags; dc = (struct wbcDomainControllerInfo *)wbcAllocateMemory( 1, sizeof(struct wbcDomainControllerInfo), wbcDomainControllerInfoDestructor); BAIL_ON_PTR_ERROR(dc, wbc_status); /* Send request */ wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); dc->dc_name = strdup(response.data.dsgetdcname.dc_unc); BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status); *dc_info = dc; dc = NULL; done: wbcFreeMemory(dc); return wbc_status; }
/* * Trigger a no-op NETLOGON call. Lightweight version of * wbcCheckTrustCredentials, optionally return attempted DC */ wbcErr wbcCtxPingDc2(struct wbcContext *ctx, const char *domain, struct wbcAuthErrorInfo **error, char **dcname) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; ZERO_STRUCT(request); ZERO_STRUCT(response); if (domain) { strncpy(request.domain_name, domain, sizeof(request.domain_name)-1); } /* Send request */ wbc_status = wbcRequestResponse(ctx, WINBINDD_PING_DC, &request, &response); if (dcname && response.extra_data.data) { size_t len; len = response.length - sizeof(struct winbindd_response); *dcname = wbcAllocateMemory(1, len, NULL); BAIL_ON_PTR_ERROR(*dcname, wbc_status); strlcpy(*dcname, response.extra_data.data, len); } if (response.data.auth.nt_status != 0) { if (error) { wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } wbc_status = WBC_ERR_AUTH_ERROR; BAIL_ON_WBC_ERROR(wbc_status); } BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
static wbcErr wbc_create_logon_info(struct winbindd_response *resp, struct wbcLogonUserInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcLogonUserInfo *i; i = (struct wbcLogonUserInfo *)wbcAllocateMemory( 1, sizeof(struct wbcLogonUserInfo), wbcLogonUserInfoDestructor); BAIL_ON_PTR_ERROR(i, wbc_status); wbc_status = wbc_create_auth_info(resp, &i->info); BAIL_ON_WBC_ERROR(wbc_status); if (resp->data.auth.krb5ccname[0] != '\0') { wbc_status = wbcAddNamedBlob(&i->num_blobs, &i->blobs, "krb5ccname", 0, (uint8_t *)resp->data.auth.krb5ccname, strlen(resp->data.auth.krb5ccname)+1); BAIL_ON_WBC_ERROR(wbc_status); } if (resp->data.auth.unix_username[0] != '\0') { wbc_status = wbcAddNamedBlob(&i->num_blobs, &i->blobs, "unix_username", 0, (uint8_t *)resp->data.auth.unix_username, strlen(resp->data.auth.unix_username)+1); BAIL_ON_WBC_ERROR(wbc_status); } *_i = i; i = NULL; done: wbcFreeMemory(i); return wbc_status; }
static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp, struct wbcUserPasswordPolicyInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcUserPasswordPolicyInfo *i; i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory( 1, sizeof(struct wbcUserPasswordPolicyInfo), NULL); BAIL_ON_PTR_ERROR(i, wbc_status); i->min_passwordage = resp->data.auth.policy.min_passwordage; i->min_length_password = resp->data.auth.policy.min_length_password; i->password_history = resp->data.auth.policy.password_history; i->password_properties = resp->data.auth.policy.password_properties; i->expire = resp->data.auth.policy.expire; *_i = i; i = NULL; done: wbcFreeMemory(i); return wbc_status; }
/* Get alias membership for sids */ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid, struct wbcDomainSid *sids, uint32_t num_sids, uint32_t **alias_rids, uint32_t *num_alias_rids) { uint32_t i; const char *s; struct winbindd_request request; struct winbindd_response response; ssize_t extra_data_len = 0; char * extra_data = NULL; ssize_t buflen = 0; struct wbcDomainSid sid; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; uint32_t * rids = NULL; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (!dom_sid) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid)); /* Lets assume each sid is around 57 characters * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */ buflen = 57 * num_sids; extra_data = (char *)malloc(buflen); if (!extra_data) { wbc_status = WBC_ERR_NO_MEMORY; goto done; } /* Build the sid list */ for (i=0; i<num_sids; i++) { char sid_str[WBC_SID_STRING_BUFLEN]; size_t sid_len; sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str)); if (buflen < extra_data_len + sid_len + 2) { buflen *= 2; extra_data = (char *)realloc(extra_data, buflen); if (!extra_data) { wbc_status = WBC_ERR_NO_MEMORY; BAIL_ON_WBC_ERROR(wbc_status); } } strncpy(&extra_data[extra_data_len], sid_str, buflen - extra_data_len); extra_data_len += sid_len; extra_data[extra_data_len++] = '\n'; extra_data[extra_data_len] = '\0'; } extra_data_len += 1; request.extra_data.data = extra_data; request.extra_len = extra_data_len; wbc_status = wbcRequestResponse(WINBINDD_GETSIDALIASES, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); if (response.data.num_entries && !response.extra_data.data) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries, sizeof(uint32_t), NULL); BAIL_ON_PTR_ERROR(sids, wbc_status); s = (const char *)response.extra_data.data; for (i = 0; i < response.data.num_entries; i++) { char *n = strchr(s, '\n'); if (n) { *n = '\0'; } wbc_status = wbcStringToSid(s, &sid); BAIL_ON_WBC_ERROR(wbc_status); wbc_status = _sid_to_rid(&sid, &rids[i]); BAIL_ON_WBC_ERROR(wbc_status); s += strlen(s) + 1; } *num_alias_rids = response.data.num_entries; *alias_rids = rids; rids = NULL; wbc_status = WBC_ERR_SUCCESS; done: free(extra_data); winbindd_free_response(&response); wbcFreeMemory(rids); return wbc_status; }
/* Enumerate the domain trusts known by Winbind */ wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains) { struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *p = NULL; char *extra_data = NULL; struct wbcDomainInfo *d_list = NULL; int i = 0; *domains = NULL; *num_domains = 0; ZERO_STRUCT(response); /* Send request */ wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); /* Decode the response */ p = (char *)response.extra_data.data; if ((p == NULL) || (strlen(p) == 0)) { /* We should always at least get back our own SAM domain */ wbc_status = WBC_ERR_DOMAIN_NOT_FOUND; BAIL_ON_WBC_ERROR(wbc_status); } d_list = (struct wbcDomainInfo *)wbcAllocateMemory( response.data.num_entries + 1,sizeof(struct wbcDomainInfo), wbcDomainInfoListDestructor); BAIL_ON_PTR_ERROR(d_list, wbc_status); extra_data = strdup((char*)response.extra_data.data); BAIL_ON_PTR_ERROR(extra_data, wbc_status); p = extra_data; /* Outer loop processes the list of domain information */ for (i=0; i<response.data.num_entries && p; i++) { char *next = strchr(p, '\n'); if (next) { *next = '\0'; next++; } wbc_status = process_domain_info_string(&d_list[i], p); BAIL_ON_WBC_ERROR(wbc_status); p = next; } *domains = d_list; d_list = NULL; *num_domains = i; done: winbindd_free_response(&response); wbcFreeMemory(d_list); free(extra_data); return wbc_status; }
/* Get the groups a user belongs to */ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid, bool domain_groups_only, uint32_t *num_sids, struct wbcDomainSid **_sids) { uint32_t i; const char *s; struct winbindd_request request; struct winbindd_response response; struct wbcDomainSid *sids = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; int cmd; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (!user_sid) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid)); if (domain_groups_only) { cmd = WINBINDD_GETUSERDOMGROUPS; } else { cmd = WINBINDD_GETUSERSIDS; } wbc_status = wbcRequestResponse(cmd, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); if (response.data.num_entries && !response.extra_data.data) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } sids = (struct wbcDomainSid *)wbcAllocateMemory( response.data.num_entries, sizeof(struct wbcDomainSid), NULL); BAIL_ON_PTR_ERROR(sids, wbc_status); s = (const char *)response.extra_data.data; for (i = 0; i < response.data.num_entries; i++) { char *n = strchr(s, '\n'); if (n) { *n = '\0'; } wbc_status = wbcStringToSid(s, &sids[i]); BAIL_ON_WBC_ERROR(wbc_status); s += strlen(s) + 1; } *num_sids = response.data.num_entries; *_sids = sids; sids = NULL; wbc_status = WBC_ERR_SUCCESS; done: winbindd_free_response(&response); if (sids) { wbcFreeMemory(sids); } return wbc_status; }
wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, int num_rids, uint32_t *rids, const char **pp_domain_name, const char ***pnames, enum wbcSidType **ptypes) { size_t i, len, ridbuf_size; char *ridlist; char *p; struct winbindd_request request; struct winbindd_response response; char *domain_name = NULL; const char **names = NULL; enum wbcSidType *types = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (!dom_sid || (num_rids == 0)) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid)); /* Even if all the Rids were of maximum 32bit values, we would only have 11 bytes per rid in the final array ("4294967296" + \n). Add one more byte for the terminating '\0' */ ridbuf_size = (sizeof(char)*11) * num_rids + 1; ridlist = (char *)malloc(ridbuf_size); BAIL_ON_PTR_ERROR(ridlist, wbc_status); len = 0; for (i=0; i<num_rids; i++) { len += snprintf(ridlist + len, ridbuf_size - len, "%u\n", rids[i]); } ridlist[len] = '\0'; len += 1; request.extra_data.data = ridlist; request.extra_len = len; wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS, &request, &response); free(ridlist); BAIL_ON_WBC_ERROR(wbc_status); domain_name = wbcStrDup(response.data.domain_name); BAIL_ON_PTR_ERROR(domain_name, wbc_status); names = wbcAllocateStringArray(num_rids); BAIL_ON_PTR_ERROR(names, wbc_status); types = (enum wbcSidType *)wbcAllocateMemory( num_rids, sizeof(enum wbcSidType), NULL); BAIL_ON_PTR_ERROR(types, wbc_status); p = (char *)response.extra_data.data; for (i=0; i<num_rids; i++) { char *q; if (*p == '\0') { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } types[i] = (enum wbcSidType)strtoul(p, &q, 10); if (*q != ' ') { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } p = q+1; if ((q = strchr(p, '\n')) == NULL) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } *q = '\0'; names[i] = strdup(p); BAIL_ON_PTR_ERROR(names[i], wbc_status); p = q+1; } if (*p != '\0') { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } wbc_status = WBC_ERR_SUCCESS; done: winbindd_free_response(&response); if (WBC_ERROR_IS_OK(wbc_status)) { *pp_domain_name = domain_name; *pnames = names; *ptypes = types; } else { wbcFreeMemory(domain_name); wbcFreeMemory(names); wbcFreeMemory(types); } return wbc_status; }
wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids, struct wbcDomainInfo **pdomains, int *pnum_domains, struct wbcTranslatedName **pnames) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; int buflen, i, extra_len, num_domains, num_names; char *sidlist, *p, *q, *extra_data; struct wbcDomainInfo *domains = NULL; struct wbcTranslatedName *names = NULL; buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1; sidlist = (char *)malloc(buflen); if (sidlist == NULL) { return WBC_ERR_NO_MEMORY; } p = sidlist; for (i=0; i<num_sids; i++) { int remaining; int len; remaining = buflen - (p - sidlist); len = wbcSidToStringBuf(&sids[i], p, remaining); if (len > remaining) { free(sidlist); return WBC_ERR_UNKNOWN_FAILURE; } p += len; *p++ = '\n'; } *p++ = '\0'; ZERO_STRUCT(request); ZERO_STRUCT(response); request.extra_data.data = sidlist; request.extra_len = p - sidlist; wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSIDS, &request, &response); free(sidlist); if (!WBC_ERROR_IS_OK(wbc_status)) { return wbc_status; } extra_len = response.length - sizeof(struct winbindd_response); extra_data = (char *)response.extra_data.data; if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) { goto wbc_err_invalid; } p = extra_data; num_domains = strtoul(p, &q, 10); if (*q != '\n') { goto wbc_err_invalid; } p = q+1; domains = (struct wbcDomainInfo *)wbcAllocateMemory( num_domains+1, sizeof(struct wbcDomainInfo), wbcDomainInfosDestructor); if (domains == NULL) { wbc_status = WBC_ERR_NO_MEMORY; goto fail; } for (i=0; i<num_domains; i++) { q = strchr(p, ' '); if (q == NULL) { goto wbc_err_invalid; } *q = '\0'; wbc_status = wbcStringToSid(p, &domains[i].sid); if (!WBC_ERROR_IS_OK(wbc_status)) { goto fail; } p = q+1; q = strchr(p, '\n'); if (q == NULL) { goto wbc_err_invalid; } *q = '\0'; domains[i].short_name = wbcStrDup(p); if (domains[i].short_name == NULL) { wbc_status = WBC_ERR_NO_MEMORY; goto fail; } p = q+1; } num_names = strtoul(p, &q, 10); if (*q != '\n') { goto wbc_err_invalid; } p = q+1; if (num_names != num_sids) { goto wbc_err_invalid; } names = (struct wbcTranslatedName *)wbcAllocateMemory( num_names+1, sizeof(struct wbcTranslatedName), wbcTranslatedNamesDestructor); if (names == NULL) { wbc_status = WBC_ERR_NO_MEMORY; goto fail; } for (i=0; i<num_names; i++) { names[i].domain_index = strtoul(p, &q, 10); if (*q != ' ') { goto wbc_err_invalid; } p = q+1; names[i].type = strtoul(p, &q, 10); if (*q != ' ') { goto wbc_err_invalid; } p = q+1; q = strchr(p, '\n'); if (q == NULL) { goto wbc_err_invalid; } *q = '\0'; names[i].name = wbcStrDup(p); if (names[i].name == NULL) { wbc_status = WBC_ERR_NO_MEMORY; goto fail; } p = q+1; } if (*p != '\0') { goto wbc_err_invalid; } *pdomains = domains; *pnames = names; winbindd_free_response(&response); return WBC_ERR_SUCCESS; wbc_err_invalid: wbc_status = WBC_ERR_INVALID_RESPONSE; fail: winbindd_free_response(&response); wbcFreeMemory(domains); wbcFreeMemory(names); return wbc_status; }
static wbcErr wbc_create_auth_info(const struct winbindd_response *resp, struct wbcAuthUserInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcAuthUserInfo *i; struct wbcDomainSid domain_sid; char *p; uint32_t sn = 0; uint32_t j; i = (struct wbcAuthUserInfo *)wbcAllocateMemory( 1, sizeof(struct wbcAuthUserInfo), wbcAuthUserInfoDestructor); BAIL_ON_PTR_ERROR(i, wbc_status); i->user_flags = resp->data.auth.info3.user_flgs; i->account_name = strdup(resp->data.auth.info3.user_name); BAIL_ON_PTR_ERROR(i->account_name, wbc_status); if (resp->data.auth.validation_level == 6) { i->user_principal = strdup(resp->data.auth.info6.principal_name); BAIL_ON_PTR_ERROR(i->user_principal, wbc_status); } else { i->user_principal = NULL; } i->full_name = strdup(resp->data.auth.info3.full_name); BAIL_ON_PTR_ERROR(i->full_name, wbc_status); i->domain_name = strdup(resp->data.auth.info3.logon_dom); BAIL_ON_PTR_ERROR(i->domain_name, wbc_status); if (resp->data.auth.validation_level == 6) { i->dns_domain_name = strdup(resp->data.auth.info6.dns_domainname); BAIL_ON_PTR_ERROR(i->dns_domain_name, wbc_status); } else { i->dns_domain_name = NULL; } i->acct_flags = resp->data.auth.info3.acct_flags; memcpy(i->user_session_key, resp->data.auth.user_session_key, sizeof(i->user_session_key)); memcpy(i->lm_session_key, resp->data.auth.first_8_lm_hash, sizeof(i->lm_session_key)); i->logon_count = resp->data.auth.info3.logon_count; i->bad_password_count = resp->data.auth.info3.bad_pw_count; i->logon_time = resp->data.auth.info3.logon_time; i->logoff_time = resp->data.auth.info3.logoff_time; i->kickoff_time = resp->data.auth.info3.kickoff_time; i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time; i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time; i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time; i->logon_server = strdup(resp->data.auth.info3.logon_srv); BAIL_ON_PTR_ERROR(i->logon_server, wbc_status); i->logon_script = strdup(resp->data.auth.info3.logon_script); BAIL_ON_PTR_ERROR(i->logon_script, wbc_status); i->profile_path = strdup(resp->data.auth.info3.profile_path); BAIL_ON_PTR_ERROR(i->profile_path, wbc_status); i->home_directory= strdup(resp->data.auth.info3.home_dir); BAIL_ON_PTR_ERROR(i->home_directory, wbc_status); i->home_drive = strdup(resp->data.auth.info3.dir_drive); BAIL_ON_PTR_ERROR(i->home_drive, wbc_status); i->num_sids = 2; i->num_sids += resp->data.auth.info3.num_groups; i->num_sids += resp->data.auth.info3.num_other_sids; i->sids = (struct wbcSidWithAttr *)calloc( sizeof(struct wbcSidWithAttr), i->num_sids); BAIL_ON_PTR_ERROR(i->sids, wbc_status); wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid, &domain_sid); BAIL_ON_WBC_ERROR(wbc_status); sn = 0; if (!sid_attr_compose(&i->sids[sn], &domain_sid, resp->data.auth.info3.user_rid, 0)) { wbc_status = WBC_ERR_INVALID_SID; goto done; } sn++; if (!sid_attr_compose(&i->sids[sn], &domain_sid, resp->data.auth.info3.group_rid, 0)) { wbc_status = WBC_ERR_INVALID_SID; goto done; } sn++; p = (char *)resp->extra_data.data; if (!p) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } for (j=0; j < resp->data.auth.info3.num_groups; j++) { uint32_t rid; uint32_t attrs; int ret; char *s = p; char *e = strchr(p, '\n'); if (!e) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } e[0] = '\0'; p = &e[1]; ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs); if (ret != 2) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } if (!sid_attr_compose(&i->sids[sn], &domain_sid, rid, attrs)) { wbc_status = WBC_ERR_INVALID_SID; goto done; } sn++; } for (j=0; j < resp->data.auth.info3.num_other_sids; j++) { uint32_t attrs; int ret; char *s = p; char *a; char *e = strchr(p, '\n'); if (!e) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } e[0] = '\0'; p = &e[1]; e = strchr(s, ':'); if (!e) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } e[0] = '\0'; a = &e[1]; ret = sscanf(a, "0x%08X", &attrs); if (ret != 1) { wbc_status = WBC_ERR_INVALID_RESPONSE; BAIL_ON_WBC_ERROR(wbc_status); } wbc_status = wbcStringToSid(s, &i->sids[sn].sid); BAIL_ON_WBC_ERROR(wbc_status); i->sids[sn].attributes = attrs; sn++; } i->num_sids = sn; *_i = i; i = NULL; done: wbcFreeMemory(i); return wbc_status; }
wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, int num_rids, uint32_t *rids, const char **pp_domain_name, const char ***pnames, enum wbcSidType **ptypes) { struct wbcDomainSid obj_sid = {0}; size_t c; wbcErr err; char *domain; char *name; enum wbcSidType type; const char **names = NULL; enum wbcSidType *types = NULL; obj_sid.sid_rev_num = dom_sid->sid_rev_num; obj_sid.num_auths = dom_sid->num_auths + 1; for (c = 0; c < 6; c++) { obj_sid.id_auth[c] = dom_sid->id_auth[c]; } for (c = 0; c < WBC_MAXSUBAUTHS; c++) { obj_sid.sub_auths[c] = dom_sid->sub_auths[c]; } names = wbcAllocateStringArray(num_rids + 1); if (names == NULL) { err = WBC_ERR_NO_MEMORY; goto done; } types = wbcAllocateMemory(num_rids + 1, sizeof(enum wbcSidType), NULL); if (types == NULL) { err = WBC_ERR_NO_MEMORY; goto done; } for (c = 0; c < num_rids; c++) { obj_sid.sub_auths[obj_sid.num_auths - 1] = rids[c]; err = wbcLookupSid(&obj_sid, &domain, &name, &type); if (err != WBC_ERR_SUCCESS) { goto done; } names[c] = strdup(name); wbcFreeMemory(name); if (names[c] == NULL) { err = WBC_ERR_NO_MEMORY; goto done; } types[c] = type; if (c == 0) { *pp_domain_name = domain; } else { wbcFreeMemory(domain); } } *pnames = names; *ptypes = types; err = WBC_ERR_SUCCESS; done: if (err != WBC_ERR_SUCCESS) { wbcFreeMemory(types); wbcFreeMemory(names); } return err; }
/* Authenticate a user with cached credentials */ wbcErr wbcCtxCredentialCache(struct wbcContext *ctx, struct wbcCredentialCacheParams *params, struct wbcCredentialCacheInfo **info, struct wbcAuthErrorInfo **error) { wbcErr status = WBC_ERR_UNKNOWN_FAILURE; struct wbcCredentialCacheInfo *result = NULL; struct winbindd_request request; struct winbindd_response response; struct wbcNamedBlob *initial_blob = NULL; struct wbcNamedBlob *challenge_blob = NULL; size_t i; ZERO_STRUCT(request); ZERO_STRUCT(response); *info = NULL; if (error != NULL) { *error = NULL; } if ((params == NULL) || (params->account_name == NULL) || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) { status = WBC_ERR_INVALID_PARAM; goto fail; } for (i=0; i<params->num_blobs; i++) { /* * Older callers may used to provide the NEGOTIATE request * as "initial_blob", but it was completely ignored by winbindd. * * So we keep ignoring it. * * A new callers that is capable to support "new_spnego", * will provide the NEGOTIATE request as "negotiate_blob" * instead. */ if (strcasecmp(params->blobs[i].name, "negotiate_blob") == 0) { if (initial_blob != NULL) { status = WBC_ERR_INVALID_PARAM; goto fail; } initial_blob = ¶ms->blobs[i]; continue; } if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) { if (challenge_blob != NULL) { status = WBC_ERR_INVALID_PARAM; goto fail; } challenge_blob = ¶ms->blobs[i]; continue; } } if (params->domain_name != NULL) { status = wbcRequestResponse(ctx, WINBINDD_INFO, NULL, &response); if (!WBC_ERROR_IS_OK(status)) { goto fail; } snprintf(request.data.ccache_ntlm_auth.user, sizeof(request.data.ccache_ntlm_auth.user)-1, "%s%c%s", params->domain_name, response.data.info.winbind_separator, params->account_name); } else { strncpy(request.data.ccache_ntlm_auth.user, params->account_name, sizeof(request.data.ccache_ntlm_auth.user)-1); } request.data.ccache_ntlm_auth.uid = getuid(); request.data.ccache_ntlm_auth.initial_blob_len = 0; request.data.ccache_ntlm_auth.challenge_blob_len = 0; request.extra_len = 0; if (initial_blob != NULL) { request.data.ccache_ntlm_auth.initial_blob_len = initial_blob->blob.length; request.extra_len += initial_blob->blob.length; } if (challenge_blob != NULL) { request.data.ccache_ntlm_auth.challenge_blob_len = challenge_blob->blob.length; request.extra_len += challenge_blob->blob.length; } if (request.extra_len != 0) { request.extra_data.data = (char *)malloc(request.extra_len); if (request.extra_data.data == NULL) { status = WBC_ERR_NO_MEMORY; goto fail; } } if (initial_blob != NULL) { memcpy(request.extra_data.data, initial_blob->blob.data, initial_blob->blob.length); } if (challenge_blob != NULL) { memcpy(request.extra_data.data + request.data.ccache_ntlm_auth.initial_blob_len, challenge_blob->blob.data, challenge_blob->blob.length); } status = wbcRequestResponse(ctx, WINBINDD_CCACHE_NTLMAUTH, &request, &response); if (!WBC_ERROR_IS_OK(status)) { goto fail; } result = (struct wbcCredentialCacheInfo *)wbcAllocateMemory( 1, sizeof(struct wbcCredentialCacheInfo), wbcCredentialCacheInfoDestructor); if (result == NULL) { status = WBC_ERR_NO_MEMORY; goto fail; } result->num_blobs = 0; result->blobs = NULL; status = wbcAddNamedBlob(&result->num_blobs, &result->blobs, "auth_blob", 0, (uint8_t *)response.extra_data.data, response.data.ccache_ntlm_auth.auth_blob_len); if (!WBC_ERROR_IS_OK(status)) { goto fail; } status = wbcAddNamedBlob( &result->num_blobs, &result->blobs, "session_key", 0, response.data.ccache_ntlm_auth.session_key, sizeof(response.data.ccache_ntlm_auth.session_key)); if (!WBC_ERROR_IS_OK(status)) { goto fail; } if (response.data.ccache_ntlm_auth.new_spnego) { status = wbcAddNamedBlob( &result->num_blobs, &result->blobs, "new_spnego", 0, &response.data.ccache_ntlm_auth.new_spnego, sizeof(response.data.ccache_ntlm_auth.new_spnego)); if (!WBC_ERROR_IS_OK(status)) { goto fail; } } *info = result; result = NULL; status = WBC_ERR_SUCCESS; fail: free(request.extra_data.data); winbindd_free_response(&response); wbcFreeMemory(result); return status; }
wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcInterfaceDetails *info; struct wbcDomainInfo *domain = NULL; struct winbindd_request request; struct winbindd_response response; /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); info = (struct wbcInterfaceDetails *)wbcAllocateMemory( 1, sizeof(struct wbcInterfaceDetails), wbcInterfaceDetailsDestructor); BAIL_ON_PTR_ERROR(info, wbc_status); /* first the interface version */ wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); info->interface_version = response.data.interface_version; /* then the samba version and the winbind separator */ wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); info->winbind_version = strdup(response.data.info.samba_version); BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status); info->winbind_separator = response.data.info.winbind_separator; /* then the local netbios name */ wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); info->netbios_name = strdup(response.data.netbios_name); BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status); /* then the local workgroup name */ wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); info->netbios_domain = strdup(response.data.domain_name); BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status); wbc_status = wbcDomainInfo(info->netbios_domain, &domain); if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) { /* maybe it's a standalone server */ domain = NULL; wbc_status = WBC_ERR_SUCCESS; } else { BAIL_ON_WBC_ERROR(wbc_status); } if (domain) { info->dns_domain = strdup(domain->dns_name); wbcFreeMemory(domain); BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status); } else { info->dns_domain = NULL; } *_details = info; info = NULL; wbc_status = WBC_ERR_SUCCESS; done: wbcFreeMemory(info); return wbc_status; }