/* take a group id and return a filled struct group */ static struct group *wb_aix_getgrgid(gid_t gid) { struct winbindd_response response; struct winbindd_request request; struct group *grp; NSS_STATUS ret; logit("getgrgid %d\n", gid); ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.gid = gid; ret = winbindd_request_response(NULL, WINBINDD_GETGRGID, &request, &response); logit("getgrgid ret=%d\n", ret); HANDLE_ERRORS(ret); grp = fill_grent(&response.data.gr, response.extra_data.data); winbindd_free_response(&response); return grp; }
/* take a username and return a filled struct passwd */ static struct passwd *wb_aix_getpwnam(const char *name) { struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; struct passwd *pwd; if (*name == WB_AIX_ENCODED) { return wb_aix_getpwuid(decode_id(name)); } logit("getpwnam '%s'\n", name); ZERO_STRUCT(response); ZERO_STRUCT(request); STRCPY_RETNULL(request.data.username, name); ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM, &request, &response); HANDLE_ERRORS(ret); pwd = fill_pwent(&response.data.pw); winbindd_free_response(&response); logit("getpwnam gave ptr %p\n", pwd); return pwd; }
/* take a group name and return a filled struct group */ static struct group *wb_aix_getgrnam(const char *name) { struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; struct group *grp; if (*name == WB_AIX_ENCODED) { return wb_aix_getgrgid(decode_id(name)); } logit("getgrnam '%s'\n", name); ZERO_STRUCT(response); ZERO_STRUCT(request); STRCPY_RETNULL(request.data.groupname, name); ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM, &request, &response); HANDLE_ERRORS(ret); grp = fill_grent(&response.data.gr, response.extra_data.data); winbindd_free_response(&response); return grp; }
/* take a uid and return a filled struct passwd */ static struct passwd *wb_aix_getpwuid(uid_t uid) { struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; struct passwd *pwd; logit("getpwuid '%d'\n", uid); ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.uid = uid; ret = winbindd_request_response(NULL, WINBINDD_GETPWUID, &request, &response); HANDLE_ERRORS(ret); pwd = fill_pwent(&response.data.pw); winbindd_free_response(&response); logit("getpwuid gave ptr %p\n", pwd); return pwd; }
NSS_STATUS _nss_winbind_endgrent(void) { NSS_STATUS ret; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: endgrent\n", getpid()); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif if (num_gr_cache > 0) { ndx_gr_cache = num_gr_cache = 0; winbindd_free_response(&getgrent_response); } ret = winbindd_request_response(NULL, WINBINDD_ENDGRENT, NULL, NULL); #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
NSS_STATUS winbindd_get_response(struct winbindd_response *response) { struct winbindd_response lresponse; if (!response) { ZERO_STRUCT(lresponse); response = &lresponse; } init_response(response); /* Wait for reply */ if (winbindd_read_reply(response) == -1) { /* Set ENOENT for consistency. Required by some apps */ errno = ENOENT; return NSS_STATUS_UNAVAIL; } /* Throw away extra data if client didn't request it */ if (response == &lresponse) { winbindd_free_response(response); } /* Copy reply data from socket */ if (response->result != WINBINDD_OK) { return NSS_STATUS_NOTFOUND; } return NSS_STATUS_SUCCESS; }
/* list groups */ static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size) { NSS_STATUS ret; struct winbindd_request request; struct winbindd_response response; int len; char *s; if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) { logit("invalid lsgroup op\n"); errno = EINVAL; return -1; } ZERO_STRUCT(request); ZERO_STRUCT(response); ret = winbindd_request_response(NULL, WINBINDD_LIST_GROUPS, &request, &response); if (ret != 0) { errno = EINVAL; return -1; } len = strlen(response.extra_data.data); s = malloc(len+2); if (!s) { winbindd_free_response(&response); errno = ENOMEM; return -1; } memcpy(s, response.extra_data.data, len+1); replace_commas(s); results[0].attr_un.au_char = s; results[0].attr_flag = 0; winbindd_free_response(&response); return 0; }
/* take a username and return a string containing a comma-separated list of group id numbers to which the user belongs */ static char *wb_aix_getgrset(char *user) { struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; int i, idx; char *tmpbuf; int num_gids; gid_t *gid_list; char *r_user = user; if (*user == WB_AIX_ENCODED) { r_user = decode_user(r_user); if (!r_user) { errno = ENOENT; return NULL; } } logit("getgrset '%s'\n", r_user); ZERO_STRUCT(response); ZERO_STRUCT(request); STRCPY_RETNULL(request.data.username, r_user); if (*user == WB_AIX_ENCODED) { free(r_user); } ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS, &request, &response); HANDLE_ERRORS(ret); num_gids = response.data.num_entries; gid_list = (gid_t *)response.extra_data.data; /* allocate a space large enough to contruct the string */ tmpbuf = malloc(num_gids*12); if (!tmpbuf) { return NULL; } for (idx=i=0; i < num_gids-1; i++) { idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]); } idx += sprintf(tmpbuf+idx, "%u", gid_list[i]); winbindd_free_response(&response); return tmpbuf; }
static int winbindd_read_reply(struct winbindd_response *response) { int result1, result2 = 0; if (!response) { return -1; } /* Read fixed length response */ result1 = winbind_read_sock(response, sizeof(struct winbindd_response)); /* We actually send the pointer value of the extra_data field from the server. This has no meaning in the client's address space so we clear it out. */ response->extra_data.data = NULL; if (result1 == -1) { return -1; } if (response->length < sizeof(struct winbindd_response)) { return -1; } /* Read variable length response */ if (response->length > sizeof(struct winbindd_response)) { int extra_data_len = response->length - sizeof(struct winbindd_response); /* Mallocate memory for extra data */ if (!(response->extra_data.data = malloc(extra_data_len))) { return -1; } result2 = winbind_read_sock(response->extra_data.data, extra_data_len); if (result2 == -1) { winbindd_free_response(response); return -1; } } /* Return total amount of data read */ return result1 + result2; }
/* return a list of group SIDs for a user SID */ NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids, int *num_groups, char *buffer, size_t buf_size, int *errnop) { NSS_STATUS ret; struct winbindd_request request; struct winbindd_response response; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif ZERO_STRUCT(request); ZERO_STRUCT(response); strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1); request.data.sid[sizeof(request.data.sid) - 1] = '\0'; ret = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response); if (ret != NSS_STATUS_SUCCESS) { goto done; } if (buf_size < response.length - sizeof(response)) { ret = NSS_STATUS_TRYAGAIN; errno = *errnop = ERANGE; goto done; } *num_groups = response.data.num_entries; *group_sids = buffer; memcpy(buffer, response.extra_data.data, response.length - sizeof(response)); errno = *errnop = 0; done: winbindd_free_response(&response); #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
/* map a user or group name to a SID string */ NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; struct winbindd_response response; struct winbindd_request request; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif ZERO_STRUCT(response); ZERO_STRUCT(request); strncpy(request.data.name.name, name, sizeof(request.data.name.name) - 1); request.data.name.name[sizeof(request.data.name.name) - 1] = '\0'; ret = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response); if (ret != NSS_STATUS_SUCCESS) { *errnop = errno = EINVAL; goto failed; } if (buflen < strlen(response.data.sid.sid)+1) { ret = NSS_STATUS_TRYAGAIN; *errnop = errno = ERANGE; goto failed; } *errnop = errno = 0; *sid = buffer; strcpy(*sid, response.data.sid.sid); failed: winbindd_free_response(&response); #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
/* map a gid to a SID string */ NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; struct winbindd_response response; struct winbindd_request request; #ifdef DEBUG_NSS fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.gid = gid; ret = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response); if (ret != NSS_STATUS_SUCCESS) { *errnop = errno = EINVAL; goto failed; } if (buflen < strlen(response.data.sid.sid)+1) { ret = NSS_STATUS_TRYAGAIN; *errnop = errno = ERANGE; goto failed; } *errnop = errno = 0; *sid = buffer; strcpy(*sid, response.data.sid.sid); failed: winbindd_free_response(&response); #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
/* authenticate a user */ static int wb_aix_authenticate(char *user, char *pass, int *reenter, char **message) { struct winbindd_request request; struct winbindd_response response; NSS_STATUS result; char *r_user = user; logit("authenticate '%s' response='%s'\n", user, pass); *reenter = 0; *message = NULL; /* Send off request */ ZERO_STRUCT(request); ZERO_STRUCT(response); if (*user == WB_AIX_ENCODED) { r_user = decode_user(r_user); if (!r_user) { return AUTH_NOTFOUND; } } STRCPY_RET(request.data.auth.user, r_user); STRCPY_RET(request.data.auth.pass, pass); if (*user == WB_AIX_ENCODED) { free(r_user); } result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response); winbindd_free_response(&response); logit("auth result %d for '%s'\n", result, user); if (result == NSS_STATUS_SUCCESS) { errno = 0; return AUTH_SUCCESS; } return AUTH_FAILURE; }
/* change a user password */ static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message) { struct winbindd_request request; struct winbindd_response response; NSS_STATUS result; char *r_user = user; if (*user == WB_AIX_ENCODED) { r_user = decode_user(r_user); if (!r_user) { errno = ENOENT; return -1; } } logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass); *message = NULL; /* Send off request */ ZERO_STRUCT(request); ZERO_STRUCT(response); STRCPY_RET(request.data.chauthtok.user, r_user); STRCPY_RET(request.data.chauthtok.oldpass, oldpass); STRCPY_RET(request.data.chauthtok.newpass, newpass); if (*user == WB_AIX_ENCODED) { free(r_user); } result = winbindd_request_response(NULL, WINBINDD_PAM_CHAUTHTOK, &request, &response); winbindd_free_response(&response); if (result == NSS_STATUS_SUCCESS) { errno = 0; return 0; } errno = EINVAL; return -1; }
static NSS_STATUS _nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args) { nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; int af; ZERO_STRUCT(response); ZERO_STRUCT(request); /* I assume there that AI_ADDRCONFIG cases are handled in nss frontend code, at least it seems done so in solaris... we will give NO_DATA for pure IPv6; IPv4 will be returned for AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map IPv4 to IPv6. */ #if defined(AF_INET6) #ifdef HAVE_NSS_XBYY_KEY_IPNODE af = argp->key.ipnode.af_family; if(af == AF_INET6 && argp->key.ipnode.flags == 0) { argp->h_errno = NO_DATA; return NSS_STATUS_UNAVAIL; } #else /* I'm not that sure if this is correct, but... */ af = AF_INET6; #endif #endif strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1); request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0'; if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response)) == NSS_STATUS_SUCCESS ) { ret = parse_response(af, argp, &response); } winbindd_free_response(&response); return ret; }
static NSS_STATUS _nss_winbind_hosts_getbyname(nss_backend_t* be, void *args) { nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; ZERO_STRUCT(response); ZERO_STRUCT(request); strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1); request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0'; if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response)) == NSS_STATUS_SUCCESS ) { ret = parse_response(AF_INET, argp, &response); } winbindd_free_response(&response); return ret; }
static NSS_STATUS _nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args) { NSS_STATUS ret; struct winbindd_response response; struct winbindd_request request; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args; const char *p; ZERO_STRUCT(response); ZERO_STRUCT(request); #if defined(AF_INET6) /* winbindd currently does not resolve IPv6 */ if(argp->key.hostaddr.type == AF_INET6) { argp->h_errno = NO_DATA; return NSS_STATUS_UNAVAIL; } p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr, request.data.winsreq, sizeof request.data.winsreq); #else snprintf(request.data.winsreq, sizeof request.data.winsreq, "%u.%u.%u.%u", ((unsigned char *)argp->key.hostaddr.addr)[0], ((unsigned char *)argp->key.hostaddr.addr)[1], ((unsigned char *)argp->key.hostaddr.addr)[2], ((unsigned char *)argp->key.hostaddr.addr)[3]); #endif ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response); if( ret == NSS_STATUS_SUCCESS) { parse_response(argp->key.hostaddr.type, argp, &response); } winbindd_free_response(&response); return ret; }
NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; static struct winbindd_response response; struct winbindd_request request; static int keep_response; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif /* If our static buffer needs to be expanded we are called again */ if (!keep_response || uid != response.data.pw.pw_uid) { /* Call for the first time */ ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.uid = uid; ret = winbindd_request_response(NULL, WINBINDD_GETPWUID, &request, &response); if (ret == NSS_STATUS_SUCCESS) { ret = fill_pwent(result, &response.data.pw, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { keep_response = true; *errnop = errno = ERANGE; goto done; } } } else { /* We've been called again */ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { *errnop = errno = ERANGE; goto done; } keep_response = false; *errnop = errno = 0; } winbindd_free_response(&response); done: #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(), (unsigned int)uid, nss_err_str(ret), ret); #endif #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
/* 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; }
/* 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; }
/* 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; }
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; }
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; }
/* 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; }
/* 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; }
/* 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; }
NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; static struct winbindd_response response; struct winbindd_request request; static int keep_response; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif /* If our static buffer needs to be expanded we are called again */ /* Or if the stored response group name differs from the request. */ if (!keep_response || gid != response.data.gr.gr_gid) { /* Call for the first time */ ZERO_STRUCT(request); ZERO_STRUCT(response); request.data.gid = gid; ret = winbindd_request_response(NULL, WINBINDD_GETGRGID, &request, &response); if (ret == NSS_STATUS_SUCCESS) { ret = fill_grent(result, &response.data.gr, (char *)response.extra_data.data, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { keep_response = true; *errnop = errno = ERANGE; goto done; } } } else { /* We've been called again */ ret = fill_grent(result, &response.data.gr, (char *)response.extra_data.data, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { keep_response = true; *errnop = errno = ERANGE; goto done; } keep_response = false; *errnop = 0; } winbindd_free_response(&response); done: #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(), (unsigned int)gid, nss_err_str(ret), ret); #endif #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
static NSS_STATUS winbind_getgrent(enum winbindd_cmd cmd, struct group *result, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; static struct winbindd_request request; static int called_again; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getgrent\n", getpid()); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif /* Return an entry from the cache if we have one, or if we are called again because we exceeded our static buffer. */ if ((ndx_gr_cache < num_gr_cache) || called_again) { goto return_result; } /* Else call winbindd to get a bunch of entries */ if (num_gr_cache > 0) { winbindd_free_response(&getgrent_response); } ZERO_STRUCT(request); ZERO_STRUCT(getgrent_response); request.data.num_entries = MAX_GETGRENT_USERS; ret = winbindd_request_response(NULL, cmd, &request, &getgrent_response); if (ret == NSS_STATUS_SUCCESS) { struct winbindd_gr *gr_cache; int mem_ofs; /* Fill cache */ ndx_gr_cache = 0; num_gr_cache = getgrent_response.data.num_entries; /* Return a result */ return_result: gr_cache = (struct winbindd_gr *) getgrent_response.extra_data.data; /* Check data is valid */ if (gr_cache == NULL) { ret = NSS_STATUS_NOTFOUND; goto done; } /* Fill group membership. The offset into the extra data for the group membership is the reported offset plus the size of all the winbindd_gr records returned. */ mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs + num_gr_cache * sizeof(struct winbindd_gr); ret = fill_grent(result, &gr_cache[ndx_gr_cache], ((char *)getgrent_response.extra_data.data)+mem_ofs, &buffer, &buflen); /* Out of memory - try again */ if (ret == NSS_STATUS_TRYAGAIN) { called_again = true; *errnop = errno = ERANGE; goto done; } *errnop = 0; called_again = false; ndx_gr_cache++; /* If we've finished with this lot of results free cache */ if (ndx_gr_cache == num_gr_cache) { ndx_gr_cache = num_gr_cache = 0; winbindd_free_response(&getgrent_response); } } done: #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; struct winbindd_request request; static int called_again; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwent\n", getpid()); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif /* Return an entry from the cache if we have one, or if we are called again because we exceeded our static buffer. */ if ((ndx_pw_cache < num_pw_cache) || called_again) { goto return_result; } /* Else call winbindd to get a bunch of entries */ if (num_pw_cache > 0) { winbindd_free_response(&getpwent_response); } ZERO_STRUCT(request); ZERO_STRUCT(getpwent_response); request.data.num_entries = MAX_GETPWENT_USERS; ret = winbindd_request_response(NULL, WINBINDD_GETPWENT, &request, &getpwent_response); if (ret == NSS_STATUS_SUCCESS) { struct winbindd_pw *pw_cache; /* Fill cache */ ndx_pw_cache = 0; num_pw_cache = getpwent_response.data.num_entries; /* Return a result */ return_result: pw_cache = (struct winbindd_pw *) getpwent_response.extra_data.data; /* Check data is valid */ if (pw_cache == NULL) { ret = NSS_STATUS_NOTFOUND; goto done; } ret = fill_pwent(result, &pw_cache[ndx_pw_cache], &buffer, &buflen); /* Out of memory - try again */ if (ret == NSS_STATUS_TRYAGAIN) { called_again = true; *errnop = errno = ERANGE; goto done; } *errnop = errno = 0; called_again = false; ndx_pw_cache++; /* If we've finished with this lot of results free cache */ if (ndx_pw_cache == num_pw_cache) { ndx_pw_cache = num_pw_cache = 0; winbindd_free_response(&getpwent_response); } } done: #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }
/* Return passwd struct from username */ NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer, size_t buflen, int *errnop) { NSS_STATUS ret; static struct winbindd_response response; struct winbindd_request request; static int keep_response; #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name); #endif #if HAVE_PTHREAD pthread_mutex_lock(&winbind_nss_mutex); #endif /* If our static buffer needs to be expanded we are called again */ if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) { /* Call for the first time */ ZERO_STRUCT(response); ZERO_STRUCT(request); strncpy(request.data.username, name, sizeof(request.data.username) - 1); request.data.username [sizeof(request.data.username) - 1] = '\0'; ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM, &request, &response); if (ret == NSS_STATUS_SUCCESS) { ret = fill_pwent(result, &response.data.pw, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { keep_response = true; *errnop = errno = ERANGE; goto done; } } } else { /* We've been called again */ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { keep_response = true; *errnop = errno = ERANGE; goto done; } keep_response = false; *errnop = errno = 0; } winbindd_free_response(&response); done: #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(), name, nss_err_str(ret), ret); #endif #if HAVE_PTHREAD pthread_mutex_unlock(&winbind_nss_mutex); #endif return ret; }