?? vchkpw.c
字號(hào):
/* * $Id: vchkpw.c,v 1.11 2004/01/13 15:59:42 tomcollins Exp $ * Copyright (C) 1999-2003 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 <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <syslog.h>#include <errno.h>#include <sys/wait.h>#include <pwd.h>#include <sys/types.h>#include "config.h"#include "vpopmail.h"#include "vlog.h"#include "vauth.h"#include "vlimits.h"/* for cram-md5 */#include "global.h"#include "md5.h"#include "hmac_md5.h"static char hextab[]="0123456789abcdef";#ifdef HAS_SHADOW#include <shadow.h>#endif/* Definitions */#define VCHKPW_USER "USER="#define VCHKPW_HOME "HOME="#define VCHKPW_SHELL "SHELL=NOLOGIN"#define VCHKPW_VPOPUSER "VPOPUSER="/* For tracking ip of client asking for pop service */char *IpAddr;/* Embed the port in the log when smtp-auth is used */char VchkpwLogName[18];/* For logging, relay info */unsigned int LocalPort;/* storage of authentication information */#define AUTH_SIZE 156#define AUTH_INC_SIZE 155char TheName[AUTH_SIZE];char TheUser[AUTH_SIZE];char ThePass[AUTH_SIZE]; /* for C/R this is 'TheResponse' */char TheChallenge[AUTH_SIZE];char TheCrypted[AUTH_SIZE];char TheDomain[AUTH_SIZE];/* log line buffer */#define LOG_LINE_SIZE 500char LogLine[LOG_LINE_SIZE];/* environment variable buffers */#define MAX_ENV_BUF 100static char envbuf1[MAX_ENV_BUF];static char envbuf2[MAX_ENV_BUF];static char envbuf3[MAX_ENV_BUF];static char envbuf4[MAX_ENV_BUF];/* shared data */uid_t pw_uid;gid_t pw_gid;char *pw_dir=NULL;struct vqpasswd *vpw = NULL;/* Forward declaration */char *sysc(char *mess);void login_virtual_user();void login_system_user();void read_user_pass();void vlog(int verror, char *TheUser, char *TheDomain, char *ThePass, char *TheName, char *IpAddr, char *LogLine);void vchkpw_exit(int err);void run_command(char *prog);int authcram(unsigned char *response, unsigned char *challenge, unsigned char *password);int authapop(unsigned char *password, unsigned char *timestamp, unsigned char *clearpass);#define POP_CONN 0#define SMTP_CONN 1#define IMAP_CONN 2int ConnType = 0;int main( int argc, char **argv){ char *tmpstr; if ( (IpAddr = get_remote_ip()) == NULL) IpAddr=""; if ( (tmpstr = getenv("TCPLOCALPORT")) == NULL) LocalPort = 110; else LocalPort = atoi(tmpstr); /* Check which port they are coming in on and * setup the log name and connection type */ switch(LocalPort) { case 25: strcpy(VchkpwLogName, "vchkpw-smtp"); ConnType = SMTP_CONN; break; case 110: strcpy(VchkpwLogName, "vchkpw-pop3"); ConnType = POP_CONN; break; case 143: strcpy(VchkpwLogName, "vchkpw-imap"); ConnType = IMAP_CONN; break; case 465: strcpy(VchkpwLogName, "vchkpw-smtps"); ConnType = SMTP_CONN; break; case 587: strcpy(VchkpwLogName, "vchkpw-submission"); ConnType = SMTP_CONN; break; case 993: strcpy(VchkpwLogName, "vchkpw-imaps"); ConnType = IMAP_CONN; break; case 995: strcpy(VchkpwLogName, "vchkpw-pop3s"); ConnType = POP_CONN; break; default: sprintf(VchkpwLogName, "vchkpw-%u", LocalPort); /* * We're running on an unknown port, so it could be any one of * the three protocols (SMTP, POP or IMAP). Try to guess the * protocol based on argv[1]. For SMTP AUTH, argv[1] is usually * /bin/true. For IMAP, it's usually imapd (or something like * that). Keep the old default of POP. * Note that the popular Courier-IMAP does not use vchkpw, it * links libvpopmail directly into its server. */ if (strstr (argv[1], "true") != NULL) /* used as STMP AUTH */ ConnType = SMTP_CONN; else if (strstr (argv[1], "imap") != NULL) /* used with IMAP */ ConnType = IMAP_CONN; else /* default to POP */ ConnType = POP_CONN; break; } /* read in the user name and password from file descriptor 3 */ read_user_pass(); if ( parse_email( TheName, TheUser, TheDomain, AUTH_SIZE) != 0 ) { snprintf(LogLine, sizeof(LogLine), "%s: invalid user/domain characters %s:%s", VchkpwLogName, TheName, IpAddr); vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(20); } /* check if this virtual domain is in the system * we look in /var/qmail/users/cdb file * and while we are at it, let's get the domains * user id and group id. */ if ( (vpw = vauth_getpw(TheUser, TheDomain)) != NULL ) { vget_assign(TheDomain,NULL,0,&pw_uid,&pw_gid); login_virtual_user();#ifdef ENABLE_PASSWD /* if it is not in the virtual domains * then check the user in /etc/passwd */ } else if ( ENABLE_PASSWD == 1 ) { login_system_user();#endif } else { snprintf(LogLine, sizeof(LogLine), "%s: vpopmail user not found %s@%s:%s", VchkpwLogName, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(3); } vclose(); /* The user is authenticated, now setup the environment */ /* Set the programs effective group id */ if ( ConnType != SMTP_CONN && setgid(pw_gid) == -1 ) { snprintf(LogLine, sizeof(LogLine), "%s: setgid %lu failed errno %d %s@%s:%s", VchkpwLogName, (long unsigned)pw_gid, errno, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(4); } /* Set the programs effective user id */ if ( ConnType != SMTP_CONN && setuid(pw_uid) == -1 ) { snprintf(LogLine, sizeof(LogLine), "%s: setuid %lu failed errno %d %s@%s:%s", VchkpwLogName, (long unsigned)pw_uid, errno, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(5); } /* Change to the users Maildir directory * don't do this for smtp authentication connections */ if (ConnType != SMTP_CONN && chdir(pw_dir) == -1) { if ( vpw!=NULL) { if ( vmake_maildir(TheDomain, vpw->pw_dir )!= VA_SUCCESS ) { snprintf(LogLine, sizeof(LogLine), "%s: autocreate dir errno %d %s %s@%s:%s", VchkpwLogName, errno, pw_dir, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(6); } chdir(pw_dir); } else { snprintf(LogLine, sizeof(LogLine), "%s: chdir failed errno %d %s %s@%s:%s", VchkpwLogName, errno, pw_dir, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(6); } } /* The the USER variable */ snprintf (envbuf1, sizeof(envbuf1), "%s%s", VCHKPW_USER, TheUser); if ( putenv(envbuf1) == -1 ) { snprintf(LogLine, sizeof(LogLine), "%s: putenv(USER) failed errno %d %s@%s:%s", VchkpwLogName, errno, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(7); } /* Now HOME */ snprintf (envbuf2, sizeof(envbuf2), "%s%s", VCHKPW_HOME, pw_dir); if ( putenv(envbuf2) == -1 ) { snprintf(LogLine, sizeof(LogLine), "%s: putenv(HOME) failed errno %d %s@%s:%s", VchkpwLogName, errno, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(8); } /* Now SHELL */ strncpy(envbuf3,VCHKPW_SHELL,sizeof(envbuf3)); envbuf3[sizeof(envbuf3)-1] = 0; /* make sure it's NULL terminated */ if ( putenv(envbuf3) == -1 ) { snprintf(LogLine, sizeof(LogLine), "%s: putenv(SHELL) failed errno %d %s@%s:%s", VchkpwLogName, errno, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(9); } /* Now VPOPUSER */ snprintf (envbuf4, sizeof(envbuf4), "%s%s", VCHKPW_VPOPUSER, TheName); if ( putenv(envbuf4) == -1 ) { snprintf(LogLine, sizeof(LogLine), "%s: putenv(VPOPUSER) failed errno %d %s@%s:%s", VchkpwLogName, errno, TheUser, TheDomain, IpAddr); vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(10); } /* close the log connection */ if ( ENABLE_LOGGING > 0 ) closelog(); /* And now a simple way to kick off the next program */ execvp(argv[1],argv+1); /* all done, time to release resources and go away */ exit(0);}/* clean a buffer for syslog */char *sysc(char *mess){ char *ripper; for(ripper=mess;*ripper!=0;++ripper) { if ( *ripper=='%' ) *ripper = '#'; } return(mess);}void read_user_pass(){ int i,j,l; /* Read the user and password from file descriptor 3 * use TheDomain variable as temporary storage of the * full incoming line */ memset(TheDomain,0,AUTH_SIZE); for(i=0;i<AUTH_SIZE;i+=j){ /* read a chunk */ j = read(3,&TheDomain[i],AUTH_SIZE-i-1); /* on error exit out */ if ( j == -1 ) { fprintf(stderr, "%s: vchkpw is only for talking with qmail-popup and qmail-pop3d. \It is not for runnning on the command line.\n", VchkpwLogName); vchkpw_exit(11); } else if ( j == 0 ) { break; } } /* close the user/pass file descriptor */ close(3); /* parse out the name */ memset(TheName,0,AUTH_SIZE); for(l=0;l<AUTH_INC_SIZE;++l){ TheName[l] = TheDomain[l]; if ( TheName[l] == 0 ) break; if ( l==i ) break; } /* parse out the password (or response or C/R) */ memset(ThePass,0,AUTH_SIZE); for(j=0,++l;l<AUTH_INC_SIZE;++j,++l){ ThePass[j] = TheDomain[l]; if ( ThePass[j] == 0 ) break; if ( l==i ) break; } /* parse out the challenge */ memset(TheChallenge,0,AUTH_SIZE); for(j=0,++l;l<AUTH_INC_SIZE;++j,++l){ TheChallenge[j] = TheDomain[l]; if ( TheChallenge[j] == 0 ) break;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -