Handle hostnames with upper-case letters
[webmin.git] / pptp-client / save.cgi
1 #!/usr/local/bin/perl
2 # save.cgi
3 # Create, update or delete a PPTP tunnel
4
5 require './pptp-client-lib.pl';
6 &ReadParse();
7 @tunnels = &list_tunnels();
8 @secs = &list_secrets();
9 if (!$in{'new'}) {
10         ($tunnel) = grep { $_->{'name'} eq $in{'old'} } @tunnels;
11         &parse_comments($tunnel);
12         $name = &find("name", $tunnel->{'opts'});
13         $remote = &find("remotename", $tunnel->{'opts'});
14         $sec = &find_secret($name ? $name->{'value'} : &get_system_hostname(1),
15                             $remote ? $remote->{'value'} : undef);
16         &lock_file($tunnel->{'file'});
17         }
18 else {
19         $tunnel = { 'opts' => [ ] };
20         }
21 &error_setup($text{'save_err'});
22 &lock_file($config{'pap_file'});
23
24 if ($in{'delete'}) {
25         # Just delete this tunnel and it's secret (if not used by any other)
26         unlink($tunnel->{'file'});
27         }
28 else {
29         # Validate inputs
30         $in{'tunnel'} =~ /\S/ || &error($text{'save_ename'});
31         &to_ipaddress($in{'server'}) || &error($text{'save_eserver'});
32         $in{'login_def'} || $in{'login'} =~ /^\S+$/ ||
33                 &error($text{'save_elogin'});
34         $in{'remote_def'} || $in{'remote'} =~ /^\S+$/ ||
35                 &error($text{'save_eremote'});
36         $in{'file_def'} < 2 || -r $in{'file'} ||
37                 &error($text{'save_efile'});
38
39         # Add default route changes
40         if ($in{'deldef'}) {
41                 push(@routes, "delete default");
42                 }
43         if ($in{'adddef'} == 1) {
44                 push(@routes, "add default dev TUNNEL_DEV");
45                 }
46         elsif ($in{'adddef'} == 2) {
47                 &to_ipaddress($in{'def'}) || &error($text{'save_edef'});
48                 push(@routes, "add default gw ".$in{'def'});
49                 }
50
51         # Parse and add extra route commands
52         $in{'unknown'} =~ s/\r//g;
53         push(@routes, grep { /\S/ } split(/\n/, $in{'unknown'}));
54
55         # Parse and add static routes
56         for($i=0; defined($t = $in{"type_$i"}); $i++) {
57                 next if (!$t);
58                 if ($t == 1) {
59                         &check_ipaddress($in{"net_$i"}) ||
60                                 &error(&text('save_enet', $i+1));
61                         &check_ipaddress($in{"mask_$i"}) ||
62                                 &error(&text('save_emask', $i+1));
63                         $in{"gw_def_$i"} || &check_ipaddress($in{"gw_$i"}) ||
64                                 &error(&text('save_egw', $i+1));
65                         if ($in{"gw_def_$i"}) {
66                                 push(@routes,
67                                     sprintf("add -net %s dev %s netmask %s",
68                                         $in{"net_$i"}, 'TUNNEL_DEV',
69                                         $in{"mask_$i"}));
70                                 }
71                         else {
72                                 push(@routes,
73                                     sprintf("add -net %s gw %s netmask %s",
74                                         $in{"net_$i"}, $in{"gw_$i"},
75                                         $in{"mask_$i"}));
76                                 }
77                         }
78                 else {
79                         &check_ipaddress($in{"net_$i"}) ||
80                                 &error(&text('save_ehost', $i+1));
81                         $in{"mask_$i"} && &error(&text('save_emask2', $i+1));
82                         $in{"gw_def_$i"} || &check_ipaddress($in{"gw_$i"}) ||
83                                 &error(&text('save_egw2', $i+1));
84                         if ($in{"gw_def_$i"}) {
85                                 push(@routes,
86                                     sprintf("add -host %s dev %s",
87                                         $in{"net_$i"}, 'TUNNEL_DEV'));
88                                 }
89                         else {
90                                 push(@routes,
91                                     sprintf("add -host %s gw %s",
92                                         $in{"net_$i"}, $in{"gw_$i"}));
93                                 }
94                         }
95                 }
96
97
98         mkdir($config{'peers_dir'}, 0755);
99         if ($in{'new'}) {
100                 &check_clash();
101
102                 # Create file and set default options
103                 $tunnel->{'name'} = $in{'tunnel'};
104                 $tunnel->{'file'} = "$config{'peers_dir'}/$in{'tunnel'}";
105                 &lock_file($tunnel->{'file'});
106                 &save_ppp_option($tunnel->{'opts'}, $tunnel->{'file'}, undef,
107                                  { 'comment' => "PPTP Tunnel configuration for tunnel $in{'tunnel'}" });
108                 }
109         else {
110                 # Check for a re-name
111                 if ($in{'tunnel'} ne $tunnel->{'name'}) {
112                         &check_clash();
113                         $tunnel->{'name'} = $in{'tunnel'};
114                         $nf = "$config{'peers_dir'}/$in{'tunnel'}";
115                         rename($tunnel->{'file'}, $nf) ||
116                                 &error($text{'save_erename'});
117                         $tunnel->{'file'} = $nf;
118                         }
119                 }
120
121         # Save server IP
122         &save_ppp_option($tunnel->{'opts'}, $tunnel->{'file'},
123                          $tunnel->{'server_c'},
124                          { 'comment' => "Server IP: $in{'server'}" } );
125
126         # Save all routes
127         @or = @{$tunnel->{'routes_c'}};
128         for($i=0; $i<@routes || $i<@or; $i++) {
129                 &save_ppp_option($tunnel->{'opts'}, $tunnel->{'file'},
130                                  $or[$i], $routes[$i] ?
131                                         { 'comment' => "Route: $routes[$i]" } : undef);
132                 }
133
134         # Save PPP options
135         &save_ppp_option($tunnel->{'opts'}, $tunnel->{'file'}, "name",
136                          $in{'login_def'} ? undef :
137                          { 'name' => 'name', 'value' => $in{'login'} } );
138         &save_ppp_option($tunnel->{'opts'}, $tunnel->{'file'}, "remotename",
139                          $in{'remote_def'} ? undef :
140                          { 'name' => 'remotename','value' => $in{'remote'} } );
141         &save_ppp_option($tunnel->{'opts'}, $tunnel->{'file'}, "file",
142                          $in{'file_def'} == 0 ? undef :
143                          $in{'file_def'} == 1 ? 
144                                 { 'name' => 'file',
145                                   'value' => $config{'pptp_options'} } :
146                                 { 'name' => 'file',
147                                   'value' => $in{'file'} });
148         &parse_mppe_options($tunnel->{'opts'}, $tunnel->{'file'});
149
150         # Update or add to the secrets file
151         $newname = $in{'login_def'} ? &get_system_hostname(1) : $in{'login'};
152         $newremote = $in{'remote_def'} ? "*" : $in{'remote'};
153         if (!$sec) {
154                 # No old secret was found, so look for one matching the new
155                 # details
156                 $sec = &find_secret($newname, $newremote);
157                 }
158         if ($sec) {
159                 # Just update the secret for our login name with the new login
160                 # and password. This can happen when re-naming, or if a secret
161                 # for the name already exists
162                 $sec->{'client'} = $newname;
163                 if ($sec->{'server'} ne '*' && $newremote ne '*') {
164                         $sec->{'server'} = $newremote;
165                         }
166                 $sec->{'secret'} = $in{'pass'};
167                 &change_secret($sec);
168                 }
169         else {
170                 # Need to create a new secret
171                 $sec = { 'client' => $newname,
172                          'secret' => $in{'pass'},
173                          'server' => $newremote };
174                 &create_secret($sec);
175                 }
176
177         &flush_file_lines();
178         }
179 &unlock_file($tunnel->{'file'});
180 &unlock_file($config{'pap_file'});
181
182 &webmin_log($in{'new'} ? "create" : $in{'delete'} ? "delete" : "update",
183             "tunnel", $tunnel->{'name'});
184 &redirect("");
185
186 sub check_clash
187 {
188 -r "$config{'peers_dir'}/$in{'tunnel'}" && &error($text{'save_eclash'});
189 }
190
191 # find_secret(client, server)
192 # Returns the best matching secret with the given details
193 sub find_secret
194 {
195 local ($exact) = grep { $_->{'client'} eq $_[0] &&
196                         $_->{'server'} eq $_[1] } @secs;
197 return $exact if ($exact);
198 local ($client) = grep { $_->{'client'} eq $_[0] } @secs;
199 return $client;
200 }
201