/*
* $Id: qmailadmin.c,v 1.6.2.11 2006/02/05 17:03:44 tomcollins 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <dirent.h>
#include <vpopmail_config.h>
/* undef some macros that get redefined in config.h below */
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include <vpopmail.h>
#include <vauth.h>
#include <vlimits.h>
#include "alias.h"
#include "auth.h"
#include "autorespond.h"
#include "cgi.h"
#include "command.h"
#include "config.h"
#include "limits.h"
#include "mailinglist.h"
#include "printh.h"
#include "qmailadmin.h"
#include "show.h"
#include "template.h"
#include "user.h"
#include "util.h"
char Username[MAX_BUFF];
char Domain[MAX_BUFF];
char Password[MAX_BUFF];
char Gecos[MAX_BUFF];
char Quota[MAX_BUFF];
char Time[MAX_BUFF];
char ActionUser[MAX_BUFF];
char Newu[MAX_BUFF];
char Password1[MAX_BUFF];
char Password2[MAX_BUFF];
char Crypted[MAX_BUFF];
char Alias[MAX_BUFF];
char AliasType[MAX_BUFF];
char LineData[MAX_BUFF];
char Action[MAX_BUFF];
char Message[MAX_BIG_BUFF];
char StatusMessage[MAX_BIG_BUFF];
int num_of_mailinglist;
int CGIValues[256];
char Pagenumber[MAX_BUFF];
char SearchUser[MAX_BUFF];
time_t Mytime;
char *TmpCGI = NULL;
char TmpBuf[MAX_BIG_BUFF];
char TmpBuf1[MAX_BUFF];
char TmpBuf2[MAX_BUFF];
char TmpBuf3[MAX_BUFF];
char TempBuf[MAX_BUFF];
int Compressed;
FILE *actout;
FILE *lang_fs;
FILE *color_table;
char *html_text[MAX_LANG_STR+1];
struct vlimits Limits;
int AdminType;
int MaxPopAccounts;
int MaxAliases;
int MaxForwards;
int MaxAutoResponders;
int MaxMailingLists;
int DisablePOP;
int DisableIMAP;
int DisableDialup;
int DisablePasswordChanging;
int DisableWebmail;
int DisableRelay;
int CurPopAccounts;
int CurForwards;
int CurBlackholes;
int CurAutoResponders;
int CurMailingLists;
uid_t Uid;
gid_t Gid;
char RealDir[156];
char Lang[40];
int main(argc,argv)
int argc;
char *argv[];
{
const char *ip_addr=getenv("REMOTE_ADDR");
const char *x_forward=getenv("HTTP_X_FORWARDED_FOR");
char *pi;
char *rm;
char returnhttp[MAX_BUFF];
char returntext[MAX_BUFF];
struct vqpasswd *pw;
init_globals();
if (x_forward) ip_addr = x_forward;
if (!ip_addr) ip_addr = "127.0.0.1";
pi=getenv("PATH_INFO");
if ( pi ) pi = strdup(pi);
if (pi) snprintf (TmpBuf2, sizeof(TmpBuf2), "%s", pi + 5);
rm = getenv("REQUEST_METHOD");
rm = (rm == NULL ? "" : strdup(rm));
if ( strncmp(rm , "POST", 4) == 0 ) {
get_cgi();
} else {
TmpCGI = getenv("QUERY_STRING");
TmpCGI = (TmpCGI == NULL ? "" : strdup(TmpCGI));
}
if (pi && strncmp(pi, "/com/", 5) == 0) {
GetValue(TmpCGI, Username, "user=", sizeof(Username));
GetValue(TmpCGI, Domain, "dom=", sizeof(Domain));
GetValue(TmpCGI, Time, "time=", sizeof(Time));
Mytime = atoi(Time);
pw = vauth_getpw( Username, Domain );
/* get the real uid and gid and change to that user */
vget_assign(Domain,RealDir,sizeof(RealDir),&Uid,&Gid);
if ( geteuid() == 0 ) {
if ( setgid(Gid) != 0 ) perror("setgid");
if ( setuid(Uid) != 0 ) perror("setuid");
}
if ( chdir(RealDir) < 0 ) {
fprintf(stderr, "<h2>%s %s</h2>\n", html_text[171], RealDir );
}
load_limits();
set_admin_type();
if ( AdminType == USER_ADMIN || AdminType == DOMAIN_ADMIN ) {
auth_user_domain(ip_addr, pw);
} else {
auth_system(ip_addr, pw);
}
process_commands();
} else if (pi && strncmp(pi, "/passwd/", 7) == 0) {
char User[MAX_BUFF];
char *dom;
GetValue(TmpCGI, Username, "address=", sizeof(Username));
GetValue(TmpCGI, Password, "oldpass=", sizeof(Password));
GetValue(TmpCGI, Password1, "newpass1=", sizeof(Password1));
GetValue(TmpCGI, Password2, "newpass2=", sizeof(Password2));
if (*Username && (*Password == '\0') && (*Password1 || *Password2)) {
/* username entered, but no password */
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[198]);
} else if (*Username && *Password) {
/* attempt to authenticate user */
vget_assign (Domain, RealDir, sizeof(RealDir), &Uid, &Gid);
if ( geteuid() == 0 ) {
if ( setgid(Gid) != 0 ) perror("setgid");
if ( setuid(Uid) != 0 ) perror("setuid");
}
strcpy (User, Username);
if ((dom = strchr (User, '@')) != NULL) {
strcpy (Domain, dom+1);
*dom = '\0';
}
if ( *Domain == '\0' ) {
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[198]);
} else {
chdir(RealDir);
load_limits();
pw = vauth_user( User, Domain, Password, "" );
if ( pw == NULL ) {
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[198]);
} else if (pw->pw_flags & NO_PASSWD_CHNG) {
strcpy (StatusMessage, "You don't have permission to change your password.");
} else if (strcmp (Password1, Password2) != 0) {
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[200]);
} else if (*Password1 == '\0') {
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[234]);
} else if (vpasswd (User, Domain, Password1, USE_POP) != VA_SUCCESS) {
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[140]);
} else {
/* success */
snprintf (StatusMessage, sizeof(StatusMessage), "%s", html_text[139]);
*Password = '\0';
send_template ("change_password_success.html");
return 0;
}
}
}
send_template ("change_password.html");
return 0;
} else if (*rm) {
FILE *fs;
char *dom;
GetValue(TmpCGI, Username, "username=", sizeof(Username));
GetValue(TmpCGI, Domain, "domain=", sizeof(Domain));
GetValue(TmpCGI, Password, "password=", sizeof(Password));
if ((dom = strchr (Username, '@')) != NULL) {
strcpy (Domain, dom+1);
*dom = '\0';
}
vget_assign(Domain,RealDir,sizeof(RealDir),&Uid,&Gid);
if ( geteuid() == 0 ) {
if ( setgid(Gid) != 0 ) perror("setgid");
if ( setuid(Uid) != 0 ) perror("setuid");
}
/* Authenticate a user and domain admin */
if ( strlen(Domain) > 0 ) {
chdir(RealDir);
load_limits();
pw = vauth_user( Username, Domain, Password, "" );
if ( pw == NULL ) {
snprintf (StatusMessage, sizeof(StatusMessage), "%s\n", html_text[198]);
show_login();
vclose();
exit(0);
}
snprintf (TmpBuf, sizeof(TmpBuf), "%s/" MAILDIR, pw->pw_dir);
del_id_files( TmpBuf);
Mytime = time(NULL);
snprintf (TmpBuf, sizeof(TmpBuf), "%s/" MAILDIR "/%u.qw", pw->pw_dir, (unsigned int) Mytime);
fs = fopen(TmpBuf, "w");
if ( fs == NULL ) {
printf ("%s %s<br>\n", html_text[144], TmpBuf);
vclose();
exit(0);
}
memset(TmpBuf, 0, sizeof(TmpBuf));
/* set session vars */
GetValue(TmpCGI, returntext, "returntext=", sizeof(returntext));
GetValue(TmpCGI, returnhttp, "returnhttp=", sizeof(returnhttp));
snprinth (TmpBuf, sizeof(TmpBuf), "ip_addr=%C&returntext=%C&returnhttp=%C\n",
ip_addr, returntext, returnhttp);
fputs(TmpBuf,fs);
// fputs(ip_addr, fs);
fclose(fs);
vget_assign(Domain, TmpBuf1, sizeof(TmpBuf1), &Uid, &Gid);
set_admin_type();
/* show the main menu for domain admins, modify user page
for regular users */
if (AdminType == DOMAIN_ADMIN) {
show_menu(Username, Domain, Mytime);
} else {
strcpy (ActionUser, Username);
moduser();
}
vclose();
exit(0);
}
}
show_login();
vclose();
return 0;
}
void load_lang (char *lang)
{
long lang_size;
size_t bytes_read;
char *lang_entries;
char *id;
char *p;
open_lang (lang);
fseek (lang_fs, 0, SEEK_END);
lang_size = ftell (lang_fs);
lang_entries = malloc (lang_size);
if (lang_entries == NULL) return;
rewind (lang_fs);
bytes_read = fread (lang_entries, 1, lang_size, lang_fs);
/* error handling for incomplete reads? */
id = strtok (lang_entries, " \t");
while (id) {
p = strtok (NULL, "\n");
if (p == NULL) break;
html_text[atoi(id)] = p;
id = strtok (NULL, " \t");
}
/* Do not free lang_entries! html_text points into it! */
}
void init_globals()
{
char *accept_lang;
char *langptr, *qptr;
char *charset;
int lang_err;
int i;
float maxq, thisq;
memset(CGIValues, 0, sizeof(CGIValues));
CGIValues['0'] = 0;
CGIValues['1'] = 1;
CGIValues['2'] = 2;
CGIValues['3'] = 3;
CGIValues['4'] = 4;
CGIValues['5'] = 5;
CGIValues['6'] = 6;
CGIValues['7'] = 7;
CGIValues['8'] = 8;
CGIValues['9'] = 9;
CGIValues['A'] = 10;
CGIValues['B'] = 11;
CGIValues['C'] = 12;
CGIValues['D'] = 13;
CGIValues['E'] = 14;
CGIValues['F'] = 15;
CGIValues['a'] = 10;
CGIValues['b'] = 11;
CGIValues['c'] = 12;
CGIValues['d'] = 13;
CGIValues['e'] = 14;
CGIValues['f'] = 15;
actout = stdout;
memset(Username, 0, sizeof(Username));
memset(Domain, 0, sizeof(Domain));
memset(Password, 0, sizeof(Password));
memset(Quota, 0, sizeof(Quota));
memset(Time, 0, sizeof(Time));
memset(ActionUser, 0, sizeof(ActionUser));
memset(Newu, 0, sizeof(Newu));
memset(Password1, 0, sizeof(Password1));
memset(Password2, 0, sizeof(Password2));
memset(Crypted, 0, sizeof(Crypted));
memset(Alias, 0, sizeof(Alias));
memset(Message, 0, sizeof(Message));
memset(TmpBuf, 0, sizeof(TmpBuf));
memset(TmpBuf1, 0, sizeof(TmpBuf1));
memset(TmpBuf2, 0, sizeof(TmpBuf2));
memset(TmpBuf3, 0, sizeof(TmpBuf3));
AdminType = NO_ADMIN;
lang_fs = NULL;
/* Parse HTTP_ACCEPT_LANGUAGE to find highest preferred language
* that we have a translation for. Example setting:
* de-de, ja;q=0.25, en;q=0.50, de;q=0.75
* The q= lines determine which is most preferred, defaults to 1.
* Our routine starts with en at 0.0, and then would try de-de (1.00),
* de (1.00), ja (0.25), en (0.50), and then de (0.75).
*/
/* default to English at 0.00 preference */
maxq = 0.0;
strcpy (Lang, "en");
/* read in preferred languages */
langptr = getenv("HTTP_ACCEPT_LANGUAGE");
if (langptr != NULL) {
accept_lang = malloc (strlen(langptr));
strcpy (accept_lang, langptr);
langptr = strtok(accept_lang, " ,\n");
while (langptr != NULL) {
qptr = strstr (langptr, ";q=");
if (qptr != NULL) {
*qptr = '\0'; /* convert semicolon to NULL */
thisq = (float) atof (qptr+3);
} else {
thisq = 1.0;
}
/* if this is a better match than our previous best, try it */
if (thisq > maxq) {
lang_err = open_lang (langptr);
/* Remove this next section for strict interpretation of
* HTTP_ACCEPT_LANGUAGE. It will try language xx (with the
* same q value) if xx-yy fails.
*/
if ((lang_err == -1) && (langptr[2] == '-')) {
langptr[2] = '\0';
lang_err = open_lang (langptr);
}
if (lang_err == 0) {
maxq = thisq;
strcpy (Lang, langptr);
}
}
langptr = strtok (NULL, " ,\n");
}
free(accept_lang);
}
/* best language choice is now in 'Lang' */
/* build table of html_text entries */
for (i = 0; i <= MAX_LANG_STR; i++) html_text[i] = "";
/* read English first as defaults for incomplete language files */
if (strcmp (Lang, "en") != 0) load_lang ("en");
/* load the preferred language */
load_lang (Lang);
/* open the color table */
open_colortable();
umask(VPOPMAIL_UMASK);
charset = html_text[0];
printf ("Content-Type: text/html; charset=%s\n",
*charset == '\0' ? "iso-8859-1" : charset);
#ifdef NO_CACHE
printf ("Cache-Control: no-cache\n");
printf ("Cache-Control: no-store\n");
printf ("Pragma: no-cache\n");
printf ("Expires: Thu, 01 Dec 1994 16:00:00 GMT\n");
#endif
printf ("\n");
}
void del_id_files( char *dirname )
{
DIR *mydir;
struct dirent *mydirent;
mydir = opendir(dirname);
if ( mydir == NULL ) return;
while((mydirent=readdir(mydir))!=NULL){
if ( strstr(mydirent->d_name,".qw")!=0 ) {
snprintf (TmpBuf3, sizeof(TmpBuf3), "%s/%s", dirname, mydirent->d_name);
unlink(TmpBuf3);
}
}
closedir(mydir);
}
void quickAction (char *username, int action)
{
/* This feature sponsored by PinkRoccade Public Sector, Sept 2004 */
struct stat fileinfo;
char dotqmailfn[MAX_BUFF];
char *space, *ar, *ez;
char *aliasline;
/* Note that all of the functions called from quickAction() assume
* that the username to modify is in a global called "ActionUser"
* It would be better to pass this information as a parameter, but
* that's how it was originally done. The code in command.c that
* calls quickAction() passes ActionUser as the username parameter
* in hopes that someday we'll remove the globals and pass parameters.
*/
/* first check for alias/forward, autorepsonder (or even mailing list) */
aliasline = valias_select (username, Domain);
if (aliasline != NULL) {
/* Autoresponder/Mailing List detection algorithm:
* We're looking for either '/autorespond ' or '/ezmlm-reject ' to
* appear in the first line, before a space appears
*/
space = strstr (aliasline, " ");
ar = strstr (aliasline, "/autorespond ");
ez = strstr (aliasline, "/ezmlm-reject ");
if (ar && space && (ar < space)) {
/* autorepsonder */
if (action == ACTION_MODIFY) modautorespond();
else if (action == ACTION_DELETE) delautorespond();
} else if (ez && space && (ez < space)) {
/* mailing list (cdb-backend only) */
if (action == ACTION_MODIFY) modmailinglist();
else if (action == ACTION_DELETE) delmailinglist();
} else {
/* it's just a forward/alias of some sort */
if (action == ACTION_MODIFY) moddotqmail();
else if (action == ACTION_DELETE) deldotqmail();
}
} else if (vauth_getpw (username, Domain)) {
/* POP/IMAP account */
if (action == ACTION_MODIFY) moduser();
else if (action == ACTION_DELETE) {
// don't allow deletion of postmaster account
if (strcasecmp (username, "postmaster") == 0) {
snprinth (StatusMessage, sizeof(StatusMessage), "%s", html_text[317]);
show_menu(Username, Domain, Mytime);
vclose();
} else deluser();
}
} else {
/* check for mailing list on SQL backend (not in valias_select) */
snprintf (dotqmailfn, sizeof(dotqmailfn), ".qmail-%s", username);
str_replace (dotqmailfn+7, '.', ':');
if (stat (dotqmailfn, &fileinfo) == 0) {
/* mailing list (MySQL backend) */
if (action == ACTION_MODIFY) modmailinglist();
else if (action == ACTION_DELETE) delmailinglist();
} else {
/* user does not exist */
snprinth (StatusMessage, sizeof(StatusMessage), "%s (%H@%H)",
html_text[153], username, Domain);
show_menu(Username, Domain, Mytime);
vclose();
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1