#pragma implementation #include #include #include #include #include #include #include #include "mod_mailconf.h" #include "mailconf.m" #include "internal.h" #include #include #include #include "../../paths.h" #include "../module_apis/useracct_api.h" MODULE_DEFINE_VERSION(mailconf); PUBLIC MODULE_mailconf::MODULE_mailconf() : LINUXCONF_MODULE("mailconf") { linuxconf_loadmsg ("mailconf",PACKAGE_REV); module_register_api (USERACCT_API_KEY,USERACCT_API_REV ,vdomain_useracct_api_get ,vdomain_useracct_api_release); } static const char *keymenu1=NULL; static const char *keyvpopuser=NULL; static const char *keyalias=NULL; static const char *keyvalias=NULL; PUBLIC void MODULE_mailconf::setmenu ( DIALOG &dia, MENU_CONTEXT context) { if (context == MENU_NETWORK_SERVER){ keymenu1 = MSG_U(M_mailconf,"Mail delivery system (sendmail)"); dia.new_menuitem ("mailconf","",keymenu1); }else if (context == MENU_USER_SPC){ keyvpopuser = MSG_U(M_VPOP,"Virtual POP accounts (mail only)"); dia.new_menuitem ("vpopuser","",keyvpopuser); }else if (context == MENU_USER_ALIAS){ keyalias = MSG_R(M_ALIASES); dia.new_menuitem ("alias","",keyalias); keyvalias = MSG_R(M_VALIASES); dia.new_menuitem ("virtualalias","",keyvalias); } #if 0 static const char *vpolicies = MSG_U(M_VPOLICIES,"Policies for virtual domains"); "vpolicies:", vpolicies, }else if (key == vpolicies){ vdomain_editpolicies(); #endif } PUBLIC int MODULE_mailconf::domenu ( MENU_CONTEXT context, const char *key) { if (context == MENU_NETWORK_SERVER){ if (key == keymenu1){ mailconf_edit(); } }else if (context == MENU_USER_SPC){ if (key == keyvpopuser){ mailconf_editvpopusers(); } }else if (context == MENU_USER_ALIAS){ if (key == keyalias){ aliases_edit(); }else if (key == keyvalias){ vdomain_editaliases(); } } return 0; } /* Let one user edit his password in a vdomain */ static int mailconf_editupass(const char *hostname) { int ret = -1; char pwdfile[PATH_MAX],shadowfile[PATH_MAX],rootdir[PATH_MAX]; if (vdomain_locateinfo(hostname,pwdfile,shadowfile,rootdir)!=-1){ CONFIG_FILE file (pwdfile,help_nil ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","mail",0640); CONFIG_FILE file_shadow (shadowfile,help_nil ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","mail",0640); USERS users (file,file_shadow,rootdir,"","",0); userconf_editupass (users,hostname); ret = 0; } return ret; } /* Let one user edit his password in a vdomain. We learn the vdomain from the email address. */ static int mailconf_editupass() { DIALOG dia; SSTRING addr,passwd; vacation_drawinfo (dia,MSG_R(I_EMAILADRINFO)); dia.newf_str (MSG_R(F_EMAILADR),addr); dia.newf_pass (MSG_R(F_PASSWORD),passwd); vacation_drawinfo (dia,MSG_U(I_NEWPASS ,"Now enter your new password twice\n" "to make sure you typed it right")); SSTRING pass1,pass2; int field_pass = dia.getnb(); dia.newf_pass (MSG_U(F_PASS1,"New password"),pass1); dia.last_noempty(); dia.newf_pass (MSG_U(F_PASS2,"New password (retype)"),pass2); dia.last_noempty(); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_NEWPASS,"Changing your password") ,"",help_nil,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_ACCEPT){ if (pass1 != pass2){ xconf_error (MSG_U(E_PASSDIFF ,"The two password are different.\n" "Try again")); nof = field_pass; }else if (!pass_isweak(pass1.get())){ USERS *users; USER *user; SSTRING domain,uid; CONFIG_FILE *file,*file_shadow; if (vdomain_checkpass (addr,passwd,users,user ,file,file_shadow,uid,domain)!=-1){ SHADOW *shadow = users->getshadow(user); user->update_passwd (pass1.get(),shadow,false,domain.get()); perm_setbypass(true); users->write(NULL); perm_setbypass(false); xconf_notice (MSG_U(I_CHANGED,"Password changed")); delete users; delete file; delete file_shadow; addr.setempty(); passwd.setempty(); pass1.setempty(); pass2.setempty(); dia.reload(); } } } } return 0; } PUBLIC int MODULE_mailconf::dohtml (const char *key) { int ret = LNCF_NOT_APPLICABLE; if (strcmp(key,"vpass")==0){ if (mailconf_editupass ()==-1) html_setdone(); ret = 0; }else if (strncmp(key,"vpass-",6)==0){ if (mailconf_editupass (key+6)==-1) html_setdone(); ret = 0; }else if (strncmp(key,"vuser-",6)==0){ USER *like; if (special_init (POP_GROUP,like) != -1){ vdomain_editusers(like); } delete like; ret = 0; }else if (strncmp(key,"valiases",6)==0){ vdomain_editaliases(); ret = 0; }else if (strcmp(key,"vacation")==0){ vacation_login(); } return ret; } PUBLIC int MODULE_mailconf::message ( const char *msg, int argc, const char *argv[]) { int ret = LNCF_NOT_APPLICABLE; if (strcmp(msg,"listspc")==0){ vdomain_listspc (); ret = 0; }else if (strcmp(msg,"editupass")==0){ if (mailconf_editupass(argv[0])!=-1) ret = 0; }else if (strcmp(msg,"coadminauth")==0){ ret = vdomain_checkauth (argv[0],argv[1]) ? 1 : 0; }else if (strcmp(msg,"coadminpriv")==0){ PRIVILEGE *priv = (PRIVILEGE*)argv[1]; ret = vdomain_checkpriv (argv[0],priv) ? 1 : 0; }else if (strcmp(msg,"chguser")==0){ if (argc == 3){ ret = 0; SSTRING path; if (strcmp(argv[1],"/")==0){ path.setfromf ("/var/spool/mail/%s",argv[0]); }else{ path.setfromf ("/var/spool/vmail/%s/%s",argv[1],argv[0]); } struct stat st; USER *u = (USER*)argv[2]; int uid = u->getuid(); if (stat(path.get(),&st)!=-1 && st.st_uid != (uid_t)uid){ net_prtlog (MSG_U(I_CHOWN,"Changing ownership of mail file %s to %d from %d\n") ,path.get(),uid,st.st_uid); chown (path.get(),uid,st.st_gid); } } } return ret; } static HELP_FILE help_sendmail_pid ("mailconf","sendmail_pid"); static CONFIG_FILE f_sendmail_pid (VAR_RUN_SENDMAIL_PID,help_sendmail_pid ,CONFIGF_PROBED|CONFIGF_OPTIONAL); static void mailconf_setargs (DAEMON_INTERNAL *dae) { int qdelay = mailconf_getqueuedelay(); SSTRING buf; const char *stdargs = dae->cmd.args.get(); if (qdelay == 0){ buf.setfrom (stdargs); }else{ buf.setfromf("%s -q %dm",stdargs,qdelay); } dae->setargs (buf.get()); } static void daemon_addtb (SSTRINGS &tb, CONFIG_FILE &cf) { tb.add (new SSTRING (cf.getpath())); } /* Restart sendmail if ETC_SENDMAIL_CF is newer than the process */ static int mailconf_startif () { /* #Specification: sendmail / strategy sendmail depends on /etc/sendmail.cf. If the file is empty or do not exist, then sendmail is not need. It will be killed, or not started. If sendmail.cf is not empty, it will be started. If it is already running and sendmail.cf is younger than the process, it will be kill and restart. */ bool was_generated = mailconf_generate_if() == 1; int ret = -1; DAEMON_INTERNAL *dae = daemon_find ("sendmail"); if (dae != NULL){ static bool done = false; if (!done){ mailconf_setargs (dae); done = true; } dae->setpidfile (&f_sendmail_pid); if (was_generated){ // If sendmail.cf was generated, then no need to check any other // date. We send the current time as the date to compare. ret = dae->startif_date (time(NULL)); }else{ SSTRINGS tb; extern CONFIG_FILE f_sendmail,f_spam_name_allow; extern CONFIG_FILE f_spam_ip_allow,f_spam_relay_allow; daemon_addtb (tb,f_sendmail); daemon_addtb (tb,f_spam_name_allow); daemon_addtb (tb,f_spam_ip_allow); daemon_addtb (tb,f_spam_relay_allow); ret = dae->startif_file(tb); } } return ret; } PUBLIC int MODULE_mailconf::probe ( int level, // Current level being probed // Only service of this level should do something. int target, // target network runlevel of the probe // In which runlevel the machine is going to be // after the probe has completed bool) // simulation mode ? { if (level == 0){ mailconf_generate_if(); }else if (level == 1 && target >= 1){ if (!distrib_isenhanced()){ mailconf_startif(); } } return 0; } static void usage () { fprintf (stderr,MSG_U(I_USAGE ,"Module mailconf\n" "mailconf [ specific options ]\n" "\n" " --help\n" " --addvdom domain [--startuid uid ] [--daliases domain_alias ]\n" " [--faliase email_aliase_file] [ --quota max_inbox_k] \n" " --delvdom domain\n" " --addvuser domain id name\n" " --delvuser domain id\n" " --generatecf\n" " --setalias alias value ...\n" " --setvalias vdomain alias value ...\n" " --unsetalias alias [value] ...\n" " --unsetalias - [value] ...\n" " --unsetvalias vdomain alias [value] ...\n" " --unsetvalias vdomain - [value] ...\n" " --vpasswd domain id\n" "\n" )); } PUBLIC void MODULE_mailconf::usage(SSTRINGS &tb) { tb.add (new SSTRING (MSG_R(I_USAGE))); } PUBLIC int MODULE_mailconf::execmain (int argc , char *argv[], bool) { int ret = LNCF_NOT_APPLICABLE; const char *pt = strrchr(argv[0],'/'); if (pt != NULL){ pt++; }else{ pt = argv[0]; } if (strcmp(pt,"mailconf")==0){ ret = -1; if (argc == 1){ ret = mailconf_mainmenu (); }else if (argc == 2 && strcmp(argv[1],"--help")==0){ ::usage(); }else if (argc == 3 && strcmp(argv[1],"--delvdom")==0){ if (netconf_rootaccess()) vdomain_del (argv[2]); }else if (argc == 5 && strcmp(argv[1],"--addvuser")==0){ if (netconf_rootaccess()){ ret = vdomain_useradd (argv[2],argv[3],argv[4]); } }else if (argc == 4 && strcmp(argv[1],"--delvuser")==0){ if (netconf_rootaccess()){ ret = vdomain_userdel (argv[2],argv[3]); } }else if (argc == 4 && strcmp(argv[1],"--vpasswd")==0){ if (netconf_rootaccess()){ ret = vdomain_passwd (argv[2],argv[3]); } }else if (argc >= 4 && strcmp(argv[1],"--setalias")==0){ if (netconf_rootaccess()){ ret = aliases_set (argv[2],argc-3,(const char**)argv+3); } }else if (argc >= 5 && strcmp(argv[1],"--setvalias")==0){ if (netconf_rootaccess()){ ret = vdomain_setalias (argv[2],argv[3],argc-4 ,(const char**)argv+4); } }else if (argc >= 3 && strcmp(argv[1],"--unsetalias")==0){ if (netconf_rootaccess()){ ret = aliases_unset (argv[2],argc-3,(const char**)argv+3); } }else if (argc >= 4 && strcmp(argv[1],"--unsetvalias")==0){ if (netconf_rootaccess()){ ret = vdomain_unsetalias (argv[2],argv[3],argc-4 ,(const char**)argv+4); } }else if (argc > 2){ if (strcmp(argv[1],"--addvdom")==0){ if (netconf_rootaccess()){ ret = vdomain_add (argv[2],argc-3,(const char **)(argv+3)); } }else{ ::usage(); } }else if (argc == 2 && strcmp(argv[1],"--generatecf")==0){ if (netconf_rootaccess()){ MAILCONF mconf; ret = mconf.generate_if(false); } }else{ ::usage(); } } return ret; } static MODULE_mailconf mailconf;