File: ftp-gss

package info (click to toggle)
pykerberos 1.1%2Bsvn4895-1%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 264 kB
  • sloc: ansic: 1,225; python: 356; makefile: 6
file content (137 lines) | stat: -rwxr-xr-x 4,282 bytes parent folder | download | duplicates (8)
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 <jelmer@samba.org>
#
# 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()