forked from bgamble/pykerberos
-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathftp-gss
executable file
·137 lines (116 loc) · 4.18 KB
/
ftp-gss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python
##
# Copyright (c) 2008 Jelmer Vernooij <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Support for secure authentication using GSSAPI over FTP.
See RFC2228 for details.
"""
from ftplib import *
import base64, ftplib, getpass, kerberos, socket, sys
class SecureFtp(FTP):
"""Extended version of ftplib.FTP that can authenticate using GSSAPI."""
def mic_putcmd(self, line):
rc = kerberos.authGSSClientWrap(self.vc, base64.b64encode(line))
wrapped = kerberos.authGSSClientResponse(self.vc)
FTP.putcmd(self, "MIC " + wrapped)
def mic_getline(self):
resp = FTP.getline(self)
assert resp[:4] == '631 '
rc = kerberos.authGSSClientUnwrap(self.vc, resp[4:].strip("\r\n"))
response = base64.b64decode(kerberos.authGSSClientResponse(self.vc))
return response
def gssapi_login(self, user):
# Try GSSAPI login first
resp = self.sendcmd('AUTH GSSAPI')
if resp[:3] == '334':
rc, self.vc = kerberos.authGSSClientInit("ftp@%s" % self.host)
if kerberos.authGSSClientStep(self.vc, "") != 1:
while resp[:3] in ('334', '335'):
authdata = kerberos.authGSSClientResponse(self.vc)
resp = self.sendcmd('ADAT ' + authdata)
if resp[:9] in ('235 ADAT=', '335 ADAT='):
rc = kerberos.authGSSClientStep(self.vc, resp[9:])
assert ((resp[:3] == '235' and rc == 1) or
(resp[:3] == '335' and rc == 0))
print "Authenticated as %s" % kerberos.authGSSClientUserName(self.vc)
# Monkey patch ftplib
self.putcmd = self.mic_putcmd
self.getline = self.mic_getline
self.sendcmd('USER ' + user)
return resp
def test():
'''Test program.
Usage: ftp [-d] [-u[user]] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...
-d dir
-l list
-u user
'''
from getopt import getopt
if len(sys.argv) < 2:
print test.__doc__
sys.exit(0)
(opts, args) = getopt(sys.argv[1:], "d:u:r:")
debugging = 0
rcfile = None
userid = None
for (k, v) in opts:
if k == "-d":
debugging += 1
elif k == "-u":
userid = v
elif k == "-r":
rcfile = v
host = args[0]
ftp = SecureFtp(host)
ftp.set_debuglevel(debugging)
passwd = acct = ''
try:
netrc = Netrc(rcfile)
except IOError:
if rcfile is not None and userid is None:
sys.stderr.write("Could not open account file"
" -- using anonymous login.")
userid = ''
else:
if userid is None:
try:
userid, passwd, acct = netrc.get_account(host)
except KeyError:
# no account for host
sys.stderr.write(
"No account -- using anonymous login.")
userid = ''
try:
if userid:
ftp.gssapi_login(userid)
else:
ftp.login(userid, passwd, acct)
except ftplib.error_perm, e:
# Fall back to regular authentication
ftp.login(userid, passwd, acct)
for file in args[1:]:
if file[:2] == '-l':
ftp.dir(file[2:])
elif file[:2] == '-d':
cmd = 'CWD'
if file[2:]: cmd = cmd + ' ' + file[2:]
resp = ftp.sendcmd(cmd)
elif file == '-p':
ftp.set_pasv(not ftp.passiveserver)
else:
ftp.retrbinary('RETR ' + file, \
sys.stdout.write, 1024)
ftp.quit()
if __name__ == '__main__':
test()