/* 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; }
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; }
/* Convert a SID to a domain and name */ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, char **pdomain, char **pname, enum wbcSidType *pname_type) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *domain, *name; if (!sid) { return WBC_ERR_INVALID_PARAM; } /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); /* Make request */ wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request, &response); if (!WBC_ERROR_IS_OK(wbc_status)) { return wbc_status; } /* Copy out result */ wbc_status = WBC_ERR_NO_MEMORY; domain = NULL; name = NULL; domain = wbcStrDup(response.data.name.dom_name); if (domain == NULL) { goto done; } name = wbcStrDup(response.data.name.name); if (name == NULL) { goto done; } if (pdomain != NULL) { *pdomain = domain; domain = NULL; } if (pname != NULL) { *pname = name; name = NULL; } if (pname_type != NULL) { *pname_type = (enum wbcSidType)response.data.name.type; } wbc_status = WBC_ERR_SUCCESS; done: wbcFreeMemory(name); wbcFreeMemory(domain); 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; }
/* 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; }
/* 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; }
/** @brief Ping winbindd to see if the daemon is running * * @return #wbcErr **/ wbcErr wbcPing(void) { struct winbindd_request request; struct winbindd_response response; /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); return wbcRequestResponse(WINBINDD_PING, &request, &response); }
/* * 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; }
/* Authenticate a user with cached credentials */ wbcErr wbcCredentialSave(const char *user, const char *password) { struct winbindd_request request; struct winbindd_response response; ZERO_STRUCT(request); ZERO_STRUCT(response); strncpy(request.data.ccache_save.user, user, sizeof(request.data.ccache_save.user)-1); strncpy(request.data.ccache_save.pass, password, sizeof(request.data.ccache_save.pass)-1); request.data.ccache_save.uid = getuid(); return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response); }
/* * 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; }
/* 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; }
/* 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; }
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; }
/* 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; }
/* 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; }
/* Get the list of current DCs */ wbcErr wbcDcInfo(const char *domain, size_t *num_dcs, const char ***dc_names, const char ***dc_ips) { struct winbindd_request request; struct winbindd_response response; const char **names = NULL; const char **ips = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; size_t extra_len; int i; char *p; /* Initialise request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (domain != NULL) { strncpy(request.domain_name, domain, sizeof(request.domain_name) - 1); } wbc_status = wbcRequestResponse(WINBINDD_DC_INFO, &request, &response); BAIL_ON_WBC_ERROR(wbc_status); names = wbcAllocateStringArray(response.data.num_entries); BAIL_ON_PTR_ERROR(names, wbc_status); ips = wbcAllocateStringArray(response.data.num_entries); BAIL_ON_PTR_ERROR(ips, wbc_status); wbc_status = WBC_ERR_INVALID_RESPONSE; p = (char *)response.extra_data.data; if (response.length < (sizeof(struct winbindd_response)+1)) { goto done; } extra_len = response.length - sizeof(struct winbindd_response); if (p[extra_len-1] != '\0') { goto done; } for (i=0; i<response.data.num_entries; i++) { char *q; q = strchr(p, '\n'); if (q == NULL) { goto done; } names[i] = strndup(p, q-p); BAIL_ON_PTR_ERROR(names[i], wbc_status); p = q+1; q = strchr(p, '\n'); if (q == NULL) { goto done; } ips[i] = strndup(p, q-p); BAIL_ON_PTR_ERROR(ips[i], wbc_status); p = q+1; } if (p[0] != '\0') { goto done; } wbc_status = WBC_ERR_SUCCESS; done: if (response.extra_data.data) free(response.extra_data.data); if (WBC_ERROR_IS_OK(wbc_status)) { *num_dcs = response.data.num_entries; *dc_names = names; names = NULL; *dc_ips = ips; ips = NULL; } wbcFreeMemory(names); wbcFreeMemory(ips); 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 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; }
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 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; }
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; }
/* Logon a User */ wbcErr wbcCtxLogonUser(struct wbcContext *ctx, const struct wbcLogonUserParams *params, struct wbcLogonUserInfo **info, struct wbcAuthErrorInfo **error, struct wbcUserPasswordPolicyInfo **policy) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; uint32_t i; ZERO_STRUCT(request); ZERO_STRUCT(response); if (info) { *info = NULL; } if (error) { *error = NULL; } if (policy) { *policy = NULL; } if (!params) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (!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); } /* Initialize request */ request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_LMKEY; if (!params->password) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } strncpy(request.data.auth.user, params->username, sizeof(request.data.auth.user)-1); strncpy(request.data.auth.pass, params->password, sizeof(request.data.auth.pass)-1); for (i=0; i<params->num_blobs; i++) { if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) { if (params->blobs[i].blob.data) { strncpy(request.data.auth.krb5_cc_type, (const char *)params->blobs[i].blob.data, sizeof(request.data.auth.krb5_cc_type) - 1); } continue; } if (strcasecmp(params->blobs[i].name, "user_uid") == 0) { if (params->blobs[i].blob.data) { memcpy(&request.data.auth.uid, params->blobs[i].blob.data, MIN(sizeof(request.data.auth.uid), params->blobs[i].blob.length)); } continue; } if (strcasecmp(params->blobs[i].name, "flags") == 0) { if (params->blobs[i].blob.data) { uint32_t flags; memcpy(&flags, params->blobs[i].blob.data, MIN(sizeof(flags), params->blobs[i].blob.length)); request.flags |= flags; } continue; } if (strcasecmp(params->blobs[i].name, "membership_of") == 0) { if (params->blobs[i].blob.data && params->blobs[i].blob.data[0] > 0) { strncpy(request.data.auth.require_membership_of_sid, (const char *)params->blobs[i].blob.data, sizeof(request.data.auth.require_membership_of_sid) - 1); } continue; } } wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_AUTH, &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); if (info) { wbc_status = wbc_create_logon_info(&response, info); BAIL_ON_WBC_ERROR(wbc_status); } if (policy) { wbc_status = wbc_create_password_policy_info(&response, policy); BAIL_ON_WBC_ERROR(wbc_status); } done: winbindd_free_response(&response); 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; }
/* 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; }
/* 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; }
/* Authenticate with more detailed information */ wbcErr wbcCtxAuthenticateUserEx(struct wbcContext *ctx, const struct wbcAuthUserParams *params, struct wbcAuthUserInfo **info, struct wbcAuthErrorInfo **error) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; int cmd = 0; struct winbindd_request request; struct winbindd_response response; ZERO_STRUCT(request); ZERO_STRUCT(response); if (error) { *error = NULL; } if (!params) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (params->level != WBC_AUTH_USER_LEVEL_PAC && !params->account_name) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } /* Initialize request */ switch (params->level) { case WBC_AUTH_USER_LEVEL_PLAIN: cmd = WINBINDD_PAM_AUTH; request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_LMKEY; if (!params->password.plaintext) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (params->domain_name && params->domain_name[0]) { /* We need to get the winbind separator :-( */ struct winbindd_response sep_response; ZERO_STRUCT(sep_response); wbc_status = wbcRequestResponse(ctx, WINBINDD_INFO, NULL, &sep_response); BAIL_ON_WBC_ERROR(wbc_status); snprintf(request.data.auth.user, sizeof(request.data.auth.user)-1, "%s%c%s", params->domain_name, sep_response.data.info.winbind_separator, params->account_name); } else { strncpy(request.data.auth.user, params->account_name, sizeof(request.data.auth.user)-1); } strncpy(request.data.auth.pass, params->password.plaintext, sizeof(request.data.auth.pass)-1); break; case WBC_AUTH_USER_LEVEL_HASH: wbc_status = WBC_ERR_NOT_IMPLEMENTED; BAIL_ON_WBC_ERROR(wbc_status); break; case WBC_AUTH_USER_LEVEL_RESPONSE: cmd = WINBINDD_PAM_AUTH_CRAP; request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_LMKEY; if (params->password.response.lm_length && !params->password.response.lm_data) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (params->password.response.lm_length == 0 && params->password.response.lm_data) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (params->password.response.nt_length && !params->password.response.nt_data) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (params->password.response.nt_length == 0&& params->password.response.nt_data) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } strncpy(request.data.auth_crap.user, params->account_name, sizeof(request.data.auth_crap.user)-1); if (params->domain_name) { strncpy(request.data.auth_crap.domain, params->domain_name, sizeof(request.data.auth_crap.domain)-1); } if (params->workstation_name) { strncpy(request.data.auth_crap.workstation, params->workstation_name, sizeof(request.data.auth_crap.workstation)-1); } request.data.auth_crap.logon_parameters = params->parameter_control; memcpy(request.data.auth_crap.chal, params->password.response.challenge, sizeof(request.data.auth_crap.chal)); request.data.auth_crap.lm_resp_len = MIN(params->password.response.lm_length, sizeof(request.data.auth_crap.lm_resp)); if (params->password.response.lm_data) { memcpy(request.data.auth_crap.lm_resp, params->password.response.lm_data, request.data.auth_crap.lm_resp_len); } request.data.auth_crap.nt_resp_len = params->password.response.nt_length; if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) { request.flags |= WBFLAG_BIG_NTLMV2_BLOB; request.extra_len = params->password.response.nt_length; request.extra_data.data = (char *)malloc( request.extra_len); if (request.extra_data.data == NULL) { wbc_status = WBC_ERR_NO_MEMORY; BAIL_ON_WBC_ERROR(wbc_status); } memcpy(request.extra_data.data, params->password.response.nt_data, request.data.auth_crap.nt_resp_len); } else if (params->password.response.nt_data) { memcpy(request.data.auth_crap.nt_resp, params->password.response.nt_data, request.data.auth_crap.nt_resp_len); } break; case WBC_AUTH_USER_LEVEL_PAC: cmd = WINBINDD_PAM_AUTH_CRAP; request.flags = WBFLAG_PAM_AUTH_PAC | WBFLAG_PAM_INFO3_TEXT; request.extra_data.data = malloc(params->password.pac.length); if (request.extra_data.data == NULL) { wbc_status = WBC_ERR_NO_MEMORY; BAIL_ON_WBC_ERROR(wbc_status); } memcpy(request.extra_data.data, params->password.pac.data, params->password.pac.length); request.extra_len = params->password.pac.length; break; default: break; } if (cmd == 0) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } if (params->flags) { request.flags |= params->flags; } if (cmd == WINBINDD_PAM_AUTH_CRAP) { wbc_status = wbcRequestResponsePriv(ctx, cmd, &request, &response); } else { wbc_status = wbcRequestResponse(ctx, cmd, &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); if (info) { wbc_status = wbc_create_auth_info(&response, info); BAIL_ON_WBC_ERROR(wbc_status); } done: winbindd_free_response(&response); free(request.extra_data.data); return wbc_status; }