1 // Copyright (C) 2000 Mike Bell <mike@mikebell.org>,
2 // Bruce Guenter <bruceg@em.ca>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18 #include <config.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <stdio.h>
22 #include "daemon.h"
23 #include "config/configrc.h"
24 #include "misc/response.h"
25 #include "misc/lookup.h"
26 #include "misc/maildir.h"
27 #include "misc/pwentry_table.h"
28 #include "misc/stat_fns.h"
29 
autoresponse_write(const mystring & directory,const mystring & location,const mystring & disabled,const mystring & msg)30 response autoresponse_write(const mystring& directory,
31 			    const mystring& location,
32 			    const mystring& disabled,
33 			    const mystring& msg)
34 {
35   mystring tmpfile = location + ".lock";
36 
37   if(!is_dir(directory.c_str())) {
38     if(mkdir(directory.c_str(), 0755))
39       RETURN(err, "Could not create autoresponse directory");
40   }
41 
42   if(is_exist(tmpfile.c_str()))
43     RETURN(err, "Temporary autoresponse file already exists");
44 
45   if(is_exist(disabled.c_str()))
46     RETURN(err, "Autoresponse is disabled, reenable it before writing a new message");
47 
48   fdobuf out(tmpfile.c_str(), fdobuf::create | fdobuf::excl, 0644);
49   if(!out)
50     RETURN(err, "Unable to open temporary autoresponse file for writing");
51 
52   out << msg;
53   if(!out.flush() || !out.close()) {
54     unlink(tmpfile.c_str());
55     RETURN(err, "Unable to write message to file");
56   }
57   if(rename(tmpfile.c_str(), location.c_str())) {
58     unlink(tmpfile.c_str());
59     RETURN(err, "Unable to rename temporary autoresponse file");
60   }
61 
62   RETURN(ok, "Message successfully written to autoresponse file");
63 }
64 
autoresponse_disable(const mystring & location,const mystring & disabled)65 response autoresponse_disable(const mystring& location,
66 			      const mystring& disabled)
67 {
68   if(!is_exist(location.c_str()))
69     RETURN(ok, "Autoresponse file did not exist");
70   if(is_exist(disabled.c_str()))
71     RETURN(err, "Disabled autoresponse file already exists");
72   if(rename(location.c_str(), disabled.c_str()))
73     RETURN(err, "Unable to rename autoresponse file");
74   RETURN(ok, "Autoresponse file sucessfully disabled");
75 }
76 
autoresponse_enable(const mystring & location,const mystring & disabled)77 response autoresponse_enable(const mystring& location,
78 			     const mystring& disabled)
79 {
80   if(is_exist(location.c_str()))
81     RETURN(ok, "Autoresponse is already enabled");
82   if(!is_exist(disabled.c_str()))
83     RETURN(err, "Disabled autoresponse file did not exist");
84   if(rename(disabled.c_str(), location.c_str()))
85     RETURN(err, "Unable to rename previously disabled autoresponse file");
86   RETURN(ok, "Autoresponse file sucessfully restored");
87 }
88 
read_file(const mystring & filename,mystring & out)89 static bool read_file(const mystring& filename, mystring& out)
90 {
91   fdibuf in(filename.c_str());
92   if(!in)
93     return false;
94   char contents[65536];
95   unsigned contentlen;
96   in.read(contents, 65536);
97   contentlen = in.last_count();
98   out = mystring(contents, contentlen);
99   return true;
100 }
101 
autoresponse_read(const mystring & location,const mystring & disabled,int fd)102 response autoresponse_read(const mystring& location,
103 			   const mystring& disabled, int fd)
104 {
105   mystring line;
106   if(!is_exist(location.c_str()) &&
107      !is_exist(disabled.c_str()))
108     RETURN(err, "Autoresponder file does not exist");
109 
110   mystring contents;
111   if(!read_file(location, contents) &&
112      !read_file(disabled, contents))
113     RETURN(err, "Unable to read data from autoresponse file");
114   response resp(response::ok, contents);
115   resp.write(fd);
116   RETURN(ok, "Retrieved autoresponse file");
117 }
118 
autoresponse_delete(const mystring & directory)119 response autoresponse_delete(const mystring& directory)
120 {
121   if(!is_dir(directory.c_str()))
122     RETURN(err, "Autoresponse directory does not exist.");
123   if(!delete_directory(directory))
124     RETURN(err, "Could not delete autoresponse directory.");
125   RETURN(ok, "Autoresponse directory deleted.");
126 }
127 
autoresponse_status(const mystring & directory,const mystring & location,const mystring & disabled)128 response autoresponse_status(const mystring& directory,
129 			     const mystring& location,
130 			     const mystring& disabled)
131 {
132   const char* msg;
133   if(is_exist(location.c_str()))
134     msg = "enabled";
135   else if(is_exist(disabled.c_str()))
136     msg = "disabled";
137   else if(is_dir(directory.c_str()))
138     msg = "missing message file";
139   else
140     msg = "nonexistant";
141   RETURN(ok, msg);
142 }
143 
CMD_FD(autoresponse)144 CMD_FD(autoresponse)
145   // Usage: autoresponse baseuser-virtuser pass action [autorespmessage]
146 {
147 
148   mystring user = args[0];
149   mystring pass = args[1];
150   args[1] = LOG_PASSWORD;
151   mystring action = args[2];
152   mystring message;
153   if(args.count() == 4) {
154     message = args[3];
155     args[3] = LOG_MESSAGE;
156   }
157   logcommand(args);
158 
159   pwentry* pw;
160   vpwentry* vpw;
161   OK_RESPONSE(lookup_and_validate(user, pw, vpw, pass, true, true));
162 
163   const mystring directory = vpw->directory + "/" + config->autoresponse_dir();
164   const mystring filename = directory + "/" + config->autoresponse_file();
165   const mystring disabled = filename + ".disabled";
166 
167   if(action == "disable")
168     return autoresponse_disable(filename, disabled);
169   else if(action == "enable")
170     return autoresponse_enable(filename, disabled);
171   else if(action == "read")
172     return autoresponse_read(filename, disabled, fd);
173   else if(action == "write")
174     if(!message)
175       RETURN(bad, "Missing autoresponse message argument");
176     else
177       return autoresponse_write(directory, filename, disabled, message);
178   else if(action == "delete")
179     return autoresponse_delete(directory);
180   else if(action == "status")
181     return autoresponse_status(directory, filename, disabled);
182 
183   RETURN(err, "Unrecognized command");
184 }
185