1 // Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 
17 #include <config.h>
18 #include <stdlib.h>
19 #include <time.h>
20 #include "fdbuf/fdbuf.h"
21 #include "misc/passwdfn.h"
22 #include "mystring/mystring.h"
23 #include "config/configrc.h"
24 #include "misc/pwcrypt.h"
25 #include "vcommand.h"
26 #include "cli++/cli++.h"
27 
28 const char* cli_program = "vadduser";
29 const char* cli_help_prefix = "Add a user to a virtual domain\n";
30 const char* cli_help_suffix = "";
31 const char* cli_args_usage = "USERNAME [ALIAS1 ...]\n"
32 "or vaddalias USERNAME [ALIAS1 ...]";
33 const int cli_args_min = 1;
34 const int cli_args_max = -1;
35 
36 static const char* o_userdir = 0;
37 static cli_stringlist* o_forwards = 0;
38 static const char* o_personal = 0;
39 static int o_softquota = 0;
40 static int o_hardquota = 0;
41 static int o_msgsize = 0;
42 static int o_msgcount = 0;
43 static int o_expiry = 0;
44 static int o_password = true;
45 static int o_hasmailbox = true;
46 static int o_quiet = false;
47 static const char* o_pwcrypt = 0;
48 
49 // This program is used to set up a user within a virtual host.
50 // If this program is reading from a tty,
51 // it will then ask for a password (twice, to make sure you typed it in
52 // correctly), otherwise it will read the password from the input with no
53 // prompting.
54 // It will then
55 // add the user to the virtual password table in the current
56 // directory and create a mail directory for the new user.
57 // It will also add an entry for each of the named aliases.
58 
59 cli_option cli_options[] = {
60   { 'c', "msgcount", cli_option::integer, 0, &o_msgcount,
61     "Set the user's message count limit", 0 },
62   { 'D', "no-mailbox", cli_option::flag, false, &o_hasmailbox,
63     "Do not create a mailbox for this user", "true for vaddalias" },
64   { 'd', "directory", cli_option::string, 0, &o_userdir,
65     "Set the path to the user's mailbox", 0 },
66   // Set the path to the user's mailbox.
67   // Note that this directory is unconditionally prefixed with "./".
68   { 'e', "expiry", cli_option::integer, 0, &o_expiry,
69     "Set the account's expiry time (in seconds)", 0 },
70   { 'f', "forward", cli_option::stringlist, 0, &o_forwards,
71     "Add a forwarding address to this user", 0 },
72   // Add a forwarding address to this user (this may be used multiple times).
73   { 0,   "password",    cli_option::string, 0, &o_pwcrypt,
74     "Encrypted password", "asking for a password" },
75   { 'P', "no-password", cli_option::flag, false, &o_password,
76     "Do not ask for a password", 0 },
77   // Do not ask for a password,
78   // and instead set the pass phrase field to an unusable value.
79   { 'p', "personal", cli_option::string, 0, &o_personal,
80     "Set the user's personal information", 0 },
81   { 'Q', "hardquota", cli_option::integer, 0, &o_hardquota,
82     "Set the user's hard quota (in bytes)", 0 },
83   { 'q', "softquota", cli_option::integer, 0, &o_softquota,
84     "Set the user's soft quota (in bytes)", 0 },
85   { 0, "quiet", cli_option::flag, true, &o_quiet,
86     "Suppress all status messages", 0 },
87   { 'z', "msgsize", cli_option::integer, 0, &o_msgsize,
88     "Set the user's message size limit (in bytes)", 0 },
89   {0}
90 };
91 
92 // RETURN VALUE
93 //
94 // 0 if all steps were successful, non-zero otherwise.
95 // If any of the steps fail, a diagnostic message is printed.
96 
97 // SEE ALSO
98 //
99 // vsetup(1)
100 
101 // NOTES
102 // You must have either created the users subdirectory by hand or run the
103 // F<vsetup> program before using this program.
104 //
105 // This program expects the environment variable C<HOME> to be set, and
106 // executes a change directory to the contents of it before starting.  It
107 // is also required that you change user to the domain owner before using
108 // these utilities.
109 
list2str(cli_stringlist * list)110 mystring list2str(cli_stringlist* list)
111 {
112   if(!list)
113     return 0;
114   mystring result = list->string;
115   list = list->next;
116   while(list) {
117     result = result + mystring::NUL + list->string;
118     list = list->next;
119   }
120   return result;
121 }
122 
make_user(const mystring & name,const mystring & passcode)123 vpwentry* make_user(const mystring& name, const mystring& passcode)
124 {
125   mystring dir;
126   if(o_userdir)
127     dir = o_userdir;
128   else
129     dir = domain.userdir(name);
130   dir = "./" + dir;
131 
132   for(cli_stringlist* node = o_forwards; node; node = node->next) {
133     response r = domain.validate_forward(node->string);
134     if(!r) {
135       if(!o_quiet)
136 	ferr << argv0base << ": invalid forwarding address:\n  "
137 	     << r.msg << endl;
138       exit(1);
139     }
140   }
141 
142   vpwentry* vpw = new vpwentry(name.lower(), passcode, dir,
143 			       list2str(o_forwards), o_hasmailbox);
144   vpw->personal = o_personal;
145   vpw->hardquota = o_hardquota;
146   vpw->softquota = o_softquota;
147   vpw->msgcount = o_msgcount;
148   vpw->msgsize = o_msgsize;
149   vpw->expiry = o_expiry;
150   //vpw->data = list2str(o_extra);
151 
152   return vpw;
153 }
154 
add_user(const mystring & user)155 void add_user(const mystring& user)
156 {
157   if(!domain.exists(user)) {
158     mystring passcode;
159     if(o_pwcrypt)
160       passcode = o_pwcrypt;
161     else if(o_password) {
162       mystring passwd = getpasswd(argv0base);
163       if(passwd.length() == 0)
164 	exit(1);
165       passcode = pwcrypt(passwd);
166     }
167     else
168       passcode = "*";
169     vpwentry* vpw = make_user(user, passcode);
170     response resp = domain.set(vpw, true);
171     delete vpw;
172     if(!resp) {
173       if(!o_quiet)
174 	ferr << argv0base << ": error adding the virtual user:\n  "
175 	     << resp.msg << endl;
176       exit(1);
177     }
178   }
179   else {
180     ferr << argv0base << ": error: user '" << user << "' already exists."
181 	 << endl;
182     exit(1);
183   }
184 }
185 
add_alias(mystring user,mystring alias)186 void add_alias(mystring user, mystring alias)
187 {
188   alias = alias.lower();
189   user = user.lower();
190   if(!domain.exists(alias)) {
191     vpwentry vpw(alias, "*", domain.userdir(alias), user, false);
192     response resp = domain.set(&vpw, true);
193     if(!resp)
194       if(!o_quiet)
195 	ferr << argv0base << ": warning: adding the alias '"
196 	     << alias
197 	     << "' failed:\n  "
198 	     << resp.msg << endl;
199     else
200       if(!o_quiet)
201 	fout << argv0base << ": alias '" << alias << "' successfully added"
202 	     << endl;
203   }
204   else
205     if(!o_quiet)
206       ferr << argv0base << ": warning: alias '" << alias << "' already exists."
207 	   << endl;
208 }
209 
set_defaults()210 void set_defaults()
211 {
212   if(!strcmp(argv0base, "vaddalias"))
213     o_hasmailbox = false;
214   if(!o_hardquota)
215     o_hardquota = config->default_hardquota();
216   if(!o_softquota)
217     o_softquota = config->default_softquota();
218   if(!o_msgsize)
219     o_msgsize = config->default_msgsize();
220   if(!o_msgcount)
221     o_msgcount = config->default_msgcount();
222   if(!o_expiry)
223     o_expiry = config->default_expiry();
224   if(o_expiry != -1)
225     o_expiry += time(0);
226 }
227 
cli_main(int argc,char * argv[])228 int cli_main(int argc, char* argv[])
229 {
230   if(!go_home())
231     return 1;
232 
233   set_defaults();
234 
235   add_user(argv[0]);
236   if(!o_quiet)
237     fout << argv0base << ": user '" << argv[0] << "' successfully added"
238 	 << endl;
239 
240   for(int i = 1; i < argc; i++)
241     add_alias(argv[0], argv[i]);
242 
243   return 0;
244 }
245