/* * $Id: vldap.c,v 1.22 2007/05/22 03:59:00 rwidmer Exp $ * Copyright (C) 1999-2004 Inter7 Internet Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "vpopmail.h" #include "vauth.h" #include "vlimits.h" #include "vldap.h" LDAP *ld = NULL; LDAPMessage *glm = NULL; #ifdef CLEAR_PASS # define NUM_LDAP_FIELDS 9 #else # define NUM_LDAP_FIELDS 8 #endif char *ldap_fields[NUM_LDAP_FIELDS] = { "uid", /* 0 pw_name */ "userPassword", /* 1 pw_passwd */ "qmailUID", /* 2 pw_uid */ "qmailGID", /* 3 pw_gid */ "qmaildomain", /* 4 pw_gecos */ "mailMessageStore", /* 5 pw_dir */ "mailQuota", /* 6 pw_shell */ #ifndef CLEAR_PASS "objectclass" /* 7 ldap */ #else "clearPassword", /* 7 pw_clear_passwd */ "objectclass" /* 8 ldap */ #endif }; /***************************************************************************/ /* * get ldap connection info */ int load_connection_info() { FILE *fp; char conn_info[256]; char config[256]; int eof; static int loaded = 0; char *port; char delimiters[] = "|\n"; char *conf_read; if (loaded) return 0; loaded = 1; sprintf(config, "%s/etc/%s", VPOPMAILDIR, "vpopmail.ldap"); fp = fopen(config, "r"); if (fp == NULL) { fprintf(stderr, "vldap: can't read settings from %s\n", config); return(VA_NO_AUTH_CONNECTION); } /* skip comments and blank lines */ do { eof = (fgets (conn_info, sizeof(conn_info), fp) == NULL); } while (!eof && ((*conn_info == '#') || (*conn_info == '\n'))); if (eof) { /* no valid data read, return error */ fprintf(stderr, "vldap: no valid settings in %s\n", config); return(VA_NO_AUTH_CONNECTION); } conf_read = strdup(conn_info); VLDAP_SERVER = strtok(conf_read, delimiters); if (VLDAP_SERVER == NULL) return VA_PARSE_ERROR; port = strtok(NULL, delimiters); if (port == NULL) return VA_PARSE_ERROR; VLDAP_PORT = atoi(port); VLDAP_USER = strtok(NULL, delimiters); if (VLDAP_USER == NULL) return VA_PARSE_ERROR; VLDAP_PASSWORD = strtok(NULL, delimiters); if (VLDAP_PASSWORD == NULL) return VA_PARSE_ERROR; VLDAP_BASEDN = strtok(NULL, delimiters); if (VLDAP_BASEDN == NULL) return VA_PARSE_ERROR; return 0; } struct vqpasswd *vauth_getpw(char *user, char *domain) { int ret = 0; size_t len = 0; struct vqpasswd *vpw = NULL; LDAPMessage *res = NULL, *msg = NULL; char *filter = NULL, **vals = NULL, *h = NULL, *t = NULL, *passwd = NULL; char *dn = NULL; uid_t myuid; uid_t uid; gid_t gid; verrori = 0; lowerit(user); lowerit(domain); vget_assign(domain,NULL,0,&uid,&gid); myuid = geteuid(); if ( myuid != 0 && myuid != uid ) { return(NULL); } /* connect to the ldap server (if we havent already got a connection open) */ if (ld == NULL ) { if (ldap_connect() != 0) { safe_free((void **) &filter); return NULL; } } /* take a given domain, and set dn to be this format : * ou=somedomain.com,o=vpopmail */ if (compose_dn(&dn,domain) != 0) return NULL; /* take the username and create set filter ot be in this format : * (&(objectclass=qmailUser)(uid=someusername)) */ len = (strlen(user) + 32 + 1); filter = (char *)safe_malloc(len); memset((char *)filter, 0, len); snprintf(filter, len, "(&(objectclass=qmailUser)(uid=%s))", user); /* perform an ldap search * int ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res) * * Will search synchronously, and not return until the operation completes. * base : DN of the entry at which to start the search * scope : scope of the search * LDAP_SCOPE_SUBTREE means to search the object and all of its descendents. * filter : filter to apply to the search * attrs : attribute types to return from entries that match filter * attrsonly : set to 0 for attributes and attributetypes are wanted. 1 if only attributes are wanted. */ ret = ldap_search_s(ld, dn, LDAP_SCOPE_SUBTREE, filter, vldap_attrs, 0, &res); safe_free((void **) &filter); /* see if the search ran without generating an error */ if (ret != LDAP_SUCCESS ) { ldap_perror(ld,"Error"); return NULL; } /* grab a pointer to the 1st entry in the chain of search results */ msg = ldap_first_entry(ld, res); if (msg == NULL) { /* We had an error grabbing the pointer */ return NULL; } /* find out how many matches we found */ ret = ldap_count_entries(ld, msg); if (ret == -1 ) { /* an error occurred when counting the entries */ ldap_perror(ld,"Error"); return NULL; } /* Fetch userPassword first so we can make sure we're able to handle it's password encryption (if any) */ /* userPasswd / pw_password */ vals = ldap_get_values(ld, msg, "userPassword"); if (vals == NULL) { ldap_perror(ld,"Error"); return NULL; } t = h = NULL; passwd = (char *)safe_malloc((strlen(*vals) + 1)); memset((char *)passwd, 0, (strlen(*vals) + 1)); memcpy((char *)passwd, (char *)(*vals), strlen(*vals)); if (*passwd == '{') { for (t = h = (passwd + 1); *t; t++) { if (*t == '}') { *t++ = '\0'; /* This is not the best, but we keep the pointer as (h - 1) */ passwd = t; /* Check against the encryption method, and if we see something we dont recognize or support, invalidate user login. vol@inter7.com */ /* Steki Thu Jan 24 17:27:18 CET 2002 * Added check for MD5 crypted passwords */ if (strcmp(h, "crypt")&& strcmp(h, "MD5")) { free(h - 1); ldap_value_free(vals); return NULL; } break; } } /* No terminating brace found, or empty password. vol@inter7.com */ if (!(*t)) { ldap_value_free(vals); return NULL; } } /* create a vpw struct, which we will populate with the data we suck in from ldap */ vpw = (struct vqpasswd *) safe_malloc(sizeof(struct vqpasswd)); memset((struct vqpasswd *)vpw, 0, sizeof(struct vqpasswd)); vpw->pw_passwd = (char *)safe_malloc((strlen(passwd) + 1)); memset((char *)vpw->pw_passwd, 0, (strlen(passwd) + 1)); memcpy((char *)vpw->pw_passwd, (char *)(passwd), strlen(passwd)); if (vpw->pw_passwd == NULL) { free(h - 1); ldap_value_free(vals); return NULL; } /* Old passwd pointer. ..and don't forget to check if you even set the pointer *smack* vol@inter7.com */ if (h) free(h - 1); ldap_value_free(vals); /* uid / pw_name */ vals = ldap_get_values(ld, msg, "uid"); if (vals == NULL) { safe_free((void **) &vpw->pw_passwd); ldap_perror(ld,"Error"); return NULL; } vpw->pw_name = (char *)safe_malloc((strlen(*vals) + 1)); memset((char *)vpw->pw_name, 0, (strlen(*vals) + 1)); memcpy((char *)vpw->pw_name, (char *)(*vals), strlen(*vals)); ldap_value_free(vals); /* mailQuota / pw_shell */ vals = ldap_get_values(ld, msg, "mailQuota"); if (vals) vpw->pw_shell = (char *)safe_malloc((strlen(*vals) + 1)); else vpw->pw_shell = (char *)safe_malloc(1); if (vals) { memset((char *)vpw->pw_shell, 0, (strlen(*vals) + 1)); memcpy((char *)vpw->pw_shell, (char *)(*vals), strlen(*vals)); ldap_value_free(vals); } else { *vpw->pw_shell = '\0'; ldap_perror(ld,"Error"); } /* qmaildomain / pw_gecos */ vals = ldap_get_values(ld, msg, "qmaildomain"); if ( vals ) { vpw->pw_gecos = (char *)safe_malloc((strlen(*vals) + 1)); memset((char *)vpw->pw_gecos, 0, (strlen(*vals) + 1)); memcpy((char *)vpw->pw_gecos, (char *)(*vals), strlen(*vals)); ldap_value_free(vals); } else ldap_perror(ld,"Error"); /* mailMessageStore / pw_dir */ vals = ldap_get_values(ld, msg, "mailMessageStore"); if ( vals ) { vpw->pw_dir = (char *)safe_malloc((strlen(*vals) + 1)); memset((char *)vpw->pw_dir, 0, (strlen(*vals) + 1)); memcpy((char *)vpw->pw_dir, (char *)(*vals), strlen(*vals)); ldap_value_free(vals); } else ldap_perror(ld,"Error"); /* qmailUID / pw_uid */ vals = ldap_get_values(ld, msg, "qmailUID"); if ( vals ) { vpw->pw_uid = atoi(*vals); ldap_value_free(vals); } else ldap_perror(ld,"Error"); /* qmailGID / pw_gid */ vals = ldap_get_values(ld, msg, "qmailGID"); if ( vals ) { vpw->pw_gid = atoi(*vals); ldap_value_free(vals); } else ldap_perror(ld,"Error"); #ifdef CLEAR_PASS /* clearPasswd / pw_clear_passwd */ vals = ldap_get_values(ld, msg, "clearPassword"); if ( vals ) { vpw->pw_clear_passwd = (char *)safe_malloc((strlen(*vals) + 1)); memset((char *)vpw->pw_clear_passwd, 0, (strlen(*vals) + 1)); memcpy((char *)vpw->pw_clear_passwd, (char *)(*vals), strlen(*vals)); ldap_value_free(vals); } #endif vlimits_setflags (vpw, domain); return vpw; } /***************************************************************************/ void vauth_end_getall() {} /***************************************************************************/ struct vqpasswd *vauth_getall(char *domain, int first, int sortit) { int ret = 0; size_t len = 0; struct vqpasswd *pw = NULL; LDAPMessage *res = NULL; char *filter = NULL, **vals = NULL; char *basedn = NULL; /* if 1st time through, extract all users from this chosen domain */ if (first) { lowerit(domain); len = (32 + 1); filter = (char *)safe_malloc(len); memset((char *)filter, 0, len); /* connect to the ldap server if we havent already done so */ if (ld == NULL ) { if (ldap_connect() != 0) { safe_free((void **) &filter); return NULL; } } /* set basedn to be of the format : * ou=somedomain,o=vpopmail */ if (compose_dn(&basedn,domain) != 0) { safe_free((void **) &filter); return NULL; } snprintf(filter, len, "(objectclass=qmailUser)"); /* perform the lookup for all users in a given domain */ ret = ldap_search_s(ld, basedn, LDAP_SCOPE_SUBTREE, filter, vldap_attrs, 0, &res); safe_free((void **) &basedn); safe_free((void **) &filter); if (ret != LDAP_SUCCESS) { ldap_perror(ld,"Error"); return NULL; } /* sort the entries alphabetically by username if required */ if ( sortit ) { if ( ldap_sort_entries( ld, &res, "uid", &strcasecmp ) != 0) { ldap_perror(ld,"Error"); return NULL; } if (ret != LDAP_SUCCESS) return NULL; } /* get a pointer to the first user in the list */ glm = ldap_first_entry(ld, res); if (glm == NULL) return NULL; /* grab the ldap properties of this user */ vals = ldap_get_values(ld, glm, "uid"); if (vals == NULL) { ldap_perror(ld,"Error"); return NULL; } /* grab the vpopmail properties of this user */ pw = vauth_getpw(*vals, domain); return pw; } else { /* not 1st time through, so get next entry from the chain */ if (glm == NULL) /* Just to be safe. (vol@inter7.com) */ return NULL; res = glm; glm = ldap_next_entry(ld, res); if (glm == NULL) return NULL; vals = ldap_get_values(ld, glm, "uid"); if (vals == NULL) { ldap_perror(ld,"Error"); return NULL; } pw = vauth_getpw(*vals, domain); ldap_value_free(vals); return pw; } } /***************************************************************************/ /* Higher-level functions no longer crypt. Lame. vol@inter7.com */ int vauth_adduser(char *user, char *domain, char *password, char *gecos, char *dir, int apop ) { char *dn = NULL; char *dn_tmp = NULL; LDAPMod **lm = NULL; char dom_dir[156]; uid_t uid; gid_t gid; int ret = 0, vd = 0; int i,len; char *b = NULL; char crypted[100] = { 0 }; if ((dir) && (*dir)) vd = 1; if ( gecos==0 || gecos[0]==0) gecos=user; /* take a given domain, and lookup the dom_dir, uid, gid */ if ( vget_assign(domain, dom_dir, 156, &uid, &gid ) == NULL ) { fprintf(stderr, "failed to vget_assign the domain : %s", domain); return (-1); } if (vd) { ret = strlen(dom_dir) + 5 + strlen(dir) + strlen(user); } else { ret = strlen(dom_dir) + 5 + strlen(user); } b = (char *)safe_malloc(ret); memset((char *)b, 0, ret); if (vd) { snprintf(b, ret, "%s/%s/%s", dom_dir, dir, user); } else { snprintf(b, ret, "%s/%s", dom_dir, user); } dir = b; /* make an ldap connection (unless we already have one open) */ if (ld == NULL ) { if (ldap_connect() != 0) return -99; } lm = (LDAPMod **)safe_malloc(sizeof(LDAPMod *) * (NUM_LDAP_FIELDS +1)); for(i=0;imod_op = LDAP_MOD_ADD; lm[i]->mod_type = safe_strdup(ldap_fields[i]); lm[i]->mod_values = (char **)safe_malloc(sizeof(char *) * 2); lm[i]->mod_values[1] = NULL; } lm[NUM_LDAP_FIELDS] = NULL; /* lm[0] will store : uid / pw_name */ lm[0]->mod_values[0] = safe_strdup(user); /* lm[1] will store : userPassword / pw_password */ memset((char *)crypted, 0, 100); if ( password[0] == 0 ) { crypted[0] = 0; } else { mkpasswd3(password, crypted, 100); } lm[1]->mod_values[0] = (char *) safe_malloc(strlen(crypted) + 7 + 1); #ifdef MD5_PASSWORDS snprintf(lm[1]->mod_values[0], strlen(crypted) + 7 + 1, "{MD5}%s", crypted); #else snprintf(lm[1]->mod_values[0], strlen(crypted) + 7 + 1, "{crypt}%s", crypted); #endif /* lm[2] will store : qmailUID / pw_uid */ lm[2]->mod_values[0] = (char *) safe_malloc(10); if ( apop == USE_POP ) sprintf(lm[2]->mod_values[0], "%d", 1 ); else sprintf(lm[2]->mod_values[0], "%d", 2 ); /* lm[3] will store : qmailGID / pw_gid */ lm[3]->mod_values[0] = (char *) safe_malloc(10); sprintf(lm[3]->mod_values[0], "%d", 0); /* lm[4] will store : qmaildomain / pw_gecos */ lm[4]->mod_values[0] = safe_strdup(gecos); /* lm[5] will store : mailMessageStore / pw_dir */ lm[5]->mod_values[0] = safe_strdup(dir); /* lm[6] will store : mailQuota / pw_shell */ lm[6]->mod_values[0] = safe_strdup("NOQUOTA"); /* When running with clearpasswords enabled, * lm[7] will store : clearPassword / pw_clear_password */ #ifdef CLEAR_PASS /* with clear passwords, * lm[7] will store : clearPassword / pw_clear_password * lm[8] will store : objectclass */ lm[7]->mod_values[0] = strdup(password); lm[8]->mod_values[0] = safe_strdup("qmailUser"); #else /* without clear passwords, * lm[7] will store : objectclass */ lm[7]->mod_values[0] = safe_strdup("qmailUser"); #endif /* set dn_tmp to be of the format : * ou=somedomain.com,o=vpopmail */ if (compose_dn(&dn_tmp,domain) != 0) { for(i=0;i<8;++i) { safe_free((void **) &lm[i]->mod_type); safe_free((void **) &lm[i]->mod_values[0]); } safe_free((void **) &lm); safe_free((void **) &dn); return -98; } /* set dn to be of the format : * uid=someuser, ou=somedomain,o=vpopmail */ len = 4 + strlen(user) + 2 + strlen(VLDAP_BASEDN) + 4 + strlen(domain) + 1; dn = (char *) safe_malloc(len); memset((char *)dn, 0, len); snprintf(dn, len, "uid=%s, %s", user, dn_tmp); safe_free((void **) &dn_tmp); /* add object to ldap * dn is the DN of the entry to add * lm is the attributes of the entry to add */ ret = ldap_add_s(ld, dn, lm); safe_free((void **) &dn); for(i=0;imod_type); safe_free((void **) &lm[i]->mod_values[0]); } safe_free((void **) &lm); if (ret != LDAP_SUCCESS) { ldap_perror(ld,"Error"); if (ret == LDAP_ALREADY_EXISTS) return VA_USERNAME_EXISTS; return -99; } return VA_SUCCESS; } /***************************************************************************/ int vauth_adddomain( char *domain ) { int ret = 0; char *dn = NULL; LDAPMod **lm = NULL; /* make a connection to the ldap server, if we are not already connected */ if (ld == NULL ) { ret = ldap_connect(); if (ret != 0) { return -99; /* Attention I am not quite shure, when we return NULL or -99, see above */ } } lm = (LDAPMod **)safe_malloc(sizeof(LDAPMod *) * 2); lm[0] = (LDAPMod *)safe_malloc(sizeof(LDAPMod)); lm[1] = (LDAPMod *)safe_malloc(sizeof(LDAPMod)); lm[2] = NULL; memset((LDAPMod *)lm[0], 0, sizeof(LDAPMod)); memset((LDAPMod *)lm[1], 0, sizeof(LDAPMod)); lm[0]->mod_op = LDAP_MOD_ADD; lm[1]->mod_op = LDAP_MOD_ADD; lm[0]->mod_type = safe_strdup("ou"); lm[1]->mod_type = safe_strdup("objectclass"); lm[0]->mod_values = (char **)safe_malloc(sizeof(char *) * 2); lm[1]->mod_values = (char **)safe_malloc(sizeof(char *) * 2); lm[0]->mod_values[1] = NULL; lm[1]->mod_values[1] = NULL; lm[0]->mod_values[0] = safe_strdup(domain); lm[1]->mod_values[0] = safe_strdup("organizationalUnit"); /* set dn to be of the format : * ou=somedomain.com,o=vpopmail */ if (compose_dn(&dn,domain) != 0 ) { safe_free((void **) &lm[0]->mod_type); safe_free((void **) &lm[1]->mod_type); safe_free((void **) &lm[0]->mod_values[0]); safe_free((void **) &lm[1]->mod_values[0]); safe_free((void **) &lm[1]); safe_free((void **) &lm[0]); safe_free((void **) &lm); return -98; } /* dn will be ou=somedomain.com,o=vpopmail * lm will be the ldap propoerties of somedomain.com */ ret = ldap_add_s(ld, dn, lm); if (ret != LDAP_SUCCESS) { ldap_perror(ld,"Error"); return -99; } safe_free((void **) &dn); safe_free((void **) &lm[0]->mod_type); safe_free((void **) &lm[1]->mod_type); safe_free((void **) &lm[0]->mod_values[0]); safe_free((void **) &lm[1]->mod_values[0]); safe_free((void **) &lm[2]); safe_free((void **) &lm[1]); safe_free((void **) &lm[0]); safe_free((void **) &lm); if (ret != LDAP_SUCCESS) { if (ret == LDAP_ALREADY_EXISTS) return VA_USERNAME_EXISTS; return -99; } return VA_SUCCESS; } /***************************************************************************/ int vauth_deldomain( char *domain ) { int ret = 0; size_t len = 0; char *dn = NULL; struct vqpasswd *pw = NULL; /* make a connection to the ldap server, if we dont have one already */ if (ld == NULL ) { if (ldap_connect() != 0) return -99; } len = strlen(domain) + strlen(VLDAP_BASEDN) + 4 + 1; /* dn will be of the format : * ou=somedomain.com,o=vpopmail */ if (compose_dn(&dn,domain) != 0) return -98; /* loop through all the users in the domain, deleting each one */ for (pw = vauth_getall(domain, 1, 0); pw; pw = vauth_getall(domain, 0, 0)) vauth_deluser(pw->pw_name, domain); /* next, delete the actual domain */ ret = ldap_delete_s(ld, dn); safe_free((void **) &dn); if (ret != LDAP_SUCCESS ) { ldap_perror(ld,"Error"); return -99; } return VA_SUCCESS; } /***************************************************************************/ int vauth_vpasswd( char *user, char *domain, char *crypted, int apop ) { int ret = 0; struct vqpasswd *pw = NULL; pw = vauth_getpw(user, domain); if (pw == NULL) return VA_USER_DOES_NOT_EXIST; pw->pw_passwd = safe_strdup(crypted); ret = vauth_setpw(pw, domain); return ret; } /***************************************************************************/ int vauth_deluser( char *user, char *domain ) { int ret = 0; size_t len = 0; char *dn = NULL; char *dn_tmp = NULL; /* make a connection to the ldap server if we dont have one already */ if (ld == NULL ) { if (ldap_connect() != 0) return -99; } len = 4 + strlen(user) + 2 + strlen(VLDAP_BASEDN) + 4 + strlen(domain) + 1; /* make dn_tmp to be of the format * ou=somedomain.com,o=vpopmail */ if (compose_dn(&dn_tmp,domain) != 0) return -98; dn = (char *)safe_malloc(len); memset((char *)dn, 0, len); /* make dn to be of the format * uid=someuser, ou=somedomain.com,o=vpopmail */ snprintf(dn, len, "uid=%s, %s", user, dn_tmp); safe_free((void **) &dn_tmp); /* delete the user */ ret = ldap_delete_s(ld, dn); safe_free((void **) &dn); if (ret != LDAP_SUCCESS) { ldap_perror(ld,"Error"); return -99; } return VA_SUCCESS; } /***************************************************************************/ int vauth_setquota( char *username, char *domain, char *quota) { int ret = 0; struct vqpasswd *pw = NULL; if ( strlen(username) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG); #ifdef USERS_BIG_DIR if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME); #endif if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG); if ( strlen(quota) > MAX_PW_QUOTA ) return(VA_QUOTA_TOO_LONG); pw = vauth_getpw(username, domain); if ( (pw == NULL) && (verrori != 0)) return verrori; else if ( pw == NULL ) return VA_USER_DOES_NOT_EXIST; pw->pw_shell = safe_strdup(quota); ret = vauth_setpw(pw, domain); return ret; } /***************************************************************************/ int vauth_setpw( struct vqpasswd *inpw, char *domain ) { int ret = 0; size_t len = 0; char *dn = NULL; char *dn_tmp = NULL; LDAPMod **lm = NULL; int i; #ifdef SQWEBMAIL_PASS uid_t uid; gid_t gid; #endif ret = vcheck_vqpw(inpw, domain); if ( ret != 0 ) { return(ret); } if (ld == NULL ) { if (ldap_connect() != 0) return -99; } lm = (LDAPMod **)malloc(sizeof(LDAPMod *) * NUM_LDAP_FIELDS + 1); for(i=0;imod_op = LDAP_MOD_REPLACE; lm[i]->mod_values = (char **)safe_malloc(sizeof(char *) * 2); lm[i]->mod_values[1] = NULL; lm[i]->mod_type = safe_strdup(ldap_fields[i]); } lm[NUM_LDAP_FIELDS] = NULL; lm[0]->mod_values[0] = safe_strdup(inpw->pw_name); lm[1]->mod_values[0] = safe_malloc(strlen(inpw->pw_passwd) + 7 + 1); #ifdef MD5_PASSWORDS snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd) + 7 + 1, "{MD5}%s", inpw->pw_passwd); #else snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd) + 7 + 1, "{crypt}%s", inpw->pw_passwd); #endif lm[2]->mod_values[0] = (char *)safe_malloc(10); sprintf(lm[2]->mod_values[0], "%d", inpw->pw_uid); lm[3]->mod_values[0] = (char *) safe_malloc(10); sprintf(lm[3]->mod_values[0], "%d", inpw->pw_gid); if ( inpw->pw_gecos == NULL) { lm[4]->mod_values[0] = safe_strdup(""); } else { lm[4]->mod_values[0] = safe_strdup(inpw->pw_gecos); } lm[5]->mod_values[0] = safe_strdup(inpw->pw_dir); lm[6]->mod_values[0] = safe_strdup(inpw->pw_shell); #ifdef CLEAR_PASS lm[7]->mod_values[0] = safe_strdup(inpw->pw_clear_passwd); #endif lm[NUM_LDAP_FIELDS-1]->mod_values[0] = strdup("qmailUser"); if (compose_dn(&dn_tmp,domain) != 0 ) { safe_free((void **) &lm); return -98; } len = 4 + strlen(inpw->pw_name) + 2 + strlen(VLDAP_BASEDN) + 4 + strlen(domain) + 1; dn = (char *) safe_malloc (len); memset((char *)dn, 0, len); snprintf(dn, len, "uid=%s, %s", inpw->pw_name, dn_tmp); ret = ldap_modify_s(ld, dn, lm); safe_free((void **) &dn); for(i=0;ipw_dir, inpw->pw_passwd, uid, gid); #endif #ifdef ONCHANGE_SCRIPT if( allow_onchange ) { /* tell other programs that data has changed */ snprintf ( onchange_buf, MAX_BUFF, "%s@%s", inpw->pw_name, domain ); call_onchange ( "mod_user" ); } #endif return VA_SUCCESS; } /***************************************************************************/ /* Verify the connection to the authentication database */ int vauth_open( int will_update ) { #ifdef VPOPMAIL_DEBUG show_trace = ( getenv("VPSHOW_TRACE") != NULL); show_query = ( getenv("VPSHOW_QUERY") != NULL); dump_data = ( getenv("VPDUMP_DATA") != NULL); #endif #ifdef VPOPMAIL_DEBUG if( show_trace ) { fprintf( stderr, "vauth_open()\n"); } #endif /* * If the connection to this authentication database can fail * you should test access here. If it works, return 0, else * return VA_NO_AUTH_CONNECTION. You can also set the string * sqlerr to some short descriptive text about the problem, * and allocate a much longer string, pointed to by last_query * that can be displayed in an error message returned because * of this problem. * */ return( 0 ); } /***************************************************************************/ void vclose(void) { if (ld) { ldap_unbind_s(ld); ld = NULL; } } /***************************************************************************/ char *dc_filename(char *domain, uid_t uid, gid_t gid) { static char dir_control_file[MAX_DIR_NAME]; struct passwd *pw; /* if we are lucky the domain is in the assign file */ if ( vget_assign(domain,dir_control_file,MAX_DIR_NAME,NULL,NULL)!=NULL ) { strncat(dir_control_file, "/.dir-control", MAX_DIR_NAME); /* it isn't in the assign file so we have to get it from /etc/passwd */ } else { /* save some time if this is the vpopmail user */ if ( uid == VPOPMAILUID ) { strncpy(dir_control_file, VPOPMAILDIR, MAX_DIR_NAME); /* for other users, look them up in /etc/passwd */ } else if ( (pw=getpwuid(uid))!=NULL ) { strncpy(dir_control_file, pw->pw_dir, MAX_DIR_NAME); /* all else fails return a blank string */ } else { return(""); } /* stick on the rest of the path */ strncat(dir_control_file, "/" DOMAINS_DIR "/.dir-control", MAX_DIR_NAME); } return(dir_control_file); } int vread_dir_control(vdir_type *vdir, char *domain, uid_t uid, gid_t gid) { FILE *fs; char dir_control_file[MAX_DIR_NAME]; int i; strncpy(dir_control_file,dc_filename(domain, uid, gid),MAX_DIR_NAME); if ( (fs = fopen(dir_control_file, "r")) == NULL ) { vdir->cur_users = 0; for(i=0;ilevel_start[i] = 0; vdir->level_end[i] = MAX_DIR_LIST-1; vdir->level_index[i] = 0; } vdir->level_mod[0] = 0; vdir->level_mod[1] = 2; vdir->level_mod[2] = 4; vdir->level_cur = 0; vdir->level_max = MAX_DIR_LEVELS; vdir->the_dir[0] = 0; return(-1); } fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->cur_users = atol(dir_control_file); fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->level_cur = atoi(dir_control_file); fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->level_max = atoi(dir_control_file); fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->level_start[0] = atoi(dir_control_file); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_start[1] = atoi(&dir_control_file[i]); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_start[2] = atoi(&dir_control_file[i]); fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->level_end[0] = atoi(dir_control_file); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_end[1] = atoi(&dir_control_file[i]); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_end[2] = atoi(&dir_control_file[i]); fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->level_mod[0] = atoi(dir_control_file); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_mod[1] = atoi(&dir_control_file[i]); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_mod[2] = atoi(&dir_control_file[i]); fgets(dir_control_file, MAX_DIR_NAME, fs ); vdir->level_index[0] = atoi(dir_control_file); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_index[1] = atoi(&dir_control_file[i]); for(i=0;dir_control_file[i]!=' ';++i); ++i; vdir->level_index[2] = atoi(&dir_control_file[i]); fgets(dir_control_file, MAX_DIR_NAME, fs ); for(i=0;dir_control_file[i]!=0;++i) { if (dir_control_file[i] == '\n') { dir_control_file[i] = 0; } } fgets(dir_control_file, MAX_DIR_NAME, fs ); for(i=0;dir_control_file[i]!=0;++i) { if (dir_control_file[i] == '\n') { dir_control_file[i] = 0; } } strncpy(vdir->the_dir, dir_control_file, MAX_DIR_NAME); fclose(fs); return(0); } int vwrite_dir_control(vdir_type *vdir, char *domain, uid_t uid, gid_t gid) { FILE *fs; char dir_control_file[MAX_DIR_NAME]; char dir_control_tmp_file[MAX_DIR_NAME]; strncpy(dir_control_file,dc_filename(domain, uid, gid),MAX_DIR_NAME); snprintf(dir_control_tmp_file, MAX_DIR_NAME, "%s.%d", dir_control_file, getpid()); if ( (fs = fopen(dir_control_tmp_file, "w+")) == NULL ) { return(-1); } fprintf(fs, "%lu\n", vdir->cur_users); fprintf(fs, "%d\n", vdir->level_cur); fprintf(fs, "%d\n", vdir->level_max); fprintf(fs, "%d %d %d\n", vdir->level_start[0], vdir->level_start[1], vdir->level_start[2]); fprintf(fs, "%d %d %d\n", vdir->level_end[0], vdir->level_end[1], vdir->level_end[2]); fprintf(fs, "%d %d %d\n", vdir->level_mod[0], vdir->level_mod[1], vdir->level_mod[2]); fprintf(fs, "%d %d %d\n", vdir->level_index[0], vdir->level_index[1], vdir->level_index[2]); fprintf(fs, "%s\n", vdir->the_dir); fclose(fs); rename( dir_control_tmp_file, dir_control_file); chown(dir_control_file,uid, gid); return(0); } int vdel_dir_control(char *domain) { char dir_control_file[MAX_DIR_NAME]; vget_assign(domain, dir_control_file, 156, NULL,NULL); strncat(dir_control_file,"/.dir-control", MAX_DIR_NAME); return(unlink(dir_control_file)); } /***************************************************************************/ #ifdef ENABLE_AUTH_LOGGING int vset_lastauth_time(char *user, char *domain, char *remoteip, time_t cur_time ) { char *tmpbuf; FILE *fs; struct vqpasswd *vpw; struct utimbuf ubuf; uid_t uid; gid_t gid; if ((vpw = vauth_getpw( user, domain )) == NULL) return (0); tmpbuf = (char *) safe_malloc(MAX_BUFF); sprintf(tmpbuf, "%s/lastauth", vpw->pw_dir); if ( (fs = fopen(tmpbuf,"w+")) == NULL ) { safe_free((void **) &tmpbuf); return(-1); } fprintf(fs, "%s", remoteip); fclose(fs); ubuf.actime = cur_time; ubuf.modtime = cur_time; utime(tmpbuf, &ubuf); vget_assign(domain,NULL,0,&uid,&gid); chown(tmpbuf,uid,gid); safe_free((void **) &tmpbuf); return(0); } int vset_lastauth(char *user, char *domain, char *remoteip ) { return(vset_lastauth_time(user, domain, remoteip, time(NULL) )); } time_t vget_lastauth( struct vqpasswd *pw, char *domain) { char *tmpbuf; struct stat mystatbuf; tmpbuf = (char *) safe_malloc(MAX_BUFF); sprintf(tmpbuf, "%s/lastauth", pw->pw_dir); if ( stat(tmpbuf,&mystatbuf) == -1 ) { safe_free((void **) &tmpbuf); return(0); } safe_free((void **) &tmpbuf); return(mystatbuf.st_mtime); } char *vget_lastauthip( struct vqpasswd *pw, char *domain) { static char tmpbuf[MAX_BUFF]; FILE *fs; snprintf(tmpbuf, MAX_BUFF, "%s/lastauth", pw->pw_dir); if ( (fs=fopen(tmpbuf,"r"))==NULL) return(NULL); fgets(tmpbuf,MAX_BUFF,fs); fclose(fs); return(tmpbuf); } #endif /* ENABLE_AUTH_LOGGING */ /***************************************************************************/ #ifdef IP_ALIAS_DOMAINS int vget_ip_map( char *ip, char *domain, int domain_size) { FILE *fs; char tmpbuf[156]; char *tmpstr; if ( ip == NULL || strlen(ip) <= 0 ) return(-1); /* open the ip_alias_map file */ snprintf(tmpbuf, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE); if ( (fs = fopen(tmpbuf,"r")) == NULL ) return(-1); while( fgets(tmpbuf, 156, fs) != NULL ) { tmpstr = strtok(tmpbuf, IP_ALIAS_TOKENS); if ( tmpstr == NULL ) continue; if ( strcmp(ip, tmpstr) != 0 ) continue; tmpstr = strtok(NULL, IP_ALIAS_TOKENS); if ( tmpstr == NULL ) continue; strncpy(domain, tmpstr, domain_size); fclose(fs); return(0); } fclose(fs); return(-1); } /***************************************************************************/ /* * Add an ip to domain mapping * It will remove any duplicate entry before adding it * */ int vadd_ip_map( char *ip, char *domain) { FILE *fs; char tmpbuf[156]; if ( ip == NULL || strlen(ip) <= 0 ) return(-1); if ( domain == NULL || strlen(domain) <= 0 ) return(-10); vdel_ip_map( ip, domain ); snprintf(tmpbuf, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE); if ( (fs = fopen(tmpbuf,"a+")) == NULL ) return(-1); fprintf( fs, "%s %s\n", ip, domain); fclose(fs); return(0); } int vdel_ip_map( char *ip, char *domain) { FILE *fs; FILE *fs1; char file1[156]; char file2[156]; char tmpbuf[156]; char tmpbuf1[156]; char *ip_f; char *domain_f; if ( ip == NULL || strlen(ip) <= 0 ) return(-1); if ( domain == NULL || strlen(domain) <= 0 ) return(-1); snprintf(file1, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE); if ( (fs = fopen(file1,"r")) == NULL ) return(-1); snprintf(file2, 156, "%s/%s.%d", VPOPMAILDIR, IP_ALIAS_MAP_FILE, getpid()); if ( (fs1 = fopen(file2,"w")) == NULL ) { fclose(fs); return(-1); } while( fgets(tmpbuf, 156, fs) != NULL ) { strncpy(tmpbuf1,tmpbuf, 156); ip_f = strtok(tmpbuf, IP_ALIAS_TOKENS); if ( ip_f == NULL ) continue; domain_f = strtok(NULL, IP_ALIAS_TOKENS); if ( domain_f == NULL ) continue; if ( strcmp(ip, ip_f) == 0 && strcmp(domain,domain_f) == 0) continue; fprintf(fs1, tmpbuf1); } fclose(fs); fclose(fs1); if ( rename( file2, file1) < 0 ) return(-1); return(0); } int vshow_ip_map( int first, char *ip, char *domain) { static FILE *fs = NULL; char tmpbuf[156]; char *tmpstr; if ( ip == NULL ) return(-1); if ( domain == NULL ) return(-1); if ( first == 1 ) { if ( fs != NULL ) { fclose(fs); fs = NULL; } snprintf(tmpbuf, 156, "%s/%s", VPOPMAILDIR, IP_ALIAS_MAP_FILE); if ( (fs = fopen(tmpbuf,"r")) == NULL ) return(-1); } if ( fs == NULL ) return(-1); while (1) { if (fgets(tmpbuf, 156, fs) == NULL ) { fclose(fs); fs = NULL; return(0); } tmpstr = strtok(tmpbuf, IP_ALIAS_TOKENS); if ( tmpstr == NULL ) continue; strcpy( ip, tmpstr); tmpstr = strtok(NULL, IP_ALIAS_TOKENS); if ( tmpstr == NULL ) continue; strcpy( domain, tmpstr); return(1); } return(-1); } #endif /***************************************************************************/ /* take a given domain, and set dn to be a string of this format : * ou=somedomain,o=vpopmail */ int compose_dn (char **dn, char *domain) { size_t len = 0; len = strlen(domain) + strlen(VLDAP_BASEDN) + 5; *dn = (char *)safe_malloc(len); memset((char *)*dn, 0, len); snprintf(*dn,len,"ou=%s,%s",domain,VLDAP_BASEDN); return 0; } /***************************************************************************/ int ldap_connect () { int ret = 0; /* Set verror here and unset it when successful, is ok, because if one of these three steps fail the whole auth_connection failed */ verrori = load_connection_info(); if (verrori) return -1; ld = ldap_init(VLDAP_SERVER, VLDAP_PORT); if (ld == NULL) { ldap_perror(ld,"Failed to inititialize LDAP-Connection"); return -99; } ret = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &ldapversion ); if (ret != LDAP_OPT_SUCCESS) { ldap_perror(ld,"Failed to set LDAP-Option"); return -99; } ret = ldap_simple_bind_s(ld, VLDAP_USER, VLDAP_PASSWORD); if (ret != LDAP_SUCCESS) { ldap_perror(ld,"Error"); return (VA_NO_AUTH_CONNECTION); } verrori = 0; return VA_SUCCESS; } /***************************************************************************/ void safe_free (void **p) { if (*p) { free (*p); *p = 0; } } /***************************************************************************/ char *safe_strdup (const char *s) { char *p; size_t l; if (!s || !*s) return 0; l = strlen (s) + 1; p = (char *)safe_malloc (l); memcpy (p, s, l); return (p); } /***************************************************************************/ void *safe_malloc (size_t siz) { void *p; if (siz == 0) return 0; if ((p = (void *) malloc (siz)) == 0) { printf("No more memory...exiting\n"); exit (1); } return (p); } /***************************************************************************/ int vauth_crypt(char *user,char *domain,char *clear_pass,struct vqpasswd *vpw) { if ( vpw == NULL ) return(-1); return(strcmp(crypt(clear_pass,vpw->pw_passwd),vpw->pw_passwd)); } /***************************************************************************/