/* Extension to POP server for virtual mail server management. Written by Jacques Gelinas jacques@solucorp.qc.ca Use as needed :-) This does not supersede the original POP server license. It only apply to this file. */ #include #include #include #include #include #include #include #include #include #include #include "pop3.h" void strlwr (char *dst, const char *src, int size) { size--; while (*src != '\0' && size > 0){ *dst++ = tolower(*src); src++; size--; } *dst = '\0'; } /* Extract which virtual host is expected by the POP client. Return -1 if any error. */ int vmail_getourname(char *name, int sizename) { int ret = -1; struct sockaddr_in adr; unsigned int len = sizeof(adr); if (getsockname (0,(struct sockaddr*)&adr,&len) != -1){ struct hostent *ent; /* syslog (LOG_ERR,"connexion de %d %x",adr.sin_port,adr.sin_addr); */ ent = gethostbyaddr ((const char*)&adr.sin_addr ,sizeof(adr.sin_addr.s_addr),AF_INET); /* syslog (LOG_DEBUG,"connexion de %p",ent); */ if (ent != NULL){ strlwr (name,ent->h_name,sizename); /* syslog (LOG_DEBUG,"connexion de %s",name); */ ret = 0; }else{ long a = ntohl (*(long*)(&adr.sin_addr)); syslog (LOG_ERR,"Can't convert IP number %lu.%lu.%lu.%lu to name, using main domain" ,(a>>24)&0xff,(a>>16)&0xff,(a>>8)&0xff,a&0xff); } }else{ syslog (LOG_ERR,"getsockname failed (errno %m)"); } return ret; } static int vmail_splitline (const char *line, char words[9][100]) { int nbword = 0; char *dst = words[0]; int i; for (i=0; i<9; i++) words[i][0] = '\0'; while (*line != '\0' && *line != '\n'){ if (*line == ':'){ line++; *dst = '\0'; nbword++; dst = words[nbword]; }else{ *dst++ = *line++; } } *dst = '\0'; return nbword; } /* Format the gecos field so it can be used as an email targer Turn all spaces into dots. 2 spaces are turnes into a single dot. */ static void vmail_formatgecos(const char *orig, char *mail_gecos) { while (*orig != '\0'){ if (isspace(*orig)){ *mail_gecos++ = '.'; orig++; while (isspace(*orig)) orig++; }else{ *mail_gecos++ = *orig++; } } *mail_gecos = '\0'; } /* Lookup a user in a file with the same layout as /etc/passwd */ struct passwd *vmail_getpwnam ( const char *pwdfile, const char *shadow_file, const char *user, bool nocase, // Case insensitive match of the user id bool match_gecos) // Try to match the full name as well { struct passwd *ret = NULL; FILE *fin = fopen (pwdfile,"r"); if (fin != NULL){ char buf[400]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ static char words[9][100]; static struct passwd p; vmail_splitline (buf,words); char gecos[100]; if (match_gecos) vmail_formatgecos(words[4],gecos); if (strcmp(user,words[0])==0 || (nocase && strcasecmp(user,words[0])==0) || (match_gecos && strcasecmp(user,gecos)==0)){ p.pw_name = words[0]; p.pw_passwd = words[1]; p.pw_uid = atoi(words[2]); p.pw_gid = atoi(words[3]); p.pw_gecos = words[4]; p.pw_dir = words[5]; p.pw_shell = words[6]; ret = &p; break; } } fclose (fin); if (ret != NULL){ fin = fopen (shadow_file,"r"); if (fin != NULL){ while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char words[9][100]; vmail_splitline (buf,words); if (strcmp(user,words[0])==0){ int last = atoi(words[2]); int expire = atoi(words[6]); int disable = atoi(words[7]); time_t tim = time(NULL); int days = tim/(24*60*60); if ((disable > 0 && disable < days) || (expire > 0 && last > 0 && last + expire < days)){ strcpy (ret->pw_passwd,"*"); }else{ strcpy (ret->pw_passwd,words[1]); } break; } } fclose (fin); } } } return ret; }