Instead of keeping separate groups and gids arrays, create struct

group_info and use it to store both, along with a count for each.
Cache group info on a per-user basis using getgrouplist() to get
the groups.  We no longer need special to special case the user or
list user for user_in_group() and thus no longer need to reset the
groups list when listing another user.
This commit is contained in:
Todd C. Miller
2011-07-20 11:58:45 -04:00
parent 906cede7ae
commit b124635b04
15 changed files with 517 additions and 288 deletions

View File

@@ -328,7 +328,7 @@ struct sudo_ldap_handle {
LDAP *ld;
struct ldap_result *result;
char *username;
char **groups;
struct group_list *grlist;
};
struct sudo_nss sudo_nss_ldap = {
@@ -974,6 +974,7 @@ sudo_ldap_build_pass1(struct passwd *pw)
{
struct group *grp;
char *buf, timebuffer[TIMEFILTER_LENGTH];
struct group_list *grlist;
size_t sz = 0;
int i;
@@ -984,16 +985,15 @@ sudo_ldap_build_pass1(struct passwd *pw)
/* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
sz += 29 + strlen(pw->pw_name);
/* Add space for groups */
/* Add space for primary and supplementary groups */
if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
sz += 12 + strlen(grp->gr_name); /* primary group */
gr_delref(grp);
sz += 12 + strlen(grp->gr_name);
}
if (strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
for (i = 0; i < user_ngroups; i++) {
if (user_gids[i] == pw->pw_gid)
if ((grlist = get_group_list(pw)) != NULL) {
for (i = 0; i < grlist->ngroups; i++) {
if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
continue;
sz += 12 + strlen(user_groups[i]); /* supplementary group */
sz += 12 + strlen(grlist->groups[i]);
}
}
@@ -1019,24 +1019,29 @@ sudo_ldap_build_pass1(struct passwd *pw)
(void) strlcat(buf, ")", sz);
/* Append primary group */
if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
if (grp != NULL) {
(void) strlcat(buf, "(sudoUser=%", sz);
(void) strlcat(buf, grp->gr_name, sz);
(void) strlcat(buf, ")", sz);
gr_delref(grp);
}
/* Append supplementary groups */
if (strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
for (i = 0; i < user_ngroups; i++) {
if (user_gids[i] == pw->pw_gid)
if (grlist != NULL) {
for (i = 0; i < grlist->ngroups; i++) {
if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
continue;
(void) strlcat(buf, "(sudoUser=%", sz);
(void) strlcat(buf, user_groups[i], sz);
(void) strlcat(buf, grlist->groups[i], sz);
(void) strlcat(buf, ")", sz);
}
}
/* Done with groups. */
if (grlist != NULL)
grlist_delref(grlist);
if (grp != NULL)
gr_delref(grp);
/* Add ALL to list and end the global OR */
if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
errorx(1, _("sudo_ldap_build_pass1 allocation mismatch"));
@@ -2022,7 +2027,7 @@ sudo_ldap_open(struct sudo_nss *nss)
handle->ld = ld;
handle->result = NULL;
handle->username = NULL;
handle->groups = NULL;
handle->grlist = NULL;
nss->handle = handle;
return 0;
@@ -2280,7 +2285,7 @@ sudo_ldap_result_free_nss(struct sudo_nss *nss)
efree(handle->username);
handle->username = NULL;
}
handle->groups = NULL;
handle->grlist = NULL;
handle->result = NULL;
}
}
@@ -2306,7 +2311,7 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
* have to contact the LDAP server again.
*/
if (handle->result) {
if (handle->groups == user_groups &&
if (handle->grlist == user_group_list &&
strcmp(pw->pw_name, handle->username) == 0) {
DPRINTF(("reusing previous result (user %s) with %d entries",
handle->username, handle->result->nentries), 1);
@@ -2380,7 +2385,7 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
/* Store everything in the sudo_nss handle. */
handle->result = lres;
handle->username = estrdup(pw->pw_name);
handle->groups = user_groups;
handle->grlist = user_group_list;
return lres;
}