/* * Convert 'identifier' into canonical form. * Returns a pointer to a static buffer containing the canonical form * or NULL if 'identifier' is invalid. * * XXX If any of the characters marked with 0 are valid and are cropping up, * the right thing to do is probably to canonicalize the identifier to two * representations: one for getpwent calls and one for folder names. The * latter canonicalizes to a MUTF7 representation. */ static const char *mycanonifyid(const char *identifier, size_t len) { static char retbuf[81]; struct group *grp; char sawalpha; char *p; int username_tolower = 0; if(!len) len = strlen(identifier); if(len >= sizeof(retbuf)) return NULL; memmove(retbuf, identifier, len); retbuf[len] = '\0'; /* This used to be far more restrictive, but many sites seem to ignore the * ye olde Unix conventions of username. Specifically, we used to * - drop case on the buffer * - disallow lots of non-alpha characters ('-', '_', others) * Now we do neither of these, but impose a very different policy based on * the character map above. */ if (!strncmp(retbuf, "group:", 6)) { grp = getgrnam(retbuf+6); if (!grp) return NULL; if (strlen(grp->gr_name) >= sizeof(retbuf)-6) return NULL; strcpy(retbuf+6, grp->gr_name); return retbuf; } /* Copy the string and look up values in the allowedchars array above. * If we see any we don't like, reject the string. * Lowercase usernames if requested. */ username_tolower = libcyrus_config_getswitch(CYRUSOPT_USERNAME_TOLOWER); sawalpha = 0; for(p = retbuf; *p; p++) { if (username_tolower && Uisupper(*p)) *p = tolower((unsigned char)*p); switch (allowedchars[*(unsigned char*) p]) { case 0: return NULL; case 2: sawalpha = 1; /* FALL THROUGH */ default: ; } } /* we used to enforce "has to be one alpha char" */ /* now we don't */ /* if (!sawalpha) return NULL; */ return retbuf; }
/* * Set the current user to 'identifier'. 'cacheid', if non-null, * points to a 16-byte binary key to cache identifier's information * with. */ static struct auth_state *mynewstate(const char *identifier) { struct auth_state *newstate; struct passwd *pwd; struct group *grp; #if defined(HAVE_GETGROUPLIST) && defined(__GLIBC__) gid_t gid, *groupids = NULL; int ret, ngroups = 10, oldngroups; #else char **mem; #endif identifier = mycanonifyid(identifier, 0); if (!identifier) return 0; if (!strncmp(identifier, "group:", 6)) return 0; newstate = (struct auth_state *)xmalloc(sizeof(struct auth_state)); strcpy(newstate->userid, identifier); strarray_init(&newstate->groups); if(!libcyrus_config_getswitch(CYRUSOPT_AUTH_UNIX_GROUP_ENABLE)) return newstate; pwd = getpwnam(identifier); #if defined(HAVE_GETGROUPLIST) && defined(__GLIBC__) gid = pwd ? pwd->pw_gid : (gid_t) -1; /* get the group ids */ do { groupids = (gid_t *)xrealloc((gid_t *)groupids, ngroups * sizeof(gid_t)); oldngroups = ngroups; /* copy of ngroups for comparision */ ret = getgrouplist(identifier, gid, groupids, &ngroups); /* * This is tricky. We do this as long as getgrouplist tells us to * realloc _and_ the number of groups changes. It tells us to realloc * also in the case of failure... */ } while (ret == -1 && ngroups != oldngroups); if (ret == -1) goto err; while (ngroups--) { if (pwd || groupids[ngroups] != gid) { if ((grp = getgrgid(groupids[ngroups]))) strarray_append(&newstate->groups, grp->gr_name); } } err: if (groupids) free(groupids); #else /* !HAVE_GETGROUPLIST */ setgrent(); while ((grp = getgrent())) { for (mem = grp->gr_mem; *mem; mem++) { if (!strcmp(*mem, identifier)) break; } if (*mem || (pwd && pwd->pw_gid == grp->gr_gid)) strarray_append(&newstate->groups, grp->gr_name); } endgrent(); #endif /* HAVE_GETGROUPLIST */ return newstate; }