wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; if (!sid) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); request.data.uid = uid; /* Make request */ wbc_status = wbcRequestResponse(WINBINDD_UID_TO_SID, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); wbc_status = wbcStringToSid(response.data.sid.sid, sid); BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
/** @brief Remove a group id mapping * * @param gid Gid of the mapping to remove. * @param *sid Pointer to the sid of the mapping to remove. * * @return #wbcErr **/ wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *sid_string = NULL; if (!sid) { return WBC_ERR_INVALID_PARAM; } /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); /* Make request */ request.data.dual_idmapset.id = gid; request.data.dual_idmapset.type = _ID_TYPE_GID; wbc_status = wbcSidToString(sid, &sid_string); BAIL_ON_WBC_ERROR(wbc_status); strncpy(request.data.dual_idmapset.sid, sid_string, sizeof(request.data.dual_idmapset.sid)-1); wbcFreeMemory(sid_string); wbc_status = wbcRequestResponse(WINBINDD_REMOVE_MAPPING, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
/* Trigger a change of the trust credentials for a specific domain */ wbcErr wbcCtxChangeTrustCredentials(struct wbcContext *ctx, const char *domain, struct wbcAuthErrorInfo **error) { 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 = wbcRequestResponsePriv(ctx, WINBINDD_CHANGE_MACHACC, &request, &response); 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; }
/* Get extended domain controller information */ wbcErr wbcLookupDomainControllerEx(const char *domain, struct wbcGuid *guid, const char *site, uint32_t flags, struct wbcDomainControllerInfoEx **dc_info) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; /* 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); request.data.dsgetdcname.flags = flags; strncpy(request.data.dsgetdcname.domain_name, domain, sizeof(request.data.dsgetdcname.domain_name)-1); if (site) { strncpy(request.data.dsgetdcname.site_name, site, sizeof(request.data.dsgetdcname.site_name)-1); } if (guid) { char *str = NULL; wbc_status = wbcGuidToString(guid, &str); BAIL_ON_WBC_ERROR(wbc_status); strncpy(request.data.dsgetdcname.domain_guid, str, sizeof(request.data.dsgetdcname.domain_guid)-1); wbcFreeMemory(str); } /* Send request */ wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); if (dc_info) { wbc_status = wbc_create_domain_controller_info_ex(&response, dc_info); BAIL_ON_WBC_ERROR(wbc_status); } wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
/* Lookup the current status of a trusted domain */ 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 = talloc(NULL, struct wbcDomainInfo); BAIL_ON_PTR_ERROR(info, wbc_status); info->short_name = talloc_strdup(info, response.data.domain_info.name); BAIL_ON_PTR_ERROR(info->short_name, wbc_status); info->dns_name = talloc_strdup(info, 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; wbc_status = WBC_ERR_SUCCESS; done: if (!WBC_ERROR_IS_OK(wbc_status)) { talloc_free(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; }
/* @brief Convert a character string to a binary GUID */ wbcErr wbcStringToGuid(const char *str, struct wbcGuid *guid) { uint32_t time_low; uint32_t time_mid, time_hi_and_version; uint32_t clock_seq[2]; uint32_t node[6]; int i; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!guid) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (!str) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (11 == sscanf(str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", &time_low, &time_mid, &time_hi_and_version, &clock_seq[0], &clock_seq[1], &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { wbc_status = WBC_ERR_SUCCESS; } else if (11 == sscanf(str, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", &time_low, &time_mid, &time_hi_and_version, &clock_seq[0], &clock_seq[1], &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { wbc_status = WBC_ERR_SUCCESS; } BAIL_ON_WBC_ERROR(wbc_status); guid->time_low = time_low; guid->time_mid = time_mid; guid->time_hi_and_version = time_hi_and_version; guid->clock_seq[0] = clock_seq[0]; guid->clock_seq[1] = clock_seq[1]; for (i=0;i<6;i++) { guid->node[i] = node[i]; } wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
/* Convert a binary GUID to a character string */ wbcErr wbcGuidToString(const struct wbcGuid *guid, char **guid_string) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!guid) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } *guid_string = talloc_asprintf(NULL, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->time_low, guid->time_mid, guid->time_hi_and_version, guid->clock_seq[0], guid->clock_seq[1], guid->node[0], guid->node[1], guid->node[2], guid->node[3], guid->node[4], guid->node[5]); BAIL_ON_PTR_ERROR((*guid_string), wbc_status); wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
/* Resolve an IP address via WINS into a NetbiosName */ wbcErr wbcResolveWinsByIP(const char *ip, char **name) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *name_str; ZERO_STRUCT(request); ZERO_STRUCT(response); /* Send request */ strncpy(request.data.winsreq, ip, sizeof(request.data.winsreq)-1); wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); /* Display response */ name_str = wbcStrDup(response.data.winsresp); BAIL_ON_PTR_ERROR(name_str, wbc_status); *name = name_str; wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
/* Resolve a NetbiosName via WINS */ wbcErr wbcResolveWinsByName(const char *name, char **ip) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *ipaddr; ZERO_STRUCT(request); ZERO_STRUCT(response); /* Send request */ strncpy(request.data.winsreq, name, sizeof(request.data.winsreq)-1); wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); /* Display response */ ipaddr = talloc_strdup(NULL, response.data.winsresp); BAIL_ON_PTR_ERROR(ipaddr, wbc_status); *ip = ipaddr; wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
wbcErr wbcAllocateGid(gid_t *pgid) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!pgid) return WBC_ERR_INVALID_PARAM; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); /* Make request */ wbc_status = wbcRequestResponse(WINBINDD_ALLOCATE_GID, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); /* Copy out result */ *pgid = response.data.gid; wbc_status = WBC_ERR_SUCCESS; done: 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; }
/* 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; }
wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid, char **pdomain, char **pfullname, enum wbcSidType *pname_type) { wbcErr wbc_status; char *domain = NULL; char *name = NULL; enum wbcSidType name_type; wbc_status = wbcLookupSid(sid, &domain, &name, &name_type); BAIL_ON_WBC_ERROR(wbc_status); if (name_type == WBC_SID_NAME_USER) { uid_t uid; struct passwd *pwd; wbc_status = wbcSidToUid(sid, &uid); BAIL_ON_WBC_ERROR(wbc_status); wbc_status = wbcGetpwuid(uid, &pwd); BAIL_ON_WBC_ERROR(wbc_status); wbcFreeMemory(name); name = wbcStrDup(pwd->pw_gecos); wbcFreeMemory(pwd); BAIL_ON_PTR_ERROR(name, wbc_status); } wbc_status = WBC_ERR_SUCCESS; done: if (WBC_ERROR_IS_OK(wbc_status)) { *pdomain = domain; *pfullname = name; *pname_type = name_type; } else { wbcFreeMemory(domain); wbcFreeMemory(name); } return wbc_status; }
/* Convert a domain and name to SID */ wbcErr wbcLookupName(const char *domain, const char *name, struct wbcDomainSid *sid, enum wbcSidType *name_type) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!sid || !name_type) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); /* dst is already null terminated from the memset above */ strncpy(request.data.name.dom_name, domain, sizeof(request.data.name.dom_name)-1); strncpy(request.data.name.name, name, sizeof(request.data.name.name)-1); wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); wbc_status = wbcStringToSid(response.data.sid.sid, sid); BAIL_ON_WBC_ERROR(wbc_status); *name_type = (enum wbcSidType)response.data.sid.type; wbc_status = WBC_ERR_SUCCESS; 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; }
wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid) { struct winbindd_request request; struct winbindd_response response; char *sid_string = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!sid || !puid) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); wbc_status = wbcSidToString(sid, &sid_string); BAIL_ON_WBC_ERROR(wbc_status); strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); wbcFreeMemory(sid_string); /* Make request */ wbc_status = wbcRequestResponse(WINBINDD_SID_TO_UID, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); *puid = response.data.uid; wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
/* Authenticate a username/password pair */ wbcErr wbcCtxAuthenticateUser(struct wbcContext *ctx, const char *username, const char *password) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcAuthUserParams params; ZERO_STRUCT(params); params.account_name = username; params.level = WBC_AUTH_USER_LEVEL_PLAIN; params.password.plaintext = password; wbc_status = wbcCtxAuthenticateUserEx(ctx, ¶ms, NULL, NULL); BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
wbcErr wbcSidToString(const struct wbcDomainSid *sid, char **sid_string) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; uint32_t id_auth; int i; char *tmp = NULL; if (!sid) { wbc_status = WBC_ERR_INVALID_SID; BAIL_ON_WBC_ERROR(wbc_status); } id_auth = sid->id_auth[5] + (sid->id_auth[4] << 8) + (sid->id_auth[3] << 16) + (sid->id_auth[2] << 24); tmp = talloc_asprintf(NULL, "S-%d-%d", sid->sid_rev_num, id_auth); BAIL_ON_PTR_ERROR(tmp, wbc_status); for (i=0; i<sid->num_auths; i++) { char *tmp2; tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]); BAIL_ON_PTR_ERROR(tmp2, wbc_status); tmp = tmp2; } *sid_string = tmp; tmp = NULL; wbc_status = WBC_ERR_SUCCESS; done: talloc_free(tmp); return wbc_status; }
/* Trigger a logoff notification to Winbind for a specific user */ wbcErr wbcCtxLogoffUser(struct wbcContext *ctx, const char *username, uid_t uid, const char *ccfilename) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; /* validate input */ if (!username) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } ZERO_STRUCT(request); ZERO_STRUCT(response); strncpy(request.data.logoff.user, username, sizeof(request.data.logoff.user)-1); request.data.logoff.uid = uid; if (ccfilename) { strncpy(request.data.logoff.krb5ccname, ccfilename, sizeof(request.data.logoff.krb5ccname)-1); } /* Send request */ wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF, &request, &response); /* Take the response above and return it to the caller */ done: return wbc_status; }
/** @brief Set the highwater mark for allocated gids. * * @param gid_hwm The new gid highwater mark value * * @return #wbcErr **/ wbcErr wbcSetGidHwm(gid_t gid_hwm) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); /* Make request */ request.data.dual_idmapset.id = gid_hwm; request.data.dual_idmapset.type = _ID_TYPE_GID; wbc_status = wbcRequestResponse(WINBINDD_SET_HWM, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
/* Change a password for a user */ wbcErr wbcChangeUserPassword(const char *username, const char *old_password, const char *new_password) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcChangePasswordParams params; ZERO_STRUCT(params); params.account_name = username; params.level = WBC_CHANGE_PASSWORD_LEVEL_PLAIN; params.old_password.plaintext = old_password; params.new_password.plaintext = new_password; wbc_status = wbcChangeUserPasswordEx(¶ms, NULL, NULL, NULL); BAIL_ON_WBC_ERROR(wbc_status); done: return wbc_status; }
/* Trigger an extended logoff notification to Winbind for a specific user */ wbcErr wbcCtxLogoffUserEx(struct wbcContext *ctx, const struct wbcLogoffUserParams *params, struct wbcAuthErrorInfo **error) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; size_t i; /* validate input */ if (!params || !params->username) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if ((params->num_blobs > 0) && (params->blobs == NULL)) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if ((params->num_blobs == 0) && (params->blobs != NULL)) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } ZERO_STRUCT(request); ZERO_STRUCT(response); strncpy(request.data.logoff.user, params->username, sizeof(request.data.logoff.user)-1); for (i=0; i<params->num_blobs; i++) { if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) { if (params->blobs[i].blob.data) { strncpy(request.data.logoff.krb5ccname, (const char *)params->blobs[i].blob.data, sizeof(request.data.logoff.krb5ccname) - 1); } continue; } if (strcasecmp(params->blobs[i].name, "user_uid") == 0) { if (params->blobs[i].blob.data) { memcpy(&request.data.logoff.uid, params->blobs[i].blob.data, MIN(params->blobs[i].blob.length, sizeof(request.data.logoff.uid))); } continue; } if (strcasecmp(params->blobs[i].name, "flags") == 0) { if (params->blobs[i].blob.data) { memcpy(&request.flags, params->blobs[i].blob.data, MIN(params->blobs[i].blob.length, sizeof(request.flags))); } continue; } } /* Send request */ wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF, &request, &response); /* Take the response above and return it to the caller */ 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; }
/* Convert a character string to a binary SID */ wbcErr wbcStringToSid(const char *str, struct wbcDomainSid *sid) { const char *p; char *q; uint32_t x; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!sid) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Sanity check for either "S-" or "s-" */ if (!str || (str[0]!='S' && str[0]!='s') || (str[1]!='-')) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Get the SID revision number */ p = str+2; x = (uint32_t)strtol(p, &q, 10); if (x==0 || !q || *q!='-') { wbc_status = WBC_ERR_INVALID_SID; BAIL_ON_WBC_ERROR(wbc_status); } sid->sid_rev_num = (uint8_t)x; /* Next the Identifier Authority. This is stored in big-endian in a 6 byte array. */ p = q+1; x = (uint32_t)strtol(p, &q, 10); if (!q || *q!='-') { wbc_status = WBC_ERR_INVALID_SID; BAIL_ON_WBC_ERROR(wbc_status); } sid->id_auth[5] = (x & 0x000000ff); sid->id_auth[4] = (x & 0x0000ff00) >> 8; sid->id_auth[3] = (x & 0x00ff0000) >> 16; sid->id_auth[2] = (x & 0xff000000) >> 24; sid->id_auth[1] = 0; sid->id_auth[0] = 0; /* now read the the subauthorities */ p = q +1; sid->num_auths = 0; while (sid->num_auths < WBC_MAXSUBAUTHS) { x=(uint32_t)strtoul(p, &q, 10); if (p == q) break; if (q == NULL) { wbc_status = WBC_ERR_INVALID_SID; BAIL_ON_WBC_ERROR(wbc_status); } sid->sub_auths[sid->num_auths++] = x; if (*q != '-') { break; } p = q + 1; } /* IF we ended early, then the SID could not be converted */ if (q && *q!='\0') { wbc_status = WBC_ERR_INVALID_SID; BAIL_ON_WBC_ERROR(wbc_status); } wbc_status = WBC_ERR_SUCCESS; done: return wbc_status; }
/* Lists Groups */ wbcErr wbcListGroups(const char *domain_name, uint32_t *_num_groups, const char ***_groups) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; uint32_t num_groups = 0; const char **groups = NULL; const char *next; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (domain_name) { strncpy(request.domain_name, domain_name, sizeof(request.domain_name)-1); } wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); groups = wbcAllocateStringArray(response.data.num_entries); if (groups == NULL) { return WBC_ERR_NO_MEMORY; } /* Look through extra data */ next = (const char *)response.extra_data.data; while (next) { const char *current; char *k; if (num_groups >= response.data.num_entries) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } current = next; k = strchr(next, ','); if (k) { k[0] = '\0'; next = k+1; } else { next = NULL; } groups[num_groups] = strdup(current); BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status); num_groups += 1; } if (num_groups != response.data.num_entries) { wbc_status = WBC_ERR_INVALID_RESPONSE; goto done; } *_num_groups = response.data.num_entries; *_groups = groups; groups = NULL; wbc_status = WBC_ERR_SUCCESS; done: winbindd_free_response(&response); wbcFreeMemory(groups); 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; }
/* 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; }
/* Change a password for a user with more detailed information upon failure */ wbcErr wbcCtxChangeUserPasswordEx(struct wbcContext *ctx, const struct wbcChangePasswordParams *params, struct wbcAuthErrorInfo **error, enum wbcPasswordChangeRejectReason *reject_reason, struct wbcUserPasswordPolicyInfo **policy) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; int cmd = 0; /* validate input */ if (!params->account_name) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (error) { *error = NULL; } if (policy) { *policy = NULL; } if (reject_reason) { *reject_reason = -1; } ZERO_STRUCT(request); ZERO_STRUCT(response); switch (params->level) { case WBC_CHANGE_PASSWORD_LEVEL_PLAIN: cmd = WINBINDD_PAM_CHAUTHTOK; if (!params->account_name) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } strncpy(request.data.chauthtok.user, params->account_name, sizeof(request.data.chauthtok.user) - 1); if (params->old_password.plaintext) { strncpy(request.data.chauthtok.oldpass, params->old_password.plaintext, sizeof(request.data.chauthtok.oldpass) - 1); } if (params->new_password.plaintext) { strncpy(request.data.chauthtok.newpass, params->new_password.plaintext, sizeof(request.data.chauthtok.newpass) - 1); } break; case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE: cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP; if (!params->account_name || !params->domain_name) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->old_password.response.old_lm_hash_enc_length && !params->old_password.response.old_lm_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->old_password.response.old_lm_hash_enc_length == 0 && params->old_password.response.old_lm_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->old_password.response.old_nt_hash_enc_length && !params->old_password.response.old_nt_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->old_password.response.old_nt_hash_enc_length == 0 && params->old_password.response.old_nt_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->new_password.response.lm_length && !params->new_password.response.lm_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->new_password.response.lm_length == 0 && params->new_password.response.lm_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->new_password.response.nt_length && !params->new_password.response.nt_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } if (params->new_password.response.nt_length == 0 && params->new_password.response.nt_data) { wbc_status = WBC_ERR_INVALID_PARAM; goto done; } strncpy(request.data.chng_pswd_auth_crap.user, params->account_name, sizeof(request.data.chng_pswd_auth_crap.user) - 1); strncpy(request.data.chng_pswd_auth_crap.domain, params->domain_name, sizeof(request.data.chng_pswd_auth_crap.domain) - 1); if (params->new_password.response.nt_data) { request.data.chng_pswd_auth_crap.new_nt_pswd_len = params->new_password.response.nt_length; memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, params->new_password.response.nt_data, request.data.chng_pswd_auth_crap.new_nt_pswd_len); } if (params->new_password.response.lm_data) { request.data.chng_pswd_auth_crap.new_lm_pswd_len = params->new_password.response.lm_length; memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, params->new_password.response.lm_data, request.data.chng_pswd_auth_crap.new_lm_pswd_len); } if (params->old_password.response.old_nt_hash_enc_data) { request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = params->old_password.response.old_nt_hash_enc_length; memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc, params->old_password.response.old_nt_hash_enc_data, request.data.chng_pswd_auth_crap.old_nt_hash_enc_len); } if (params->old_password.response.old_lm_hash_enc_data) { request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = params->old_password.response.old_lm_hash_enc_length; memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc, params->old_password.response.old_lm_hash_enc_data, request.data.chng_pswd_auth_crap.old_lm_hash_enc_len); } break; default: wbc_status = WBC_ERR_INVALID_PARAM; goto done; break; } /* Send request */ wbc_status = wbcRequestResponse(ctx, cmd, &request, &response); if (WBC_ERROR_IS_OK(wbc_status)) { goto done; } /* Take the response above and return it to the caller */ if (response.data.auth.nt_status != 0) { if (error) { wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } } if (policy) { wbc_status = wbc_create_password_policy_info(&response, policy); BAIL_ON_WBC_ERROR(wbc_status); } if (reject_reason) { *reject_reason = response.data.auth.reject_reason; } wbc_status = WBC_ERR_PWD_CHANGE_FAILED; BAIL_ON_WBC_ERROR(wbc_status); done: 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; }