📄 vpopmail.c
字号:
if ( strlen(gecos) >= MAX_PW_GECOS ) return(VA_GECOS_TOO_LONG); umask(VPOPMAIL_UMASK); lowerit(username); lowerit(domain); if ( is_username_valid(username) != 0 ) return(VA_ILLEGAL_USERNAME); if ( is_domain_valid(domain) != 0 ) return(VA_INVALID_DOMAIN_NAME); if ( vauth_getpw( username, domain ) != NULL ) return(VA_USERNAME_EXISTS); /* record the dir where the vadduser command was run from */ getcwd(calling_dir, sizeof(calling_dir)); /* lookup the home dir, uid and gid for the domain */ if ( vget_assign(domain, Dir, sizeof(Dir), &uid, &gid)==NULL) { return(VA_DOMAIN_DOES_NOT_EXIST); } /* make sure we can load domain limits for default quota */ if (vget_limits(domain, &limits) != 0) { return(VA_CANNOT_READ_LIMITS); } /* go to the domain's home dir (ie test it exists) */ /* would a stat be a better option here? */ if ( chdir(Dir) != 0 ) { return(VA_BAD_D_DIR); } /* create dir for the the user */ if ( (user_hash=make_user_dir(username, domain, uid, gid)) == NULL ) { chdir(calling_dir); if (verrori != 0 ) return(verrori); else return(VA_BAD_U_DIR); } /* add the user to the auth backend */ if (vauth_adduser(username, domain, password, gecos, user_hash, apop )!=0) { fprintf(stderr, "Failed while attempting to add user to auth backend\n"); /* back out of changes made so far */ chdir(Dir); if (strlen(user_hash)>0) { chdir(user_hash);} vdelfiles(username); chdir(calling_dir); return(VA_NO_AUTH_CONNECTION); } if (limits.defaultquota > 0) { if (limits.defaultmaxmsgcount > 0) snprintf (quota, sizeof(quota), "%dS,%dC", limits.defaultquota, limits.defaultmaxmsgcount); else snprintf (quota, sizeof(quota), "%dS", limits.defaultquota); } else { if (limits.defaultmaxmsgcount > 0) snprintf (quota, sizeof(quota), "%dC", limits.defaultmaxmsgcount); else strcpy (quota, "NOQUOTA"); } vsetuserquota (username, domain, quota);#ifdef SQWEBMAIL_PASS { /* create the sqwebmail-pass file in the user's maildir * This file contains a copy of the user's crypted password */ struct vqpasswd *mypw; mypw = vauth_getpw( username, domain); if ( mypw != NULL ) { vsqwebmail_pass( mypw->pw_dir, mypw->pw_passwd, uid, gid); } }#endif#ifdef ENABLE_AUTH_LOGGING if (vset_lastauth(username,domain,NULL_REMOTE_IP) !=0) { /* should we back out of all the work we have done so far? */ chdir(calling_dir); fprintf (stderr, "Failed to create create lastauth entry\n"); return (VA_NO_AUTH_CONNECTION); }#endif /* jump back into the dir from which the vadduser was run */ chdir(calling_dir); return(VA_SUCCESS);}/************************************************************************/char randltr(void){ static const char saltchar[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; return saltchar[(rand() % 64)];}/************************************************************************//* * encrypt a password * Input * clearpass = pointer to clear text password * ssize = size of the crypted pointer buffer * * Output * copies the encrypted password into the crypted * character pointer * * Return code: * VA_CRYPT_FAILED = encryption failed * VA_SUCCESS = 0 = encryption success * */int mkpasswd3( char *clearpass, char *crypted, int ssize ){ char *tmpstr; char salt[12]; static int seeded = 0; if (!seeded) { seeded = 1; srand (time(NULL)^(getpid()<<15)); }#ifdef MD5_PASSWORDS salt[0] = '$'; salt[1] = '1'; salt[2] = '$'; salt[3] = randltr(); salt[4] = randltr(); salt[5] = randltr(); salt[6] = randltr(); salt[7] = randltr(); salt[8] = randltr(); salt[9] = randltr(); salt[10] = randltr(); salt[11] = 0;#else salt[0] = randltr(); salt[1] = randltr(); salt[2] = 0;#endif tmpstr = crypt(clearpass,salt); if ( tmpstr == NULL ) return(VA_CRYPT_FAILED); strncpy(crypted,tmpstr, ssize); return(VA_SUCCESS);}/************************************************************************//* * prompt the command line and get a password twice, that matches */char *vgetpasswd(char *user) { static char pass1[128]; char pass2[128]; char prompt[128]; /* Michael Bowe 14th August 2003 * Is setting up a static pass1 and returning a pointer * to it is the best way to run this function? Maybe there * is a better way we can do this.... */ memset(pass1, 0, sizeof(pass1)); snprintf( prompt, sizeof(prompt), "Please enter password for %s: ", user); while( 1 ) { snprintf(pass1, sizeof(pass1), "%s", getpass(prompt)); snprintf(pass2, sizeof(pass2), "%s", getpass("enter password again: ")); if ( strcmp( pass1, pass2 ) != 0 ) { printf("Passwords do not match, try again\n"); } else { break; } } return(pass1);}/************************************************************************//* * vdelfiles : delete a directory tree * * input: directory to start the deletion * output: * 0 on success * -1 on failer */int vdelfiles(char *dir){ DIR *mydir; struct dirent *mydirent; struct stat statbuf; /* Modified By David Wartell david@actionwebservices.com to work with * Solaris. Unlike Linux, Solaris will NOT return error when unlink() * is called on a directory. A correct implementation to support * Linux & Solaris is to test to see if the file is a directory. * If it is not a directory unlink() it. * If unlink() returns an error return error. */ if (lstat(dir, &statbuf) == 0) { /* if dir is not a directory unlink it */ if ( !( S_ISDIR(statbuf.st_mode) ) ) { if ( unlink(dir) == 0 ) { /* return success we deleted the file */ return(0); } else { /* error, return error to calling function, * we couldn't unlink the file */ return(-1); } } } else { /* error, return error to calling function, * we couldn't lstat the file */ return(-1); } /* go to the directory, and check for error */ if (chdir(dir) == -1) { /* error, return error to calling function */ return(-1); } /* open the directory and check for an error */ if ( (mydir = opendir(".")) == NULL ) { /* error, return error */ fprintf(stderr, "Failed to opendir()"); return(-1); } while((mydirent=readdir(mydir))!=NULL){ /* skip the current directory and the parent directory entries */ if ( strncmp(mydirent->d_name,".", 2) !=0 && strncmp(mydirent->d_name,"..", 3)!=0 ) { /* stat the file to check it's type, I/O expensive */ stat( mydirent->d_name, &statbuf); /* Is the entry a directory? */ if ( S_ISDIR(statbuf.st_mode) ) { /* delete the sub tree, -1 means an error */ if ( vdelfiles ( mydirent->d_name) == -1 ) { /* on error, close the directory stream */ closedir(mydir); /* and return error */ return(-1); } /* the entry is not a directory, unlink it to delete */ } else { /* unlink the file and check for error */ if (unlink(mydirent->d_name) == -1) { /* print error message and return and error */ fprintf (stderr, "Failed to delete directory %s", mydirent->d_name); return(-1); } } } } /* close the directory stream, we don't need it anymore */ closedir(mydir); /* go back to the parent directory and check for error */ if (chdir("..") == -1) { /* print error message and return an error */ fprintf(stderr, "Failed to cd to parent"); return(-1); } /* delete the directory, I/O expensive */ rmdir(dir); /* return success */ return(0);}/************************************************************************//* * Add a domain to all the control files * And signal qmail * domain is the domain name * dir is the full path to the domain directory * uid and gid are the uid/gid to store in the assign file */int add_domain_assign( char *alias_domain, char *real_domain, char *dir, uid_t uid, gid_t gid ){ FILE *fs1 = NULL; struct stat mystat; char tmpstr1[MAX_BUFF]; char tmpstr2[MAX_BUFF]; snprintf(tmpstr1, sizeof(tmpstr1), "%s/users/assign", QMAILDIR); /* stat assign file, if it's not there create one */ if ( stat(tmpstr1,&mystat) != 0 ) { /* put a . on one line by itself */ if ( (fs1 = fopen(tmpstr1, "w+"))==NULL ) { fprintf(stderr, "could not open assign file\n"); return(-1); } fputs(".\n", fs1); fclose(fs1); } snprintf(tmpstr2, sizeof(tmpstr2), "+%s-:%s:%lu:%lu:%s:-::", alias_domain, real_domain, (long unsigned)uid, (long unsigned)gid, dir); /* update the file and add the above line and remove duplicates */ if (update_file(tmpstr1, tmpstr2) !=0 ) { fprintf (stderr, "Failed while attempting to update_file() the assign file\n"); return (-1); } /* set the mode in case we are running with a strange mask */ chmod(tmpstr1, VPOPMAIL_QMAIL_MODE ); /* compile the assign file */ /* as of the 5.4 builds, we always need an updated assign file since * we call vget_assign to add the postmaster account. The correct * solution is to cache the information somewhere so vget_assign * can pull from cache instead of having to read the assign file. */ /* if ( OptimizeAddDomain == 0 ) */ update_newu(); /* If we have more than 50 domains in rcpthosts * make a morercpthosts and compile it */ if ( count_rcpthosts() >= 50 ) { snprintf(tmpstr1, sizeof(tmpstr1), "%s/control/morercpthosts", QMAILDIR); if (update_file(tmpstr1, alias_domain) !=0) { fprintf (stderr, "Failed while attempting to update_file() the morercpthosts file\n"); return (-1); } snprintf(tmpstr1, sizeof(tmpstr1), "%s/control/morercpthosts", QMAILDIR); chmod(tmpstr1, VPOPMAIL_QMAIL_MODE ); if ( OptimizeAddDomain == 0 ) compile_morercpthosts(); /* or just add to rcpthosts */ } else { snprintf(tmpstr1, sizeof(tmpstr1), "%s/control/rcpthosts", QMAILDIR); if (update_file(tmpstr1, alias_domain) != 0) { fprintf (stderr, "Failed while attempting to update_file() the rcpthosts file\n"); return (-1); } snprintf(tmpstr1, sizeof(tmpstr1), "%s/control/rcpthosts", QMAILDIR); chmod(tmpstr1, VPOPMAIL_QMAIL_MODE ); } /* Add to virtualdomains file and remove duplicates and set mode */ snprintf(tmpstr1, sizeof(tmpstr1), "%s/control/virtualdomains", QMAILDIR ); snprintf(tmpstr2, sizeof(tmpstr2), "%s:%s", alias_domain, alias_domain ); if (update_file(tmpstr1, tmpstr2) !=0 ) { fprintf (stderr, "Failed while attempting to update_file() the virtualdomains file\n"); return (-1); }; chmod(tmpstr1, VPOPMAIL_QMAIL_MODE ); /* make sure it's not in locals and set mode */ snprintf(tmpstr1, sizeof(tmpstr1), "%s/control/locals", QMAILDIR); if (remove_line( alias_domain, tmpstr1) < 0) { fprintf (stderr, "Failure while attempting to remove_line() the locals file\n"); return(-1); } chmod(tmpstr1, VPOPMAIL_QMAIL_MODE ); return(0);}/************************************************************************//* * delete a domain from the control files * the control files consist of : * - /var/qmail/control/rcpthosts * - /var/qmail/control/virtualdomains */int del_control(char *domain ) { char tmpbuf1[MAX_BUFF]; char tmpbuf2[MAX_BUFF]; struct stat statbuf; int problem_occurred = 0; /* delete entry from control/rcpthosts (if it is found) */ snprintf(tmpbuf1, sizeof(tmpbuf1), "%s/control/rcpthosts", QMAILDIR); switch ( remove_line( domain, tmpbuf1) ) { case -1 : /* error ocurred in remove line */ fprintf (stderr, "Failed while attempting to remove_line() the rcpthosts file\n"); problem_occurred = 1; break; case 0 : /* not found in rcpthosts, so try morercpthosts */ snprintf(tmpbuf1, sizeof(tmpbuf1), "%s/control/morercpthosts", QMAILDIR); switch (remove_line( domain, tmpbuf1) ) { case -1 : /* error ocurred in remove line * but this is normal enough as on smaller servers, the morercpthosts * file wont exist. So ignore this 'error' condition. */ break; case 0 : /* not found in morercpthosts */ break; case 1 : /* was removed from morercpthosts */ /* now test to see if morercpthosts exists */ if ( stat( tmpbuf1, &statbuf) == 0 ) { /* morercpthosts exists. Now check to see if its empty */ if ( statbuf.st_size == 0 ) { /* is empty. So delete it */ unlink(tmpbuf1); /* also delete the morercpthosts.cdb */ strncat(tmpbuf1, ".cdb", sizeof(tmpbuf1)-strlen(tmpbuf1)-1); unlink(tmpbuf1); } else { /* morercpthosts is not empty, so compile it */ compile_morercpthosts(); /* make sure correct permissions are set on morercpthosts */ chmod(tmpbuf1, VPOPMAIL_QMAIL_MODE ); } } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -