Hi Guido,
On Thu, Jun 12, 2008 at 05:39:57PM +0200, Guido Günther wrote:
> On Thu, Jun 12, 2008 at 04:01:06PM +0200, Jelmer Vernooij wrote:
> > Hi Guido,
> > Am Donnerstag, den 12.06.2008, 09:51 +0200 schrieb Guido Günther:
> > > On Wed, Jun 11, 2008 at 11:14:52PM +0200, Jelmer Vernooij wrote:
> > > > How should I go about allowing more generic use? Would it be ok to
> > > > break the existing API? Should I add a new call?
> > > I think the API can be extended without breaking it. The current call
> > > sets GSS_AUTH_P_NONE. If you want to setup real message integrity
> > > checking/encryption we can add these as parameters.
> > > We can also skip the part you ripped out by just jumping over it in case
> > > we pass in a NULL/NONE username.
> > Thanks, I'll have a look at doing that.
> Looking at your code this should indeed work out. We can simply skip the
> code you ripped out in case user == NULL in
> authenticate_gss_client_wrap. I should have moved this part into a
> different function in the first place.
Makes sense; I've attached a patch that does this. Does this look ok?
> [..snip..]
> > > I'd be interested to know what kind of respone buffer you pass in in
> > > that case.
> > I'm implementing RFC2228 (GSSAPI Authentication + Encryption for FTP).
> > The attached script extends ftplib.FTP to support GSSAPI logins and
> > provides a very simple command-line FTP client that supports GSSAPI
> > logins. It needs the patch I attached earlier. Feel free to include it
> > in pykerberos as example; I can provide it under a different license if
> > necessary.
> This would make a great example indeed!
Updated version attached as well, with license changed to apache
license.
Cheers,
Jelmer
##
# 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("[EMAIL PROTECTED]" % 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()
=== modified file 'pysrc/kerberos.py'
--- pysrc/kerberos.py 2008-05-23 16:41:18 +0000
+++ pysrc/kerberos.py 2008-06-12 20:58:46 +0000
@@ -146,12 +146,12 @@
@return: a result code (see above)
"""
-def authGSSClientWrap(context, data, user):
+def authGSSClientWrap(context, data, user=None):
"""
Perform the client side GSSAPI wrap step.
@param data:the result of the authGSSClientResponse after the authGSSClientUnwrap
- @param user: the user to authorize
+ @param user: the user to authorize (optional)
@return: a result code (see above)
"""
=== modified file 'src/kerberos.c'
--- src/kerberos.c 2008-05-23 16:40:38 +0000
+++ src/kerberos.c 2008-06-12 20:59:04 +0000
@@ -201,19 +201,25 @@
{
gss_client_state *state;
PyObject *pystate;
- char *challenge, *user;
+ char *challenge, *user = NULL;
int result = 0;
- if (!PyArg_ParseTuple(args, "Oss", &pystate, &challenge, &user) || !PyCObject_Check(pystate))
+ if (!PyArg_ParseTuple(args, "Os|z", &pystate, &challenge, &user) || !PyCObject_Check(pystate))
return NULL;
state = (gss_client_state *)PyCObject_AsVoidPtr(pystate);
if (state == NULL)
return NULL;
- result = authenticate_gss_client_wrap(state, challenge, user);
- if (result == AUTH_GSS_ERROR)
- return NULL;
+ if (user == NULL) {
+ result = authenticate_gss_client_wrap(state, challenge);
+ if (result == AUTH_GSS_ERROR)
+ return NULL;
+ } else {
+ result = authenticate_gss_client_wrap_username(state, challenge, user);
+ if (result == AUTH_GSS_ERROR)
+ return NULL;
+ }
return Py_BuildValue("i", result);
}
=== modified file 'src/kerberosgss.c'
--- src/kerberosgss.c 2008-05-23 16:40:38 +0000
+++ src/kerberosgss.c 2008-06-12 20:53:54 +0000
@@ -309,7 +309,58 @@
return ret;
}
-int authenticate_gss_client_wrap(gss_client_state* state, const char* challenge, const char* user)
+int authenticate_gss_client_wrap(gss_client_state* state, const char* data)
+{
+ OM_uint32 maj_stat;
+ OM_uint32 min_stat;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+ int ret = AUTH_GSS_CONTINUE;
+
+ // Always clear out the old response
+ if (state->response != NULL)
+ {
+ free(state->response);
+ state->response = NULL;
+ }
+
+ if (data && *data)
+ {
+ int len;
+ input_token.value = base64_decode(data, &len);
+ input_token.length = len;
+ }
+
+ // Do GSSAPI wrap
+ maj_stat = gss_wrap(&min_stat,
+ state->context,
+ 0,
+ GSS_C_QOP_DEFAULT,
+ &input_token,
+ NULL,
+ &output_token);
+
+ if (maj_stat != GSS_S_COMPLETE)
+ {
+ set_gss_error(maj_stat, min_stat);
+ ret = AUTH_GSS_ERROR;
+ goto end;
+ }
+ else
+ ret = AUTH_GSS_COMPLETE;
+ // Grab the client response to send back to the server
+ if (output_token.length)
+ {
+ state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
+ maj_stat = gss_release_buffer(&min_stat, &output_token);
+ }
+end:
+ if (output_token.value)
+ gss_release_buffer(&min_stat, &output_token);
+ return ret;
+}
+
+int authenticate_gss_client_wrap_username(gss_client_state* state, const char* challenge, const char* user)
{
OM_uint32 maj_stat;
OM_uint32 min_stat;
=== modified file 'src/kerberosgss.h'
--- src/kerberosgss.h 2008-05-23 16:40:38 +0000
+++ src/kerberosgss.h 2008-06-12 20:51:42 +0000
@@ -53,7 +53,8 @@
int authenticate_gss_client_clean(gss_client_state *state);
int authenticate_gss_client_step(gss_client_state *state, const char *challenge);
int authenticate_gss_client_unwrap(gss_client_state* state, const char* challenge);
-int authenticate_gss_client_wrap(gss_client_state* state, const char* challenge, const char* user);
+int authenticate_gss_client_wrap(gss_client_state* state, const char* challenge);
+int authenticate_gss_client_wrap_username(gss_client_state* state, const char* challenge, const char* user);
int authenticate_gss_server_init(const char* service, gss_server_state* state);
int authenticate_gss_server_clean(gss_server_state *state);
_______________________________________________
calendarserver-dev mailing list
[email protected]
http://lists.macosforge.org/mailman/listinfo.cgi/calendarserver-dev