--- lib/auth_plain.orig Sun Dec 26 16:49:14 1999 +++ lib/auth_plain.c Sun Dec 26 16:45:23 1999 @@ -0,0 +1,250 @@ +/* auth_unix.c -- Unix passwd file authorization + * + * Copyright 1998 by Carnegie Mellon University + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of CMU not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + */ + +/* + * $Id: auth_unix.c,v 1.25 1999/01/09 08:32:59 tjs Exp $ + */ + +#include +#include +#include +#include + +#include "auth.h" +#include "xmalloc.h" + +struct auth_state { + char userid[81]; + char **group; + int ngroups; +}; + +static struct auth_state auth_anonymous = { + "anonymous", 0, 0 +}; + +/* + * Determine if the user is a member of 'identifier' + * Returns one of: + * 0 User does not match identifier + * 1 identifier matches everybody + * 2 User is in the group that is identifier + * 3 User is identifer + */ +auth_memberof(auth_state, identifier) +struct auth_state *auth_state; +const char *identifier; +{ + int i; + + if (!auth_state) auth_state = &auth_anonymous; + + if (strcmp(identifier, "anyone") == 0) return 1; + + if (strcmp(identifier, auth_state->userid) == 0) return 3; + + if (strncmp(identifier, "group:", 6) != 0) return 0; + + for (i=0; ingroups; i++) { + if (strcmp(identifier+6, auth_state->group[i]) == 0) return 2; + } + return 0; +} + +/* Map of which characters are allowed by auth_canonifyid. + * Key: 0 -> not allowed (special, ctrl, or would confuse Unix or imapd) + * 1 -> allowed, but requires an alpha somewhere else in the string + * 2 -> allowed, and is an alpha + * + * At least one character must be an alpha. + * + * This may not be restrictive enough. + * Here are the reasons for the restrictions: + * + * & forbidden because of MUTF-7. (This could be fixed.) + * : forbidden because it's special in /etc/passwd + * / forbidden because it can't be used in a mailbox name + * * % forbidden because they're IMAP magic in the LIST/LSUB commands + * ? it just scares me + * ctrl chars, DEL + * can't send them as IMAP characters in plain folder names, I think + * 80-FF forbidden because you can't send them in IMAP anyway + * (and they're forbidden as folder names). (This could be fixed.) + * + * + and - are *allowed* although '+' is probably used for userid+detail + * subaddressing and qmail users use '-' for subaddressing. + * + * Identifiers don't require a digit, really, so that should probably be + * relaxed, too. + */ +static char allowedchars[256] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00-0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10-1F */ + 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* 20-2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 30-3F */ + + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 40-4F */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, /* 50-5F */ + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 60-6F */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, /* 70-7F */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * 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. + */ +char *auth_canonifyid(identifier) +const char *identifier; +{ + static char retbuf[81]; + struct group *grp; + char sawalpha; + char *p; + + if (strcasecmp(identifier, "anonymous") == 0) { + return "anonymous"; + } + if (strcasecmp(identifier, "anybody") == 0 || + strcasecmp(identifier, "anyone") == 0) { + return "anyone"; + } + + if (strlen(identifier) >= sizeof(retbuf)) return 0; + strcpy(retbuf, identifier); + + /* 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 0; + strcpy(retbuf+6, grp->gr_name); + return retbuf; + } + + if (strlen(identifier) >= sizeof(retbuf)) return 0; + + /* Copy the string and look up values in the allowedchars array above. + * If we see any we don't like, reject the string. + */ + p = retbuf; + sawalpha = 0; + while (*identifier) { + *p = *identifier++; + + switch (allowedchars[*(unsigned char*) p]) { + case 0: + return NULL; + + case 2: + sawalpha = 1; + /* FALL THROUGH */ + + default: + ; + } + p++; + } + *p = 0; + + if (!sawalpha) return NULL; /* has to be one alpha char */ + + 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. + */ +struct auth_state * +auth_newstate(identifier, cacheid) +const char *identifier; +const char *cacheid; +{ + struct auth_state *newstate; + struct passwd *pwd; + struct group *grp; + char **mem; + + identifier = auth_canonifyid(identifier); + if (!identifier) return 0; + if (!strncmp(identifier, "group:", 6)) return 0; + + pwd = getpwnam(identifier); + + newstate = (struct auth_state *)xmalloc(sizeof(struct auth_state)); + + strcpy(newstate->userid, identifier); + newstate->ngroups = 0; + newstate->group = (char **) 0; + + 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)) { + newstate->ngroups++; + newstate->group = (char **)xrealloc((char *)newstate->group, + newstate->ngroups * sizeof(char *)); + newstate->group[newstate->ngroups-1] = xstrdup(grp->gr_name); + } + } + endgrent(); + return newstate; +} + +void +auth_freestate(auth_state) +struct auth_state *auth_state; +{ + if (auth_state->group) free((char *)auth_state->group); + free((char *)auth_state); +} + +