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'
>
37 <style type='text/css'
>
44 <script type='text/javascript' src='debug.js'
></script>
46 <script type='text/javascript'
>
48 // <% 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"); %>
50 ftplimit
= nvram
.ftp_limit
.split(',');
51 if (ftplimit
.length
!= 3) ftplimit
= [0,3,60];
53 var aftg
= new TomatoGrid();
55 aftg
.exist = function(f
, v
)
57 var data
= this.getAllData();
58 for (var i
= 0; i
< data
.length
; ++i
) {
59 if (data
[i
][f
] == v
) return true;
64 aftg
.existName = function(name
)
66 return this.exist(0, name
);
69 aftg
.sortCompare = function(a
, b
) {
70 var da
= a
.getRowData();
71 var db
= b
.getRowData();
72 var r
= cmpText(da
[this.sortColumn
], db
[this.sortColumn
]);
73 return this.sortAscending
? r
: -r
;
76 aftg
.verifyFields = function(row
, quiet
)
79 f
= fields
.getAll(row
);
85 if (!v_length(f
[0], quiet
, 1)) return 0;
87 s
= f
[0].value
.trim().replace(/\s+/g, ' ');
89 if (s
.search(/^[a-zA-Z0-9_\-]+$/) == -1) {
90 ferror
.set(f
[0], 'Invalid user name. Only characters "A-Z 0-9 - _" are allowed.', quiet
);
93 if (this.existName(s
)) {
94 ferror
.set(f
[0], 'Duplicate user name.', quiet
);
97 if (s
== 'root' || s
== 'admin') {
98 ferror
.set(f
[0], 'User names "root" and "admin" are not allowed.', quiet
);
104 if (!v_length(f
[1], quiet
, 1)) return 0;
105 if (!v_nodelim(f
[1], quiet
, 'Password', 1)) return 0;
106 if (f
[2].value
== 'Private') {
108 f
[3].disabled
= true;
111 f
[3].disabled
= false;
112 if (!v_nodelim(f
[3], quiet
, 'Root Directory', 1) || !v_path(f
[3], quiet
, 0)) return 0;
118 aftg
.resetNewEditor = function() {
121 f
= fields
.getAll(this.newEditor
);
126 f
[2].selectedIndex
= 0;
130 aftg
.setup = function()
132 this.init('aft-grid', 'sort', 50, [
133 { type
: 'text', maxlen
: 50 },
134 { type
: 'password', maxlen
: 50, peekaboo
: 1 },
135 { type
: 'select', options
: [['Read/Write', 'Read/Write'],['Read Only', 'Read Only'],['View Only', 'View Only'],['Private', 'Private']] },
136 { type
: 'text', maxlen
: 128 }
138 this.headerSet(['User Name', 'Password', 'Access', 'Root Directory*']);
140 var s
= nvram
.ftp_users
.split('>');
141 for (var i
= 0; i
< s
.length
; ++i
) {
142 var t
= s
[i
].split('<');
147 this.insertData(-1, t
);
151 this.showNewEditor();
152 this.resetNewEditor();
155 function verifyFields(focused
, quiet
)
160 a
= E('_ftp_enable').value
;
162 elem
.display(PR(b
), (a
!= 0));
164 elem
.display(PR(b
), (a
== 1));
166 E('_f_limit').disabled
= (a
!= 1);
167 b
= E('_f_limit').checked
;
168 elem
.display(PR('_f_limit_hit'), PR('_f_limit_sec'), (a
== 1 && b
));
169 E('_ftp_anonymous').disabled
= (a
== 0);
170 E('_f_ftp_super').disabled
= (a
== 0);
171 E('_f_log_ftp').disabled
= (a
== 0);
172 E('_ftp_pubroot').disabled
= (a
== 0);
173 E('_ftp_pvtroot').disabled
= (a
== 0);
174 E('_ftp_anonroot').disabled
= (a
== 0);
175 E('_ftp_dirlist').disabled
= (a
== 0);
176 E('_ftp_max').disabled
= (a
== 0);
177 E('_ftp_ipmax').disabled
= (a
== 0);
178 E('_ftp_rate').disabled
= (a
== 0);
179 E('_ftp_anonrate').disabled
= (a
== 0);
180 E('_ftp_staytimeout').disabled
= (a
== 0);
181 E('_ftp_custom').disabled
= (a
== 0);
184 if (!v_port('_ftp_port', quiet
|| !ok
)) ok
= 0;
185 if (!v_range('_ftp_max', quiet
|| !ok
, 0, 12)) ok
= 0;
186 if (!v_range('_ftp_ipmax', quiet
|| !ok
, 0, 12)) ok
= 0;
187 if (!v_range('_ftp_rate', quiet
|| !ok
, 0, 99999)) ok
= 0;
188 if (!v_range('_ftp_anonrate', quiet
|| !ok
, 0, 99999)) ok
= 0;
189 if (!v_range('_ftp_staytimeout', quiet
|| !ok
, 0, 65535)) ok
= 0;
190 if (!v_length('_ftp_custom', quiet
|| !ok
, 0, 2048)) ok
= 0;
191 if (!v_path('_ftp_pubroot', quiet
|| !ok
, 0)) ok
= 0;
192 if (!v_path('_ftp_pvtroot', quiet
|| !ok
, 0)) ok
= 0;
193 if (!v_path('_ftp_anonroot', quiet
|| !ok
, 0)) ok
= 0;
195 if (!v_range('_f_limit_hit', quiet
|| !ok
, 1, 100)) ok
= 0;
196 if (!v_range('_f_limit_sec', quiet
|| !ok
, 3, 3600)) ok
= 0;
202 if ((b
.value
.length
) && (!_v_iptaddr(b
, quiet
|| !ok
, 15, 1, 1))) ok
= 0;
203 else ferror
.clear(b
);
211 if (aftg
.isEditing()) return;
212 if (!verifyFields(null, 0)) return;
216 var data
= aftg
.getAllData();
218 for (var i
= 0; i
< data
.length
; ++i
) r
.push(data
[i
].join('<'));
219 fom
.ftp_users
.value
= r
.join('>');
221 fom
.ftp_sip
.value
= fom
.f_ftp_sip
.value
.split(/\s*,\s*/).join(',');
222 fom
.ftp_super
.value
= E('_f_ftp_super').checked
? 1 : 0;
223 fom
.log_ftp
.value
= E('_f_log_ftp').checked
? 1 : 0;
225 fom
.ftp_limit
.value
= (E('_f_limit').checked
? 1 : 0) +
226 ',' + E('_f_limit_hit').value
+ ',' + E('_f_limit_sec').value
;
234 <form id='_fom' method='post' action='tomato.cgi'
>
235 <table id='container' cellspacing=
0>
236 <tr><td colspan=
2 id='header'
>
237 <div class='title'
>Tomato
</div>
238 <div class='version'
>Version <%
version(); %></div>
240 <tr id='body'
><td id='navi'
><script type='text/javascript'
>navi()</script></td>
242 <div id='ident'
><%
ident(); %></div>
246 <input type='hidden' name='_nextpage' value='nas-ftp.asp'
>
247 <input type='hidden' name='_service' value='ftpd-restart'
>
249 <input type='hidden' name='ftp_super'
>
250 <input type='hidden' name='log_ftp'
>
251 <input type='hidden' name='ftp_users'
>
252 <input type='hidden' name='ftp_sip'
>
253 <input type='hidden' name='ftp_limit'
>
255 <div class='section-title'
>FTP Server Configuration
</div>
256 <div class='section'
>
257 <script type='text/javascript'
>
258 createFieldTable('', [
259 { title
: 'Enable FTP Server', name
: 'ftp_enable', type
: 'select',
260 options
: [['0', 'No'],['1', 'Yes, WAN and LAN'],['2', 'Yes, LAN only']],
261 value
: nvram
.ftp_enable
},
262 { title
: 'FTP Port', indent
: 2, name
: 'ftp_port', type
: 'text', maxlen
: 5, size
: 7, value
: fixPort(nvram
.ftp_port
, 21) },
263 { title
: 'Allowed Remote<br>Address(es)', indent
: 2, name
: 'f_ftp_sip', type
: 'text', maxlen
: 512, size
: 64, value
: nvram
.ftp_sip
,
264 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>' },
265 { title
: 'Anonymous Users Access', name
: 'ftp_anonymous', type
: 'select',
266 options
: [['0', 'Disabled'],['1', 'Read/Write'],['2', 'Read Only'],['3', 'Write Only']],
267 value
: nvram
.ftp_anonymous
},
268 { title
: 'Allow Admin Login*', name
: 'f_ftp_super', type
: 'checkbox',
269 suffix
: ' <small>Allows users to connect with admin account.</small>',
270 value
: nvram
.ftp_super
== 1 },
271 { title
: 'Log FTP requests and responses', name
: 'f_log_ftp', type
: 'checkbox',
272 value
: nvram
.log_ftp
== 1 }
275 <small><br>*
Avoid using this option when FTP server is enabled for WAN. IT PROVIDES FULL ACCESS TO THE ROUTER FILE SYSTEM!
</small>
278 <div class='section-title'
>Directories
</div>
279 <div class='section'
>
280 <script type='text/javascript'
>
281 createFieldTable('', [
282 { title
: 'Anonymous Root Directory*', name
: 'ftp_anonroot', type
: 'text', maxlen
: 256, size
: 32,
283 suffix
: ' <small>(for anonymous connections)</small>',
284 value
: nvram
.ftp_anonroot
},
285 { title
: 'Public Root Directory*', name
: 'ftp_pubroot', type
: 'text', maxlen
: 256, size
: 32,
286 suffix
: ' <small>(for authenticated users access, if not specified for the user)</small>',
287 value
: nvram
.ftp_pubroot
},
288 { title
: 'Private Root Directory**', name
: 'ftp_pvtroot', type
: 'text', maxlen
: 256, size
: 32,
289 suffix
: ' <small>(for authenticated users access in private mode)</small>',
290 value
: nvram
.ftp_pvtroot
},
291 { title
: 'Directory Listings', name
: 'ftp_dirlist', type
: 'select',
292 options
: [['0', 'Enabled'],['1', 'Disabled'],['2', 'Disabled for Anonymous']],
293 suffix
: ' <small>(always enabled for Admin)</small>',
294 value
: nvram
.ftp_dirlist
}
298 <br>*
When no directory is specified, /mnt is used as a root directory.
299 <br>**
In private mode, the root directory is the directory under the
"Private Root Directory" with the name matching the name of the user.
303 <div class='section-title'
>Limits
</div>
304 <div class='section'
>
305 <script type='text/javascript'
>
306 createFieldTable('', [
307 { title
: 'Maximum Users Allowed to Log in', name
: 'ftp_max', type
: 'text', maxlen
: 5, size
: 7,
308 suffix
: ' <small>(0 - unlimited)</small>',
309 value
: nvram
.ftp_max
},
310 { title
: 'Maximum Connections from the same IP', name
: 'ftp_ipmax', type
: 'text', maxlen
: 5, size
: 7,
311 suffix
: ' <small>(0 - unlimited)</small>',
312 value
: nvram
.ftp_ipmax
},
313 { title
: 'Maximum Bandwidth for Anonymous Users', name
: 'ftp_anonrate', type
: 'text', maxlen
: 5, size
: 7,
314 suffix
: ' <small>KBytes/sec (0 - unlimited)</small>',
315 value
: nvram
.ftp_anonrate
},
316 { title
: 'Maximum Bandwidth for Authenticated Users', name
: 'ftp_rate', type
: 'text', maxlen
: 5, size
: 7,
317 suffix
: ' <small>KBytes/sec (0 - unlimited)</small>',
318 value
: nvram
.ftp_rate
},
319 { title
: 'Idle Timeout', name
: 'ftp_staytimeout', type
: 'text', maxlen
: 5, size
: 7,
320 suffix
: ' <small>seconds (0 - no timeout)</small>',
321 value
: nvram
.ftp_staytimeout
},
322 { title
: 'Limit Connection Attempts', name
: 'f_limit', type
: 'checkbox',
323 value
: ftplimit
[0] != 0 },
324 { title
: '', indent
: 2, multi
: [
325 { name
: 'f_limit_hit', type
: 'text', maxlen
: 4, size
: 6, suffix
: ' <small>every</small> ', value
: ftplimit
[1] },
326 { name
: 'f_limit_sec', type
: 'text', maxlen
: 4, size
: 6, suffix
: ' <small>seconds</small>', value
: ftplimit
[2] }
332 <div class='section-title'
>Custom Configuration
</div>
333 <div class='section'
>
334 <script type='text/javascript'
>
335 createFieldTable('', [
336 { 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
}
341 <div class='section-title'
>User Accounts
</div>
342 <div class='section'
>
343 <table class='tomato-grid' cellspacing=
1 id='aft-grid'
></table>
344 <script type='text/javascript'
>aftg
.setup();</script>
346 *
When no Root Directory is specified for the user, the default
"Public Root Directory" is used.
353 <tr><td id='footer' colspan=
2>
354 <span id='footer-msg'
></span>
355 <input type='button' value='Save' id='save-button' onclick='save()'
>
356 <input type='button' value='Cancel' id='cancel-button' onclick='javascript:reloadPage();'
>
360 <script type='text/javascript'
>verifyFields(null, 1);</script>