📄 vpopmail.c
字号:
struct vqpasswd *vauth_user(char *user, char *domain, char* password, char *apop) { struct vqpasswd *mypw; char *tmpstr; uid_t uid; gid_t gid; if ( password == NULL ) return(NULL); mypw = vauth_getpw(user, domain); if ( mypw == NULL ) return(NULL); if ( vauth_crypt(user, domain, password, mypw) != 0 ) return(NULL); tmpstr = vget_assign(domain, NULL, 0, &uid, &gid ); mypw->pw_uid = uid; mypw->pw_gid = gid; return(mypw); }/************************************************************************//* * default_domain() * returns a pointer to a string, containing * the default domain (or blank if not set). Loads from * ~vpopmail/etc/defaultdomain. Only loads once per program * execution. */char *default_domain(){ static int init = 0; static char d[MAX_PW_DOMAIN]; char path[MAX_BUFF]; int dlen; FILE *fs; if (!init) { init++; d[0] = '\0'; /* make sure d is empty in case file doesn't exist */ snprintf (path, sizeof(path), "%s/etc/defaultdomain", VPOPMAILDIR); fs = fopen (path, "r"); if (fs != NULL) { fgets (d, sizeof(d), fs); fclose (fs); dlen = strlen(d) - 1; if (d[dlen] == '\n') { d[dlen] = '\0'; } } } return d;} /************************************************************************//* * If domain is blank, set it to the VPOPMAIL_DOMAIN environment * variable, an ip alias domain, or the default domain. */void vset_default_domain( char *domain ) { char *tmpstr, *cp;#ifdef IP_ALIAS_DOMAINS char host[MAX_BUFF];#endif if (domain != NULL) { if (strlen(domain)>0) { /* domain isnt blank, so dont try to set it */ return; } } /* domain is blank, so now try various lookups to set it */ tmpstr = getenv("VPOPMAIL_DOMAIN"); if ( tmpstr != NULL) { /* As a security precaution, remove all but good chars */ for (cp = tmpstr; *(cp += strspn(cp, ok_env_chars)); /* */) {*cp='_';} /* Michael Bowe 14th August 2003 * How can we prevent possible buffer overflows here * For the moment, stick with a conservative size of MAX_PW_DOMAIN */ snprintf(domain, MAX_PW_DOMAIN, "%s", tmpstr); return; }#ifdef IP_ALIAS_DOMAINS tmpstr = getenv("TCPLOCALIP"); /* courier-imap uses IPv6 */ if ( tmpstr != NULL ) { /* As a security precaution, remove all but good chars */ for (cp = tmpstr; *(cp += strspn(cp, ok_env_chars)); ) {*cp='_';} /* Michael Bowe 14th August 2003 * Mmmm Yuk below. What if TCPLOCALIP=":\0" * Buffer overflow. * Need to perhaps at least check strlen of tmpstr */ if ( tmpstr[0] == ':') { tmpstr +=2; while(*tmpstr!=':') ++tmpstr; ++tmpstr; } } memset(host,0,sizeof(host)); /* take the ip address that the connection was made to * and go and look this up in our vip map * and then store the domain into the host var */ if ( vget_ip_map(tmpstr,host,sizeof(host))==0 && !host_in_locals(host)){ if ( strlen(host) > 0 ) { /* Michael Bowe 14th August 2003 * How can we prevent possible buffer overflows here * For the moment, stick with a conservative size of MAX_PW_DOMAIN */ snprintf(domain, MAX_PW_DOMAIN, "%s", host); } return; }#endif /* IP_ALIAS_DOMAINS */ /* Michael Bowe 14th August 2003 * How can we prevent possible buffer overflows here * For the moment, stick with a conservative size of MAX_PW_DOMAIN */ snprintf(domain, MAX_PW_DOMAIN, "%s", DEFAULT_DOMAIN);}/************************************************************************/#ifdef IP_ALIAS_DOMAINS/* look to see if the nominated domain is is locals file * return 1 if there is a match * return 0 if there is no match */int host_in_locals(char *domain){ int i; char tmpbuf[MAX_BUFF]; FILE *fs; snprintf(tmpbuf, sizeof(tmpbuf), "%s/control/locals", QMAILDIR); if ((fs = fopen(tmpbuf,"r")) == NULL) { return(0); } while( fgets(tmpbuf,sizeof(tmpbuf),fs) != NULL ) { /* usually any newlines into nulls */ for(i=0;tmpbuf[i]!=0;++i) if (tmpbuf[i]=='\n') tmpbuf[i]=0; /* Michael Bowe 14th August 2003 * What happens if domain isnt null terminated? */ if (( strcmp( domain, tmpbuf)) == 0 ) { /* we found a match */ fclose(fs); return(1); } /* always match with localhost */ if ( strcmp(domain, "localhost") == 0 && strstr(domain,"localhost") != NULL ) { fclose(fs); return(1); } } fclose(fs); return(0);}#endif/************************************************************************//* Convert error flag to text */char *verror(int va_err ){ switch(va_err) { case VA_SUCCESS: return("Success"); case VA_ILLEGAL_USERNAME: return("Illegal username"); case VA_USERNAME_EXISTS: return("Username exists"); case VA_BAD_DIR: return("Unable to chdir to vpopmail directory"); case VA_BAD_U_DIR: return("Unable to chdir to vpopmail/users directory"); case VA_BAD_D_DIR: return("Unable to chdir to vpopmail/" DOMAINS_DIR " directory"); case VA_BAD_V_DIR: return("Unable to chdir to vpopmail/" DOMAINS_DIR "/domain directory"); case VA_EXIST_U_DIR: return("User's directory already exists?"); case VA_BAD_U_DIR2: return("Unable to chdir to user's directory"); case VA_SUBDIR_CREATION: return("Creation of user's subdirectories failed?"); case VA_USER_DOES_NOT_EXIST: return("User does not exist"); case VA_DOMAIN_DOES_NOT_EXIST: return("Domain does not exist"); case VA_INVALID_DOMAIN_NAME: return("Invalid domain name"); case VA_DOMAIN_ALREADY_EXISTS: return("Domain already exists"); case VA_COULD_NOT_MAKE_DOMAIN_DIR: return("Could not make domain dir"); case VA_COULD_NOT_OPEN_QMAIL_DEFAULT: return("Could not open qmail default"); case VA_CAN_NOT_MAKE_DOMAINS_DIR: return("Can not make " DOMAINS_DIR " directory"); case VA_COULD_NOT_UPDATE_FILE: return("Could not update file"); case VA_CRYPT_FAILED: return("Crypt failed"); case VA_COULD_NOT_OPEN_DOT_QMAIL: return("Could not open dot qmail file"); case VA_BAD_CHAR: return("bad character"); case VA_BAD_UID: return("running as invalid uid"); case VA_NO_AUTH_CONNECTION: return("no auth connection"); case VA_MEMORY_ALLOC_ERR: return("memory allocation error"); case VA_USER_NAME_TOO_LONG: return("user name too long"); case VA_DOMAIN_NAME_TOO_LONG: return("domain name too long"); case VA_PASSWD_TOO_LONG: return("password too long"); case VA_GECOS_TOO_LONG: return("gecos too long"); case VA_QUOTA_TOO_LONG: return("quota too long"); case VA_DIR_TOO_LONG: return("dir too long"); case VA_CLEAR_PASSWD_TOO_LONG: return("clear password too long"); case VA_ALIAS_LINE_TOO_LONG: return("alias line too long"); case VA_NULL_POINTER: return("null pointer"); case VA_INVALID_EMAIL_CHAR: return("invalid email character"); case VA_PARSE_ERROR: return("error parsing data"); case VA_CANNOT_READ_LIMITS: return("can't read domain limits"); default: return("Unknown error"); }}/************************************************************************//* Michael Bowe 21st Aug 2003 * This function doesnt appear to be used by vpopmail or qmailadmin * Consider it for removal perhaps *//* Add an entry to a domain/.qmail-alias file */int vadddotqmail( char *alias, char *domain,... ) { struct vqpasswd *mypw = NULL; FILE *fs; va_list args; char *email; char Dir[MAX_BUFF]; uid_t uid; gid_t gid; char tmpbuf[MAX_BUFF]; /* extract the details for the domain (Dir, uid, gid) */ if ( vget_assign(domain, Dir, sizeof(Dir), &uid, &gid ) == NULL) { return(VA_DOMAIN_DOES_NOT_EXIST); } /* open the .qmail-alias file for writing */ snprintf(tmpbuf, sizeof(tmpbuf), "%s/.qmail-%s", Dir, alias); if ((fs=fopen(tmpbuf, "w")) == NULL) return(VA_COULD_NOT_OPEN_DOT_QMAIL); va_start(args,domain); while ( (email=va_arg(args, char *)) != NULL ) { /* are we dealing with an email address? */ if ( strstr(email, "@") == NULL ) { /* not an email address */ /* get passwd entry for this user */ mypw = vauth_getpw( email, domain ); if ( mypw == NULL ) return(VA_USER_DOES_NOT_EXIST); /* write out the appropriate maildir entry for this user */ fprintf(fs, "%s/Maildir/\n", mypw->pw_dir); } else { /* yes, we have an email address, so write it out */ fprintf(fs, "%s\n", email); } } fclose(fs); /* setup the permission of the .qmail-alias file */ snprintf(tmpbuf, sizeof(tmpbuf), "%s/.qmail-%s", Dir, alias); chown(tmpbuf,uid,gid); va_end(args); return(VA_SUCCESS);}/************************************************************************//* Michael Bowe 21st Aug 2003 * This function doesnt appear to be used by vpopmail or qmailadmin * Consider it for removal perhaps */ /* delete a domain/qmail-alias file */int vdeldotqmail( char *alias, char *domain ){ char Dir[MAX_BUFF]; uid_t uid; gid_t gid; char tmpbuf[MAX_BUFF]; if ( vget_assign(domain, Dir, sizeof(Dir), &uid, &gid ) == NULL) { return(VA_DOMAIN_DOES_NOT_EXIST); } snprintf(tmpbuf, sizeof(tmpbuf), "%s/.qmail-%s", Dir, alias); if ( unlink(tmpbuf) < 0 ) return(VA_COULD_NOT_OPEN_DOT_QMAIL); return(VA_SUCCESS);}/************************************************************************//* * Given the domain name: * * get dir, uid, gid from the users/cdb file (if they are not passed as NULL) * * If domain is an alias domain, then domain gets updated to be the real domain * * Function will return the domain directory on success * or return NULL if the domain does not exist. * * This function caches last lookup in memory to increase speed */char *vget_assign(char *domain, char *dir, int dir_len, uid_t *uid, gid_t *gid){ FILE *fs; int dlen; int i; char *ptr; static char *in_domain = NULL; static int in_domain_size = 0; static char *in_dir = NULL; static int in_dir_size = 0; static uid_t in_uid = -1; static gid_t in_gid = -1; char cdb_key[MAX_BUFF]; char cdb_file[MAX_BUFF]; char *cdb_buf; /* cant lookup a null domain! */ if ( domain == NULL || *domain == 0) return(NULL); /* if domain matches last lookup, use cached values */ lowerit(domain); if ( in_domain_size != 0 && in_domain != NULL && in_dir != NULL && strcmp( in_domain, domain )==0 ) { /* return the vars, if the user has asked for them */ if ( uid!=NULL ) *uid = in_uid; if ( gid!=NULL ) *gid = in_gid; if ( dir!=NULL ) snprintf(dir, dir_len, "%s", in_dir); /* cached lookup complete, exit out now */ return(in_dir); } /* this is a new lookup, free memory from last lookup if necc. */ if ( in_domain != NULL ) { free(in_domain); in_domain = NULL; } if ( in_dir != NULL ) { free(in_dir); in_dir = NULL; } /* build up a search string so we can search the cdb file */ snprintf(cdb_key, sizeof(cdb_key), "!%s-", domain); /* work out the location of the cdb file */ snprintf(cdb_file, sizeof(cdb_file), "%s/users/cdb", QMAILDIR); /* try to open the cdb file */ if ( (fs = fopen(cdb_file, "r")) == 0 ) { return(NULL); } /* search the cdb file for our requested domain */ i = cdb_seek(fileno(fs), cdb_key, strlen(cdb_key), &dlen); in_uid = -1; in_gid = -1; if ( i == 1 ) { /* we found a matching record in the cdb file * so next create a storage buffer, and then read it in */ cdb_buf = malloc(dlen); i = fread(cdb_buf, sizeof(char), dlen, fs); /* format of cdb_buf is : * realdomain.com\0uid\0gid\0path\0 */ /* get the real domain */ ptr = cdb_buf; /* point to start of cdb_buf (ie realdomain) */ in_domain_size = strlen(ptr)+1; /* how long is the domain name? cache the length */ in_domain = malloc(in_domain_size); /* create storage space for domain cache */ snprintf(in_domain, in_domain_size, "%s", ptr); /* suck out the domain, store into cache */ /* get the uid */ while( *ptr != 0 ) ++ptr; /* advance pointer past the realdomain */ ++ptr; /* skip over the null */ in_uid = atoi(ptr); /* suck out the uid */ if ( uid!=NULL) *uid = in_uid; /* if the user requested the uid, give it to them */ /* get the gid */ while( *ptr != 0 ) ++ptr; /* skip over the uid */ ++ptr; /* skip over the null */ in_gid = atoi(ptr); /* suck out the gid */ if ( gid!=NULL) *gid = in_gid; /* if the user requested the gid, give it to them */ /* get the domain directory */ while( *ptr != 0 ) ++ptr; /* skip over the gid */ ++ptr; /* skip over the null */ if ( dir!=NULL ) strncpy( dir, ptr, dir_len); /* if user requested dir, give it */ in_dir_size = strlen(ptr)+1; /* how long is dir? cache the length */ in_dir = malloc(in_dir_size); /* create storage space for dir cache */ snprintf(in_dir, in_dir_size, "%s", ptr); /* suck out the dir, and store it in cache */ free(cdb_buf); /* when vget_assign is called with the domain parameter set as an alias domain, * it is meant to replace this alias domain with the real domain * * in_domain contains the real domain, so do this replacement now. * * Michael Bowe 21st Aug 2003. Need to watch out for buffer overflows here. * We
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -