1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML
4.0//EN'
>
6 For use with Tomato Firmware only.
7 No part of this file may be used without permission.
11 <meta http-equiv='content-type' content='text/html;charset=utf-
8'
>
12 <meta name='robots' content='noindex,nofollow'
>
13 <title>[<%
ident(); %>] NAS: FTP Server
</title>
14 <link rel='stylesheet' type='text/css' href='tomato.css'
>
15 <link rel='stylesheet' type='text/css' href='color.css'
>
16 <script type='text/javascript' src='tomato.js'
></script>
19 <style tyle='text/css'
>
32 <style type='text/css'
>
39 <script type='text/javascript' src='debug.js'
></script>
41 <script type='text/javascript'
>
43 // <% nvram("ftp_enable,ftp_super,ftp_anonymous,ftp_dirlist,ftp_port,ftp_max,ftp_ipmax,ftp_staytimeout,ftp_rate,ftp_anonrate,ftp_anonroot,ftp_pubroot,ftp_pvtroot,ftp_custom,ftp_users,ftp_sip,ftp_limit,log_ftp"); %>
45 ftplimit
= nvram
.ftp_limit
.split(',');
46 if (ftplimit
.length
!= 3) ftplimit
= [0,3,60];
48 var aftg
= new TomatoGrid();
50 aftg
.exist = function(f
, v
)
52 var data
= this.getAllData();
53 for (var i
= 0; i
< data
.length
; ++i
) {
54 if (data
[i
][f
] == v
) return true;
59 aftg
.existName = function(name
)
61 return this.exist(0, name
);
64 aftg
.sortCompare = function(a
, b
) {
65 var da
= a
.getRowData();
66 var db
= b
.getRowData();
67 var r
= cmpText(da
[this.sortColumn
], db
[this.sortColumn
]);
68 return this.sortAscending
? r
: -r
;
71 aftg
.verifyFields = function(row
, quiet
)
74 f
= fields
.getAll(row
);
79 if (!v_length(f
[0], quiet
, 1)) return 0;
81 s
= f
[0].value
.trim().replace(/\s+/g, ' ');
83 if (s
.search(/^[a-zA-Z0-9_\-]+$/) == -1) {
84 ferror
.set(f
[0], 'Invalid user name. Only characters "A-Z 0-9 - _" are allowed.', quiet
);
87 if (this.existName(s
)) {
88 ferror
.set(f
[0], 'Duplicate user name.', quiet
);
94 if (!v_length(f
[1], quiet
, 1)) return 0;
95 if (!v_nodelim(f
[1], quiet
, 'Password', 1)) return 0;
100 aftg
.resetNewEditor = function() {
103 f
= fields
.getAll(this.newEditor
);
108 f
[2].selectedIndex
= 0;
111 aftg
.setup = function()
113 this.init('aft-grid', 'sort', 50, [
114 { type
: 'text', maxlen
: 50 },
115 { type
: 'password', maxlen
: 50, peekaboo
: 1 },
116 { type
: 'select', options
: [['Read/Write', 'Read/Write'],['Read Only', 'Read Only'],['View Only', 'View Only'],['Private', 'Private']] }
118 this.headerSet(['User Name', 'Password', 'Access']);
120 var s
= nvram
.ftp_users
.split('>');
121 for (var i
= 0; i
< s
.length
; ++i
) {
122 var t
= s
[i
].split('<');
124 this.insertData(-1, t
);
128 this.showNewEditor();
129 this.resetNewEditor();
132 function verifyFields(focused
, quiet
)
137 a
= E('_ftp_enable').value
;
139 elem
.display(PR(b
), (a
!= 0));
141 elem
.display(PR(b
), (a
== 1));
143 E('_f_limit').disabled
= (a
!= 1);
144 b
= E('_f_limit').checked
;
145 elem
.display(PR('_f_limit_hit'), PR('_f_limit_sec'), (a
== 1 && b
));
146 E('_ftp_anonymous').disabled
= (a
== 0);
147 E('_f_ftp_super').disabled
= (a
== 0);
148 E('_f_log_ftp').disabled
= (a
== 0);
149 E('_ftp_pubroot').disabled
= (a
== 0);
150 E('_ftp_pvtroot').disabled
= (a
== 0);
151 E('_ftp_anonroot').disabled
= (a
== 0);
152 E('_ftp_dirlist').disabled
= (a
== 0);
153 E('_ftp_max').disabled
= (a
== 0);
154 E('_ftp_ipmax').disabled
= (a
== 0);
155 E('_ftp_rate').disabled
= (a
== 0);
156 E('_ftp_anonrate').disabled
= (a
== 0);
157 E('_ftp_staytimeout').disabled
= (a
== 0);
158 E('_ftp_custom').disabled
= (a
== 0);
161 if (!v_port('_ftp_port', quiet
|| !ok
)) ok
= 0;
162 if (!v_range('_ftp_max', quiet
|| !ok
, 0, 12)) ok
= 0;
163 if (!v_range('_ftp_ipmax', quiet
|| !ok
, 0, 12)) ok
= 0;
164 if (!v_range('_ftp_rate', quiet
|| !ok
, 0, 99999)) ok
= 0;
165 if (!v_range('_ftp_anonrate', quiet
|| !ok
, 0, 99999)) ok
= 0;
166 if (!v_range('_ftp_staytimeout', quiet
|| !ok
, 0, 65535)) ok
= 0;
167 if (!v_length('_ftp_custom', quiet
|| !ok
, 0, 2048)) ok
= 0;
168 if (!v_path('_ftp_pubroot', quiet
|| !ok
, 0)) ok
= 0;
169 if (!v_path('_ftp_pvtroot', quiet
|| !ok
, 0)) ok
= 0;
170 if (!v_path('_ftp_anonroot', quiet
|| !ok
, 0)) ok
= 0;
172 if (!v_range('_f_limit_hit', quiet
|| !ok
, 1, 100)) ok
= 0;
173 if (!v_range('_f_limit_sec', quiet
|| !ok
, 3, 3600)) ok
= 0;
179 if ((b
.value
.length
) && (!_v_iptaddr(b
, quiet
|| !ok
, 15, 1, 1))) ok
= 0;
180 else ferror
.clear(b
);
188 if (aftg
.isEditing()) return;
189 if (!verifyFields(null, 0)) return;
193 var data
= aftg
.getAllData();
195 for (var i
= 0; i
< data
.length
; ++i
) r
.push(data
[i
].join('<'));
196 fom
.ftp_users
.value
= r
.join('>');
198 fom
.ftp_sip
.value
= fom
.f_ftp_sip
.value
.split(/\s*,\s*/).join(',');
199 fom
.ftp_super
.value
= E('_f_ftp_super').checked
? 1 : 0;
200 fom
.log_ftp
.value
= E('_f_log_ftp').checked
? 1 : 0;
202 fom
.ftp_limit
.value
= (E('_f_limit').checked
? 1 : 0) +
203 ',' + E('_f_limit_hit').value
+ ',' + E('_f_limit_sec').value
;
211 <form id='_fom' method='post' action='tomato.cgi'
>
212 <table id='container' cellspacing=
0>
213 <tr><td colspan=
2 id='header'
>
214 <div class='title'
>Tomato
</div>
215 <div class='version'
>Version <%
version(); %></div>
217 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
219 <div id='ident'
><%
ident(); %></div>
223 <input type='hidden' name='_nextpage' value='nas-ftp.asp'
>
224 <input type='hidden' name='_service' value='ftpd-restart'
>
226 <input type='hidden' name='ftp_super'
>
227 <input type='hidden' name='log_ftp'
>
228 <input type='hidden' name='ftp_users'
>
229 <input type='hidden' name='ftp_sip'
>
230 <input type='hidden' name='ftp_limit'
>
232 <div class='section-title'
>FTP Server Configuration
</div>
233 <div class='section'
>
234 <script type='text/javascript'
>
235 createFieldTable('', [
236 { title
: 'Enable FTP Server', name
: 'ftp_enable', type
: 'select',
237 options
: [['0', 'No'],['1', 'Yes, WAN and LAN'],['2', 'Yes, LAN only']],
238 value
: nvram
.ftp_enable
},
239 { title
: 'FTP Port', indent
: 2, name
: 'ftp_port', type
: 'text', maxlen
: 5, size
: 7, value
: fixPort(nvram
.ftp_port
, 21) },
240 { title
: 'Allowed Remote<br>Address(es)', indent
: 2, name
: 'f_ftp_sip', type
: 'text', maxlen
: 512, size
: 64, value
: nvram
.ftp_sip
,
241 suffix
: '<br><small>(optional; ex: "1.1.1.1", "1.1.1.0/24", "1.1.1.1 - 2.2.2.2" or "me.example.com")</small>' },
242 { title
: 'Anonymous Users Access', name
: 'ftp_anonymous', type
: 'select',
243 options
: [['0', 'Disabled'],['1', 'Read/Write'],['2', 'Read Only'],['3', 'Write Only']],
244 value
: nvram
.ftp_anonymous
},
245 { title
: 'Allow Admin Login*', name
: 'f_ftp_super', type
: 'checkbox',
246 suffix
: ' <small>Allows users to connect with admin account.</small>',
247 value
: nvram
.ftp_super
== 1 },
248 { title
: 'Log FTP requests and responses', name
: 'f_log_ftp', type
: 'checkbox',
249 value
: nvram
.log_ftp
== 1 }
252 <small><br>*
Avoid using this option when FTP server is enabled for WAN. IT PROVIDES FULL ACCESS TO THE ROUTER FILE SYSTEM!
</small>
255 <div class='section-title'
>Directories
</div>
256 <div class='section'
>
257 <script type='text/javascript'
>
258 createFieldTable('', [
259 { title
: 'Public Root Directory*', name
: 'ftp_pubroot', type
: 'text', maxlen
: 256, size
: 32,
260 suffix
: ' <small>(for authenticated users access)</small>',
261 value
: nvram
.ftp_pubroot
},
262 { title
: 'Private Root Directory**', name
: 'ftp_pvtroot', type
: 'text', maxlen
: 256, size
: 32,
263 suffix
: ' <small>(for authenticated users access in private mode)</small>',
264 value
: nvram
.ftp_pvtroot
},
265 { title
: 'Anonymous Root Directory*', name
: 'ftp_anonroot', type
: 'text', maxlen
: 256, size
: 32,
266 suffix
: ' <small>(for anonymous connections)</small>',
267 value
: nvram
.ftp_anonroot
},
268 { title
: 'Directory Listings', name
: 'ftp_dirlist', type
: 'select',
269 options
: [['0', 'Enabled'],['1', 'Disabled'],['2', 'Disabled for Anonymous']],
270 suffix
: ' <small>(always enabled for Admin)</small>',
271 value
: nvram
.ftp_dirlist
}
275 <br>*
When no directory is specified, /mnt is used as a root directory.
276 <br>**
In private mode, the root directory is the directory under the
"Private Root Directory" with the name matching the name of the user.
280 <div class='section-title'
>Limits
</div>
281 <div class='section'
>
282 <script type='text/javascript'
>
283 createFieldTable('', [
284 { title
: 'Maximum Users Allowed to Log in', name
: 'ftp_max', type
: 'text', maxlen
: 5, size
: 7,
285 suffix
: ' <small>(0 - unlimited)</small>',
286 value
: nvram
.ftp_max
},
287 { title
: 'Maximum Connections from the same IP', name
: 'ftp_ipmax', type
: 'text', maxlen
: 5, size
: 7,
288 suffix
: ' <small>(0 - unlimited)</small>',
289 value
: nvram
.ftp_ipmax
},
290 { title
: 'Maximum Bandwidth for Anonymous Users', name
: 'ftp_anonrate', type
: 'text', maxlen
: 5, size
: 7,
291 suffix
: ' <small>KBytes/sec (0 - unlimited)</small>',
292 value
: nvram
.ftp_anonrate
},
293 { title
: 'Maximum Bandwidth for Authenticated Users', name
: 'ftp_rate', type
: 'text', maxlen
: 5, size
: 7,
294 suffix
: ' <small>KBytes/sec (0 - unlimited)</small>',
295 value
: nvram
.ftp_rate
},
296 { title
: 'Idle Timeout', name
: 'ftp_staytimeout', type
: 'text', maxlen
: 5, size
: 7,
297 suffix
: ' <small>seconds (0 - no timeout)</small>',
298 value
: nvram
.ftp_staytimeout
},
299 { title
: 'Limit Connection Attempts', name
: 'f_limit', type
: 'checkbox',
300 value
: ftplimit
[0] != 0 },
301 { title
: '', indent
: 2, multi
: [
302 { name
: 'f_limit_hit', type
: 'text', maxlen
: 4, size
: 6, suffix
: ' <small>every</small> ', value
: ftplimit
[1] },
303 { name
: 'f_limit_sec', type
: 'text', maxlen
: 4, size
: 6, suffix
: ' <small>seconds</small>', value
: ftplimit
[2] }
309 <div class='section-title'
>Custom Configuration
</div>
310 <div class='section'
>
311 <script type='text/javascript'
>
312 createFieldTable('', [
313 { title
: '<a href="http://vsftpd.beasts.org/vsftpd_conf.html" target="_new">Vsftpd</a><br>Custom Configuration', name
: 'ftp_custom', type
: 'textarea', value
: nvram
.ftp_custom
}
318 <div class='section-title'
>User Accounts
</div>
319 <div class='section'
>
320 <table class='tomato-grid' cellspacing=
1 id='aft-grid'
></table>
321 <script type='text/javascript'
>aftg
.setup();</script>
327 <tr><td id='footer' colspan=
2>
328 <span id='footer-msg'
></span>
329 <input type='button' value='Save' id='save-button' onclick='save()'
>
330 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'
>
334 <script type='text/javascript'
>verifyFields(null, 1);</script>