Ok, I'm attaching the patch. This is for 1.6.24, 
and there are some things that could use some 
work. Right now, all the LDAP stuff is set with 
defines (this was done for a specific case, so 
that was fine at the time). This was pretty much 
directly taken from the auth_unix.c groups setup. 
If anyone finds this useful, perhaps they would 
like to make it simpler to use.
        The important things are the server address and the 
search options. You need to define a couple 
things. The server and basedn are simple and can 
probably be easily broken out into configuration 
options.
        The search string is different. MY_LDAP_GIDATTR is 
the attribute you want to search on. The 
MY_LDAP_UIDATTR and MY_LDAP_EXTRA are used in 
conjunction with the username to form the search 
string (In this case, the uniqueMember entry in 
the group matched the fully qualified dn of the 
user). This is on line 305 and will almost 
definitely need to be altered to be useful. I am 
not sure how this could be broken out simply, and 
am open to ideas.
        If anyone has suggestions, questions, or comments 
on this, please let me know.

Jules Agee wrote:

> Yes, having LDAP groups would make shared mailboxes usable in our 
> organization without adding a great deal of administration overhead as 
> it would without LDAP.
> 
> Todd Nemanich wrote:
> 
>> I actually have some code to do LDAP based groups. It is not 
>> excessively flexible, because I don't really know LDAP. But I'm sure 
>> it could be easily adapted to take the search constraints as a 
>> configuration option. Is anyone interested in this?
>>
>> Lawrence Greenfield wrote:
>>
>>>    From: "Tim Pushor" <[EMAIL PROTECTED]>
>>>    Date: Tue, 20 Nov 2001 14:38:31 -0700
>>>
>>>    While we are talking about taking cyrus and SASL to the next 
>>> level, is there
>>>    any plan to remove the dependance that Cyrus has on UNIX groups 
>>> for group
>>>    based ACL's?
>>>
>>> Well, it doesn't.  It can also use the AFS PTS server for groups.
>>> We (CMU) haven't written anything else because we haven't yet needed
>>> anything else.  I can easily imagine an LDAP authorization module
>>> working much the same way the PTS authorization module works, and it's
>>> something we'll probably look into doing, but only when we really feel
>>> the need.
>>>
>>> It shouldn't be all that hard for someone else to write such an LDAP
>>> authorization module.
>>>
>>> Larry
>>>
>>>
>>>
>>
>>
>>
> 
> 

diff -Naur ../cyrus-imapd-1.6.24/configure cyrus-imapd-1.6.24/configure
--- ../cyrus-imapd-1.6.24/configure     Tue May 23 21:11:17 2000
+++ cyrus-imapd-1.6.24/configure        Mon Jun 25 12:49:58 2001
@@ -3000,6 +3000,9 @@
        fi
 fi
 
+if test "$WITH_AUTH" = krb_pts; then
+       LIBS="$SAVE_LIBS -lldap -llber"
+fi
 
 if test "$WITH_AUTH" = krb_pts; then
        EXTRA_SUBDIRS="${EXTRA_SUBDIRS} ptclient"
diff -Naur ../cyrus-imapd-1.6.24/configure.in cyrus-imapd-1.6.24/configure.in
--- ../cyrus-imapd-1.6.24/configure.in  Tue May 16 10:50:40 2000
+++ cyrus-imapd-1.6.24/configure.in     Mon Jun 25 12:49:01 2001
@@ -408,6 +408,9 @@
        fi)
 AC_SUBST(WITH_AUTH)
 if test "$WITH_AUTH" = krb_pts; then
+       LIBS="$SAVE_LIBS -lldap -llber"
+fi
+if test "$WITH_AUTH" = krb_pts; then
        EXTRA_SUBDIRS="${EXTRA_SUBDIRS} ptclient"
        EXTRA_OUTPUT="${EXTRA_OUTPUT} ptclient/Makefile"
        AC_DEFINE_UNQUOTED(CYRUS_PATH,"$cyrus_prefix")
diff -Naur ../cyrus-imapd-1.6.24/lib/auth_ldap.c cyrus-imapd-1.6.24/lib/auth_ldap.c
--- ../cyrus-imapd-1.6.24/lib/auth_ldap.c       Wed Dec 31 19:00:00 1969
+++ cyrus-imapd-1.6.24/lib/auth_ldap.c  Mon Jun 25 12:26:16 2001
@@ -0,0 +1,314 @@
+/*
+ * $Id: auth_ldap.c,v 0.90 2001/06/25 08:32:59 todd Exp $
+ */
+
+/*
+#include <pwd.h>
+#include <grp.h>
+*/
+#include <ctype.h>
+#include <string.h>
+#include <lber.h>
+#include <ldap.h>
+#include <stdlib.h>
+
+#include "auth.h"
+#include "xmalloc.h"
+
+struct auth_state {
+    char userid[81];
+    char **group;
+    int ngroups;
+};
+
+/* These defines set how the searching is done to get the group lists Cyrus IMAP */
+
+#define MY_LDAP_SERVER "10.0.11.6"
+#define MY_LDAP_BASEDN "ou=maillists,ou=groups,dc=my,dc=toplevel"
+#define MY_LDAP_GIDATTR        "uniqueMember"
+#define MY_LDAP_UIDATTR        "cn"
+#define MY_LDAP_EXTRA  ",ou=people,dc=my,dc=toplevel"
+
+
+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; i<auth_state->ngroups; 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, 0, 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;
+
+    /* Here we hit the LDAP to get our groups */
+
+    get_users_groups(identifier,&newstate->group,&newstate->ngroups);
+    
+
+/*
+    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);
+}
+
+
+/* 
+       Returns:
+               0 - ok
+               1 - Error connecting to LDAP
+               2 - Error during anonymous bind
+               3 - Error during search
+*/
+int get_users_groups(char * cn, char *** groups,int * grpct) {
+       LDAP *ld;
+       LDAPMessage *result,*entry;
+       char *attrs[2];
+       char filter[200];
+       char *dn,*thisatr;
+       char **vals,**atrval,**atit;
+       int ldbind_res,tmp;
+
+       vals=NULL;
+       if ((ld = ldap_open(MY_LDAP_SERVER,LDAP_PORT)) == NULL) {
+               return 1;
+       }
+       if (ldap_simple_bind_s(ld,"","") != LDAP_SUCCESS) {
+               ldap_unbind(ld);
+               return 2;
+       }
+       
+snprintf(filter,200,"%s=%s=%s%s",MY_LDAP_GIDATTR,MY_LDAP_UIDATTR,cn,MY_LDAP_EXTRA);
+
+       /* We trust the LDAP, so only get the group names that match */
+       attrs[0]="cn";
+       attrs[1]=NULL;
+
+       if (ldap_search_s(ld,MY_LDAP_BASEDN,LDAP_SCOPE_SUBTREE,filter,attrs,0,&result) 
+!= LDAP_SUCCESS) {
+               ldap_unbind(ld);
+               return 3;
+       }
+
+       /* Now we pull out our values */
+       *grpct=ldap_count_entries(ld,result);
+       if (*grpct > 0) {
+               tmp=0;
+               vals=calloc(*grpct,sizeof(char*));
+               entry=ldap_first_entry(ld,result);
+               while(tmp < *grpct) {
+                       atrval=NULL;
+                       atrval=ldap_get_values(ld,entry,MY_LDAP_UIDATTR);
+                       atit=atrval;
+                       while(*atit) {
+                               vals[tmp]=strdup(*atit);
+                               atit++;
+                       }
+                       ldap_value_free(atrval);
+                       entry=ldap_next_entry(ld,entry);
+                       tmp++;
+               }
+               
+       }
+
+       *groups=vals;
+       ldap_unbind(ld);
+       return 0;
+
+
+}
+
+

Reply via email to